From 5377b0735f44ad78184a1b0092a327e22203a02a Mon Sep 17 00:00:00 2001 From: Ishant Mrinal Haloi Date: Thu, 4 May 2023 21:43:57 +0530 Subject: [PATCH 1/9] add _repr_jpg_ for ipython display Signed-off-by: Ishant Mrinal Haloi --- Tests/test_file_jpeg.py | 13 +++++++++++++ src/PIL/Image.py | 23 ++++++++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 73a00386f6f..3676c8f0746 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -922,6 +922,19 @@ def closure(mode, *args): im.load() ImageFile.LOAD_TRUNCATED_IMAGES = False + def test_repr_jpg(self): + im = hopper() + + with Image.open(BytesIO(im._repr_jpg_())) as repr_jpg: + assert repr_jpg.format == "JPEG" + assert_image_equal(im, repr_jpg) + + def test_repr_jpg_error(self): + im = hopper("F") + + with pytest.raises(ValueError): + im._repr_jpg_() + @pytest.mark.skipif(not is_win32(), reason="Windows only") @skip_unless_feature("jpg") diff --git a/src/PIL/Image.py b/src/PIL/Image.py index bee9e23d088..557810f6c1f 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -633,19 +633,36 @@ def _repr_pretty_(self, p, cycle): ) ) - def _repr_png_(self): + def _repr_image(self, format): """iPython display hook support + :param format: Image format. :returns: png version of the image as bytes """ b = io.BytesIO() try: - self.save(b, "PNG") + self.save(b, format) except Exception as e: - msg = "Could not save to PNG for display" + msg = f"Could not save to {format} for display" raise ValueError(msg) from e return b.getvalue() + def _repr_png_(self): + """iPython display hook support for PNG format. + + :returns: png version of the image as bytes + """ + return self._repr_image("PNG") + + def _repr_jpg_(self): + """iPython display hook support for JPEG format. + + :returns: jpg version of the image as bytes + """ + return self._repr_image("JPEG") + + _repr_jpeg_ = _repr_jpg_ + @property def __array_interface__(self): # numpy array interface support From 93e507294bb5f54ea8ac43a596fd0d2677e2cdad Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 5 May 2023 08:19:43 +1000 Subject: [PATCH 2/9] Only assert image is similar --- Tests/test_file_jpeg.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 3676c8f0746..0247527f5b2 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -922,18 +922,18 @@ def closure(mode, *args): im.load() ImageFile.LOAD_TRUNCATED_IMAGES = False - def test_repr_jpg(self): + def test_repr_jpeg(self): im = hopper() - with Image.open(BytesIO(im._repr_jpg_())) as repr_jpg: - assert repr_jpg.format == "JPEG" - assert_image_equal(im, repr_jpg) + with Image.open(BytesIO(im._repr_jpeg_())) as repr_jpeg: + assert repr_jpeg.format == "JPEG" + assert_image_similar(im, repr_jpeg, 17) - def test_repr_jpg_error(self): + def test_repr_jpeg_error(self): im = hopper("F") with pytest.raises(ValueError): - im._repr_jpg_() + im._repr_jpeg_() @pytest.mark.skipif(not is_win32(), reason="Windows only") From 2d841e16c2d7b16f6fe0b156c79a13affd9ac630 Mon Sep 17 00:00:00 2001 From: Ishant Mrinal Haloi Date: Sat, 6 May 2023 10:31:58 +0530 Subject: [PATCH 3/9] Apply suggestions from code review Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- src/PIL/Image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 557810f6c1f..3c0094817c5 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -637,7 +637,7 @@ def _repr_image(self, format): """iPython display hook support :param format: Image format. - :returns: png version of the image as bytes + :returns: image as bytes, saved into the given format. """ b = io.BytesIO() try: From ccdce1791dab1e754df17d21a771c8ac073b7c58 Mon Sep 17 00:00:00 2001 From: Ishant Mrinal Haloi Date: Sat, 6 May 2023 10:35:28 +0530 Subject: [PATCH 4/9] rename format to image_format --- src/PIL/Image.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 3c0094817c5..33984e59416 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -633,17 +633,17 @@ def _repr_pretty_(self, p, cycle): ) ) - def _repr_image(self, format): + def _repr_image(self, image_format): """iPython display hook support - :param format: Image format. + :param image_format: Image format. :returns: image as bytes, saved into the given format. """ b = io.BytesIO() try: - self.save(b, format) + self.save(b, image_format) except Exception as e: - msg = f"Could not save to {format} for display" + msg = f"Could not save to {image_format} for display" raise ValueError(msg) from e return b.getvalue() From 46708099b10a99b3d35d7eae624e83daa6d67bf9 Mon Sep 17 00:00:00 2001 From: Ishant Mrinal Haloi Date: Fri, 12 May 2023 21:56:40 +0530 Subject: [PATCH 5/9] Apply suggestions from code review Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- src/PIL/Image.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 33984e59416..21305d52a4e 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -654,15 +654,13 @@ def _repr_png_(self): """ return self._repr_image("PNG") - def _repr_jpg_(self): + def _repr_jpeg_(self): """iPython display hook support for JPEG format. :returns: jpg version of the image as bytes """ return self._repr_image("JPEG") - _repr_jpeg_ = _repr_jpg_ - @property def __array_interface__(self): # numpy array interface support From 2db9c68571f3be1d29888b3497f4e2af518a2d36 Mon Sep 17 00:00:00 2001 From: Ishant Mrinal Haloi Date: Sat, 13 May 2023 07:32:02 +0530 Subject: [PATCH 6/9] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ondrej Baranovič <3819630+nulano@users.noreply.github.com> Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- src/PIL/Image.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 21305d52a4e..3522ff6d017 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -634,8 +634,7 @@ def _repr_pretty_(self, p, cycle): ) def _repr_image(self, image_format): - """iPython display hook support - + """Helper function for iPython display hook :param image_format: Image format. :returns: image as bytes, saved into the given format. """ @@ -657,7 +656,7 @@ def _repr_png_(self): def _repr_jpeg_(self): """iPython display hook support for JPEG format. - :returns: jpg version of the image as bytes + :returns: jpeg version of the image as bytes """ return self._repr_image("JPEG") From 59b7a48570cd9c7a2fae1e0876c5072bdd780338 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 13 May 2023 12:24:50 +1000 Subject: [PATCH 7/9] Updated docstrings --- src/PIL/Image.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 3522ff6d017..105c83a8b95 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -634,7 +634,8 @@ def _repr_pretty_(self, p, cycle): ) def _repr_image(self, image_format): - """Helper function for iPython display hook + """Helper function for iPython display hook. + :param image_format: Image format. :returns: image as bytes, saved into the given format. """ @@ -1122,7 +1123,6 @@ def quantize( Available methods are :data:`Dither.NONE` or :data:`Dither.FLOYDSTEINBERG` (default). :returns: A new image - """ self.load() From f3283837630e25f88f1d8f73961c898d88ab1aee Mon Sep 17 00:00:00 2001 From: Ishant Mrinal Haloi Date: Sun, 14 May 2023 11:11:56 +0530 Subject: [PATCH 8/9] Apply suggestions from code review Co-authored-by: Hugo van Kemenade --- src/PIL/Image.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 105c83a8b95..e0fb6a8858c 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -650,14 +650,14 @@ def _repr_image(self, image_format): def _repr_png_(self): """iPython display hook support for PNG format. - :returns: png version of the image as bytes + :returns: PNG version of the image as bytes """ return self._repr_image("PNG") def _repr_jpeg_(self): """iPython display hook support for JPEG format. - :returns: jpeg version of the image as bytes + :returns: JPEG version of the image as bytes """ return self._repr_image("JPEG") From 9754c8d18dc8f013193d18810b9de4f2b68694ff Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 14 May 2023 22:42:39 +1000 Subject: [PATCH 9/9] Added release notes --- docs/releasenotes/10.0.0.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/releasenotes/10.0.0.rst b/docs/releasenotes/10.0.0.rst index e2005b710e6..ececfa20d74 100644 --- a/docs/releasenotes/10.0.0.rst +++ b/docs/releasenotes/10.0.0.rst @@ -160,6 +160,18 @@ TODO Other Changes ============= +Support display_jpeg() in IPython +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In addition to ``display()`` and ``display_png``, ``display_jpeg()`` can now +also be used to display images in IPython:: + + from PIL import Image + from IPython.display import display_jpeg + + im = Image.new("RGB", (100, 100), (255, 0, 0)) + display_jpeg(im) + Support reading signed 8-bit TIFF images ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^