fix: complete image pipeline - rotation, URL, preview

- Add rotation_degrees parameter to ImageProcessor.process_photo()
- Pass rotation through _auto_save_photo_from_extraction() to processor
- Allow no-crop fallback when crop_bounds is None
- Add buildPhotoUrl() helper to resolve backend URLs correctly
- Update frontend components to use backend URL for image sources
- Replace Use/Skip Photo buttons with checkbox in AI extraction UI
- Add images/ to .gitignore to prevent accidental commits

Addresses: rotation never applied, image 404s (relative to Next.js not backend), preview blank in edit form
This commit is contained in:
2026-04-22 08:50:25 +03:00
parent 1c13ebd76f
commit 64d177e791
10 changed files with 79 additions and 70 deletions

View File

@@ -43,7 +43,7 @@ class ImageProcessor:
self.logger = logger
def process_photo(
self, file_bytes: bytes, crop_bounds: Optional[Dict] = None
self, file_bytes: bytes, crop_bounds: Optional[Dict] = None, rotation_degrees: float = 0
) -> Dict:
"""
Process a photo with EXIF rotation, smart cropping, and compression.
@@ -51,6 +51,7 @@ class ImageProcessor:
Args:
file_bytes: Raw image file bytes
crop_bounds: Optional manual crop bounds {x, y, width, height}
rotation_degrees: Optional manual rotation in degrees (applied after crop)
Returns:
{
@@ -136,6 +137,11 @@ class ImageProcessor:
)
crop_method = 'pillow'
# Apply manual rotation if provided
if abs(rotation_degrees) > 0.5:
cropped_image = cropped_image.rotate(-rotation_degrees, expand=True)
self.logger.info(f"Applied manual rotation: {rotation_degrees}°")
# Resize and compress
compressed_bytes = self._resize_and_compress(cropped_image)