Skip to content

exif_transpose overwrites the original image exif #5546

@artemisart

Description

@artemisart

What did you do?

Use ImageOps.exif_tranpose on an image with an EXIF orientation code (not in [None, 0, 1]).

What did you expect to happen?

exif_transpose() should be immutable and returns a new image with the correct orientation.

What actually happened?

exif_transpose() returns a new image but also modifies the original image exif info in-place (deletes the orientation, key 0x112).
It's a pretty big problem if your work with rotated images because it breaks the original images, if you e.g. call again exif_transpose() on it the EXIF orientation value is not there but the image content is not correctly rotated.

What are your OS, Python and Pillow versions?

  • OS: ubuntu 18.04
  • Python: 3.8.8
  • Pillow: 8.2.0

Code

import PIL, PIL.ImageOps
# if you have an image with exif
pil = PIL.Image.open(file)
# otherwise
import requests
resp = requests.get('https://raw.githubusercontent.com/recurser/exif-orientation-examples/master/Portrait_3.jpg', stream=True)
resp.raw.decode_content = True
pil = PIL.Image.open(resp.raw)

print(pil.getexif().get(0x0112))  # 3
correct_image = PIL.ImageOps.exif_transpose(pil)
print(pil.getexif().get(0x0112))  # None, but should be 3

Proposed fix

Replace the first line of exif_tranpose in https://pillow.readthedocs.io/en/stable/_modules/PIL/ImageOps.html#exif_transpose with

from copy import deepcopy  # copy may be enough, I didn't try it

-    exif = image.getexif()
+    exif = deepcopy(image.getexif())

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugAny unexpected behavior, until confirmed feature.Exif

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions