Image handling#
The default content types and behaviors use the field plone.namedfile.NamedBlobImage
for all images.
For this field, image scaling and HTML tag creation is provided by the plone.namedfile.scaling
module, specifically in the ImageScaling
view.
Given a Dexterity content type named news-item1
with a plone.namedfile.NamedBlobImage
field named image
, we can use the following APIs to access the image scales and manage scales.
Note
We will use the image object as context in the following examples.
Default scales#
In /@@imaging-controlpanel
Plone allows you to configure which scales are available and what dimensions they should have.
By default, we have the following scales configured:
huge 1600:65536
great 1200:65536
larger 1000:65536
large 800:65536
teaser 600:65536
preview 400:65536
mini 200:65536
thumb 128:128
tile 64:64
icon 32:32
listing 16:16
You can add or change scales as you like.
The scales are defined in plone.base.interfaces.controlpanel
.
Image resolving by URI#
Plone can resolve an image scale via URI in different ways.
By field and scale name#
Given our news-item1
with the field image
, we can get the name scale thumb
as follows:
http://localhost:8080/Plone/news-item1/@@images/image/thumb
To get the original image, you can leave out the scale:
http://localhost:8080/Plone/news-item1/@@images/image
By cacheable scale UID name#
When an image scale is created, it will be cached under the name UID.EXT
(such as f4c34254b44ba351af7393bfe0296664.jpeg
) in the object annotations.
Scaling keeps the uploaded formats, except for TIFF which ends up as JPEG.
It can be resolved as follows:
http://localhost:8080/Plone/news-item1/@@images/3d182f34-8773-4f20-a79d-8774c3151b7e.jpeg
This is useful for caching URLs in Varnish or the browser. In case the uploaded image or scale definitions have changed, they will be saved again under a different UID. This changes the URL and forces either the browser, or a cache proxy such as Varnish, to fetch it again. When a scale has changed, the old stored entry in the annotation will be deleted after 24 hours. If one changes an image which is used in multiple pages, the updated versions will only be shown after a restart of the Plone instance, saving the pages again, or after 24 hours.
Image tag#
To get an HTML tag for a scaled image, you can use the ImageScaling
view as follows:
from plone import api
scale_util = api.content.get_view("images", context, request)
tag = scale_util.tag("image", scale="mini")
To get a specific image size:
from plone import api
scale_util = api.content.get_view("images", context, request)
tag = scale_util.tag("image", width=600, height=200)
The complete list of arguments with their default values is shown in the following example.
from plone import api
scale_util = api.content.get_view("images", context, request)
tag = scale_util.tag(
fieldname=None,
scale=None,
height=None,
width=None,
mode="scale"
)
If you pass additional kwargs
to tag
, they become attributes on tag
.
Image scaling without tag creation#
To get the scaling information only without creating an HTML tag, you can use the ImageScaling
view as follows:
from plone import api
scale_util = api.content.get_view("images", context, request)
# The default `Image` content type's field name is "image".
# On the following line of code, "image" is the field name.
image_scale = scale_util.scale("image", scale="mini")
print(image_scale.url)
print(image_scale.width)
print(image_scale.height)
This will produce the following output:
http://localhost:8080/Plone/news-item1/@@images/3d182f34-8773-4f20-a79d-8774c3151b7e.jpeg
200
110
The most important properties are the following:
data
fieldname
height
mimetype
srcset
srcset_attribute
tag
uid
url
width
You can directly create an HTML tag from image_scale
:
>>> print(image_scale.tag())
<img src="http://localhost:8080/Plone/news/newsitem1/@@images/9f676d46-0cb3-4512-a831-a5db4079bdfa.jpeg" alt="News Item 1!" title="News Item 1" height="21" width="32" srcset="http://localhost:8080/Plone/news/newsitem1/@@images/4a68513c-cffd-4de0-8a35-80627945b80f.jpeg 2x, http://localhost:8080/Plone/news/newsitem1/@@images/c32929c6-cb89-4ce7-846f-38adf29c09a4.jpeg 3x" />
Instead of using the configured named scales, you can get an HTML tag with any specific size in pixels:
from plone import api
scale_util = api.content.get_view("images", context, request)
tag = scale_util.scale("image", width=600, height=200)
Using image_scale
in templates#
You could use the URL-variant from above, but that version would not be cached. To create a cached scale in a page template you can do the following:
<div tal:define="scale_view context/@@images;
image_scale python: scale_view.scale('image', 'mini')">
<img
src="${python: image_scale.url}"
width="${python: image_scale.width"
height="${python: image_scale.height}"
>
</div>
Or you can get the HTML tag back, and replace the current tag with it:
<div tal:define="scale_view context/@@images">
<img tal:replace="structure python: scale_view.tag('image', 'mini')">
</div>
You can also provide the following keyword arguments to set title
, alt
, or css_class
for the generated tag:
<div tal:define="scale_view context/@@images">
<img tal:replace="structure python: scale_view.tag('banner', 'mini', title='The Banner', alt='Alternative text', css_class='banner')">
</div>
Get image_scale
by cached UID name#
If you only have the cached image name from a URL and need to get the image scale, unfortunately you can't use restrictedTraverse()
, as this will not be able to resolve the scale.
But you can use this workaround, by calling the publishTraverse
method in ImageScaling
directly:
import re
from plone import api
uri = "http://localhost:8080/Plone/news-item1/@@images/3d182f34-8773-4f20-a79d-8774c3151b7e.jpeg"
image_url = re.compile(r"(.*@@images)\/([a-zA-Z0-9.-]*)\/?([a-zA-Z]*)")
url_match = image_url.match(uri)
groups = url_match.groups()
# ("http://localhost:8080/Plone/news-item1", "3d182f34-8773-4f20-a79d-8774c3151b7e.jpeg")
scale_util = api.content.get_view("images", context, request)
image_scale = scaling_util.publishTraverse(context.REQUEST, groups[1])
Scaling mode
#
Changed in version 6.0: Added mode
to replace the deprecated direction
.
Added new option names for mode
to align with CSS background-size
values, and deprecated previous names keep
, thumbnail
, scale-crop-to-fit
, down
, scale-crop-to-fill
, and up
.
Scaling is intended for the optimal display of images in a web browser.
To scale an image, you can use the mode
parameter to control the scaling output.
You must use either width
or height
, or both.
Three different scaling options are supported.
They correspond to the CSS background-size
values.
The possible options for mode
are listed below, where the default option is scale
.
scale
This is the default option.
scale
scales to the requested dimensions without cropping. The resulting image may have a different size than requested. This option requires bothwidth
andheight
to be specified. It does not scale up.Deprecated option names:
keep
,thumbnail
.contain
contain
starts by scaling the image either to the smaller dimension when you give bothwidth
andheight
, or to the only given dimension, then crops to the other dimension if needed.Deprecated option names:
scale-crop-to-fit
,down
.cover
cover
scales the image either to the larger dimension when you give bothwidth
andheight
, or to the only given dimension, up to the size you specify. Despite the deprecated option name, it does not crop.Deprecated option names:
scale-crop-to-fill
,up
.
Permissions#
The ImageScaling
view explicitly checks the permissions of the current user.
To access image scales, which are normally not accessible to the current user, override the validate_access
method in plone.namedfile.scaling.ImageScale
.
Responsive image support#
Plone supports the generation of picture
tags with srcset
s for image optimization.
Additionally, you can define media queries for art direction and further optimization.
The configuration allows you to define different picture
variants, such as Large
, Medium
, or Small
.
Users can choose from them in editors, such as TinyMCE, and developers can use them in templates.
To generate a picture
tag, use the following code.
from plone import api
scale_util = api.content.get_view("images", context, request)
tag = scale_util.picture("image", scale="larger", picture_variant="large")
The same can be done from a template.
<div tal:define="scale_view context/@@images">
<img tal:replace="structure python:scale_view.picture('image', scale='larger', picture_variant='large'" />
</div>
picture
variants#
In /@@imaging-controlpanel
Plone allows you to define picture
variants with a list of available image scales.
These are used for HTML srcset attributes.
A srcset
attribute can help the browser to serve the best fitting image size for the current user's display.
Default configuration#
The default configuration covers image size optimization, and will provide the browser with the needed information to load the optimal image size.
{
"large": {
"title": "Large",
"sourceset": [
"scale": "larger",
"additionalScales": ["preview", "teaser", "large", "great", "huge"],
],
},
"medium": {
"title": "Medium",
"sourceset": [
"scale": "teaser",
"additionalScales": ["preview", "large", "larger", "great"],
],
},
"small": {
"title": "Small",
"sourceset": [
"scale": "preview",
"additionalScales": ["large", "larger"],
],
},
}
Optional settings#
The sourceset
property is an array and can have more than one entry.
If we have the following two entries, the image_srcset
output filter will generate one source
tag for each entry and an additional img
tag from the last entry.
{
"medium": {
"title": "Large",
"sourceset": [
{
"scale": "mobile_crop",
"media": "(max-width: 768px)",
"additionalScales": ["mobile_crop_highres"],
},
{
"scale": "teaser",
"media": "(min-width: 769px)",
"additionalScales": ["large", "larger", "great", "huge"],
}
],
},
}
Filtering scales#
By default, for every srcset
, all available scales will be included in the srcset
.
{
"large": {
"title": "Large",
"sourceset": [
{"scale": "larger"},
],
},
}
To restrict the list of used scales inside a srcset
, you can set the additionalScales
parameter with an array of allowed scales.
Without this parameter, all scales which are not globally excluded scales will be used.
"small": {
"title": "Small",
"sourceset": [
{
"scale": "preview",
"additionalScales": ["large", "larger", "great", "huge"],
},
],
},
This means the generated srcset
will contain the scales from preview
up to huge
, but not mini
, for example.
Hiding a picture
variant in editors#
It is possible to hide a picture
variant in editors.
This is useful when you want to define a picture
variant to be used in templates only.
"leadimage": {
"title": "Lead image",
"sourceset": [
{
"scale": "preview",
"additionalScales": ["large", "larger"],
"hideInEditor": true,
},
],
},
Art direction#
With image size optimization, the browser is able to choose the optimal image for each display size. But we have no control over which scale the browser will actually use. For example to force the browser to use a zoomed version of an image for smaller screens, we can use media queries. The technique is called art direction.
Let's have a look at a more advanced configuration:
{
"large": {
"title": "Large",
"sourceset": [
{"scale": "larger"},
],
},
"medium": {
"title": "Medium",
"sourceset": [
{
"scale": "mobile_crop",
"media": "(max-width: 768px)",
"additionalScales": ["mobile_crop_highres"],
},
{
"scale": "teaser",
"media": "(min-width: 769px)",
"additionalScales": ["large", "larger", "great", "huge"],
}
],
},
"small": {
"title": "Small",
"sourceset": [
{"scale": "preview"},
],
},
}
This will result in a srcset
as in the following example for a medium image:
<picture>
<source media="(max-width: 677px)"
srcset="resolveuid/45fed06defa54d15b37c5b1dc882710c/@@images/image/mobile_crop 800w,
resolveuid/45fed06defa54d15b37c5b1dc882710c/@@images/image/mobile_crop_highres 1600w">
<source media="(min-width: 678px)"
srcset="resolveuid/45fed06defa54d15b37c5b1dc882710c/@@images/image/teaser 600w,
resolveuid/45fed06defa54d15b37c5b1dc882710c/@@images/image/large 800w,
resolveuid/45fed06defa54d15b37c5b1dc882710c/@@images/image/larger 1000w,
resolveuid/45fed06defa54d15b37c5b1dc882710c/@@images/image/great 1200w">
<img alt="Alternative text"
class="image-richtext image-size-medium"
loading="lazy"
src="resolveuid/45fed06defa54d15b37c5b1dc882710c/@@images/image/teaser"
width="600"
height="400">
</picture>
Note
Please note that this example has the resolve_uid_and_caption
filter disabled to see the scale names better.
The real src
URLs look more like http://localhost:8080/Plone50/dsc04791.jpg/@@images/778f9c06-36b0-485d-ab80-12c623dc4bc3.jpeg
.
Image scales from catalog brain#
For all NamedBlobImage
fields, we can get existing scale information directly from the catalog brain.
Given a content type with a NamedBlobField
named picture
, we can get the following information by calling the image_scales
attribute on the catalog brain.
(Pdb) pp brain.image_scales
{'picture': [{'content-type': 'image/jpeg',
'download': '@@images/picture-800-ddae07fbc46b293155bd6fcda7f2572a.jpeg',
'filename': 'my-picture.jpg',
'height': 800,
'scales': {'icon': {'download': '@@images/picture-32-f2f815374aa5434e06fb3a95306527fd.jpeg',
'height': 32,
'width': 32},
'large': {'download': '@@images/picture-800-4dab3b3cc42abb6fad29258c7430070a.jpeg',
'height': 800,
'width': 800},
'listing': {'download': '@@images/picture-16-d3ac2117158cf38d0e15c5f5feb8b75d.jpeg',
'height': 16,
'width': 16},
'mini': {'download': '@@images/picture-200-3de96ae4288dfb18f5589c89b861ecc1.jpeg',
'height': 200,
'width': 200},
'preview': {'download': '@@images/picture-400-60f60942c8e4ddd7dcdfa90527a8bae0.jpeg',
'height': 400,
'width': 400},
'teaser': {'download': '@@images/picture-600-1ada88b8af6748e9cbe18a34c3127443.jpeg',
'height': 600,
'width': 600},
'thumb': {'download': '@@images/picture-128-80fce253497f7a745315f58f3e8f3a0c.jpeg',
'height': 128,
'width': 128},
'tile': {'download': '@@images/picture-64-220d6703eac104c59774a379a8276e76.jpeg',
'height': 64,
'width': 64}},
'size': 238977,
'width': 800}]}
This information shows we have everything we need to generate our image URLs, without waking up any objects.
<li tal:define="preview python: brain.image_scales['picture'][0]['scales']['preview']">
<img src="${brain/getURL}/${python: preview['download']}"
width="${python: preview['width']}"
height="${python: preview['height']}" />
</li>