Skip to content

Commit

Permalink
Merge pull request #575 from autoantwort/feature/srcset
Browse files Browse the repository at this point in the history
Make it possible to generate srcset with the thumbnail template tag
  • Loading branch information
vstoykov authored Jul 22, 2024
2 parents c4ed0bb + 973990d commit aea457b
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 1 deletion.
9 changes: 9 additions & 0 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,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
``<img>`` 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``
Expand Down
27 changes: 26 additions & 1 deletion imagekit/templatetags/imagekit.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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):
Expand Down Expand Up @@ -126,11 +128,27 @@ 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")
if kwargs.get('format'):
kwargs['format'] = kwargs['format'][:]
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()}

Expand All @@ -140,6 +158,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('<img %s />' % attr_str)
Expand Down Expand Up @@ -245,7 +266,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 "format", "anchor", and "crop".
kwargs "format", "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)::
Expand Down
9 changes: 9 additions & 0 deletions tests/test_thumbnail_tag.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest
import re
from django.template import TemplateSyntaxError

from . import imagegenerators # noqa
Expand Down Expand Up @@ -89,6 +90,14 @@ def test_alternate_generator():
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


def test_alternate_format():
ttag = r"""{% thumbnail '100x' img format='webp' as th %}{{ th.url }}"""
clear_imagekit_cache()
Expand Down

0 comments on commit aea457b

Please sign in to comment.