Pepguy commited on
Commit
6deee40
·
verified ·
1 Parent(s): e364d6d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -3
app.py CHANGED
@@ -2,6 +2,8 @@
2
  import os
3
  import io
4
  import json
 
 
5
  import base64
6
  import logging
7
  import uuid
@@ -216,29 +218,70 @@ def upload_b64_to_firebase(base64_str: str, path: str, content_type="image/jpeg"
216
  raise
217
 
218
  # ---------- Image helpers (with EXIF transpose) ----------
 
 
 
219
  def read_image_bytes(file_storage) -> Tuple[np.ndarray, int, int, bytes]:
 
 
 
 
 
220
  data = file_storage.read()
221
- img = Image.open(io.BytesIO(data))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  try:
223
  img = ImageOps.exif_transpose(img)
224
  except Exception:
 
225
  pass
 
 
226
  img = img.convert("RGB")
227
  w, h = img.size
228
- arr = np.array(img)[:, :, ::-1]
229
- return arr, w, h, data
 
 
 
 
 
 
 
 
 
230
 
231
  def crop_and_b64(bgr_img: np.ndarray, x: int, y: int, w: int, h: int, max_side=512) -> str:
 
 
 
232
  h_img, w_img = bgr_img.shape[:2]
233
  x = max(0, int(x)); y = max(0, int(y))
234
  x2 = min(w_img, int(x + w)); y2 = min(h_img, int(y + h))
235
  crop = bgr_img[y:y2, x:x2]
236
  if crop.size == 0:
237
  return ""
 
238
  max_dim = max(crop.shape[0], crop.shape[1])
239
  if max_dim > max_side:
240
  scale = max_side / max_dim
241
  crop = cv2.resize(crop, (int(crop.shape[1] * scale), int(crop.shape[0] * scale)), interpolation=cv2.INTER_AREA)
 
242
  _, jpeg = cv2.imencode(".jpg", crop, [int(cv2.IMWRITE_JPEG_QUALITY), 82])
243
  return base64.b64encode(jpeg.tobytes()).decode("ascii")
244
 
 
2
  import os
3
  import io
4
  import json
5
+ from io import BytesIO
6
+
7
  import base64
8
  import logging
9
  import uuid
 
218
  raise
219
 
220
  # ---------- Image helpers (with EXIF transpose) ----------
221
+
222
+ # Replace existing read_image_bytes and crop_and_b64 with this block
223
+
224
  def read_image_bytes(file_storage) -> Tuple[np.ndarray, int, int, bytes]:
225
+ """
226
+ Read bytes, apply EXIF orientation, return BGR numpy, width, height and re-encoded JPEG bytes.
227
+ This ensures the bytes we pass to Gemini / upload to storage are physically upright
228
+ (EXIF orientation is applied and not left in metadata).
229
+ """
230
  data = file_storage.read()
231
+ try:
232
+ img = Image.open(io.BytesIO(data))
233
+ except Exception as e:
234
+ # fallback: try to decode raw bytes via OpenCV
235
+ try:
236
+ arr_np = np.frombuffer(data, np.uint8)
237
+ cv_img = cv2.imdecode(arr_np, cv2.IMREAD_COLOR)
238
+ if cv_img is None:
239
+ raise
240
+ h, w = cv_img.shape[:2]
241
+ # re-encode to jpeg bytes to have consistent format
242
+ _, jpeg = cv2.imencode(".jpg", cv_img, [int(cv2.IMWRITE_JPEG_QUALITY), 92])
243
+ return cv_img, w, h, jpeg.tobytes()
244
+ except Exception as ee:
245
+ raise
246
+
247
+ # physically apply EXIF rotation if present
248
  try:
249
  img = ImageOps.exif_transpose(img)
250
  except Exception:
251
+ # ignore failures here; proceed with original image
252
  pass
253
+
254
+ # ensure RGB and get size
255
  img = img.convert("RGB")
256
  w, h = img.size
257
+
258
+ # re-encode to JPEG bytes to strip EXIF orientation tag (important!)
259
+ buf = BytesIO()
260
+ # We intentionally omit any EXIF bytes when saving so orientation is cleared.
261
+ img.save(buf, format="JPEG", quality=92, optimize=True)
262
+ jpeg_bytes = buf.getvalue()
263
+
264
+ # convert to BGR numpy for OpenCV operations
265
+ arr = np.array(img)[:, :, ::-1] # RGB -> BGR
266
+ return arr, w, h, jpeg_bytes
267
+
268
 
269
  def crop_and_b64(bgr_img: np.ndarray, x: int, y: int, w: int, h: int, max_side=512) -> str:
270
+ """
271
+ Crop from BGR image (already upright), optionally resize, encode as JPEG and return base64 string.
272
+ """
273
  h_img, w_img = bgr_img.shape[:2]
274
  x = max(0, int(x)); y = max(0, int(y))
275
  x2 = min(w_img, int(x + w)); y2 = min(h_img, int(y + h))
276
  crop = bgr_img[y:y2, x:x2]
277
  if crop.size == 0:
278
  return ""
279
+ # resize if too large
280
  max_dim = max(crop.shape[0], crop.shape[1])
281
  if max_dim > max_side:
282
  scale = max_side / max_dim
283
  crop = cv2.resize(crop, (int(crop.shape[1] * scale), int(crop.shape[0] * scale)), interpolation=cv2.INTER_AREA)
284
+ # encode to JPEG (this will be upright because bgr_img was exif_transposed)
285
  _, jpeg = cv2.imencode(".jpg", crop, [int(cv2.IMWRITE_JPEG_QUALITY), 82])
286
  return base64.b64encode(jpeg.tobytes()).decode("ascii")
287