"""Optional image metadata and computer-vision hints for image observations.""" from __future__ import annotations import io from typing import Any def image_metadata(data: bytes) -> dict[str, Any]: """Read safe image metadata without changing the original upload.""" try: from PIL import Image, ImageOps with Image.open(io.BytesIO(data)) as image: normalized = ImageOps.exif_transpose(image) return { "width": int(normalized.width), "height": int(normalized.height), "format": str(image.format or "").lower(), "orientation": "landscape" if normalized.width >= normalized.height else "portrait", "has_alpha": "A" in normalized.getbands(), } except Exception as error: return {"error": f"image metadata unavailable: {type(error).__name__}"} def cv_hints(data: bytes) -> dict[str, Any]: """Return conservative CV hints; OpenCV is intentionally optional.""" try: import cv2 # type: ignore import numpy as np # type: ignore except Exception: return {"available": False, "hints": []} try: image = cv2.imdecode(np.frombuffer(data, dtype=np.uint8), cv2.IMREAD_GRAYSCALE) if image is None: return {"available": True, "hints": [], "error": "image decode failed"} edges = cv2.Canny(image, 50, 150) lines = cv2.HoughLinesP(edges, 1, 3.141592653589793 / 180, threshold=50, minLineLength=30, maxLineGap=8) line_hints = [] for line in (lines[:32] if lines is not None else []): x1, y1, x2, y2 = [int(value) for value in line[0]] line_hints.append({"type": "line", "start_px": [x1, y1], "end_px": [x2, y2]}) return {"available": True, "hints": line_hints, "edge_pixels": int((edges > 0).sum())} except Exception as error: return {"available": True, "hints": [], "error": f"cv failed: {type(error).__name__}"}