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 tempfile import TemporaryDirectory
from fastapi import HTTPException, UploadFile from fastapi import HTTPException, UploadFile
from PIL import Image, UnidentifiedImageError from PIL import Image, ImageOps, UnidentifiedImageError
try: try:
from pillow_heif import register_heif_opener 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: 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)) prepared.thumbnail((MAX_IMAGE_SIDE, MAX_IMAGE_SIDE))
output = BytesIO() output = BytesIO()
+28
View File
@@ -63,6 +63,19 @@ def make_image_upload(
return (filename, output.getvalue(), "image/png") 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): def read_jpeg_size(image_bytes):
with Image.open(BytesIO(image_bytes)) as image: with Image.open(BytesIO(image_bytes)) as image:
return image.format, image.size 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) 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): def test_can_upload_image_for_item(client, db_session):
box = Box(name="Main Box") box = Box(name="Main Box")
db_session.add(box) db_session.add(box)