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 Source generates responsive <img> tags
with srcset attributes.
{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"
/>
Parameters
-
- Type
- string
- Required
true
Public path to the source image (for example
/fileadmin/), typically generated viafoo. jpg f:.uri. image ()
-
- Type
- int|float
- Default
- 0
Base width in pixels for the rendered
<img>.0resolves automatically from the source file. Clamped by the processor to 1--8192 when baked into the variant URL.
-
- Type
- int|float
- Default
- 0
Base height in pixels.
0preserves aspect ratio relative to width. Clamped by the processor to 1--8192.
-
- Type
- array
- Default
- []
Responsive set in the form
{max. Each entry becomes aWidth: {width: int, height: int}} <source media="tag.(max- width: <max Width>px)">
-
- Type
- string
- Default
- empty string
Alternative text for the image. Always rendered (even when empty) to keep assistive-tech compatibility.
-
- Type
- string
- Default
- empty string
HTML-escaped title attribute.
-
- Type
- string
- Default
- empty string
CSS classes for the
<img>tag. Includelazyloadto switch from native to JS-based lazy loading (see Lazy loading).
-
- Type
- string
- Default
- cover
Render mode.
coverresizes images to fully cover the given dimensions (crop/fill).fitresizes images to fit within the given dimensions.
-
- Type
- boolean
- Default
- false
Add
loading="lazy"(native lazy loading).
-
- Type
- boolean
- Default
- false
Enable width-based responsive
srcsetinstead of the density-based2xoutput (preserved for backward compatibility).
-
- 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.
-
- Type
- string
- Default
- auto, (min-width: 992px) 991px, 100vw
Responsive
sizesattribute for the generated<img>tag.
-
- Type
- string
- Default
- empty string
Native HTML
fetchpriorityattribute. Allowed values:high,low,auto. Omitted when empty.
-
- Type
- boolean
- Default
- false
Add
skipto everyWeb P=1 /processed/URL the ViewHelper renders (src,srcset, width variants and<source>sets), so the processor writes no.webpsidecar for these variants. See Variant negotiation.
-
- Type
- boolean
- Default
- false
Add
skipto everyAvif=1 /processed/URL the ViewHelper renders, so the processor writes no.avifsidecar for these variants. With both flags set, each variant is written in its source format only. See Variant negotiation.
-
- Type
- array
- Default
- []
Extra HTML attributes merged into the rendered tag.
Note
Quality and output format are not exposed as ViewHelper
arguments. Quality defaults to 75 and is baked into the
generated /processed/... URL; the variant's
file extension is inherited from the source image. Only
the generation of the WebP/AVIF sidecars can be switched
off per call, with
skipWebP and
skipAvif. Use
the URL format and
variant negotiation
to influence the served format.
Source set configuration
Define source sets per media breakpoint via the set
attribute:
<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}
}"
/>
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.
<nr:sourceSet
path="{f:uri.image(
image: image,
width: '960',
height: '690',
cropVariant: 'default'
)}"
width="960"
height="690"
mode="fit"
/>
Lazy loading
Both modes support lazy loading via the native
loading="lazy" attribute. When using JS-based lazy
loading (class="lazyload"), the data-
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):
/processed/<original-path>.<mode-config>.<ext>?sig=<signature>[&<query>]
<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,tifortiff(any case). Other extensions are answered with HTTP 400. The processor decides at response time whether to serve the original, the.webpsidecar, or the.avifsidecar, based on which of these files exist on disk (see Variant negotiation).
/processed/fileadmin/photos/hero.w1200h800m0q85.jpg?sig=3f2c...
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 skip / skip 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:
sigis an HMAC (SHA-1, via TYPO3'sHash) of the URL-decoded variant path -- source path, mode config and extension -- keyed withService $GLOBALSplus a secret specific to this extension.['TYPO3_ CONF_ VARS'] ['SYS'] ['encryption Key'] - The
sourceViewHelper signs every URL it renders.Set - 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
skip/Web P skipflags 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.Avif
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
skiporWeb P skipsigned by an earlier version -- built withAvif getor 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 toResource Path () signwhere you sign URLs yourself.() - URLs written by hand in templates or content need a signature.
Build them in PHP with
Sourceor sign the path with theSet View Helper:: get Resource Path () Netresearch\service (Nr Image Optimize\ Service\ Variant Url Signer sign, with the URL-decoded path and the flags the URL carries).(string $variant Path, bool $skip Web P, bool $skip Avif) - Changing the
encryptioninvalidates all signatures; flush the page cache afterwards.Key - Without an
encryptionno signature is issued or accepted.Key
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:
skipWeb P=1 - Do not produce a WebP variant for this URL.
skipAvif=1 - Do not produce an AVIF variant for this URL.
The source 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 quality and quality 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:
quality(defaultWebp 75)- Output quality for the generated WebP variant. At
100the WebP variant is encoded lossless and typically comes out several times larger than the primary JPEG variant. quality(defaultAvif 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: quality 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.
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_image_optimize']['qualityWebp'] = 75;
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_image_optimize']['qualityAvif'] = 60;
The settings can also be edited via the backend: Admin Tools > Settings > Extension Configuration > nr_image_optimize.
Attention
Per-format quality is not part of the processed-variant cache filename. Changing either setting only affects newly generated variants -- clear already-processed images (see Clear processed images) to apply the new quality to existing ones.
WebP/AVIF generation
New in version 2.6.0
The generate and generate 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:
generate(defaultWebp 1)- Write a
.webpsidecar for each processed variant. generate(defaultAvif 1)- Write an
.avifsidecar for each processed variant.
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_image_optimize']['generateWebp'] = false;
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_image_optimize']['generateAvif'] = true;
The per-URL skip and skip 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.
Attention
The switches only control generation. Sidecars already on disk are still served. Clear already-processed images (see Clear processed images) to remove them.
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
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:
- Imagick when the
imagickPHP extension is loaded (preferred -- supports AVIF natively if the underlying ImageMagick build does). - GD when
imagickis unavailable and thegdextension is loaded.
If neither extension is present, the factory throws a
Runtime with a descriptive message. Use the
backend maintenance module
to verify driver availability on your host.
Middleware registration
Configuration/RequestMiddlewares.php registers the
Processing on the frontend pipeline before
typo3/. 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.
Trusted storage symlinks
New in version 2.3.0
The additional extension configuration
setting.
The processor validates that both the source image and the
target variant resolve (via realpath) to a location
inside an allowed root -- the public webroot, or a Local FAL
storage's own base path -- before reading or writing anything.
This rejects requests for images reached through a symlink that
escapes those roots (for example a symlink accidentally or
maliciously pointing at /etc).
Some deployments relocate TYPO3 core's own
_processed_ image cache -- a subdirectory inside a FAL
storage's own directory, e.g. fileadmin/_ --
onto local/ephemeral storage, to keep frequently-rewritten
derivative images off shared/NFS storage. That leaves only a
symlink behind inside the storage, which the FAL-storage
basePath lookup above does not see (it only resolves the
storage's own base path, never looks inside it), so variant
requests for such images are rejected even though the original
file is legitimately part of the deployed application.
The additional extension configuration
setting closes this gap on an explicit, per-instance, opt-in
basis: a comma-separated list of directory names that, when
found as a symlink directly inside a Local FAL storage's base
path, are resolved and added to the allow-list too.
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_image_optimize']['additionalTrustedStorageSymlinks'] = '_processed_';
The setting can also be edited via the backend: Admin Tools > Settings > Extension Configuration > nr_image_optimize.
Attention
This widens the set of filesystem locations the processor will read from and publicly serve variants of. Only add well-known, infrastructure-managed names here -- never a name an untrusted party (e.g. an FTP-only content account) could create on their own. The default is empty, which keeps today's behavior unchanged for every installation that does not configure it.
Additional trusted roots
New in version 2.4.0
The additional 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 additional 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.
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_image_optimize']['additionalTrustedRoots'] = '/mnt/custom-assets';
The setting can also be edited via the backend: Admin Tools > Settings > Extension Configuration > nr_image_optimize.
Attention
This widens the set of filesystem locations the processor will read from and publicly serve variants of. Only add paths you fully trust. Relative paths are rejected outright (never resolved against the PHP process's working directory). The default is empty, which keeps today's behavior unchanged for every installation that does not configure it.