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

# Changelog {#changelog}

## 1.6.0 {#changelog-1-6-0}

-   Added: `generateWebp` and `generateAvif` extension
    configuration settings (both default on) that stop the processor
    from writing the `.webp` or `.avif` file next to each
    processed variant. The per-URL `skipWebP`/`skipAvif`
    parameters still apply on top; sidecars already on disk keep
    being served until the processed images are cleared. See
    [WebP/AVIF generation](https://docs.typo3.org/permalink/netresearch/nr-image-optimize:configuration-sidecar-formats@1.6).
-   Fixed: AVIF output quality is capped at 99. At quality 100
    ImageMagick asks the AOM encoder for lossless AVIF, which it
    rejects, so `qualityAvif = 100` produced no AVIF variant and a
    processed AVIF original requested with `q100` failed with
    HTTP 500.
-   Changed (docs): the `qualityWebp` setting label and the
    configuration docs state that `100` produces lossless WebP,
    typically several times the size of the JPEG variant.

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

-   Added: targeted deletion of processed variants by original path,
    directory prefix, or glob pattern (`*`/`?`) in the maintenance
    backend module -- similar to a CDN cache invalidation, instead of
    clearing the whole "processed" directory. Runs asynchronously with
    a confirmation dialog and refreshes the statistics afterward. Port
    of the main-branch feature.
-   Fixed: the maintenance module no longer risks exhausting memory on
    large "processed" trees. Opening the module recomputed directory
    statistics synchronously by materializing every file into an array
    just to sort it once for the top-5 largest files -- on large
    instances (measured  500k files) this could exhaust a typical 256M
    PHP `memory_limit` with a fatal error, on top of blocking page
    rendering. Statistics are now maintained as a size-bounded top-5
    list during a single directory walk and fetched asynchronously
    instead of blocking `indexAction()`. Port of the main-branch fix.
-   Fixed: the maintenance module now respects TYPO3's backend dark
    mode. Card headers, extension tags, and status badges used raw
    Bootstrap `bg-*`/`text-bg-*` utility classes that TYPO3's
    dark-mode gate never resets, rendering a solid near-white
    background regardless of the active color scheme. Replaced with
    TYPO3's own `badge-*` modifiers and plain `card-header`.
-   Fixed: the statistics JSON response no longer fails outright on a
    non-UTF-8 file name in "processed" -- invalid bytes are now
    substituted instead of aborting the whole response.
-   Added: a "Performance model" section in the Introduction
    contrasting this extension's render-vs-process decoupling with
    TYPO3 core's `f:image`/`ImageService`, which processes every
    referenced image synchronously during page render. Backed by a
    real measurement showing a 1,000x-50,000x per-image gap on cold
    render.
-   Changed (CI): replaced a temporary `rector/rector` cap with a
    `ssch/typo3-rector: ^3.15.1` floor once that release shipped the
    upstream container-API fix, and aligned the patch-coverage target
    with `main` (80%, was 100%).

## 1.4.1 {#changelog-1-4-1}

-   Fixed: every README/Documentation `SourceSetViewHelper` example
    used a non-existent `file` argument -- only `path` is
    registered, so these examples failed at Fluid render time. Also
    removed a fictitious `format` confval, added the real arguments
    (`alt`, `title`, `class`, `attributes`, `set`,
    `lazyload`) that were missing from both READMEs' parameter
    lists, and documented the [nr:image:optimize/nr:image:analyze
    CLI commands](https://docs.typo3.org/permalink/netresearch/nr-image-optimize:usage-cli@1.6) and the on-upload compression feature,
    both previously undocumented anywhere.
-   Fixed: this changelog and `CHANGELOG.md` had fallen behind --
    backfilled the missing 1.3.1 and 1.3.2 entries.

## 1.4.0 {#changelog-1-4-0}

-   Added: on-upload compression. `OptimizeOnUploadListener`
    subscribes to `AfterFileAddedEvent` and
    `AfterFileReplacedEvent` and runs `optipng`,
    `gifsicle`, and `jpegoptim` inline as a file lands,
    instead of relying on a separate cron/CLI pass. Port of the
    main-branch feature released in 2.2.2.
-   Added: `nr:image:optimize` and `nr:image:analyze` console
    commands to cover existing files -- bulk optimization with
    filter/dry-run support, and a heuristic per-image savings
    report without modifying files. See
    [Usage](https://docs.typo3.org/permalink/netresearch/nr-image-optimize:usage-cli@1.6).
-   Fixed: bulk `nr:image:optimize`/`nr:image:analyze` no
    longer abort the whole run when a single file fails. A stale
    FAL identifier (e.g. after an out-of-band folder rename)
    raised an uncaught `RuntimeException` mid-run, discarding
    progress already made. Both commands now catch per-file
    failures, report them individually, and continue with the
    rest of the queue.

> [!WARNING]
> **Attention**
>
> `OptimizeOnUploadListener` is registered by default and
> runs inline on every upload/replace. If your workflow depends
> on uploads being stored byte-for-byte as they arrived,
> disable the listener in your site package's `Services.yaml`
> before upgrading -- see the CHANGELOG's "Upgrading" note for
> 1.4.0.

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

-   Fixed: animated GIFs are passed through unprocessed instead
    of being collapsed to their first frame. GIFs with more than
    one frame are excluded from variant processing; the original
    file is copied to the variant path and served as-is. WebP/AVIF
    sidecar generation is skipped for animated GIFs too. Port of
    the main-branch fix (2.x PR #143).

## 1.3.1 {#changelog-1-3-1}

-   Fixed: URL dimensions of `0` (meaning "derive this side from
    the aspect ratio", as `SourceSetViewHelper` always writes
    both dimensions into the variant URL) were floored to `1`
    by dimension clamping, turning height-based or width-based
    variants into 1x1 pixel images. `0` now derives the missing
    side from the aspect ratio, as it already did for an absent
    dimension.

## 1.3.0 {#changelog-1-3-0}

-   Added: `additionalTrustedRoots` extension configuration --
    per-instance, opt-in, comma-separated list of absolute
    filesystem paths, outside FAL and TYPO3-internal locations,
    that are realpath-resolved and added to the path-validation
    allow-list. TYPO3's `var/` directory is now trusted
    automatically. Port of the fix on `main` (2.4.0). See
    [Additional trusted roots](https://docs.typo3.org/permalink/netresearch/nr-image-optimize:configuration-additional-trusted-roots@1.6).
-   Added: `qualityWebp` (default `75`) and `qualityAvif`
    (default `60`) extension configuration settings, so the
    WebP and AVIF sidecar variants can be tuned independently of
    the primary variant's quality. AVIF's steeper quality scale
    previously meant AVIF variants came out larger than WebP at
    the same numeric quality. Port of the fix on `main` (2.4.0).
    See [WebP/AVIF output quality](https://docs.typo3.org/permalink/netresearch/nr-image-optimize:configuration-sidecar-quality@1.6).
-   Fixed: the Maintenance module's "clear processed images"
    action failed whenever `processed` was a symlink to a
    shared volume -- a common Deployer/CI deployment layout. It
    validated the target with `realpath()`-equality, which
    resolves the symlink and never matches, so clearing failed on
    every symlinked deployment. The directory is now emptied in
    place instead of recreated, so the symlink survives. Port of
    the fix on `main` (2.4.0).

## 1.2.0 {#changelog-1-2-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@1.6).
-   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.

## 1.1.3 {#changelog-1-1-3}

-   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@1.6) for the trade-off. Port of the
    fix on `main` (2.2.4).

## 1.1.2 {#changelog-1-1-2}

-   Fixed: silent HTTP 400 responses now log their rejection reason
    via `error_log()` (URL-pattern mismatch and
    path-outside-allowed-roots branches).
-   Fixed: a transient `StorageRepository` failure during early
    TYPO3 bootstrap no longer poisons the per-process allowed-roots
    cache; the degraded fallback is kept only for the current
    request.
-   Fixed: `getAllowedRoots()` is memoized per request, avoiding
    redundant lookups and repeated log lines.
-   Fixed: a filesystem-root public path (`/`) no longer rejects
    every valid path.

## 1.1.1 {#changelog-1-1-1}

-   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. Backport of the fix on
    `main`, 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.
-   Changed (BC): dropped PHP 8.1 support. The TYPO3_12
    maintenance branch now requires PHP 8.2 or newer
    (TYPO3 v12 itself still supports PHP 8.1, but this
    extension aligns with the `netresearch/typo3-ci-workflows`
    tooling which requires PHP 8.2+).

## 1.1.0 {#changelog-1-1-0}

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

Comprehensive quality review: security hardening, performance
improvements, backend maintenance module, responsive srcset,
and expanded test coverage.

-   Added backend maintenance module with directory statistics,
    system requirements check, and clear processed images action.
-   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.
-   Added path traversal hardening and XSS prevention.
-   Added DoS prevention via dimension and quality clamping.
-   Added HTTP caching headers (`Cache-Control: immutable`,
    `ETag`, `Last-Modified`).
-   Added 15 language localizations.
-   Added 33+ unit tests, fuzz tests, and functional tests.
-   Added full TYPO3 documentation structure.

## 1.0.3 {#changelog-1-0-3}

-   Fixed `Processor::getValueFromMode()` TypeError for
    non-matching URLs (crawler/bot srcset descriptors).

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

-   Fixed nullable `dirname` access in
    `SourceSetViewHelper`.

## 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.
