Added ImageOps auto_transpose

This commit is contained in:
Andrew Murray 2019-09-13 20:10:05 +10:00
parent 929c817014
commit aa7efbbbc9
10 changed files with 80 additions and 34 deletions

BIN
Tests/images/g4_orientation_1.tif Executable file

Binary file not shown.

BIN
Tests/images/g4_orientation_2.tif Executable file

Binary file not shown.

BIN
Tests/images/g4_orientation_3.tif Executable file

Binary file not shown.

BIN
Tests/images/g4_orientation_4.tif Executable file

Binary file not shown.

BIN
Tests/images/g4_orientation_5.tif Executable file

Binary file not shown.

BIN
Tests/images/g4_orientation_6.tif Executable file

Binary file not shown.

BIN
Tests/images/g4_orientation_7.tif Executable file

Binary file not shown.

BIN
Tests/images/g4_orientation_8.tif Executable file

Binary file not shown.

View File

@ -70,6 +70,9 @@ class TestImageOps(PillowTestCase):
ImageOps.exif_transpose(hopper("L")) ImageOps.exif_transpose(hopper("L"))
ImageOps.exif_transpose(hopper("RGB")) ImageOps.exif_transpose(hopper("RGB"))
ImageOps.auto_transpose(hopper("L"))
ImageOps.auto_transpose(hopper("RGB"))
def test_1pxfit(self): def test_1pxfit(self):
# Division by zero in equalize if image is 1 pixel high # Division by zero in equalize if image is 1 pixel high
newimg = ImageOps.fit(hopper("RGB").resize((1, 1)), (35, 35)) newimg = ImageOps.fit(hopper("RGB").resize((1, 1)), (35, 35))
@ -250,28 +253,47 @@ class TestImageOps(PillowTestCase):
exts = [".jpg"] exts = [".jpg"]
if HAVE_WEBP and _webp.HAVE_WEBPANIM: if HAVE_WEBP and _webp.HAVE_WEBPANIM:
exts.append(".webp") exts.append(".webp")
for ext in exts: for transpose in [ImageOps.exif_transpose, ImageOps.auto_transpose]:
base_im = Image.open("Tests/images/hopper" + ext) for ext in exts:
base_im = Image.open("Tests/images/hopper" + ext)
orientations = [base_im] orientations = [base_im]
for i in range(2, 9): for i in range(2, 9):
im = Image.open("Tests/images/hopper_orientation_" + str(i) + ext) im = Image.open("Tests/images/hopper_orientation_" + str(i) + ext)
orientations.append(im) orientations.append(im)
for i, orientation_im in enumerate(orientations): for i, orientation_im in enumerate(orientations):
for im in [orientation_im, orientation_im.copy()]: # ImageFile # Image for im in [
if i == 0: orientation_im,
self.assertNotIn("exif", im.info) orientation_im.copy(),
else: ]: # ImageFile # Image
original_exif = im.info["exif"] if i == 0:
transposed_im = ImageOps.exif_transpose(im) self.assertNotIn("exif", im.info)
self.assert_image_similar(base_im, transposed_im, 17) else:
if i == 0: original_exif = im.info["exif"]
self.assertNotIn("exif", im.info) transposed_im = transpose(im)
else: self.assert_image_similar(base_im, transposed_im, 17)
self.assertNotEqual(transposed_im.info["exif"], original_exif) if i == 0:
self.assertNotIn("exif", im.info)
else:
self.assertNotEqual(
transposed_im.info["exif"], original_exif
)
self.assertNotIn(0x0112, transposed_im.getexif()) self.assertNotIn(0x0112, transposed_im.getexif())
# Repeat the operation, to test that it does not keep transposing # Repeat the operation,
transposed_im2 = ImageOps.exif_transpose(transposed_im) # to test that it does not keep transposing
self.assert_image_equal(transposed_im2, transposed_im) transposed_im2 = transpose(transposed_im)
self.assert_image_equal(transposed_im2, transposed_im)
def test_auto_transpose(self):
base_im = Image.open("Tests/images/g4_orientation_1.tif")
for i in range(2, 9):
im = Image.open("Tests/images/g4_orientation_" + str(i) + ".tif")
transposed_im = ImageOps.auto_transpose(im)
self.assert_image_similar(base_im, transposed_im, 0.7)
# Repeat the operation, to test that it does not keep transposing
transposed_im2 = ImageOps.auto_transpose(transposed_im)
self.assert_image_equal(transposed_im2, transposed_im)

View File

@ -520,16 +520,7 @@ def solarize(image, threshold=128):
return _lut(image, lut) return _lut(image, lut)
def exif_transpose(image): def _transpose(image, orientation, exif=None):
"""
If an image has an EXIF Orientation tag, return a new image that is
transposed accordingly. Otherwise, return a copy of the image.
:param image: The image to transpose.
:return: An image.
"""
exif = image.getexif()
orientation = exif.get(0x0112)
method = { method = {
2: Image.FLIP_LEFT_RIGHT, 2: Image.FLIP_LEFT_RIGHT,
3: Image.ROTATE_180, 3: Image.ROTATE_180,
@ -541,7 +532,40 @@ def exif_transpose(image):
}.get(orientation) }.get(orientation)
if method is not None: if method is not None:
transposed_image = image.transpose(method) transposed_image = image.transpose(method)
del exif[0x0112] if exif:
transposed_image.info["exif"] = exif.tobytes() del exif[0x0112]
transposed_image.info["exif"] = exif.tobytes()
return transposed_image return transposed_image
return image.copy() return image.copy()
def exif_transpose(image):
"""
If an image has an EXIF Orientation tag, return a new image that is
transposed accordingly. Otherwise, return a copy of the image.
:param image: The image to transpose.
:return: An image.
"""
exif = image.getexif()
orientation = exif.get(0x0112)
return _transpose(image, orientation, exif)
def auto_transpose(image):
"""
If an image has an EXIF or TIFF Orientation tag, return a new image that is
transposed accordingly. Otherwise, return a copy of the image.
:param image: The image to transpose.
:return: An image.
"""
exif = image.getexif()
orientation = exif.get(0x0112)
if orientation and orientation != 1:
return _transpose(image, orientation, exif)
elif hasattr(image, "tag_v2"):
orientation = image.tag_v2.get(0x0112)
return _transpose(image, orientation)
else:
return image.copy()