Configuration 

The extension works out of the box with sensible defaults. All three operating modes -- on-demand frontend processing, on-upload compression, and bulk CLI -- activate automatically after installation. This page documents the extension points that can be tweaked.

SourceSetViewHelper 

The SourceSetViewHelper generates responsive <img> tags with srcset attributes.

Basic ViewHelper usage
{namespace nr=Netresearch\NrImageOptimize\ViewHelpers}

<nr:sourceSet path="{f:uri.image(image: image)}"
              width="1200"
              height="800"
              alt="{image.properties.alternative}"
              sizes="(max-width: 768px) 100vw, 50vw"
              responsiveSrcset="1"
/>
Copied!

Parameters 

path
Type
string
Required

true

Public path to the source image (for example /fileadmin/foo.jpg), typically generated via f:uri.image().

width
Type
int|float
Default
0

Base width in pixels for the rendered <img>. 0 resolves automatically from the source file. Clamped by the processor to 1--8192 when baked into the variant URL.

height
Type
int|float
Default
0

Base height in pixels. 0 preserves aspect ratio relative to width. Clamped by the processor to 1--8192.

set
Type
array
Default
[]

Responsive set in the form {maxWidth: {width: int, height: int}}. Each entry becomes a <source media="(max-width: <maxWidth>px)"> tag.

alt
Type
string
Default
empty string

Alternative text for the image. Always rendered (even when empty) to keep assistive-tech compatibility.

title
Type
string
Default
empty string

HTML-escaped title attribute.

class
Type
string
Default
empty string

CSS classes for the <img> tag. Include lazyload to switch from native to JS-based lazy loading (see Lazy loading).

mode
Type
string
Default
cover

Render mode. cover resizes images to fully cover the given dimensions (crop/fill). fit resizes images to fit within the given dimensions.

lazyload
Type
boolean
Default
false

Add loading="lazy" (native lazy loading).

responsiveSrcset
Type
boolean
Default
false

Enable width-based responsive srcset instead of the density-based 2x output (preserved for backward compatibility).

widthVariants
Type
string|array
Default
480, 576, 640, 768, 992, 1200, 1800

Width variants for responsive srcset (comma-separated string or array). Only honored when responsiveSrcset is enabled.

sizes
Type
string
Default
auto, (min-width: 992px) 991px, 100vw

Responsive sizes attribute for the generated <img> tag.

fetchpriority
Type
string
Default
empty string

Native HTML fetchpriority attribute. Allowed values: high, low, auto. Omitted when empty.

skipWebP
Type
boolean
Default
false

Add skipWebP=1 to every /processed/ URL the ViewHelper renders (src, srcset, width variants and <source> sets), so the processor writes no .webp sidecar for these variants. See Variant negotiation.

skipAvif
Type
boolean
Default
false

Add skipAvif=1 to every /processed/ URL the ViewHelper renders, so the processor writes no .avif sidecar for these variants. With both flags set, each variant is written in its source format only. See Variant negotiation.

attributes
Type
array
Default
[]

Extra HTML attributes merged into the rendered tag.

Source set configuration 

Define source sets per media breakpoint via the set attribute:

Source set with breakpoint-specific dimensions
<nr:sourceSet
    path="{f:uri.image(
        image: image,
        width: '960',
        height: '690',
        cropVariant: 'default'
    )}"
    set="{
        480:{width: 160, height: 90},
        800:{width: 400, height: 300}
    }"
/>
Copied!

Render modes 

cover
Default. Resizes images to fully cover the provided width and height.
fit
Resizes images so they fit within the provided width and height.
Using fit mode
<nr:sourceSet
    path="{f:uri.image(
        image: image,
        width: '960',
        height: '690',
        cropVariant: 'default'
    )}"
    width="960"
    height="690"
    mode="fit"
/>
Copied!

Lazy loading 

Both modes support lazy loading via the native loading="lazy" attribute. When using JS-based lazy loading (class="lazyload"), the data-srcset attribute is added automatically.

Backward compatibility 

By default responsiveSrcset is false, preserving the existing 2x density-based srcset behavior. All existing templates continue to work without modifications.

Variant URL format 

Processed variants are served from a dedicated URL path. The ViewHelper generates these URLs automatically. Any URL of this form is intercepted by the ProcessingMiddleware, but a variant that is not on disk yet is only created for a signed URL (see Signed variant URLs):

