Skip to content

Commit

Permalink
Merge branch 'version-2.10'
Browse files Browse the repository at this point in the history
  • Loading branch information
jrief committed Sep 12, 2024
2 parents 1bc0334 + a2c271f commit d4e8d0c
Show file tree
Hide file tree
Showing 10 changed files with 50 additions and 35 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
strategy:
max-parallel: 4
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
python-version: ['3.9', '3.10', '3.11', '3.12']

steps:
- uses: actions/checkout@v2
Expand Down
9 changes: 7 additions & 2 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
Changes
=======

next
----
2.10 (2024-09-11)
-----------------
* Drop support for Python-3.8.
* Drop support for Django-4.1 and earlier.
* Add support for Django-5.1.
* Experimental support for animated image formats. See documentation for more infos.
* Fix #642: Do not scale images (SVG) without size information.
* Fix #366: Keep ICC profile when saving image, if present.


2.9 (2024-07-25)
Expand Down
9 changes: 8 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,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
-------------
Expand Down
2 changes: 1 addition & 1 deletion easy_thumbnails/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION = (2, 9, 0, 'final', 0)
VERSION = (2, 10, 0, 'final', 0)


def get_version(*args, **kwargs):
Expand Down
3 changes: 3 additions & 0 deletions easy_thumbnails/engine.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os

from io import BytesIO, StringIO

from django.utils.module_loading import import_string
Expand Down Expand Up @@ -59,6 +60,8 @@ def save_pil_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:
Expand Down
4 changes: 3 additions & 1 deletion easy_thumbnails/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,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)
Expand Down Expand Up @@ -399,7 +400,7 @@ def generate_thumbnail(self, thumbnail_options, silent_template_exception=False)
else:
img = engine.save_pil_image(
thumbnail_image, filename=filename, quality=quality,
subsampling=subsampling)
subsampling=subsampling, keep_icc_profile=thumbnail_options.get('keep_icc_profile', False))
data = img.read()

# S3 requires the data as bytes.
Expand Down Expand Up @@ -631,6 +632,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
Expand Down
22 changes: 7 additions & 15 deletions easy_thumbnails/storage.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
from django.core.files.storage import FileSystemStorage
from django.utils.deconstruct import deconstructible
from django.utils.functional import LazyObject

from easy_thumbnails.conf import settings


def get_storage():
# If the user has specified a custom storage backend, use it.
from django.core.files.storage.handler import InvalidStorageError
from django.core.files.storage import storages, default_storage

try:
from django.core.files.storage.handler import InvalidStorageError
from django.core.files.storage import storages
try:
return storages[settings.THUMBNAIL_DEFAULT_STORAGE_ALIAS]
except (InvalidStorageError):
pass
except (ImportError, TypeError):
pass
from django.core.files.storage import get_storage_class
storage_class = get_storage_class(settings.THUMBNAIL_DEFAULT_STORAGE)
class ThumbnailDefaultStorage(LazyObject):
def _setup(self):
self._wrapped = storage_class()
return ThumbnailDefaultStorage()
return storages[settings.THUMBNAIL_DEFAULT_STORAGE_ALIAS]
except InvalidStorageError:
return default_storage


@deconstructible
Expand Down
13 changes: 12 additions & 1 deletion easy_thumbnails/tests/test_engine.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from unittest import TestCase
from PIL import Image
from PIL import Image, ImageCms

from easy_thumbnails import engine

Expand All @@ -17,3 +17,14 @@ def test_save_jpeg_la(self):
data = engine.save_pil_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_pil_image(source, filename='test.jpg', keep_icc_profile=True)
img = Image.open(data)

self.assertNotEqual(img.info.get('icc_profile'), None)
18 changes: 7 additions & 11 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def read_files(*filenames):
packages=find_packages(),
include_package_data=True,
install_requires=[
"django>=2.2",
"django>=4.2",
"pillow",
],
extras_require={
Expand All @@ -41,27 +41,23 @@ def read_files(*filenames):
"reportlab",
],
},
python_requires=">=3.6",
python_requires=">=3.9",
classifiers=[
"Development Status :: 5 - Production/Stable",
"Environment :: Web Environment",
"Framework :: Django",
"Framework :: Django :: 2.2",
"Framework :: Django :: 3.0",
"Framework :: Django :: 3.1",
"Framework :: Django :: 3.2",
"Framework :: Django :: 4.0",
"Framework :: Django :: 4.1",
"Framework :: Django :: 4.2",
"Framework :: Django :: 5.0",
"Framework :: Django :: 5.1",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Libraries :: Application Frameworks",
"Topic :: Software Development :: Libraries :: Python Modules",
],
Expand Down
3 changes: 1 addition & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ skip_missing_interpreters = True

[gh-actions]
python =
3.8: py38
3.9: py39
3.10: py310
3.11: py311
Expand All @@ -23,7 +22,7 @@ extras =
deps =
django42: Django<4.3
django50: Django<5.1
django51: Django>=5.1a1,<5.2
django51: Django>=5.1,<5.2
testfixtures
coverage
commands =
Expand Down

0 comments on commit d4e8d0c

Please sign in to comment.