Skip to content
13 changes: 13 additions & 0 deletions Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
23 changes: 20 additions & 3 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -633,19 +633,36 @@ def _repr_pretty_(self, p, cycle):
)
)

def _repr_png_(self):
def _repr_image(self, format):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we change format to something that doesn't shadow a builtin?

"""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
Expand Down