import cv2 import numpy as np from pathlib import Path import uuid import os from datetime import datetime from typing import Tuple, Dict, Any, Optional from app.core.config import settings def save_uploaded_image(file_data: bytes, filename: str) -> Dict[str, Any]: """ Save an uploaded image to the storage directory and return metadata. Args: file_data: The binary content of the uploaded file filename: Original filename of the uploaded file Returns: Dict with image metadata including path, size, etc. """ # Generate a unique filename to avoid conflicts extension = Path(filename).suffix.lower() date_prefix = datetime.now().strftime("%Y%m%d") unique_id = str(uuid.uuid4()) safe_filename = f"{date_prefix}_{unique_id}{extension}" # Create full path file_path = settings.IMAGE_DIR / safe_filename # Write file to disk with open(file_path, "wb") as f: f.write(file_data) # Get image dimensions if it's an image file width, height = None, None try: img = cv2.imread(str(file_path)) if img is not None: height, width, _ = img.shape except Exception: pass return { "file_path": str(file_path), "filename": filename, "file_size": len(file_data), "width": width, "height": height, "mime_type": get_mime_type(extension) } def get_mime_type(extension: str) -> str: """Map file extension to MIME type.""" mime_types = { ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".png": "image/png", ".gif": "image/gif", ".bmp": "image/bmp", ".tiff": "image/tiff", ".tif": "image/tiff", } return mime_types.get(extension.lower(), "application/octet-stream") def load_image(file_path: str) -> Optional[np.ndarray]: """Load an image from file path.""" if not os.path.exists(file_path): return None img = cv2.imread(file_path) if img is None: return None return cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # Convert to RGB def resize_image(image: np.ndarray, target_size: Tuple[int, int]) -> np.ndarray: """Resize image to target size.""" return cv2.resize(image, target_size, interpolation=cv2.INTER_AREA) def normalize_image(image: np.ndarray) -> np.ndarray: """Normalize image pixel values to [0, 1].""" return image.astype(np.float32) / 255.0