Skip to content

ImageWorks

ImageWorks is the image processing engine in Total CMS. It transforms images on-the-fly by passing parameters to methods like cms.media.imagePath(), cms.media.galleryPath(), and cms.render.image(). Transformed images are cached automatically.

{# Basic usage #}
<img src="{{ cms.media.imagePath('hero', {w: 800, h: 600, fit: 'crop'}) }}">
{# Gallery image #}
<img src="{{ cms.media.galleryPath('vacation', 'sunset.jpg', {w: 400, fm: 'webp'}) }}">
ParameterTypeDescription
wintegerWidth in pixels
hintegerHeight in pixels
fitstringHow the image fits the dimensions (see below)
dprfloatDevice pixel ratio (e.g., 2 for retina)
ValueDescription
containResize to fit within dimensions, preserving aspect ratio
maxSame as contain but won’t upscale
fillResize to fill dimensions, cropping as needed
stretchStretch to exact dimensions (distorts)
cropCrop to exact dimensions
crop-{position}Crop anchored to a position (see below)
crop-focalpointCrop using the image’s saved focal point

Use with fit: 'crop-{position}':

top-left, top, top-right, left, center, right, bottom-left, bottom, bottom-right

{# Crop from the top of the image #}
{{ cms.media.imagePath('hero', {w: 800, h: 400, fit: 'crop-top'}) }}
{# Crop using the focal point set in the admin #}
{{ cms.media.imagePath('portrait', {w: 300, h: 300, fit: 'crop-focalpoint'}) }}
ParameterTypeDescription
fmstringOutput format: jpg, png, gif, webp, avif
qintegerQuality (1-100, default varies by format)
{# Convert to WebP at 80% quality #}
{{ cms.media.imagePath('photo', {w: 1200, fm: 'webp', q: 80}) }}
{# AVIF for maximum compression #}
{{ cms.media.imagePath('photo', {w: 1200, fm: 'avif', q: 70}) }}
ParameterTypeDescription
blurintegerBlur amount (0-100)
sharpintegerSharpen amount (0-100)
pixelintegerPixelate amount (0-1000)
filtstringFilter: greyscale, sepia
briintegerBrightness adjustment (-100 to 100)
conintegerContrast adjustment (-100 to 100)
gamfloatGamma correction (0.1 to 9.99)
{# Blurred background #}
{{ cms.media.imagePath('bg', {w: 1920, blur: 20}) }}
{# Greyscale thumbnail #}
{{ cms.media.imagePath('portrait', {w: 200, filt: 'greyscale'}) }}
{# Sharpened product photo #}
{{ cms.media.imagePath('product', {w: 600, sharp: 15}) }}
ParameterTypeDescription
borderstringBorder in format: size,color,method

Border methods: overlay (default), shrink, expand

{# 10px white border #}
{{ cms.media.imagePath('photo', {w: 500, border: '10,ffffff,overlay'}) }}
ParameterTypeDescription
flipstringFlip: h (horizontal), v (vertical), both
orstringOrientation: auto, 0, 90, 180, 270

Overlay another image as a watermark.

ParameterTypeDescription
markstringWatermark image filename
markwmixedWatermark width (pixels or percentage like 25w)
markhmixedWatermark height (pixels or percentage like 25h)
markposstringPosition: top-left, top, top-right, left, center, right, bottom-left, bottom, bottom-right
markpadintegerPadding from edge in pixels
markalphaintegerOpacity (0-100, where 100 is fully opaque)
markfitstringHow the watermark fits: contain, max, fill, stretch, crop
{# Logo watermark in bottom-right corner #}
{{ cms.media.imagePath('photo', {
w: 1200,
mark: 'logo.png',
markw: '15w',
markpos: 'bottom-right',
markpad: 20,
markalpha: 70
}) }}

You can configure watermarks at the schema, collection, or per-object level using property settings. These are applied automatically without needing to pass parameters in templates.

{
"image": {
"field": "image",
"label": "Photo",
"settings": {
"watermark": {
"mark": "logo.png",
"markw": "20w",
"markpos": "bottom-right",
"markpad": 15,
"markalpha": 60
}
}
}
}

Watermark settings follow the three-level override hierarchy: schema → collection → per-object. Override at the collection level in collection meta, or per-object using custom properties.

Render text directly on images without needing a separate watermark image.

ParameterTypeDescription
marktextstringText to render
marktextfontstringFont family name (TTF/OTF from the watermark-fonts depot)
marktextsizeintegerText size in pixels (default: 500)
marktextcolorstringText color as hex without # (e.g., ffffff)
marktextbgstringBackground color as hex (optional, transparent if not set)
marktextpadintegerPadding around text in pixels (default: 10)
marktextangleintegerRotation angle in degrees (-360 to 360, default: 0)
marktextposstringPosition (same options as image watermarks)
marktextwmixedMax text width in pixels or relative (e.g., 50w for 50% of image width)
marktextalphaintegerTransparency (0-100, where 100 is fully opaque)

Upload TTF or OTF fonts to the watermark-fonts depot (configurable via watermarkFontsDepot setting). The default font is RobotoRegular.

{# Simple copyright watermark #}
{{ cms.media.imagePath('hero', {
w: 1200,
marktext: 'Copyright 2026',
marktextsize: 24,
marktextcolor: 'ffffff',
marktextpos: 'bottom-right',
marktextpad: 15,
marktextalpha: 70
}) }}
{# Custom font with background #}
{{ cms.media.imagePath('product', {
w: 800,
marktext: 'Premium Quality',
marktextfont: 'Dorsa-Regular',
marktextsize: 120,
marktextcolor: 'ffffff',
marktextbg: '000000',
marktextpad: 20,
marktextpos: 'bottom-right',
marktextalpha: 80
}) }}
{# Diagonal DRAFT watermark #}
{{ cms.media.imagePath('document', {
marktext: 'DRAFT',
marktextsize: 200,
marktextangle: -45,
marktextcolor: 'ff0000',
marktextpos: 'center',
marktextalpha: 50
}) }}

Images in Total CMS have an automatically extracted color palette (up to 5 colors). You can reference these palette colors in border and bg (background) parameters.

Use palette0 through palette4 to reference extracted colors:

{# Background color from the image's dominant color #}
{{ cms.media.imagePath('photo', {w: 800, bg: 'palette0'}) }}
{# Border using a palette color #}
{{ cms.media.imagePath('photo', {w: 500, border: '10,palette1,overlay'}) }}

Set default ImageWorks parameters that apply to every image transformation. Configure in tcms.php:

return [
'imageworks' => [
'defaults' => [
'q' => 85,
'fm' => 'webp',
],
],
];

Any parameters passed in templates override the defaults.

Define reusable parameter sets that can be referenced by name. Configure in tcms.php:

return [
'imageworks' => [
'presets' => [
'thumbnail' => [
'w' => 200,
'h' => 200,
'fit' => 'crop',
'q' => 80,
],
'hero' => [
'w' => 1920,
'h' => 600,
'fit' => 'crop-focalpoint',
'fm' => 'webp',
'q' => 85,
],
'avatar' => [
'w' => 100,
'h' => 100,
'fit' => 'crop',
],
],
],
];

Use presets by passing the p parameter:

{{ cms.media.imagePath('photo', {p: 'thumbnail'}) }}
{{ cms.media.imagePath('banner', {p: 'hero'}) }}
{# Override specific preset values #}
{{ cms.media.imagePath('photo', {p: 'thumbnail', w: 300}) }}

Presets that use crop-focalpoint in their fit value will automatically use each image’s saved focal point.

Transformed images are cached automatically on disk. The cache directory is .cache within the image storage directory. When the source image changes, cached versions are regenerated on the next request.

To clear the ImageWorks cache, use the emergency cache clear endpoint or clear the .cache directories from storage.

ImageWorks images are served via the /imageworks/ endpoint:

/imageworks/{type}/{id}/{filename}?{parameters}

Where type is image or gallery, id is the object ID, and parameters are ImageWorks transformation params. You typically don’t need to construct these URLs manually — use cms.media.imagePath() and cms.media.galleryPath() instead.