Skip to content

Commit

Permalink
Fix EXIF orientation in API image loading
Browse files Browse the repository at this point in the history
  • Loading branch information
burgalon committed Feb 29, 2024
1 parent cf2772f commit 23984e7
Showing 1 changed file with 51 additions and 0 deletions.
51 changes: 51 additions & 0 deletions modules/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,55 @@ def verify_url(url):
return True


# 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

def decode_base64_to_image(encoding):
if encoding.startswith("http://") or encoding.startswith("https://"):
if not opts.api_enable_requests:
Expand All @@ -86,6 +135,7 @@ def decode_base64_to_image(encoding):
response = requests.get(encoding, timeout=30, headers=headers)
try:
image = Image.open(BytesIO(response.content))
image = _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 +144,7 @@ def decode_base64_to_image(encoding):
encoding = encoding.split(";")[1].split(",")[1]
try:
image = Image.open(BytesIO(base64.b64decode(encoding)))
image = _apply_exif_orientation(image)
return image
except Exception as e:
raise HTTPException(status_code=500, detail="Invalid encoded image") from e
Expand Down

0 comments on commit 23984e7

Please sign in to comment.