Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/179.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
set sizes attribute on picture-tags [MrTango]
2 changes: 2 additions & 0 deletions news/180.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
allow to set lazy to false, to suppress the loading="lazy" attribute
[MrTango]
32 changes: 19 additions & 13 deletions plone/namedfile/picture.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,19 @@ def get_scale_width(self, scale):
return scale_info[0]

def create_picture_tag(
self, sourceset, attributes, uid=None, fieldname=None, resolve_urls=False
self,
sourceset,
attributes,
uid=None,
fieldname=None,
resolve_urls=False,
lazy=True,
):
"""Converts the img tag to a picture tag with picture_variant definition"""
width = None
height = None
target_width = None
sizes = ""
src = attributes.get("src")
if not uid and not src:
raise TypeError("Either uid or attributes['src'] need to be given.")
Expand All @@ -68,6 +76,7 @@ def create_picture_tag(
for i, source in enumerate(sourceset):
target_scale = source["scale"]
media = source.get("media")
sizes = source.get("sizes")

additional_scales = source.get("additionalScales", None)
if additional_scales is None:
Expand All @@ -78,6 +87,8 @@ def create_picture_tag(
source_srcset = []
for scale in source_scales:
scale_width = self.get_scale_width(scale)
if scale == target_scale:
target_width = scale_width
if not scale_width:
logger.warning("No width found for scale %s.", scale)
continue
Expand All @@ -86,13 +97,13 @@ def create_picture_tag(
scale_obj = scale_view.scale(fieldname, scale, pre=True)
scale_url = scale_obj.url
else:
# obj = self.resolve_uid_url(src)
# scale_view = obj.unrestrictedTraverse("@@images", None)
# scale_obj = scale_view.scale(fieldname, scale, pre=True)
# scale_url = scale_obj.url
scale_url = self.update_src_scale(src=src, scale=scale)
source_srcset.append(f"{scale_url} {scale_width}w")
source_tag = soup.new_tag("source", srcset=",\n".join(source_srcset))
if not sizes:
sizes = f"(min-width: 576px) {target_width}px, (min-width: 768px) 600px, 98vw"
source_tag = soup.new_tag(
"source", srcset=",\n".join(source_srcset), sizes=sizes
)
if media:
source_tag["media"] = media
picture_tag.append(source_tag)
Expand All @@ -104,19 +115,14 @@ def create_picture_tag(
width = scale_obj.width
height = scale_obj.height
else:
# obj = self.resolve_uid_url(src)
# scale_view = obj.unrestrictedTraverse("@@images", None)
# scale_obj = scale_view.scale(fieldname, target_scale, pre=True)
# scale_url = scale_obj.url
# width = scale_obj.width
# height = scale_obj.height
scale_url = self.update_src_scale(src=src, scale=target_scale)
img_tag = soup.new_tag("img", src=scale_url)
for k, attr in attributes.items():
if k in ["src", "srcset"]:
continue
img_tag.attrs[k] = attr
img_tag["loading"] = "lazy"
if lazy:
img_tag["loading"] = "lazy"
if width:
img_tag["width"] = width
if height:
Expand Down
2 changes: 2 additions & 0 deletions plone/namedfile/scaling.py
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,7 @@ def picture(
alt=None,
css_class=None,
title=_marker,
lazy=True,
**kwargs,
):
img2picturetag = Img2PictureTag()
Expand Down Expand Up @@ -735,6 +736,7 @@ def picture(
resolve_urls=True,
uid=scale.context.UID(),
fieldname=fieldname,
lazy=lazy,
).prettify()

def srcset(
Expand Down
82 changes: 77 additions & 5 deletions plone/namedfile/tests/test_scaling.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ def patch_Img2PictureTag_picture_variants():
"sourceset": [
{
"scale": "preview",
"additionalScales": ["preview", "large", "larger"],
"additionalScales": ["large", "larger"],
"sizes": "(min-width: 576px) 350px, (min-width: 768px) 600px, 98vw",
}
],
},
Expand Down Expand Up @@ -538,22 +539,93 @@ def testGetPictureTagByName(self, mock_uuid_to_object):
mock_uuid_to_object.return_value = self.item
tag = self.scaling.picture("image", picture_variant="medium")
expected = """<picture>
<source srcset="http://nohost/item/@@images/image-600-....png 600w,
<source...srcset="http://nohost/item/@@images/image-600-....png 600w,
http://nohost/item/@@images/image-400-....png 400w,
http://nohost/item/@@images/image-800-....png 800w,
http://nohost/item/@@images/image-1000-....png 1000w,
http://nohost/item/@@images/image-1200-....png 1200w"/>
http://nohost/item/@@images/image-1200-....png 1200w".../>
<img...src="http://nohost/item/@@images/image-600-....png".../>
</picture>"""
self.assertTrue(_ellipsis_match(expected, tag.strip()))
# The exact placement of the img tag attributes can differ, especially
# with different beautifulsoup versions.
# So check here that all attributes are present.
self.assertIn('height="200"', tag)
self.assertIn('loading="lazy"', tag)
self.assertIn('title="foo"', tag)
self.assertIn('width="200"', tag)
self.assertIn('sizes="(min-width: 576px) 600px, 98vw"', tag)

@patch.object(
plone.namedfile.scaling,
"get_picture_variants",
new=patch_Img2PictureTag_picture_variants,
spec=True,
)
@patch.object(
plone.namedfile.picture,
"get_allowed_scales",
new=patch_Img2PictureTag_allowed_scales,
spec=True,
)
@patch.object(plone.namedfile.picture, "uuidToObject", spec=True)
def testGetPictureTagByNameNotLazy(self, mock_uuid_to_object):
ImageScaling._sizes = patch_Img2PictureTag_allowed_scales()
mock_uuid_to_object.return_value = self.item
tag = self.scaling.picture("image", picture_variant="medium", lazy=False)
print(tag)
expected = """<picture>
<source...srcset="http://nohost/item/@@images/image-600-....png 600w,
http://nohost/item/@@images/image-400-....png 400w,
http://nohost/item/@@images/image-800-....png 800w,
http://nohost/item/@@images/image-1000-....png 1000w,
http://nohost/item/@@images/image-1200-....png 1200w".../>
<img...src="http://nohost/item/@@images/image-600-....png".../>
</picture>"""
self.assertTrue(_ellipsis_match(expected, tag.strip()))
# The exact placement of the img tag attributes can differ, especially
# with different beautifulsoup versions.
# So check here that all attributes are present.
self.assertIn('height="200"', tag)
self.assertNotIn('loading="lazy"', tag)
self.assertIn('title="foo"', tag)
self.assertIn('width="200"', tag)
self.assertIn('sizes="(min-width: 576px) 600px, 98vw"', tag)

@patch.object(
plone.namedfile.scaling,
"get_picture_variants",
new=patch_Img2PictureTag_picture_variants,
spec=True,
)
@patch.object(
plone.namedfile.picture,
"get_allowed_scales",
new=patch_Img2PictureTag_allowed_scales,
spec=True,
)
@patch.object(plone.namedfile.picture, "uuidToObject", spec=True)
def testGetPictureTagCustomSizes(self, mock_uuid_to_object):
ImageScaling._sizes = patch_Img2PictureTag_allowed_scales()
mock_uuid_to_object.return_value = self.item
tag = self.scaling.picture("image", picture_variant="small")
expected = """<picture>
<source...srcset="http://nohost/item/@@images/image-400-....png 400w,
http://nohost/item/@@images/image-800-....png 800w,
http://nohost/item/@@images/image-1000-....png 1000w".../>
<img...src="http://nohost/item/@@images/image-400-....png".../>
</picture>"""
self.assertTrue(_ellipsis_match(expected, tag.strip()))
# The exact placement of the img tag attributes can differ, especially
# with different beautifulsoup versions.
# So check here that all attributes are present.
self.assertIn('height="200"', tag)
self.assertIn('loading="lazy"', tag)
self.assertIn('title="foo"', tag)
self.assertIn('width="200"', tag)
self.assertIn(
'sizes="(min-width: 576px) 350px, (min-width: 768px) 600px, 98vw"', tag
)

@patch.object(
plone.namedfile.scaling,
Expand All @@ -579,11 +651,11 @@ def testGetPictureTagWithAltAndTitle(self, mock_uuid_to_object):
)
base = self.item.absolute_url()
expected = f"""<picture>
<source srcset="{base}/@@images/image-600-....png 600w,
<source...srcset="{base}/@@images/image-600-....png 600w,
{base}/@@images/image-400-....png 400w,
{base}/@@images/image-800-....png 800w,
{base}/@@images/image-1000-....png 1000w,
{base}/@@images/image-1200-....png 1200w"/>
{base}/@@images/image-1200-....png 1200w".../>
<img...src="{base}/@@images/image-600-....png".../>
</picture>"""
self.assertTrue(_ellipsis_match(expected, tag.strip()))
Expand Down
6 changes: 3 additions & 3 deletions plone/namedfile/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ def get_exif(image, content_type=None, width=None, height=None):
except Exception as e:
# TODO: determ which error really happens
# Should happen if data is to short --> first_bytes
log.warn(e)
log.warning(e)
exif_data = exif_data = {
"0th": {
piexif.ImageIFD.XResolution: (width, 1),
Expand All @@ -299,7 +299,7 @@ def rotate_image(image_data, method=None, REQUEST=None):
try:
exif_data = piexif.load(img.info["exif"])
except ValueError:
log.warn("Exif information corrupt")
log.warning("Exif information corrupt")
pass
if exif_data and piexif.ImageIFD.Orientation in exif_data["0th"]:
orientation = exif_data["0th"][piexif.ImageIFD.Orientation]
Expand Down Expand Up @@ -366,7 +366,7 @@ def rotate_image(image_data, method=None, REQUEST=None):
try:
exif_bytes = piexif.dump(exif_data)
except Exception as e:
log.warn(e)
log.warning(e)
del exif_data["Exif"][piexif.ExifIFD.SceneType]
# This Element piexif.ExifIFD.SceneType cause error on dump
exif_bytes = piexif.dump(exif_data)
Expand Down
Loading