@@ -74,6 +74,55 @@ def verify_url(url):
74
74
return True
75
75
76
76
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
+
77
126
def decode_base64_to_image (encoding ):
78
127
if encoding .startswith ("http://" ) or encoding .startswith ("https://" ):
79
128
if not opts .api_enable_requests :
@@ -86,6 +135,7 @@ def decode_base64_to_image(encoding):
86
135
response = requests .get (encoding , timeout = 30 , headers = headers )
87
136
try :
88
137
image = Image .open (BytesIO (response .content ))
138
+ image = _apply_exif_orientation (image )
89
139
return image
90
140
except Exception as e :
91
141
raise HTTPException (status_code = 500 , detail = "Invalid image url" ) from e
@@ -94,6 +144,7 @@ def decode_base64_to_image(encoding):
94
144
encoding = encoding .split (";" )[1 ].split ("," )[1 ]
95
145
try :
96
146
image = Image .open (BytesIO (base64 .b64decode (encoding )))
147
+ image = _apply_exif_orientation (image )
97
148
return image
98
149
except Exception as e :
99
150
raise HTTPException (status_code = 500 , detail = "Invalid encoded image" ) from e
0 commit comments