The platform's central abstraction, in one line: an input type defines what an editor can enter, a layout area binds one input type to a named slot, a layout groups areas and points at a template, a record or component holds the content for each area, and the template reads it back. Read this book straight after the template languages.
L1–L3
Unit 08 · Images end to end
Resizing, converting and rendering an image
Images end to endPage 33 of 45Updated
Resize an image, convert its format and render the tag: what getResized(), toOptimizedFormat(), toFormat() and getHtml() do, the order to chain them in and why, and what happens to pixel sizes in a style attribute.
Who this is for. Developers rendering images in templates. After this page you can serve an image at the size and format the design needs, chain the calls in the order that fails safely and caches once, and pass the attributes that matter.
Resizing with getResized()
getResized(width, height, strategy) is the call you will use most. Pass null for a dimension you do not set. The strategy says how the requested box is reconciled with the image's own shape; it defaults to auto, and all seven are on Resize strategies.
Nothing is resized while the template renders. The call returns a new image object whose path describes the resize; the resized file is generated the first time a browser requests that path, then cached. The first visitor waits slightly longer and everyone after them gets the cached copy. If the requested size equals the original's, nothing is resized and the plain path is used.
Calling getResized() twice does not resize twice: the second call replaces the first. Two format conversions behave the same way.
When a resize is impossible
A strategy that does not exist, or one called without a dimension it needs (fit with only a width, say), is an error. What happens next depends on where the call sits in the chain:
On an image straight from an area, the error is logged and the original, full-size image is returned. The page renders, with a much heavier file than intended.
On an image that has already been resized or converted, for example after toOptimizedFormat(), the error is not caught and the page fails.
If an image on a live page is unexpectedly heavy, check its resize arguments first.
Converting the format
toOptimizedFormat()
toOptimizedFormat() converts to WebP; call it without an argument. It returns the image unchanged when it is an SVG or already WebP, so it is safe to call on every image.
A converted image's path ends in the new extension and names the original format in f: hero.jpg becomes hero.webp?f=jpg. The conversion is done when the file is requested. If no image service can do it then, the original file is delivered under that URL instead (see Compression, image services and imported images).
toFormat()
toFormat(target, sources) converts explicitly. With the optional list of source formats, it converts only images whose current format is in the list and returns the rest unchanged; an image already in the target format is returned unchanged too. The case that motivates it is a consumer that cannot take WebP, such as an email client or a social network's sharing image: convert GIFs to PNG, and leave everything else alone.
Template code
{$image->toFormat('png', ['gif'])->getPath()}
{{ image.toFormat('png', ['gif']).getPath() }}
Converting the format
To convert an image, ask for png or webp, whether through toFormat() or in the URL (see Converting to PNG or WebP). For a consumer that needs an image other than WebP, ask for PNG.
The order does not change the pixels. Each call adds its transformation to the image object, and when the file is requested the image service applies them in its own fixed order, resize, then convert, then compress, whatever order the template called them in. So getResized(800, 450, 'fit')->toOptimizedFormat() and toOptimizedFormat()->getResized(800, 450, 'fit') deliver the same image. The order matters for two other reasons:
Errors. Resizing first keeps the quiet fallback above: a bad resize on the original returns the original. Converting first turns the same mistake into a failed page.
Caching. The query string follows the call order. Resizing first gives hero.webp?w=800&h=450&s=fit&f=jpg; converting first gives hero.webp?f=jpg&w=800&h=450&s=fit. They are two URLs for one image, so templates that mix the orders cache every image twice.
The rule: in every template, resize, then convert, then render with getHtml() or take the URL with getPath(). Without a conversion, resize, then render.
Rendering the tag with getHtml()
getHtml() takes the HTML attributes as an array and returns the markup: an <img>, or a <picture> when the site generates picture tags (see Picture tags and responsive sources). Printing the image object directly, {$image} or {{ image }}, does the same with no attributes.
Defaults to the image's name when you do not pass it.
loading
Written as given, with no default. Use 'lazy' below the fold; leave it off for the main image at the top of a page.
fetchpriority
Written as given, with no default. 'high' suits the main image at the top of a page.
class
Written as given.
width, height
Added automatically from the size you asked getResized() for. Asking for only a width gives only a width attribute plus an aspect-ratio style. An image that was not resized gets neither, so pass them yourself: 'width' => $image->getWidth().
Anything else
Written as given, except that an array value is dropped. offeredSizes is read by the picture tag and never printed.
Attribute values are not escaped
getHtml() writes every attribute value into the tag as it is, including the default alt taken from the image's name. A name with a quote in it, or alt text an editor typed, can break the tag. Escape every value you pass: |escape in Smarty, |e in Twig.
Pixel sizes in a style attribute become the image size
If you pass a style with a width or height in pixels, getHtml() takes them out of the style, resizes the image to them, and writes them as width and height attributes. The src is a resized file, not the original scaled down by CSS. With both a width and a height the resize uses the exact strategy; with one, auto. Values in other units, such as % or rem, stay in the style untouched. This happens on the site's pages, not in the admin.
Here the image is resized to 300 pixels wide, the tag gets width="300", and only border-radius: 8px is left in the style. It stops a page downloading a 3,000-pixel file to show it at 300, and it surprises anyone who looks for their width in the style and finds it gone.