From 93ee915c3490e49cf0153c82fd202467a361c6b1 Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Thu, 26 Feb 2026 09:17:37 +0100 Subject: [PATCH 1/3] add original size scale in the srcset --- news/+originalinsrcset.feature | 1 + src/plone/namedfile/scaling.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 news/+originalinsrcset.feature diff --git a/news/+originalinsrcset.feature b/news/+originalinsrcset.feature new file mode 100644 index 00000000..f79e7c17 --- /dev/null +++ b/news/+originalinsrcset.feature @@ -0,0 +1 @@ +Add original image size url in the srcset generated in the srcset method @erral diff --git a/src/plone/namedfile/scaling.py b/src/plone/namedfile/scaling.py index f4bd8204..5001c682 100644 --- a/src/plone/namedfile/scaling.py +++ b/src/plone/namedfile/scaling.py @@ -764,6 +764,21 @@ def srcset( ) srcset_urls = [] + + # get first the original image url + scale = storage.pre_scale( + fieldname=fieldname, + width=original_width, + height=original_height, + mode="scale" + ) + if scale: + extension = scale["mimetype"].split("/")[-1].lower() + srcset_urls.append( + f'{self.context.absolute_url()}/@@images/{scale["uid"]}.{extension} {scale["width"]}w' + ) + + # then get the urls of the scales that are smaller than the original for width, height in self.available_sizes.values(): if width <= original_width: scale = storage.pre_scale( @@ -773,6 +788,7 @@ def srcset( srcset_urls.append( f'{self.context.absolute_url()}/@@images/{scale["uid"]}.{extension} {scale["width"]}w' ) + attributes = {} if title is _marker: attributes["title"] = self.context.Title() From 77d976bfa7758ecba98897643f756050c60dc4c0 Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Thu, 26 Feb 2026 11:24:22 +0100 Subject: [PATCH 2/3] avoid duplicating the scale if the original's size is one of the scales --- src/plone/namedfile/scaling.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/plone/namedfile/scaling.py b/src/plone/namedfile/scaling.py index 5001c682..1c9a82c0 100644 --- a/src/plone/namedfile/scaling.py +++ b/src/plone/namedfile/scaling.py @@ -765,18 +765,20 @@ def srcset( srcset_urls = [] - # get first the original image url - scale = storage.pre_scale( - fieldname=fieldname, - width=original_width, - height=original_height, - mode="scale" - ) - if scale: - extension = scale["mimetype"].split("/")[-1].lower() - srcset_urls.append( - f'{self.context.absolute_url()}/@@images/{scale["uid"]}.{extension} {scale["width"]}w' + # get first the original image url if its width is not in the available sizes + available_widths = [width for (width, height) in self.available_sizes.values()] + if original_width not in available_widths: + scale = storage.pre_scale( + fieldname=fieldname, + width=original_width, + height=original_height, + mode="scale", ) + if scale: + extension = scale["mimetype"].split("/")[-1].lower() + srcset_urls.append( + f'{self.context.absolute_url()}/@@images/{scale["uid"]}.{extension} {scale["width"]}w' + ) # then get the urls of the scales that are smaller than the original for width, height in self.available_sizes.values(): From 27c2ffa96f5fb2f55385bf0dd90ec0c080ba2aa6 Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Thu, 26 Feb 2026 11:24:44 +0100 Subject: [PATCH 3/3] adjust the tests to use as a base an image whose size is not one of the scales --- src/plone/namedfile/tests/test_scaling.py | 35 +++++++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/plone/namedfile/tests/test_scaling.py b/src/plone/namedfile/tests/test_scaling.py index f66cd455..ad90b144 100644 --- a/src/plone/namedfile/tests/test_scaling.py +++ b/src/plone/namedfile/tests/test_scaling.py @@ -813,6 +813,30 @@ def testOversizedHighPixelDensityScale(self): self.assertEqual(len(foo.srcset), 1) self.assertEqual(foo.srcset[0]["scale"], 2) + +class TestImgSrcSet(unittest.TestCase): + + layer = PLONE_NAMEDFILE_INTEGRATION_TESTING + + def setUp(self): + sm = getSiteManager() + sm.registerAdapter(PrimaryFieldInfo) + + # We use the 900 px wide image to test that the original url + # is rendered next to the all other scale urls + data = getFile("900.jpg") + item = DummyContent() + item.image = MockNamedImage(data, "image/jpeg", "image.jpg") + self.layer["app"]._setOb("item", item) + self.item = self.layer["app"].item + self._orig_sizes = ImageScaling._sizes + self.scaling = ImageScaling(self.item, None) + + def tearDown(self): + ImageScaling._sizes = self._orig_sizes + sm = getSiteManager() + sm.unregisterAdapter(PrimaryFieldInfo) + def testImgSrcSet(self): """test rendered srcset values""" self.scaling.available_sizes = { @@ -830,7 +854,7 @@ def testImgSrcSet(self): } tag = self.scaling.srcset("image", sizes="50vw") base = self.item.absolute_url() - expected = f"""foo""" + expected = f"""foo""" self.assertTrue(_ellipsis_match(expected, tag.strip())) def testImgSrcSetCustomSrc(self): @@ -850,7 +874,7 @@ def testImgSrcSetCustomSrc(self): } tag = self.scaling.srcset("image", sizes="50vw", scale_in_src="mini") base = self.item.absolute_url() - expected = f"""foo""" + expected = f"""foo""" self.assertTrue(_ellipsis_match(expected, tag.strip())) def testImgSrcSetInexistentScale(self): @@ -874,7 +898,7 @@ def testImgSrcSetInexistentScale(self): "image", sizes="50vw", scale_in_src="inexistent-scale-name" ) base = self.item.absolute_url() - expected = f"""foo""" + expected = f"""foo""" self.assertTrue(_ellipsis_match(expected, tag.strip())) def testImgSrcSetCustomTitle(self): @@ -894,7 +918,7 @@ def testImgSrcSetCustomTitle(self): } tag = self.scaling.srcset("image", sizes="50vw", title="My Custom Title") base = self.item.absolute_url() - expected = f"""foo""" + expected = f"""foo""" self.assertTrue(_ellipsis_match(expected, tag.strip())) def testImgSrcSetAdditionalAttributes(self): @@ -921,8 +945,7 @@ def testImgSrcSetAdditionalAttributes(self): loading="lazy", ) base = self.item.absolute_url() - - expected = f"""This image shows nothing""" + expected = f"""This image shows nothing""" self.assertTrue(_ellipsis_match(expected, tag.strip()))