---
title: "Changelog"
manual: "Image Optimization for TYPO3"
version: "2.6"
permalink: "https://docs.typo3.org/permalink/netresearch/nr-image-optimize:changelog@2.6"
source: "Changelog/Index.rst"
rendered: "2026-09-25T11:13:49+00:00"
---

# Changelog {#changelog}

## 2.6.0 {#changelog-2-6-0}

-   Added: `generateWebp` and `generateAvif` extension settings
    turn generation of the `.webp` or `.avif` sidecar off for the
    whole installation (see [WebP/AVIF generation](https://docs.typo3.org/permalink/netresearch/nr-image-optimize:configuration-sidecar-formats@2.6)). Both
    default to on; the per-URL `skipWebP` / `skipAvif` parameters
    still apply on top. Sidecars already on disk are served until the
    processed images are cleared.
-   Added: the maintenance module deletes only the processed variants
    derived from a given original file path, a directory prefix
    (trailing `/`) or a glob pattern (`*` / `?`), instead of
    clearing the whole `processed/` directory.
-   Fixed: AVIF variants are written when `qualityAvif` is `100`.
    At quality 100 ImageMagick requests lossless AVIF, the AOM encoder
    rejects it, and no AVIF variant was written. The processor now hands
    at most `99` to the AVIF encoder.
-   Fixed: processed AVIF originals requested with `q100` no longer
    fail with HTTP 500. Their URL quality is capped at `99` as well;
    the cached file name keeps `q100`.
-   Fixed: the maintenance module no longer walks `processed/`
    while rendering the page. Statistics load asynchronously, and the
    five largest files are tracked during the directory pass instead of
    collecting every file, which exhausted `memory_limit` on large
    `processed/` trees.
-   Fixed: the documentation describes variant selection as the
    processor does it (see [Variant negotiation](https://docs.typo3.org/permalink/netresearch/nr-image-optimize:configuration-variant-negotiation@2.6)):
    the first non-empty file of `.avif`, `.webp` and the original is
    served, the `Accept` header is not inspected, and `skipWebP` /
    `skipAvif` only suppress generation. See
    [pull request #203](https://github.com/netresearch/t3x-nr-image-optimize/pull/203).

## 2.5.0 {#changelog-2-5-0}

-   Added: `image` and `cropVariant` arguments on `SourceSetViewHelper`
    -- when a FAL `FileReference` is passed via `image`, the ViewHelper
    derives the effective height from that image's crop-variant area
    (falling back to its original aspect ratio when the variant has no crop
    data), instead of requiring callers to pre-compute a crop-aware height
    themselves via a separate, site-specific ViewHelper. `height` remains
    authoritative when `image` is omitted.

## 2.4.2 {#changelog-2-4-2}

-   Fixed: source images under a folder with a non-ASCII character
    (e.g. an umlaut) no longer return an empty-body HTTP 500 for
    `/processed/*` requests. The regression was in
    `intervention/image` v4: `InputHandler::handle()` checks
    `BinaryImageDecoder` before `FilePathImageDecoder`, and
    `BinaryImageDecoder`'s heuristic treats any string containing a
    byte outside printable ASCII as binary image data -- including a
    legitimate absolute path whose only non-ASCII content is a UTF-8
    umlaut. Wrapping the path in `SplFileInfo` before handing it to
    `ImageManager::read()`/`decode()` makes decoder selection match
    on input *type* rather than content, sidestepping the heuristic.
    `v3` (3.7.2, 3.11.1) was not affected -- no `TYPO3_12` backport
    needed. See
    [pull request #156](https://github.com/netresearch/t3x-nr-image-optimize/pull/156).

## 2.4.1 {#changelog-2-4-1}

-   Fixed: the TYPO3 version constraint now targets the v14 LTS.
    `typo3/cms-core` was declared as `^13.4 || ^14.0` and
    `ext_emconf.php` as `13.4.0-14.4.99`, which also covered
    the 14.0--14.2 sprint releases. Both now target 14.3
    (`^13.4 || ^14.3`, `13.4.0-14.3.99`). See
    [pull request #139](https://github.com/netresearch/t3x-nr-image-optimize/pull/139).
-   Fixed: the version metadata published to Packagist matches the
    release again. The `v2.4.0` tag was first pushed against a commit
    whose `ext_emconf.php` still read `2.3.1`. Packagist
    recorded that reference for `2.4.0` and, under its
    immutable-version policy, kept it when the tag was moved -- so
    `2.4.0` installed via Composer reports `2.3.1` to the Extension
    Manager. Installs from 2.4.1 on carry the matching version. The
    `2.4.0` release on TER is unaffected.

## 2.4.0 {#changelog-2-4-0}

-   Added: `Environment::getVarPath()` (the composer-mode
    `var/` directory, a sibling of `public/` rather than
    nested under it) is now an allowed root for path validation, so
    TYPO3-internal generated assets (cache, lock, transient, log) are
    accepted.
-   Added: `additionalTrustedRoots` extension configuration --
    per-instance, opt-in, comma-separated list of absolute filesystem
    paths that are realpath-resolved and added directly to the
    path-validation allow-list. Closes the gap for integrator-trusted
    locations that are neither a FAL storage base path nor one of the
    hardcoded TYPO3-internal locations. See
    [Additional trusted roots](https://docs.typo3.org/permalink/netresearch/nr-image-optimize:configuration-additional-trusted-roots@2.6).
-   Added: configurable WebP/AVIF output quality via the new
    `qualityWebp` (default 75) and `qualityAvif` (default 60)
    extension-configuration settings. Previously both variants were
    encoded at the same numeric quality as the primary image; AVIF's
    steeper quality scale made AVIF variants larger than WebP at
    matching numbers, so format negotiation ended up serving the
    biggest file. The lower AVIF default keeps AVIF variants
    genuinely smaller than WebP while staying visually comparable.
    See [WebP/AVIF output quality](https://docs.typo3.org/permalink/netresearch/nr-image-optimize:configuration-sidecar-quality@2.6). Changing either setting
    requires clearing processed images, since per-format quality is
    not part of the cache filename. Reported in
    [issue #132](https://github.com/netresearch/t3x-nr-image-optimize/issues/132).
-   Fixed: `clear-processed-images` (Maintenance module) failed on
    symlinked deployments. The action validated the target path with
    `realpath()`, which resolves a `processed` symlink
    (shared-directory deployment layouts, e.g. Deployer) to its
    target and never matched `<public>/processed` -- so
    clearing failed on every symlinked deployment. The directory is
    now emptied in place instead of `rmdir()` \+ `mkdir()`,
    preserving the symlink. Reported in
    [issue #131](https://github.com/netresearch/t3x-nr-image-optimize/issues/131).

## 2.3.1 {#changelog-2-3-1}

-   Fixed: the backend module icon and Maintenance module templates
    were not TYPO3 v14 theme-aware. The module icon
    (`module-image-optimize.svg`) and extension icon
    (`Extension.svg`) were flat, hard-coded tiles that did not
    adapt to the v14 backend light/dark colour scheme. The
    Maintenance module's Fluid templates also used Bootstrap utility
    classes with fixed light values (`bg-light`, `table-light`,
    `text-dark`), causing card headers, table heads, and code chips
    to render as light boxes on a dark backend. The module icon is
    now theme-aware via `fill="currentColor"` (TYPO3 v14+, with a
    legacy full-colour tile kept for v13), and the templates use
    adaptive `bg-body-tertiary` tokens instead.

## 2.3.0 {#changelog-2-3-0}

-   Added: `additionalTrustedStorageSymlinks` extension
    configuration -- per-instance, opt-in, comma-separated list of
    directory names that, when found as a symlink directly inside a
    Local FAL storage's own base path (e.g.
    `fileadmin/_processed_`), are resolved and added to the
    path-validation allow-list. Closes the gap where deployments
    relocate TYPO3 core's own `_processed_` image cache onto
    local/ephemeral storage to keep it off shared/NFS storage,
    leaving a symlink behind that the FAL-storage basePath lookup
    cannot see. Default empty; keeps today's behaviour for every
    installation that doesn't opt in. See [Trusted storage symlinks](https://docs.typo3.org/permalink/netresearch/nr-image-optimize:configuration-trusted-storage-symlinks@2.6).
    Reported in
    [issue #120](https://github.com/netresearch/t3x-nr-image-optimize/issues/120).
-   Fixed: images published via `public/_assets/<hash>`
    symlinks (extension `Resources/Public/` assets) were
    rejected with HTTP 400. TYPO3 core publishes each extension's
    `Resources/Public/` directory by symlinking
    `public/_assets/<hash>/` to a location outside the public
    webroot. `getAllowedRoots()` did not resolve these symlinks, so
    variant requests for e.g. an extension's default/fallback image
    failed even though the file is a legitimate part of the deployed
    application. Every immediate child of `_assets` is now
    resolved individually. Reported in
    [issue #117](https://github.com/netresearch/t3x-nr-image-optimize/issues/117).

## 2.2.4 {#changelog-2-2-4}

-   Fixed: the `sourceSet` ViewHelper passes absolute URLs
    (`http://`, `https://`, `//`), `data:` URIs, and URLs
    carrying a query string through unchanged and renders them as a
    plain `<img>` tag. Previously such paths — e.g. the tokenized
    `eID=dumpFile` URLs [fal_securedownload](https://extensions.typo3.org/extension/fal_securedownload)
    generates for files in non-public storages — were mangled into
    broken `/processed/...` variant paths. The access control
    of the generating extension stays intact; see
    [Public images only: absolute URLs are passed through](https://docs.typo3.org/permalink/netresearch/nr-image-optimize:usage-protected-files@2.6) for the trade-off.
-   Fixed: backend module labels are resolved via array format.

## 2.2.3 {#changelog-2-2-3}

-   Fixed: processed image requests no longer return
    HTTP 400 when `fileadmin` (or any other Local
    FAL storage) is a symlink to an external location
    such as an NFS/EFS mount. `isPathWithinAllowedRoots`
    now accepts any realpath-resolved path that lies
    within the TYPO3 public root or the realpath of any
    configured Local storage's `basePath`. Symlinks
    placed *inside* a storage that escape every allowed
    root -- e.g. `fileadmin/evil` -> `/etc`
    -- continue to be rejected. Reported in
    [issue #70](https://github.com/netresearch/t3x-nr-image-optimize/issues/70).
-   Hardened: paths containing NUL bytes are rejected
    outright, closing a minor realpath-bypass via the
    not-yet-existing-path parent-walk branch.
-   Changed (BC for subclasses and manual instantiators):
    `Netresearch\\NrImageOptimize\\Processor` gains a
    new required `StorageRepository` constructor
    parameter. Consumers that autowire the service (the
    default in TYPO3 12+) are unaffected; any code that
    extends the class or constructs it by hand must
    forward the new dependency.

## 2.2.2 {#changelog-2-2-2}

-   Added `OptimizeOnUploadListener` -- PSR-14 listener
    that runs `optipng` / `gifsicle` / `jpegoptim` on
    `AfterFileAddedEvent` and `AfterFileReplacedEvent`.
    Keyed by `storageUid . ':' . identifier` to avoid
    cross-storage re-entrancy collisions; restores
    `setEvaluatePermissions` in a `finally` block.
-   Added `nr:image:optimize` -- bulk optimization command
    with `--dry-run`, `--storages`, `--jpeg-quality`,
    and `--strip-metadata` options. Uses a streaming
    Generator over `sys_file` so large installations
    don't load the full index into memory.
-   Added `nr:image:analyze` -- heuristic analysis
    command that estimates optimization potential without
    invoking any binary. Fast even on large installations.
-   Added `ImageOptimizer` service -- shared backend used
    by the listener and both CLI commands. Env overrides
    (`OPTIPNG_BIN`, `GIFSICLE_BIN`, `JPEGOPTIM_BIN`)
    are authoritative: a set-but-invalid override is
    reported as unavailable rather than silently falling
    back to `$PATH`. `$PATH` lookups also verify
    `is_executable()`.

## 2.2.1 {#changelog-2-2-1}

-   Adjusted author information in `ext_emconf.php`.

## 2.2.0 {#changelog-2-2-0}

-   Fixed: always render `alt` attribute on generated
    `<img>` tags.
-   Expanded unit test coverage for Processor and
    SourceSetViewHelper.

## 2.1.0 {#changelog-2-1-0}

<!-- TODO: no Markdown rendering for "versionadded" -->

Width-based responsive srcset with sizes
attribute, configurable width variants, and
fetchpriority support.

-   Added responsive width-based `srcset` generation as
    opt-in feature.
-   Added `widthVariants` parameter for custom breakpoints.
-   Added `sizes` parameter for responsive image sizing.
-   Added `fetchpriority` attribute for resource hints.
-   Optimized default `sizes` attribute values.

## 2.0.1 {#changelog-2-0-1}

-   Fixed `declare` statement issue preventing TER
    publishing via GitHub Actions.

## 2.0.0 {#changelog-2-0-0}

<!-- TODO: no Markdown rendering for "versionadded" -->

TYPO3 13 compatibility with PHP 8.2--8.4 support.

-   Added TYPO3 13 compatibility.
-   Added PHP 8.2, 8.3, and 8.4 support.
-   Dropped support for older TYPO3 versions.
-   Switched to Intervention Image 3.x.
-   Removed obsolete system binary checks.

## 1.0.1 {#changelog-1-0-1}

-   Added `ext_emconf.php` for classic installation.

## 1.0.0 {#changelog-1-0-0}

-   Initial stable release.
-   GitHub Actions CI workflows.

## 0.1.5 {#changelog-0-1-5}

-   Fixed `strtolower()` null argument error.
-   Fixed array offset access on boolean value.
-   Allowed numeric characters in file extensions.
-   Added extension icon.
-   Corrected crop variant examples.
-   Improved lazy loading behavior.
