Skip to content

Commit 5900321

Browse files
1r00tcodingjoe
andauthored
Fix #67 -- Rotate thumbnails based on EXIF information (#68)
Some images, particularly JPEGs recorded by digital cameras, save images with as they come from the sensor and add an EXIF tag for the correct rotation. When creating smaller versions for responsive image delivery we should rotate images in advance, not only crop correctly but to lower client performance requirements. Co-authored-by: Johannes Maron <[email protected]>
1 parent efc5654 commit 5900321

File tree

2 files changed

+29
-2
lines changed

2 files changed

+29
-2
lines changed

pictures/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ def path(self) -> Path:
6666
return Path(self.storage.path(self.name))
6767

6868
def process(self, image) -> Image:
69+
image = ImageOps.exif_transpose(image) # crates a copy
6970
height = self.height or self.width / Fraction(*image.size)
7071
size = math.floor(self.width), math.floor(height)
7172

7273
if self.aspect_ratio:
7374
image = ImageOps.fit(image, size)
7475
else:
75-
image = image.copy()
7676
image.thumbnail(size)
7777
return image
7878

tests/test_models.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import contextlib
2+
import io
23
from fractions import Fraction
34
from pathlib import Path
45
from unittest.mock import Mock
56

67
import pytest
78
from django.core.files.storage import default_storage
8-
from PIL import Image
9+
from django.core.files.uploadedfile import SimpleUploadedFile
10+
from PIL import Image, ImageDraw
911

1012
from pictures.models import PictureField, SimplePicture
1113
from tests.testapp.models import Profile, SimpleModel
@@ -108,6 +110,31 @@ def test_save(self, stub_worker, image_upload_file):
108110
assert default_storage.exists(obj.picture.name)
109111
assert obj.picture.aspect_ratios["16/9"]["WEBP"][100].path.exists()
110112

113+
@pytest.mark.django_db
114+
def test_exif_transpose(self, stub_worker):
115+
img = Image.new("RGB", (600, 800), (255, 0, 0))
116+
draw = ImageDraw.Draw(img)
117+
draw.rectangle((300, 0, 600, 800), fill=(0, 0, 255)) # blue is on the right
118+
exif = img.getexif()
119+
exif[0x0112] = 8 # pretend to be rotated by 90 degrees
120+
121+
with io.BytesIO() as output:
122+
img.save(output, format="JPEG", exif=exif)
123+
image_file = SimpleUploadedFile("image.jpg", output.getvalue())
124+
125+
obj = SimpleModel(picture=image_file)
126+
obj.save()
127+
stub_worker.join()
128+
129+
assert default_storage.exists(obj.picture.name)
130+
assert obj.picture.aspect_ratios["16/9"]["WEBP"][100].path.exists()
131+
with Image.open(
132+
obj.picture.aspect_ratios["16/9"]["WEBP"][100].path
133+
) as img_small:
134+
assert img_small.size == (100, 56)
135+
pixels = img_small.load()
136+
assert pixels[0, 0] == (2, 0, 255) # blue is on the top, always blue!
137+
111138
@pytest.mark.django_db
112139
def test_save__is_blank(self, monkeypatch):
113140
obj = SimpleModel()

0 commit comments

Comments
 (0)