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

Fix EXIF orientation in API image loading #15062

Merged
merged 1 commit into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions modules/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def decode_base64_to_image(encoding):
response = requests.get(encoding, timeout=30, headers=headers)
try:
image = Image.open(BytesIO(response.content))
image = images.apply_exif_orientation(image)
return image
except Exception as e:
raise HTTPException(status_code=500, detail="Invalid image url") from e
Expand All @@ -94,6 +95,7 @@ def decode_base64_to_image(encoding):
encoding = encoding.split(";")[1].split(",")[1]
try:
image = Image.open(BytesIO(base64.b64decode(encoding)))
image = images.apply_exif_orientation(image)
return image
except Exception as e:
raise HTTPException(status_code=500, detail="Invalid encoded image") from e
Expand Down
49 changes: 49 additions & 0 deletions modules/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -797,3 +797,52 @@ def flatten(img, bgcolor):

return img.convert('RGB')


# https://www.exiv2.org/tags.html
_EXIF_ORIENT = 274 # exif 'Orientation' tag

def apply_exif_orientation(image):
"""
Applies the exif orientation correctly.

This code exists per the bug:
https://github.com/python-pillow/Pillow/issues/3973
with the function `ImageOps.exif_transpose`. The Pillow source raises errors with
various methods, especially `tobytes`

Function based on:
https://github.com/wkentaro/labelme/blob/v4.5.4/labelme/utils/image.py#L59
https://github.com/python-pillow/Pillow/blob/7.1.2/src/PIL/ImageOps.py#L527

Args:
image (PIL.Image): a PIL image

Returns:
(PIL.Image): the PIL image with exif orientation applied, if applicable
"""
if not hasattr(image, "getexif"):
return image

try:
exif = image.getexif()
except Exception: # https://github.com/facebookresearch/detectron2/issues/1885
exif = None

if exif is None:
return image

orientation = exif.get(_EXIF_ORIENT)

method = {
2: Image.FLIP_LEFT_RIGHT,
3: Image.ROTATE_180,
4: Image.FLIP_TOP_BOTTOM,
5: Image.TRANSPOSE,
6: Image.ROTATE_270,
7: Image.TRANSVERSE,
8: Image.ROTATE_90,
}.get(orientation)

if method is not None:
return image.transpose(method)
return image
Loading