Bake the EXIF orientation into the srgbified image
- ID
79cf9d5- date
2024-03-25 23:05:51+00:00- author
Alex Chan <alex@alexwlchan.net>- parent
9d72235- message
Bake the EXIF orientation into the srgbified image- changed files
3 files, 35 additions, 8 deletions
Changed files
images/examples/taylorswift.jpg (0) → images/examples/taylorswift.jpg (3939779)
diff --git a/images/examples/taylorswift.jpg b/images/examples/taylorswift.jpg
new file mode 100644
index 0000000..b3885f6
Binary files /dev/null and b/images/examples/taylorswift.jpg differ
images/srgbify.py (1814) → images/srgbify.py (2255)
diff --git a/images/srgbify.py b/images/srgbify.py
index e60be3f..959a941 100755
--- a/images/srgbify.py
+++ b/images/srgbify.py
@@ -6,13 +6,16 @@ This is particularly useful for screenshots on macOS, which are taken
with the display's colour profile (e.g. Display LCD or Display P3), but
which I want to convert to sRGB for converting on the web.
+This script strips out EXIF metadata.
+
Based on https://github.com/python-pillow/Pillow/issues/1662
"""
import io
import sys
+import typing
-from PIL import Image, ImageCms
+from PIL import Image, ImageCms, ImageOps
from PIL.ImageCms import PyCMSError
from pillow_heif import register_heif_opener
@@ -20,7 +23,7 @@ from pillow_heif import register_heif_opener
register_heif_opener()
-def convert_image_to_srgb(im: Image) -> Image:
+def convert_image_to_srgb(im: Image) -> typing.Union[Image, None]:
"""
Convert an image to sRGB and return a new Image instance.
"""
@@ -28,10 +31,17 @@ def convert_image_to_srgb(im: Image) -> Image:
# If this image doesn't have a colour profile, we're done.
if icc_profile is None:
- return im
+ return None
- # Otherwise, convert the image to an sRGB colour profile and return that.
+ # If the image has an EXIF orientation tag, it will be stripped out
+ # upon saving (like all EXIF metadata).
+ #
+ # To avoid any weird rotation issues, bake the rotation into the image.
+ # See https://github.com/python-pillow/Pillow/issues/4703#issuecomment-645219973
+ # or the associated test.
+ im = ImageOps.exif_transpose(im)
+ # Otherwise, convert the image to an sRGB colour profile and return that.
try:
return ImageCms.profileToProfile(
im,
@@ -64,7 +74,7 @@ if __name__ == "__main__":
im = Image.open(path)
out_im = convert_image_to_srgb(im)
- if out_im != im:
+ if out_im is not None:
out_im.save(path)
print(path)
images/test_srgbify.py (1762) → images/test_srgbify.py (2378)
diff --git a/images/test_srgbify.py b/images/test_srgbify.py
index aed3d10..a4172d2 100644
--- a/images/test_srgbify.py
+++ b/images/test_srgbify.py
@@ -1,4 +1,5 @@
import filecmp
+import pathlib
from PIL import Image
@@ -13,9 +14,7 @@ def test_it_ignores_an_image_which_is_already_srgb():
"""
im = Image.open("images/examples/Shoes-sRGB.jpg")
- new_im = convert_image_to_srgb(im)
-
- assert new_im is im
+ assert convert_image_to_srgb(im) is None
def test_it_converts_a_display_p3_image_to_srgb(tmp_path):
@@ -65,3 +64,21 @@ def test_it_converts_images_with_a_grey_profile():
new_im = convert_image_to_srgb(im)
assert new_im.mode == "RGB"
+
+
+def test_it_preserves_rotation_from_exif_orientation(tmp_path: pathlib.Path):
+ """
+ This is based on a photo exported from my Apple Photos Library
+ which was rotated by 90 degrees upon transformation.
+
+ This was caused by an image with an EXIF orientation tag that was
+ being stripped on save. I found a solution in the Pillow issue tracker.
+
+ See https://github.com/alexwlchan/scripts/issues/21
+ See https://github.com/python-pillow/Pillow/issues/4703
+ """
+ im = Image.open("images/examples/taylorswift.jpg")
+
+ new_im = convert_image_to_srgb(im)
+
+ assert new_im.size == (3024, 4032)