Providers
All providers implement Timber\Chainsaw\Provider\ProviderInterface:
interface Provider {
public function url(Image $image): string;
}
Call (string) $image or echo $image to trigger the provider and get the URL.
Overview
| Provider | Type |
|---|---|
| Intervention | Local (GD / Imagick / libvips) |
| Imagine | Local (GD / Imagick / Gmagick) |
| Cloudflare | CDN (Freemium SaaS) |
| Cloudinary | CDN (Freemium SaaS) |
| ImageKit | CDN (Freemium SaaS) |
| imgix | CDN (Paid SaaS) |
| imgproxy | CDN (Self-hosted OSS) |
| Thumbor | CDN (Self-hosted OSS) |
| Imagor | CDN (Self-hosted OSS) |
| wsrv.nl | CDN (Free public service) |
Per-manipulator support breadth varies — the full support matrix is the authoritative comparison.
Feature comparison
| Feature | Intervention | Imagine | Cloudflare | Cloudinary | ImageKit | imgix | imgproxy | Imagor | Thumbor | wsrv |
|---|---|---|---|---|---|---|---|---|---|---|
| Local processing | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Format negotiation | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Data URIs | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| URL signing | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| BlurHash | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| ThumbHash | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Watermark | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
Not all manipulators are supported by every provider. Unsupported manipulators throw UnsupportedManipulator. See the full support matrix.
Multiple providers
A factory wraps exactly one provider. To mix backends — for example Cloudflare for most images (no server load) and Intervention for the few needing manipulations Cloudflare can’t do — wrap several ImageFactory instances in a FactoryRegistry and pick one explicitly by name. The registry never auto-routes; the call site stays in control.
It mirrors Symfony’s Asset Packages: one nameless default plus any number of named factories.
use Timber\Chainsaw\FactoryRegistry;
use Timber\Chainsaw\ImageFactory;
$registry = new FactoryRegistry(
default: new ImageFactory($interventionProvider),
factories: [
'cloudflare' => new ImageFactory($cloudflareProvider),
'cloudinary' => new ImageFactory($cloudinaryProvider),
],
);
$registry->image('photo.jpg'); // default factory
$registry->image('photo.jpg', 'cloudflare'); // named factory
$registry->factory('cloudflare'); // the underlying ImageFactory
Encoding, presets, and defaults stay per-factory — one provider’s settings rarely fit another (Cloudflare can’t emit gif/png the same way, Cloudinary has f_auto). Each factory keeps its own, and caches don’t collide: every provider owns its own cache surface (local providers their Flysystem variant cache; URL-grammar providers delegate to the CDN).
| Method | Returns |
|---|---|
image(source, name?, meta?) |
Image from the named factory — the default when name is null |
factory(name?) |
the ImageFactory (default when name is null); throws FactoryNotFound for an unknown name |
has(name) |
whether a named factory is registered |
names() |
the registered names (the default is nameless and excluded) |
purger(name?) |
a purger — see Cache Purging → Multiple providers |
In Twig the same name flows through img(source, name) — see Twig Integration.