diff --git a/Tests/test_file_psd.py b/Tests/test_file_psd.py index a376ba2e887..1047c294438 100644 --- a/Tests/test_file_psd.py +++ b/Tests/test_file_psd.py @@ -9,6 +9,7 @@ from PIL import Image, PsdImagePlugin from .helper import ( + assert_image_equal, assert_image_equal_tofile, assert_image_similar, hopper, @@ -111,6 +112,17 @@ def test_seek_tell() -> None: assert layer_number == 2 +def test_seek_back_to_initial_frame() -> None: + # Seeking away from the initial frame and then back should produce the same image + with Image.open(test_file) as im: + initial_frame = im.copy() + + im.seek(2) + im.seek(1) + + assert_image_equal(im, initial_frame) + + def test_seek_eoferror() -> None: with Image.open(test_file) as im: with pytest.raises(EOFError): @@ -228,11 +240,5 @@ def test_bounds_crash_overflow() -> None: with Image.open("Tests/images/psd-oob-write-overflow.psd") as im: assert isinstance(im, PsdImagePlugin.PsdImageFile) im.load() - if sys.maxsize <= 2**32: - with pytest.raises(OverflowError): - im.seek(im.n_frames) - else: + with pytest.raises(OverflowError if sys.maxsize <= 2**32 else ValueError): im.seek(im.n_frames) - - with pytest.raises(ValueError): - im.load() diff --git a/docs/releasenotes/13.0.0.rst b/docs/releasenotes/13.0.0.rst index b9906b7f19d..54ef1308952 100644 --- a/docs/releasenotes/13.0.0.rst +++ b/docs/releasenotes/13.0.0.rst @@ -228,3 +228,10 @@ position or contents. :py:meth:`~PIL.Image.Image.tobytes` also now explicitly cleans up its encoder on both success and failure, rather than relying on object destruction. + +Fixed reading PSD layers at the wrong file offset +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When seeking to a layer of a PSD image, the pixel data was read from the wrong +position in the file, so :py:meth:`~PIL.Image.Image.seek` returned unrelated +bytes reinterpreted as image data instead of that layer's actual content. diff --git a/src/PIL/PsdImagePlugin.py b/src/PIL/PsdImagePlugin.py index e39843e9dc8..4bd6b3b90aa 100644 --- a/src/PIL/PsdImagePlugin.py +++ b/src/PIL/PsdImagePlugin.py @@ -158,8 +158,7 @@ def layers( if isinstance(self._fp, DeferredError): raise self._fp.ex self._fp.seek(self._layers_position) - _layer_data = io.BytesIO(ImageFile._safe_read(self._fp, self._layers_size)) - layers = _layerinfo(_layer_data, self._layers_size) + layers = _layerinfo(self._fp, self._layers_size) self._n_frames = len(layers) return layers