Added inPlace argument to exif_transpose()

This commit is contained in:
Andrew Murray 2023-04-15 21:03:59 +10:00
parent 8740e32619
commit 8d3014b8bf
3 changed files with 42 additions and 21 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 B

View File

@ -404,6 +404,18 @@ def test_exif_transpose():
assert 0x0112 not in transposed_im.getexif() assert 0x0112 not in transposed_im.getexif()
def test_exif_transpose_inplace():
with Image.open("Tests/images/orientation_rectangle.jpg") as im:
assert im.size == (2, 1)
assert im.getexif()[0x0112] == 8
expected = im.rotate(90, expand=True)
ImageOps.exif_transpose(im, inPlace=True)
assert im.size == (1, 2)
assert 0x0112 not in im.getexif()
assert_image_equal(im, expected)
def test_autocontrast_cutoff(): def test_autocontrast_cutoff():
# Test the cutoff argument of autocontrast # Test the cutoff argument of autocontrast
with Image.open("Tests/images/bw_gradient.png") as img: with Image.open("Tests/images/bw_gradient.png") as img:

View File

@ -576,19 +576,20 @@ def solarize(image, threshold=128):
return _lut(image, lut) return _lut(image, lut)
def exif_transpose(image): def exif_transpose(image, inPlace=False):
""" """
If an image has an EXIF Orientation tag, other than 1, return a new image If an image has an EXIF Orientation tag, other than 1, transpose the image
that is transposed accordingly. The new image will have the orientation accordingly, and remove the orientation data.
data removed.
Otherwise, return a copy of the image.
:param image: The image to transpose. :param image: The image to transpose.
:return: An image. :param inPlace: Boolean.
If ``True``, the original image is modified in-place, and ``None`` is returned.
If ``False`` (default), a new :py:class:`~PIL.Image.Image` object is returned
with the transposition applied. If there is no transposition, a copy of the
image will be returned.
""" """
exif = image.getexif() image_exif = image.getexif()
orientation = exif.get(0x0112) orientation = image_exif.get(0x0112)
method = { method = {
2: Image.Transpose.FLIP_LEFT_RIGHT, 2: Image.Transpose.FLIP_LEFT_RIGHT,
3: Image.Transpose.ROTATE_180, 3: Image.Transpose.ROTATE_180,
@ -600,22 +601,30 @@ 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)
transposed_exif = transposed_image.getexif() if inPlace:
if 0x0112 in transposed_exif: image.im = transposed_image.im
del transposed_exif[0x0112] image.pyaccess = None
if "exif" in transposed_image.info: image._size = transposed_image._size
transposed_image.info["exif"] = transposed_exif.tobytes() exif_image = image if inPlace else transposed_image
elif "Raw profile type exif" in transposed_image.info:
transposed_image.info[ exif = exif_image.getexif()
"Raw profile type exif" if 0x0112 in exif:
] = transposed_exif.tobytes().hex() del exif[0x0112]
elif "XML:com.adobe.xmp" in transposed_image.info: if "exif" in exif_image.info:
exif_image.info["exif"] = exif.tobytes()
elif "Raw profile type exif" in exif_image.info:
exif_image.info["Raw profile type exif"] = exif.tobytes().hex()
elif "XML:com.adobe.xmp" in exif_image.info:
for pattern in ( for pattern in (
r'tiff:Orientation="([0-9])"', r'tiff:Orientation="([0-9])"',
r"<tiff:Orientation>([0-9])</tiff:Orientation>", r"<tiff:Orientation>([0-9])</tiff:Orientation>",
): ):
transposed_image.info["XML:com.adobe.xmp"] = re.sub( exif_image.info["XML:com.adobe.xmp"] = re.sub(
pattern, "", transposed_image.info["XML:com.adobe.xmp"] pattern, "", exif_image.info["XML:com.adobe.xmp"]
) )
if inPlace:
return
return transposed_image return transposed_image
if inPlace:
return
return image.copy() return image.copy()