72 lines
2.3 KiB
Python
72 lines
2.3 KiB
Python
"""Gallery EXIF extraction must report display (EXIF-rotated) dimensions.
|
|
|
|
A phone photo with EXIF Orientation 6 or 8 is stored e.g. 400x300 but
|
|
displayed 300x400. _extract_exif read img.width/img.height from the raw
|
|
buffer, so the gallery recorded the wrong aspect ratio for rotated photos
|
|
while upload_handler (which applies ImageOps.exif_transpose) got it right.
|
|
"""
|
|
|
|
import importlib
|
|
import sys
|
|
import types
|
|
from io import BytesIO
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
|
|
pytest.importorskip("PIL")
|
|
from PIL import Image
|
|
|
|
|
|
@pytest.fixture
|
|
def extract_exif(monkeypatch):
|
|
"""Import routes.gallery_helpers under a core.database stub.
|
|
|
|
_extract_exif never touches the DB, but the module imports GalleryImage
|
|
at import time and the conftest sqlalchemy stubs make the real
|
|
core.database unimportable in isolation.
|
|
"""
|
|
|
|
class _DBStub(types.ModuleType):
|
|
def __getattr__(self, name):
|
|
return MagicMock()
|
|
|
|
monkeypatch.setitem(sys.modules, "core.database", _DBStub("core.database"))
|
|
monkeypatch.delitem(sys.modules, "routes.gallery_helpers", raising=False)
|
|
mod = importlib.import_module("routes.gallery_helpers")
|
|
return mod._extract_exif
|
|
|
|
|
|
def _jpeg(width, height, orientation=None, make=None):
|
|
img = Image.new("RGB", (width, height), "blue")
|
|
exif = Image.Exif()
|
|
if orientation is not None:
|
|
exif[0x0112] = orientation # Orientation
|
|
if make is not None:
|
|
exif[0x010F] = make # Make
|
|
buf = BytesIO()
|
|
img.save(buf, format="JPEG", exif=exif)
|
|
return buf.getvalue()
|
|
|
|
|
|
def test_orientation_6_reports_display_dimensions(extract_exif):
|
|
res = extract_exif(_jpeg(400, 300, orientation=6))
|
|
assert (res["width"], res["height"]) == (300, 400)
|
|
|
|
|
|
def test_orientation_8_reports_display_dimensions(extract_exif):
|
|
res = extract_exif(_jpeg(400, 300, orientation=8))
|
|
assert (res["width"], res["height"]) == (300, 400)
|
|
|
|
|
|
def test_no_orientation_keeps_raw_dimensions(extract_exif):
|
|
res = extract_exif(_jpeg(400, 300))
|
|
assert (res["width"], res["height"]) == (400, 300)
|
|
|
|
|
|
def test_camera_fields_survive_the_transpose(extract_exif):
|
|
# exif_transpose strips the EXIF view, so tags must be read before it
|
|
res = extract_exif(_jpeg(400, 300, orientation=6, make="TestMake"))
|
|
assert res["camera_make"] == "TestMake"
|
|
assert (res["width"], res["height"]) == (300, 400)
|