From 09174c9c4fef1e2b4363e8f0e43c854a82f3b7f6 Mon Sep 17 00:00:00 2001 From: Salvatore Iovene Date: Thu, 1 Oct 2020 21:14:46 +0200 Subject: [PATCH] Keep ICC profile when saving image, if present --- README.rst | 9 ++++++++- easy_thumbnails/engine.py | 3 +++ easy_thumbnails/files.py | 4 +++- easy_thumbnails/tests/test_engine.py | 13 ++++++++++++- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 6218a4e4..70189f86 100644 --- a/README.rst +++ b/README.rst @@ -134,7 +134,14 @@ during scaling. Changes the quality of the output JPEG thumbnail. Defaults to ``85``. In Python code, this is given as a separate option to the ``get_thumbnail`` -method rather than just alter the other +method rather than just alter the other. + +``keep_icc_profile`` +-------------------- + +If `True`, when saving a thumbnail with the alias that defines this option, the +ICC profile of the image will be preserved in the thumbnail, if present in the first place. + Other options ------------- diff --git a/easy_thumbnails/engine.py b/easy_thumbnails/engine.py index e6426864..c6edcaff 100644 --- a/easy_thumbnails/engine.py +++ b/easy_thumbnails/engine.py @@ -1,4 +1,5 @@ import os + from io import BytesIO from PIL import Image @@ -57,6 +58,8 @@ def save_image(image, destination=None, filename=None, **options): max(image.size) >= settings.THUMBNAIL_PROGRESSIVE): options['progressive'] = True try: + if options.pop('keep_icc_profile', False): + options['icc_profile'] = image.info.get('icc_profile') image.save(destination, format=format, optimize=1, **options) saved = True except IOError: diff --git a/easy_thumbnails/files.py b/easy_thumbnails/files.py index 64399087..d38651f4 100644 --- a/easy_thumbnails/files.py +++ b/easy_thumbnails/files.py @@ -150,6 +150,7 @@ class ThumbnailFile(ImageFieldFile): This can be used just like a Django model instance's property for a file field (i.e. an ``ImageFieldFile`` object). """ + def __init__(self, name, file=None, storage=None, thumbnail_options=None, *args, **kwargs): fake_field = FakeField(storage=storage) @@ -400,7 +401,7 @@ def generate_thumbnail(self, thumbnail_options, high_resolution=False, img = engine.save_image( thumbnail_image, filename=filename, quality=quality, - subsampling=subsampling) + subsampling=subsampling, keep_icc_profile=thumbnail_options.get('keep_icc_profile', False)) data = img.read() thumbnail = ThumbnailFile( @@ -653,6 +654,7 @@ class ThumbnailerFieldFile(FieldFile, Thumbnailer): A field file which provides some methods for generating (and returning) thumbnail images. """ + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.source_storage = self.field.storage diff --git a/easy_thumbnails/tests/test_engine.py b/easy_thumbnails/tests/test_engine.py index 9fc6a4e3..7c5e99a5 100644 --- a/easy_thumbnails/tests/test_engine.py +++ b/easy_thumbnails/tests/test_engine.py @@ -1,5 +1,5 @@ from unittest import TestCase -from PIL import Image +from PIL import Image, ImageCms from easy_thumbnails import engine @@ -17,3 +17,14 @@ def test_save_jpeg_la(self): data = engine.save_image(source, filename='test.jpg') with Image.open(data) as img: self.assertEqual(img.mode, 'L') + + def test_save_with_icc_profile(self): + source = Image.new('RGB', (100, 100), (255, 255, 255)) + profile = ImageCms.createProfile('sRGB') + source.save('source.jpg', icc_profile=ImageCms.ImageCmsProfile(profile).tobytes()) + source = Image.open('source.jpg') + + data = engine.save_image(source, filename='test.jpg', keep_icc_profile=True) + img = Image.open(data) + + self.assertNotEqual(img.info.get('icc_profile'), None)