Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent TIFF orientation from being applied more than once #7383

Merged
merged 4 commits into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion Tests/test_file_libtiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import pytest

from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags, features
from PIL import Image, ImageFilter, ImageOps, TiffImagePlugin, TiffTags, features
from PIL.TiffImagePlugin import SAMPLEFORMAT, STRIPOFFSETS, SUBIFD

from .helper import (
Expand Down Expand Up @@ -1035,7 +1035,18 @@ def test_orientation(self):
with Image.open("Tests/images/g4_orientation_1.tif") as base_im:
for i in range(2, 9):
with Image.open("Tests/images/g4_orientation_" + str(i) + ".tif") as im:
assert 274 in im.tag_v2

im.load()
assert 274 not in im.tag_v2

assert_image_similar(base_im, im, 0.7)

def test_exif_transpose(self):
with Image.open("Tests/images/g4_orientation_1.tif") as base_im:
for i in range(2, 9):
with Image.open("Tests/images/g4_orientation_" + str(i) + ".tif") as im:
im = ImageOps.exif_transpose(im)

assert_image_similar(base_im, im, 0.7)

Expand Down
5 changes: 5 additions & 0 deletions src/PIL/ImageOps.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,7 @@ def exif_transpose(image, *, in_place=False):
with the transposition applied. If there is no transposition, a copy of the
image will be returned.
"""
image.load()
image_exif = image.getexif()
orientation = image_exif.get(ExifTags.Base.Orientation)
method = {
Expand All @@ -610,6 +611,10 @@ def exif_transpose(image, *, in_place=False):
exif = exif_image.getexif()
if ExifTags.Base.Orientation in exif:
del exif[ExifTags.Base.Orientation]
if in_place and ExifTags.Base.Orientation in getattr(
exif_image, "tag_v2", {}
homm marked this conversation as resolved.
Show resolved Hide resolved
):
del exif_image.tag_v2[ExifTags.Base.Orientation]
if "exif" in exif_image.info:
exif_image.info["exif"] = exif.tobytes()
elif "Raw profile type exif" in exif_image.info:
Expand Down
18 changes: 2 additions & 16 deletions src/PIL/TiffImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1203,20 +1203,6 @@ def load(self):
return super().load()

def load_end(self):
if self._tile_orientation:
method = {
2: Image.Transpose.FLIP_LEFT_RIGHT,
3: Image.Transpose.ROTATE_180,
4: Image.Transpose.FLIP_TOP_BOTTOM,
5: Image.Transpose.TRANSPOSE,
6: Image.Transpose.ROTATE_270,
7: Image.Transpose.TRANSVERSE,
8: Image.Transpose.ROTATE_90,
}.get(self._tile_orientation)
if method is not None:
self.im = self.im.transpose(method)
self._size = self.im.size

# allow closing if we're on the first frame, there's no next
# This is the ImageFile.load path only, libtiff specific below.
if not self.is_animated:
Expand All @@ -1233,6 +1219,8 @@ def load_end(self):
continue
exif.get_ifd(key)

ImageOps.exif_transpose(self, in_place=True)

def _load_libtiff(self):
"""Overload method triggered when we detect a compressed tiff
Calls out to libtiff"""
Expand Down Expand Up @@ -1542,8 +1530,6 @@ def _setup(self):
palette = [o8(b // 256) for b in self.tag_v2[COLORMAP]]
self.palette = ImagePalette.raw("RGB;L", b"".join(palette))

self._tile_orientation = self.tag_v2.get(ExifTags.Base.Orientation)


#
# --------------------------------------------------------------------
Expand Down