Download the PHP package chamber-orchestra/image-bundle without Composer
On this page you can find all versions of the php package chamber-orchestra/image-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download chamber-orchestra/image-bundle
More information about chamber-orchestra/image-bundle
Files in chamber-orchestra/image-bundle
Package image-bundle
Short Description Symfony 8 bundle for on-demand image processing, resizing, cropping, AVIF/WebP conversion, and caching. Filter pipelines with fit, fill, optimize, strip, interlace processors and avifenc, cwebp, MozJPEG, pngquant post-processors. Filesystem, stream, and S3 loaders/resolvers. HMAC-signed runtime URLs for any client. Async processing via Messenger. Twig filters and responsive
License MIT
Homepage https://github.com/chamber-orchestra/image-bundle
Informations about the package image-bundle
ChamberOrchestra ImageBundle
On-demand image processing, resizing, AVIF/WebP conversion, and caching for Symfony 8.
A Symfony 8 bundle for image resizing, cropping, format conversion (AVIF, WebP, PNG, JPEG), and optimisation. Process images on demand through named filter pipelines — chains of processors (fit, fill, strip, interlace, optimize, output) and post-processors (avifenc, cwebp, MozJPEG, pngquant). Cache results to the local filesystem or S3-compatible storage and serve them via a controller that issues a 301 redirect to the cached URL. Nginx, Apache, and Caddy can serve cached images directly from disk — zero PHP overhead on cache hits.
Built for PHP 8.5 and Symfony 8. A modern, type-safe alternative to LiipImagineBundle.
Table of contents
- Features
- Requirements
- Installation
- Configuration — full reference with all defaults
- Usage — Twig filters, macros, PHP API, serializer attribute
- Processors — fit, fill, optimize, strip, interlace, output
- Post-processors — avifenc, cwebp, mozjpeg, pngquant
- Loaders — filesystem, stream, S3
- Resolvers — web_path, S3, PSR-6 cache decorator
- Runtime filters — HMAC-signed URLs, client SDKs (TypeScript, React, Next.js, Vue, Swift, Kotlin)
- Cache invalidation
- Web server configuration — nginx, Apache, Caddy
- Extension points
- Testing
- License
Features
- On-demand image processing — images are processed at first request and cached permanently
- Filter pipelines — compose processors and post-processors per named filter
- Processors:
fit,fill,strip,interlace,output,optimize— resize, crop, strip metadata, set format - Post-processors:
avifenc(AVIF),cwebp(WebP),mozjpeg(JPEG optimisation),pngquant(PNG compression) - AVIF and WebP support — convert images to next-gen formats via CLI post-processors or Imagick
- Runtime filters — pass processor options at runtime via HMAC-signed URLs
- Runtime image URLs — nginx-cacheable
GET /media/{pathHash}/{optionsHash}/{name}.{format}endpoint with HMAC-validated parameters, usable from any client with the shared secret - Loaders:
filesystem(with path-traversal protection),stream(any PHP stream wrapper),s3(S3-compatible storage) - Resolvers:
web_path(filesystem + public URL),s3(S3/MinIO/DigitalOcean Spaces),cache(PSR-6 decorator) - Twig filters:
image_filter,fit,fill,optimize - Twig macros: responsive
<picture>elements with AVIF/WebP/fallback srcsets and CSS background helpers - Retina/HiDPI — built-in pixel density multiplier for 2x and 3x output
- Async processing — offload image processing to Symfony Messenger workers (requires
symfony/messenger) - Concurrency control — limit parallel processing workers via distributed locks (requires
symfony/lock) - Content-addressed caching — URL changes when the image or options change; safe for
Cache-Control: immutable - Auto cache invalidation via event subscriber (integrates with
chamber-orchestra/file-bundle) - Imagick, GD, Gmagick drivers — configurable via short aliases (
gd,imagick,gmagick) or FQCN - Configurable binary paths — set paths for
pngquant,cjpeg,cwebp,avifencin bundle config - SSRF protection —
StreamLoadervalidates URI schemes (bothscheme://and compactscheme:forms) against an allowlist (default:file,data) - DoS protection — pixel budget (25 MP), density cap (4x), and post-processor timeout cap (300s) prevent resource exhaustion
- S3 hardening —
Cache-Controlheaders, optional ACL, dangerous extension blocking on upload - Cache optimisation —
resolveIfStored()combines existence check + URL resolution in a single pass - Serializer attribute — repeatable
#[ImageFilter]generates keyed image URLs in API responses with configurable formats, densities, and cached metadata (requiressymfony/serializer) - Client SDKs — TypeScript, React, Next.js, Vue, Swift, and Kotlin signing implementations included
Requirements
| Dependency | Version |
|---|---|
| PHP | ^8.5 |
| Symfony | 8.0.* |
| imagine/imagine | ^1.3 |
| psr/cache | ^3.0 |
| ext-exif | * |
| ext-imagick (recommended) | any |
Optional CLI binaries: avifenc, cwebp, cjpeg (MozJPEG), pngquant
Optional package: aws/aws-sdk-php (for S3 loader/resolver)
Installation
Register the bundle
Import routes
Configuration
Full reference (all defaults)
Quick start (minimal)
Most defaults are sensible out of the box. A minimal configuration only needs a default filter and optionally named filters:
This registers a filesystem loader from %kernel.project_dir%/public, a web_path resolver writing to public/media, Imagick as the driver, and auto-detects Symfony Messenger for async processing — all automatically. The client filter exposes the /media/{pathHash}/{optionsHash}/{name}.{format} endpoint for use from any HTTP client.
Usage
Twig filters
fit,fill, andoptimizedispatch through the runtime filter mechanism — no named filter configuration needed. Each accepts an optionalfilterargument (default:'default') to target a specific named filter.
Twig macros
The bundle ships responsive <picture> macros that generate AVIF, WebP, and fallback <source> elements with 1x/2x/3x srcset variants. Import and use them in any template:
Each macro generates three <source> groups (AVIF, WebP, fallback) at 1x/2x/3x densities. The fit macro calls look like this under the hood:
The fill macro works identically but uses the fill filter (resize + centre-crop) instead of fit:
CSS background macros
CSS background macros output inline style attributes with custom properties for use with CSS background-image. This is useful for hero sections, banners, and other elements where CSS backgrounds are preferred:
Custom properties generated: --bg-url, --bg-url-avif, --bg-url-webp, --bg-url-2x, --bg-url-avif-2x, --bg-url-webp-2x, --bg-url-3x, --bg-url-avif-3x, --bg-url-webp-3x, --bg-width, --bg-height.
Pair with CSS to select the best format:
PHP
Serializer attribute
The #[ImageFilter] attribute generates HMAC-signed image URLs during Symfony serialization — the API counterpart to the Twig macros. Requires symfony/serializer.
Serializes to:
Multiple attributes (repeatable)
Use multiple attributes with distinct key values for different image variants:
Produces "poster": { "thumbnail": { ... }, "hero": { ... } }.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
key |
string |
'default' |
Key in the serialized output |
filter |
string |
'fill' |
Processor type: fill, fit, or optimize |
width |
int |
0 |
Logical width in CSS pixels |
height |
int |
0 |
Logical height in CSS pixels (0 = auto) |
densities |
int[] |
[1, 2, 3, 4] |
Pixel densities to generate |
preset |
string |
'default' |
Named filter from chamber_orchestra_image.filters.* |
The normalizer is registered automatically when symfony/serializer is installed. Null or non-image File properties serialize to null.
Configuration
Output formats are configurable globally — no need to specify them per attribute:
Values are validated against ImageFormat at container build time.
Serializer context
The normalizer respects standard Symfony serializer context:
IGNORED_ATTRIBUTES— excluded properties are skippedATTRIBUTES— only listed properties are processed (supports both flat['coverArt']and nested['coverArt' => ['default' => ['avif' => ['1x']]]]forms; nested filters prune the output tree)
Metadata caching
Attribute metadata is resolved via ImageFilterMetadataFactory with three layers:
- In-memory — avoids repeated lookups within the same request
- PSR-6 cache (
cache.app) — cross-request reuse (86400s TTL in prod, 60s in dev) - Reflection — cold-start fallback
In dev mode, cache keys include a fingerprint derived from file mtimes of the class, its parents, and all traits (recursively), so attribute changes auto-invalidate.
Processors
All processors are configured as key-value maps under filters.<name>.processors.
fit — Resize to bounding box
Scales the image to fit within the given dimensions while preserving aspect ratio. Never crops.
fill — Resize and centre-crop
Scales and crops to fill the exact requested dimensions. The crop is centred.
optimize — Fit without upscaling
Behaves like fit but never upscales the image. If the target dimensions are larger than the source, the original size is preserved.
strip — Remove metadata
Strips EXIF, ICC profiles, and other embedded metadata from the image.
interlace — Progressive encoding
Sets the interlacing mode for progressive JPEG or interlaced PNG output.
output — Output format and quality
Controls the output format and quality.
Shared processor options
fit, fill, and optimize share these options from AbstractResizeProcessor:
| Option | Default | Description |
|---|---|---|
width |
0 |
Target width (px). 0 = compute from aspect ratio. |
height |
0 |
Target height (px). 0 = compute from aspect ratio. |
density |
1.0 |
Pixel density multiplier. Output = size * density. |
filter |
lanczos |
Resampling filter (auto undefined for GD). |
background |
#fff |
Canvas background colour for letterboxing. |
alpha |
0 |
Background alpha (0 = opaque). |
Post-processors
Post-processors shell out to external CLI binaries and operate on the encoded image bytes. Configure them under filters.<name>.post_processors.
avifenc — Convert to AVIF
Converts JPEG, PNG, GIF, and TIFF images to AVIF format using the avifenc binary.
Requires the avifenc binary.
cwebp — Convert to WebP
Converts JPEG, PNG, GIF, and TIFF images to WebP format.
Requires the cwebp binary (e.g. apt install webp).
mozjpeg — Optimise JPEG
Re-encodes JPEG images through MozJPEG for smaller file sizes.
Requires the cjpeg binary from MozJPEG.
pngquant — Compress PNG
Compresses PNG images using lossy palette quantisation.
Requires the pngquant binary (e.g. apt install pngquant).
Loaders
Loaders retrieve the source image binary. The default loader is always filesystem.
filesystem
Loads images from one or more root directories on the local filesystem. Performs path traversal protection via realpath().
Named roots allow @name:path placeholder syntax:
Locator security
The filesystem loader uses a locator to resolve and validate image paths. Two locators are available:
-
FileSystemLocator(default) — resolves paths withrealpath()and verifies the resolved path falls within a configured root directory. Symlinks that resolve outside the root are rejected. This is the recommended locator. FileSystemInsecureLocator— more permissive with symlinked directory structures. Still rejects..traversal and verifies the resolved path is under the root, but accommodates setups where thedata_rootitself or files within it are symlinks that resolve outside the configured root. Useful for monorepo setups, Vagrant/Docker shared mounts, or when bundle assets are symlinked into the web root viaassets:install --symlink.
stream
Loads images from any PHP stream wrapper (HTTP, FTP, custom wrappers, etc.). The wrapper_prefix is prepended to the image path before calling file_get_contents(). An optional stream context can be provided for authentication or SSL options.
SSRF protection: The stream loader validates URI schemes against a strict allowlist. Both standard (https://) and compact (data:) scheme formats are detected. Bare paths (absolute or relative) are treated as implicit file scheme. By default only file and data are allowed. To allow remote fetching, add the desired schemes explicitly:
Use it in a filter pipeline:
s3 — S3-compatible storage
Loads images from S3-compatible storage (AWS S3, MinIO, DigitalOcean Spaces). Requires chamber-orchestra/file-bundle.
Custom loaders
Implement LoaderInterface and register a factory:
Resolvers
Resolvers store cached images and resolve them to browser-accessible URLs.
web_path
Writes cached files to a directory under the web root and returns a root-relative URL.
s3 — S3-compatible storage
Stores cached images in an S3-compatible bucket and resolves URLs via a CDN prefix or presigned URLs. Requires aws/aws-sdk-php.
cache (PSR-6 decorator)
Wraps any resolver with a PSR-6 cache layer to avoid filesystem is_file() checks on repeated requests.
Custom resolvers
Implement ResolverInterface and register a factory, or inject your resolver as a service:
Runtime filters
Runtime filters allow processor options to be passed at request time without pre-configuring a named filter. The URL is HMAC-signed to prevent parameter tampering.
The HMAC secret defaults to the APP_SECRET kernel parameter (standard Symfony). You can override it per filter with the secret option — useful when different filters are consumed by different clients that each hold their own signing key:
When secret is set on a filter, all signing and verification for that filter (URL generation, controller hash check, cache path derivation, cache invalidation) uses the per-filter secret instead of APP_SECRET. Filters without a secret continue to use the global secret.
Client image URLs (TypeScript / mobile clients)
For front-end apps, mobile clients (Swift, Kotlin), or any HTTP client, the bundle exposes an nginx-cacheable endpoint that generates processed images on demand:
The filter must be marked exposed: true with a dedicated secret (must differ from APP_SECRET):
Share the secret with trusted clients out-of-band. The URL is HMAC-validated — clients compute the hashes using the same algorithm as the PHP Signer.
On a cache hit the controller returns a 301 redirect to the static file; on a miss it processes the image, caches it, and redirects. Because the URL is a deterministic GET, nginx try_files can serve cached images directly without hitting PHP.
Supported formats: jpg, jpeg, png, webp, avif.
TypeScript signing implementation
Building the URL
Configure filter, secret, and baseUrl once at module level:
Usage
Responsive <picture> element (React example)
This mirrors the Twig fit / fill macros — AVIF, WebP, and fallback srcsets at 1x/2x/3x densities:
React component
Next.js server component
In Next.js server components the secret stays on the server — configure it in lib/image-config.ts and the component just calls buildPictureSources directly:
Vue component
Rendered HTML (all frameworks)
Swift signing implementation
Building the URL
Configure filter, secret, and baseUrl once at app level:
Usage
Responsive image loading (SwiftUI)
Generate URLs at multiple densities for the device screen scale:
Kotlin signing implementation
Building the URL
Configure filter, secret, and baseUrl once at app level:
Usage
Responsive image loading (Compose / Android)
Cache invalidation
When using chamber-orchestra/file-bundle, cached variants are automatically removed when a source file is deleted via FileRemoveSubscriber, which listens to PostRemoveEvent.
To remove all cached variants for a path manually:
Web server configuration
For best performance, configure your web server to serve cached images directly from disk without hitting PHP. The bundle writes processed images to the filesystem at deterministic paths — the web server checks if the file exists and serves it immediately. Only on a cache miss does the request fall through to the Symfony controller.
nginx
Apache
Caddy
How it works
- First request (cache miss): the file doesn't exist on disk, so
try_filesfalls through toindex.php. The Symfony controller processes the image, stores it at{cache_path}/{pathHash}/{optionsHash}/{name}@{density}x.{format}, and returns a301redirect to the static URL. - Subsequent requests (cache hit): the web server finds the file on disk and serves it directly — PHP is never invoked. The
Cache-Control: public, immutableheader tells browsers and CDNs to cache the response indefinitely. - Cache invalidation: when the source image is deleted,
CacheManager::remove()deletes the entire{pathHash}/directory, so the next request will be a cache miss and the image will be re-processed.
Because image URLs are content-addressed (the hash changes when the source or options change), you can safely use immutable caching — stale URLs are never reused.
Extension points
- Custom processors: implement
ProcessorInterface, auto-taggedchamber_orchestra_image.filter.processor - Custom post-processors: implement
PostProcessorInterface, auto-taggedchamber_orchestra_image.filter.post_processor - Custom loaders: implement
LoaderFactoryInterface, register in your bundle'sbuild()method - Custom resolvers: implement
ResolverFactoryInterface, register in your bundle'sbuild()method, or usetype: customwith a service ID - Enums:
ImageFormat(png, jpg, webp, avif, ...) andImagineDriver(Gd, Imagick, Gmagick) are available for type-safe configuration
Testing
License
MIT. See LICENSE for details.
All versions of image-bundle with dependencies
ext-exif Version *
chamber-orchestra/file-bundle Version 8.0.*
imagine/imagine Version ^1.3
psr/cache Version ^3.0
symfony/config Version 8.0.*
symfony/dependency-injection Version 8.0.*
symfony/filesystem Version 8.0.*
symfony/http-foundation Version 8.0.*
symfony/http-kernel Version 8.0.*
symfony/mime Version 8.0.*
symfony/options-resolver Version 8.0.*
symfony/process Version 8.0.*
symfony/routing Version 8.0.*