Merge pull request #8390 from radarhere/tiff_exif_transpose

Use transposed size after opening for TIFF images
This commit is contained in:
Hugo van Kemenade 2024-09-18 22:35:01 +03:00 committed by GitHub
commit 1ee3bd1d9e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 32 additions and 32 deletions

View File

@ -49,5 +49,7 @@ def test_copy_zero() -> None:
@skip_unless_feature("libtiff") @skip_unless_feature("libtiff")
def test_deepcopy() -> None: def test_deepcopy() -> None:
with Image.open("Tests/images/g4_orientation_5.tif") as im: with Image.open("Tests/images/g4_orientation_5.tif") as im:
assert im.size == (590, 88)
out = copy.deepcopy(im) out = copy.deepcopy(im)
assert out.size == (590, 88) assert out.size == (590, 88)

View File

@ -300,9 +300,7 @@ class TestImageResize:
im.resize((10, 10), "unknown") im.resize((10, 10), "unknown")
@skip_unless_feature("libtiff") @skip_unless_feature("libtiff")
def test_load_first(self) -> None: def test_transposed(self) -> None:
# load() may change the size of the image
# Test that resize() is calling it before getting the size
with Image.open("Tests/images/g4_orientation_5.tif") as im: with Image.open("Tests/images/g4_orientation_5.tif") as im:
im = im.resize((64, 64)) im = im.resize((64, 64))
assert im.size == (64, 64) assert im.size == (64, 64)

View File

@ -92,15 +92,13 @@ def test_no_resize() -> None:
@skip_unless_feature("libtiff") @skip_unless_feature("libtiff")
def test_load_first() -> None: def test_transposed() -> None:
# load() may change the size of the image
# Test that thumbnail() is calling it before performing size calculations
with Image.open("Tests/images/g4_orientation_5.tif") as im: with Image.open("Tests/images/g4_orientation_5.tif") as im:
assert im.size == (590, 88)
im.thumbnail((64, 64)) im.thumbnail((64, 64))
assert im.size == (64, 10) assert im.size == (64, 10)
# Test thumbnail(), without draft(),
# on an image that is large enough once load() has changed the size
with Image.open("Tests/images/g4_orientation_5.tif") as im: with Image.open("Tests/images/g4_orientation_5.tif") as im:
im.thumbnail((590, 88), reducing_gap=None) im.thumbnail((590, 88), reducing_gap=None)
assert im.size == (590, 88) assert im.size == (590, 88)

View File

@ -238,8 +238,10 @@ def test_zero_size() -> None:
@skip_unless_feature("libtiff") @skip_unless_feature("libtiff")
def test_load_first() -> None: def test_transposed() -> None:
with Image.open("Tests/images/g4_orientation_5.tif") as im: with Image.open("Tests/images/g4_orientation_5.tif") as im:
assert im.size == (590, 88)
a = numpy.array(im) a = numpy.array(im)
assert a.shape == (88, 590) assert a.shape == (88, 590)

View File

@ -2332,7 +2332,6 @@ class Image:
msg = "reducing_gap must be 1.0 or greater" msg = "reducing_gap must be 1.0 or greater"
raise ValueError(msg) raise ValueError(msg)
self.load()
if box is None: if box is None:
box = (0, 0) + self.size box = (0, 0) + self.size
@ -2781,27 +2780,18 @@ class Image:
) )
return x, y return x, y
box = None preserved_size = preserve_aspect_ratio()
final_size: tuple[int, int] if preserved_size is None:
if reducing_gap is not None: return
preserved_size = preserve_aspect_ratio() final_size = preserved_size
if preserved_size is None:
return
final_size = preserved_size
box = None
if reducing_gap is not None:
res = self.draft( res = self.draft(
None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap)) None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap))
) )
if res is not None: if res is not None:
box = res[1] box = res[1]
if box is None:
self.load()
# load() may have changed the size of the image
preserved_size = preserve_aspect_ratio()
if preserved_size is None:
return
final_size = preserved_size
if self.size != final_size: if self.size != final_size:
im = self.resize(final_size, resample, box=box, reducing_gap=reducing_gap) im = self.resize(final_size, resample, box=box, reducing_gap=reducing_gap)

View File

@ -322,7 +322,7 @@ class ImageFile(Image.Image):
def load_prepare(self) -> None: def load_prepare(self) -> None:
# create image memory if necessary # create image memory if necessary
if self._im is None or self.im.mode != self.mode or self.im.size != self.size: if self._im is None:
self.im = Image.core.new(self.mode, self.size) self.im = Image.core.new(self.mode, self.size)
# create palette (optional) # create palette (optional)
if self.mode == "P": if self.mode == "P":

View File

@ -1194,8 +1194,8 @@ class TiffImageFile(ImageFile.ImageFile):
# Create a new core image object on second and # Create a new core image object on second and
# subsequent frames in the image. Image may be # subsequent frames in the image. Image may be
# different size/mode. # different size/mode.
Image._decompression_bomb_check(self.size) Image._decompression_bomb_check(self._tile_size)
self.im = Image.core.new(self.mode, self.size) self.im = Image.core.new(self.mode, self._tile_size)
def _seek(self, frame: int) -> None: def _seek(self, frame: int) -> None:
self.fp = self._fp self.fp = self._fp
@ -1275,6 +1275,11 @@ class TiffImageFile(ImageFile.ImageFile):
return self._load_libtiff() return self._load_libtiff()
return super().load() return super().load()
def load_prepare(self) -> None:
if self._im is None:
self.im = Image.core.new(self.mode, self._tile_size)
ImageFile.ImageFile.load_prepare(self)
def load_end(self) -> None: def load_end(self) -> None:
# allow closing if we're on the first frame, there's no next # allow closing if we're on the first frame, there's no next
# This is the ImageFile.load path only, libtiff specific below. # This is the ImageFile.load path only, libtiff specific below.
@ -1416,7 +1421,12 @@ class TiffImageFile(ImageFile.ImageFile):
if not isinstance(xsize, int) or not isinstance(ysize, int): if not isinstance(xsize, int) or not isinstance(ysize, int):
msg = "Invalid dimensions" msg = "Invalid dimensions"
raise ValueError(msg) raise ValueError(msg)
self._size = xsize, ysize self._tile_size = xsize, ysize
orientation = self.tag_v2.get(ExifTags.Base.Orientation)
if orientation in (5, 6, 7, 8):
self._size = ysize, xsize
else:
self._size = xsize, ysize
logger.debug("- size: %s", self.size) logger.debug("- size: %s", self.size)
@ -1559,7 +1569,7 @@ class TiffImageFile(ImageFile.ImageFile):
if STRIPOFFSETS in self.tag_v2: if STRIPOFFSETS in self.tag_v2:
offsets = self.tag_v2[STRIPOFFSETS] offsets = self.tag_v2[STRIPOFFSETS]
h = self.tag_v2.get(ROWSPERSTRIP, ysize) h = self.tag_v2.get(ROWSPERSTRIP, ysize)
w = self.size[0] w = xsize
else: else:
# tiled image # tiled image
offsets = self.tag_v2[TILEOFFSETS] offsets = self.tag_v2[TILEOFFSETS]
@ -1593,9 +1603,9 @@ class TiffImageFile(ImageFile.ImageFile):
) )
) )
x = x + w x = x + w
if x >= self.size[0]: if x >= xsize:
x, y = 0, y + h x, y = 0, y + h
if y >= self.size[1]: if y >= ysize:
x = y = 0 x = y = 0
layer += 1 layer += 1
else: else: