From 02d60e20a198483b24c07ed4e202b7a95f85c4c2 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 26 Jun 2024 10:28:14 +0200 Subject: [PATCH 1/2] Make it possible to generate srcset with the thumbnail template tag --- docs/configuration.rst | 9 +++++++++ imagekit/templatetags/imagekit.py | 27 ++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 84636cee..c2733c54 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -17,6 +17,15 @@ Settings The directory to which image files will be cached. +.. attribute:: IMAGEKIT_DEFAULT_THUMBNAIL_SRCSET_SCALES + + :default: ``None`` + + A list of scale factors, for example ``[2, 3]``. If specified, every + ```` generated by the ``thumbnail`` template tag will have a ``srcset`` + attribute with the given scales. To prevent this, set ``srcset=None``. + + .. attribute:: IMAGEKIT_DEFAULT_FILE_STORAGE :default: ``None`` diff --git a/imagekit/templatetags/imagekit.py b/imagekit/templatetags/imagekit.py index b2bbfe72..51dab481 100644 --- a/imagekit/templatetags/imagekit.py +++ b/imagekit/templatetags/imagekit.py @@ -3,6 +3,7 @@ from django.utils.encoding import force_str from django.utils.html import escape from django.utils.safestring import mark_safe +from django.conf import settings from ..cachefiles import ImageCacheFile from ..registry import generator_registry @@ -13,6 +14,7 @@ ASSIGNMENT_DELIMETER = 'as' HTML_ATTRS_DELIMITER = '--' DEFAULT_THUMBNAIL_GENERATOR = 'imagekit:thumbnail' +default_thumbnail_srcset_scales = getattr(settings, 'IMAGEKIT_DEFAULT_THUMBNAIL_SRCSET_SCALES', None) def get_cachefile(context, generator_id, generator_kwargs, source=None): @@ -124,9 +126,25 @@ def render(self, context): # recursion errors when anchor is set to a SafeString instance. # This converts the SafeString into a str instance. kwargs['anchor'] = kwargs['anchor'][:] + srcset_scales = default_thumbnail_srcset_scales + if "srcset" in kwargs: + if kwargs['srcset'] is not None: + srcset_scales = list(map(float, kwargs['srcset'].split())) + else: + srcset_scales = None + kwargs.pop("srcset") generator = generator_registry.get(generator_id, **kwargs) file = ImageCacheFile(generator) + srcset = [] + if srcset_scales: + for scale in srcset_scales: + scaled_kwargs = dict(kwargs) + if scaled_kwargs.get("height"): + scaled_kwargs["height"] = int(scaled_kwargs["height"] * scale) + if scaled_kwargs.get("width"): + scaled_kwargs["width"] = int(scaled_kwargs["width"] * scale) + srcset.append(ImageCacheFile(generator_registry.get(generator_id, **scaled_kwargs))) attrs = {k: v.resolve(context) for k, v in self._html_attrs.items()} @@ -136,6 +154,9 @@ def render(self, context): attrs.update(width=file.width, height=file.height) attrs['src'] = file.url + if len(srcset) > 0: + attrs['srcset'] = f'{file.url} 1x , ' + ' , '.join( + f'{entry[0].url} {entry[1]}x' for entry in zip(srcset, srcset_scales)) attr_str = ' '.join('%s="%s"' % (escape(k), escape(v)) for k, v in attrs.items()) return mark_safe('' % attr_str) @@ -241,7 +262,11 @@ def thumbnail(parser, token): The thumbnail tag supports the "--" and "as" bits for adding html attributes and assigning to a variable, respectively. It also accepts the - kwargs "anchor", and "crop". + kwargs "srcset", "anchor", and "crop". + + To use "srcset" (generating multiple thumbnails for different pixel densities) list the scale factors:: + + {% thumbnail '100x100' mymodel.profile_image srcset='2 3' %} To use "smart cropping" (the ``SmartResize`` processor):: From 581127928507ad6f929b9671d36103d8e1fa3e09 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Mon, 8 Jul 2024 19:05:08 +0200 Subject: [PATCH 2/2] Add srcset tests --- tests/test_thumbnail_tag.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_thumbnail_tag.py b/tests/test_thumbnail_tag.py index f3bdfda6..adc7fb0b 100644 --- a/tests/test_thumbnail_tag.py +++ b/tests/test_thumbnail_tag.py @@ -1,4 +1,5 @@ import pytest +import re from django.template import TemplateSyntaxError from . import imagegenerators # noqa @@ -87,3 +88,11 @@ def test_alternate_generator(): clear_imagekit_cache() html = render_tag(ttag) assert html == '1' + + +def test_srcset_arg(): + ttag = r"""{% thumbnail '100x' img srcset="1.5 2" %}""" + clear_imagekit_cache() + html = render_tag(ttag) + srcset_regex = re.compile('srcset=".* 1x ,.* 1\\.5x ,.* 2.0x"') + assert srcset_regex.search(html) is not None