Skip to content

Commit 33fbe94

Browse files
Merge pull request #15062 from astriaai/fix-exif-orientation-api
Fix EXIF orientation in API image loading
2 parents 92d77e3 + 67d8daf commit 33fbe94

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

modules/api/api.py

+2
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ def decode_base64_to_image(encoding):
8686
response = requests.get(encoding, timeout=30, headers=headers)
8787
try:
8888
image = Image.open(BytesIO(response.content))
89+
image = images.apply_exif_orientation(image)
8990
return image
9091
except Exception as e:
9192
raise HTTPException(status_code=500, detail="Invalid image url") from e
@@ -94,6 +95,7 @@ def decode_base64_to_image(encoding):
9495
encoding = encoding.split(";")[1].split(",")[1]
9596
try:
9697
image = Image.open(BytesIO(base64.b64decode(encoding)))
98+
image = images.apply_exif_orientation(image)
9799
return image
98100
except Exception as e:
99101
raise HTTPException(status_code=500, detail="Invalid encoded image") from e

modules/images.py

+49
Original file line numberDiff line numberDiff line change
@@ -800,3 +800,52 @@ def flatten(img, bgcolor):
800800

801801
return img.convert('RGB')
802802

803+
804+
# https://www.exiv2.org/tags.html
805+
_EXIF_ORIENT = 274 # exif 'Orientation' tag
806+
807+
def apply_exif_orientation(image):
808+
"""
809+
Applies the exif orientation correctly.
810+
811+
This code exists per the bug:
812+
https://github.com/python-pillow/Pillow/issues/3973
813+
with the function `ImageOps.exif_transpose`. The Pillow source raises errors with
814+
various methods, especially `tobytes`
815+
816+
Function based on:
817+
https://github.com/wkentaro/labelme/blob/v4.5.4/labelme/utils/image.py#L59
818+
https://github.com/python-pillow/Pillow/blob/7.1.2/src/PIL/ImageOps.py#L527
819+
820+
Args:
821+
image (PIL.Image): a PIL image
822+
823+
Returns:
824+
(PIL.Image): the PIL image with exif orientation applied, if applicable
825+
"""
826+
if not hasattr(image, "getexif"):
827+
return image
828+
829+
try:
830+
exif = image.getexif()
831+
except Exception: # https://github.com/facebookresearch/detectron2/issues/1885
832+
exif = None
833+
834+
if exif is None:
835+
return image
836+
837+
orientation = exif.get(_EXIF_ORIENT)
838+
839+
method = {
840+
2: Image.FLIP_LEFT_RIGHT,
841+
3: Image.ROTATE_180,
842+
4: Image.FLIP_TOP_BOTTOM,
843+
5: Image.TRANSPOSE,
844+
6: Image.ROTATE_270,
845+
7: Image.TRANSVERSE,
846+
8: Image.ROTATE_90,
847+
}.get(orientation)
848+
849+
if method is not None:
850+
return image.transpose(method)
851+
return image

0 commit comments

Comments
 (0)