URL template
/processed/<original-path>.<mode-config>.<ext>?sig=<signature>[&<query>]
Copied!
<original-path>
Public path of the source image, including the /fileadmin/ (or other storage) prefix. Path traversal sequences (..) are rejected at URL-parsing time.
<mode-config>

Concatenation of one or more of:

w<n>
Target width in pixels.
h<n>
Target height in pixels.
q<n>
Quality (1--100).
m<n>
Processing mode (0 = cover, 1 = scale/fit).
<ext>
Source image extension: jpg, jpeg, png, gif, webp, avif, bmp, tif or tiff (any case). Other extensions are answered with HTTP 400. The processor decides at response time whether to serve the original, the .webp sidecar, or the .avif sidecar, based on which of these files exist on disk (see Variant negotiation).
Example URL
/processed/fileadmin/photos/hero.w1200h800m0q85.jpg?sig=3f2c...
Copied!

Signed variant URLs 

Changed in version 2.6.1

A variant that is not on disk yet is created only for a URL with a valid sig parameter. Before, any URL of the documented form created a variant.

Changed in version 2.7.0

The signature also covers the skipWebP / skipAvif flags. URLs without flags keep their signature; URLs with a flag that were signed before need a new one (see below).

Creating a variant costs CPU time, memory and disk space, so the processor creates one only when the URL carries a signature issued by the installation itself:

  • sig is an HMAC (SHA-1, via TYPO3's HashService) of the URL-decoded variant path -- source path, mode config and extension -- keyed with $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] plus a secret specific to this extension.
  • The sourceSet ViewHelper signs every URL it renders.
  • A URL without a valid signature is answered with HTTP 403 unless the variant is already on disk; existing variants are served without a signature.
  • A URL with the skipWebP / skipAvif flags is signed over the path and those flags. A flag added to or removed from a signed URL invalidates the signature (HTTP 403 unless the variant is on disk). Otherwise anyone could request a variant first with a flag and so strip its sidecar for every visitor. A URL without flags is signed over the path alone, as before.

Consequences for existing installations:

  • Pages rendered before the update carry unsigned URLs. Flush the page cache after updating, so variants that do not exist yet can be created.
  • Since 2.7.0 the skip flags are signed. A URL with skipWebP or skipAvif signed by an earlier version -- built with getResourcePath() or signed by hand -- is answered with HTTP 403 until it is signed again. Flush the page cache after updating if such URLs exist, and pass the flags to sign() where you sign URLs yourself.
  • URLs written by hand in templates or content need a signature. Build them in PHP with SourceSetViewHelper::getResourcePath() or sign the path with the Netresearch\NrImageOptimize\Service\VariantUrlSigner service (sign(string $variantPath, bool $skipWebP, bool $skipAvif), with the URL-decoded path and the flags the URL carries).
  • Changing the encryptionKey invalidates all signatures; flush the page cache afterwards.
  • Without an encryptionKey no signature is issued or accepted.

Variant negotiation 

When the processor generates a variant, it writes the original file to disk and additionally produces a .webp and an .avif sidecar (same base name), unless the format is turned off (see WebP/AVIF generation).

The processor does not inspect the Accept request header. On each request it serves the first non-empty file it finds on disk, in this order: the .avif sidecar, the .webp sidecar, the original format.

Two query parameters let callers opt out of sidecar generation for individual URLs:

skipWebP=1
Do not produce a WebP variant for this URL.
skipAvif=1
Do not produce an AVIF variant for this URL.

The sourceSet ViewHelper adds these flags to every URL it renders when its skipWebP or skipAvif argument is set.

The flags only control generation. The query string is not part of the variant file name, so a URL with a skip flag shares its files with the same URL without it: a sidecar already written for that variant is served either way, and a variant first created with a skip flag gets no such sidecar later until the processed images are cleared (see Clear processed images).

These flags are useful when specific consumers (for example e-mail clients or legacy RSS renderers) cannot handle modern formats.

WebP/AVIF output quality 

New in version 2.4.0

The qualityWebp and qualityAvif extension configuration settings.

The primary variant's quality is controlled per-request via the q<n> URL segment (see Variant URL format). The .webp and .avif sidecars previously reused that same numeric quality, but AVIF's quality scale is steeper than WebP's or JPEG's -- at matching numbers an AVIF file comes out larger than the WebP sidecar, defeating the point of serving AVIF at all.

Two extension configuration settings control sidecar quality independently of the primary variant:

qualityWebp (default 75)
Output quality for the generated WebP variant. At 100 the WebP variant is encoded lossless and typically comes out several times larger than the primary JPEG variant.
qualityAvif (default 60)
Output quality for the generated AVIF variant. The lower default keeps AVIF variants genuinely smaller than WebP while staying visually comparable.

Changed in version 2.6.0

AVIF output quality is capped at 99: qualityAvif for the AVIF variant, and the URL quality (q100) for processed AVIF originals. At 100 ImageMagick switches to lossless AVIF encoding, which returns no image data, so no AVIF variant was written and a processed AVIF original failed with HTTP 500.

config/system/additional.php
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_image_optimize']['qualityWebp'] = 75;
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_image_optimize']['qualityAvif'] = 60;
Copied!

The settings can also be edited via the backend: Admin Tools > Settings > Extension Configuration > nr_image_optimize.

WebP/AVIF generation 

New in version 2.6.0

The generateWebp and generateAvif extension configuration settings.

By default the processor writes a .webp and an .avif file next to every processed variant. Two switches turn either format off for the whole installation, for example to save storage when one sidecar format is enough:

generateWebp (default 1)
Write a .webp sidecar for each processed variant.
generateAvif (default 1)
Write an .avif sidecar for each processed variant.
config/system/additional.php
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_image_optimize']['generateWebp'] = false;
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_image_optimize']['generateAvif'] = true;
Copied!

The per-URL skipWebP and skipAvif query parameters (see Variant negotiation) still apply on top: a format is generated only if its switch is on and the URL does not skip it.

Cache headers 

Processed variant URLs are effectively content-addressed -- any change to dimensions, quality, or format produces a different URL. The processor therefore responds with an immutable, long-lived cache header:

Cache-Control: public, max-age=31536000, immutable
Copied!

This value is a compile-time constant and not user-configurable.

Image driver selection 

Intervention Image is instantiated through \Netresearch\NrImageOptimize\Service\ImageManagerFactory, which selects the best available driver at runtime:

  1. Imagick when the imagick PHP extension is loaded (preferred -- supports AVIF natively if the underlying ImageMagick build does).
  2. GD when imagick is unavailable and the gd extension is loaded.

If neither extension is present, the factory throws a RuntimeException with a descriptive message. Use the backend maintenance module to verify driver availability on your host.

Middleware registration 

Configuration/RequestMiddlewares.php registers the ProcessingMiddleware on the frontend pipeline before typo3/cms-frontend/site. This ordering is required so the middleware can intercept /processed/ URLs before TYPO3's frontend routing claims them. The registration has no user-configurable options.

Processor limits 

The processor enforces the following bounds when parsing a URL:

Signature
A variant that is not on disk yet is created only for a signed URL (see Signed variant URLs).
Image types
Only the extensions listed in Variant URL format are accepted, and only source files whose content is a JPEG, PNG, GIF, WebP, AVIF, BMP or TIFF image are decoded. Anything else is answered with HTTP 400.
MAX_DIMENSION
Width and height are clamped to 1--8192 pixels to prevent denial-of-service via excessive memory allocation.
MIN_QUALITY / MAX_QUALITY
Quality is clamped to 1--100.
LOCK_MAX_RETRIES
Up to 10 attempts (at 100 ms intervals) to acquire the per-variant processing lock before returning HTTP 503. Prevents duplicate work when multiple clients hit the same uncached variant simultaneously.

Additional trusted roots 

New in version 2.4.0

The additionalTrustedRoots extension configuration setting.

Some deployments need to serve variants of images that live under an absolute filesystem path that is neither the public webroot, a Local FAL storage's own base path, nor one of the hardcoded TYPO3-internal locations (var/, symlinked processed/uploads, or extension-published _assets/<hash> directories) -- for example a custom mount managed outside of FAL.

The additionalTrustedRoots extension configuration setting closes this gap on an explicit, per-instance, opt-in basis: a comma-separated list of absolute filesystem paths that are realpath-resolved and added to the allow-list directly.

config/system/additional.php
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_image_optimize']['additionalTrustedRoots'] = '/mnt/custom-assets';
Copied!

The setting can also be edited via the backend: Admin Tools > Settings > Extension Configuration > nr_image_optimize.