Skip to content

Commit

Permalink
Do not read layers when opening
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed May 2, 2024
1 parent 58a4797 commit 02c17be
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 14 deletions.
24 changes: 15 additions & 9 deletions Tests/test_file_psd.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import pytest

from PIL import Image, PsdImagePlugin, UnidentifiedImageError
from PIL import Image, PsdImagePlugin

from .helper import assert_image_equal_tofile, assert_image_similar, hopper, is_pypy

Expand Down Expand Up @@ -150,14 +150,6 @@ def test_combined_larger_than_size() -> None:
@pytest.mark.parametrize(
"test_file,raises",
[
(
"Tests/images/timeout-1ee28a249896e05b83840ae8140622de8e648ba9.psd",
UnidentifiedImageError,
),
(
"Tests/images/timeout-598843abc37fc080ec36a2699ebbd44f795d3a6f.psd",
UnidentifiedImageError,
),
("Tests/images/timeout-c8efc3fded6426986ba867a399791bae544f59bc.psd", OSError),
("Tests/images/timeout-dedc7a4ebd856d79b4359bbcc79e8ef231ce38f6.psd", OSError),
],
Expand All @@ -167,3 +159,17 @@ def test_crashes(test_file: str, raises) -> None:
with pytest.raises(raises):
with Image.open(f):
pass


@pytest.mark.parametrize(
"test_file",
[
"Tests/images/timeout-1ee28a249896e05b83840ae8140622de8e648ba9.psd",
"Tests/images/timeout-598843abc37fc080ec36a2699ebbd44f795d3a6f.psd",
],
)
def test_layer_crashes(test_file: str) -> None:
with open(test_file, "rb") as f:
with Image.open(f) as im:
with pytest.raises(SyntaxError):
im.layers
30 changes: 25 additions & 5 deletions src/PIL/PsdImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from __future__ import annotations

import io
from functools import cached_property

Check warning on line 21 in src/PIL/PsdImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/PsdImagePlugin.py#L21

Added line #L21 was not covered by tests

from . import Image, ImageFile, ImagePalette
from ._binary import i8
Expand Down Expand Up @@ -118,18 +119,17 @@ def _open(self):
#
# layer and mask information

self.layers = []
self._layers_position = None

Check warning on line 122 in src/PIL/PsdImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/PsdImagePlugin.py#L122

Added line #L122 was not covered by tests

size = i32(read(4))
if size:
end = self.fp.tell() + size
size = i32(read(4))
if size:
_layer_data = io.BytesIO(ImageFile._safe_read(self.fp, size))
self.layers = _layerinfo(_layer_data, size)
self._layers_position = self.fp.tell()
self._layers_size = size

Check warning on line 130 in src/PIL/PsdImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/PsdImagePlugin.py#L129-L130

Added lines #L129 - L130 were not covered by tests
self.fp.seek(end)
self.n_frames = len(self.layers)
self.is_animated = self.n_frames > 1
self._n_frames = None

Check warning on line 132 in src/PIL/PsdImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/PsdImagePlugin.py#L132

Added line #L132 was not covered by tests

#
# image descriptor
Expand All @@ -141,6 +141,26 @@ def _open(self):
self.frame = 1
self._min_frame = 1

@cached_property
def layers(self):
layers = []
if self._layers_position is not None:
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)
self._n_frames = len(layers)
return layers

Check warning on line 152 in src/PIL/PsdImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/PsdImagePlugin.py#L144-L152

Added lines #L144 - L152 were not covered by tests

@property
def n_frames(self):
if self._n_frames is None:
self._n_frames = len(self.layers)
return self._n_frames

Check warning on line 158 in src/PIL/PsdImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/PsdImagePlugin.py#L154-L158

Added lines #L154 - L158 were not covered by tests

@property
def is_animated(self):
return len(self.layers) > 1

Check warning on line 162 in src/PIL/PsdImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/PsdImagePlugin.py#L160-L162

Added lines #L160 - L162 were not covered by tests

def seek(self, layer):
if not self._seek_check(layer):
return
Expand Down

0 comments on commit 02c17be

Please sign in to comment.