Skip to content

Commit 23984e7

Browse files
committed
Fix EXIF orientation in API image loading
1 parent cf2772f commit 23984e7

File tree

1 file changed

+51
-0
lines changed

1 file changed

+51
-0
lines changed

modules/api/api.py

+51
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,55 @@ def verify_url(url):
7474
return True
7575

7676

77+
# https://www.exiv2.org/tags.html
78+
_EXIF_ORIENT = 274 # exif 'Orientation' tag
79+
80+
def _apply_exif_orientation(image):
81+
"""
82+
Applies the exif orientation correctly.
83+
84+
This code exists per the bug:
85+
https://github.com/python-pillow/Pillow/issues/3973
86+
with the function `ImageOps.exif_transpose`. The Pillow source raises errors with
87+
various methods, especially `tobytes`
88+
89+
Function based on:
90+
https://github.com/wkentaro/labelme/blob/v4.5.4/labelme/utils/image.py#L59
91+
https://github.com/python-pillow/Pillow/blob/7.1.2/src/PIL/ImageOps.py#L527
92+
93+
Args:
94+
image (PIL.Image): a PIL image
95+
96+
Returns:
97+
(PIL.Image): the PIL image with exif orientation applied, if applicable
98+
"""
99+
if not hasattr(image, "getexif"):
100+
return image
101+
102+
try:
103+
exif = image.getexif()
104+
except Exception: # https://github.com/facebookresearch/detectron2/issues/1885
105+
exif = None
106+
107+
if exif is None:
108+
return image
109+
110+
orientation = exif.get(_EXIF_ORIENT)
111+
112+
method = {
113+
2: Image.FLIP_LEFT_RIGHT,
114+
3: Image.ROTATE_180,
115+
4: Image.FLIP_TOP_BOTTOM,
116+
5: Image.TRANSPOSE,
117+
6: Image.ROTATE_270,
118+
7: Image.TRANSVERSE,
119+
8: Image.ROTATE_90,
120+
}.get(orientation)
121+
122+
if method is not None:
123+
return image.transpose(method)
124+
return image
125+
77126
def decode_base64_to_image(encoding):
78127
if encoding.startswith("http://") or encoding.startswith("https://"):
79128
if not opts.api_enable_requests:
@@ -86,6 +135,7 @@ def decode_base64_to_image(encoding):
86135
response = requests.get(encoding, timeout=30, headers=headers)
87136
try:
88137
image = Image.open(BytesIO(response.content))
138+
image = _apply_exif_orientation(image)
89139
return image
90140
except Exception as e:
91141
raise HTTPException(status_code=500, detail="Invalid image url") from e
@@ -94,6 +144,7 @@ def decode_base64_to_image(encoding):
94144
encoding = encoding.split(";")[1].split(",")[1]
95145
try:
96146
image = Image.open(BytesIO(base64.b64decode(encoding)))
147+
image = _apply_exif_orientation(image)
97148
return image
98149
except Exception as e:
99150
raise HTTPException(status_code=500, detail="Invalid encoded image") from e

0 commit comments

Comments
 (0)