fix image orientation

This commit is contained in:
2026-04-19 14:47:18 +02:00
parent f315614657
commit 8d89caea0c
2 changed files with 32 additions and 2 deletions
+4 -2
View File
@@ -6,7 +6,7 @@ import subprocess
from tempfile import TemporaryDirectory
from fastapi import HTTPException, UploadFile
from PIL import Image, UnidentifiedImageError
from PIL import Image, ImageOps, UnidentifiedImageError
try:
from pillow_heif import register_heif_opener
@@ -59,7 +59,9 @@ def process_upload(file: UploadFile | None) -> ProcessedImage | None:
def _prepare_image(source_image: Image.Image) -> ProcessedImage:
prepared = _strip_metadata_and_convert(source_image)
# Normalize orientation from EXIF before resizing or stripping metadata.
prepared = ImageOps.exif_transpose(source_image)
prepared = _strip_metadata_and_convert(prepared)
prepared.thumbnail((MAX_IMAGE_SIDE, MAX_IMAGE_SIDE))
output = BytesIO()
+28
View File
@@ -63,6 +63,19 @@ def make_image_upload(
return (filename, output.getvalue(), "image/png")
def make_oriented_jpeg_upload(
filename="portrait.jpg",
size=(1600, 900),
orientation=6,
):
image = Image.new("RGB", size, (20, 120, 220))
exif = Image.Exif()
exif[274] = orientation
output = BytesIO()
image.save(output, format="JPEG", exif=exif)
return (filename, output.getvalue(), "image/jpeg")
def read_jpeg_size(image_bytes):
with Image.open(BytesIO(image_bytes)) as image:
return image.format, image.size
@@ -357,6 +370,21 @@ def test_can_upload_image_for_box_and_process_it(client, db_session):
assert image_size == (1600, 800)
def test_image_pipeline_applies_exif_orientation_before_saving(client, db_session):
response = create_box(client, name="Portrait Box", image=make_oriented_jpeg_upload())
assert response.status_code == 303
box = db_session.query(Box).filter_by(name="Portrait Box").one()
assert box.image_blob is not None
assert box.image_width == 900
assert box.image_height == 1600
image_format, image_size = read_jpeg_size(box.image_blob)
assert image_format == "JPEG"
assert image_size == (900, 1600)
def test_can_upload_image_for_item(client, db_session):
box = Box(name="Main Box")
db_session.add(box)