GumletProvider
Generates Gumlet transformation URLs. Gumlet is a query-string grammar close to imgix’s, on a source host that resolves relative paths against the source’s configured origin.
use Timber\Chainsaw\Provider\Gumlet\GumletProvider;
use Timber\Chainsaw\Signer\Algorithm;
use Timber\Chainsaw\Signer\SignatureEncoding;
use Timber\Chainsaw\Signer\HashUrlSigner;
$provider = new GumletProvider(
host: 'https://demo.gumlet.io',
// Optional URL signing — Gumlet's scheme is md5(token + path + query), hex:
token: $_ENV['GUMLET_TOKEN'],
signer: new HashUrlSigner(algorithm: Algorithm::Md5, encoding: SignatureEncoding::Hex),
);
Output: {host}/{source}?w=800&h=600&fit=crop&s={signature}
Prerequisites
Gumlet resolves the request path against the source’s configured origin, so a storage-relative path (PathSource) addresses a file on that origin. A fully-qualified UrlSource is supported through Gumlet’s web-proxy mode — it is URL-encoded whole (slashes and all) so it survives an origin URL that carries its own query or fragment.
Signing (secure URLs)
When a source has Secure URLs enabled, pass the source’s secret as token together with a HashUrlSigner. Gumlet’s scheme is byte-identical to imgix: md5(token + path + query) in hex, appended as the s parameter. Both token and signer must be set — with only one, URLs are emitted unsigned.
$provider = new GumletProvider(
host: 'https://demo.gumlet.io',
token: $_ENV['GUMLET_TOKEN'],
signer: new HashUrlSigner(algorithm: Algorithm::Md5, encoding: SignatureEncoding::Hex),
);
Output: {host}/{source}?w=800&s=…
The cache-bust version is folded into the query before signing, so the signature always covers it. A same-origin watermark overlay is signed automatically too (see Notes).
Manipulation support
Legend: ✅ = implemented in Chainsaw, ⚠️ = supported with caveats, 🟦 = available on the CDN, not exposed by Chainsaw, ❌ = not available on this CDN.
Resize & crop
| Manipulation | Chainsaw | Availability |
|---|---|---|
| Width | ✅ | w |
| Height | ✅ | h |
| Scale | ❌ | No scale-by-factor primitive; use width()/height() |
| Cover | ✅ | fit=crop + crop (compass, focal, smart/edges, entropy & face anchors) |
| ManualCrop | ✅ | rect=x,y,w,h |
| Contain | ✅ | fit=fit (default; preserves aspect) |
| CropToRatio | ✅ | ar + fit=crop + crop |
| Pad | ✅ | fit=fill + fill=solid + fill-color |
| Stretch | ✅ | fit=scale |
| PadToRatio | ❌ | No aspect-ratio-only pad; specify absolute dimensions via pad() |
Filters & effects
| Manipulation | Chainsaw | Availability |
|---|---|---|
| Blur | ⚠️ | blur (0…100, direct); dropped on WebP/AVIF output |
| Sharpen | ✅ | sharp |
| Brightness | ✅ | bri |
| Contrast | ⚠️ | contrast (0…100); increase-only — a negative value throws |
| Saturation | ✅ | sat |
| Greyscale | ✅ | via sat=-100 |
| Hue shift | ✅ | hue (0…360) |
| Negate / Invert | ⚠️ | invert=true; inverts the alpha channel too, so it only works on sources with no alpha channel (see notes) |
| Trim | ✅ | trim (similarity percentage) + optional trim-color |
| Gamma | ❌ | No usable gamma slider |
| Sepia | ❌ | No sepia parameter |
| Pixelate | ❌ | No pixelate parameter |
Decoration & orientation
| Manipulation | Chainsaw | Availability |
|---|---|---|
| Background | ✅ | bg (pure white nudged a hair — see notes) |
| Border | ❌ | No border/canvas parameter |
| Flip | ✅ | flip=h / flip=v |
| Rotate | ⚠️ | rotate; 90/180/270 only — arbitrary angles throw UnsupportedManipulator |
| AutoOrient | ✅ | EXIF orientation applied implicitly by default |
| Watermark | ⚠️ | overlay grammar; several limitations — see notes |
Encoding
| Format | Supported |
|---|---|
| JPEG | ✅ |
| PNG | ✅ |
| WebP | ✅ |
| AVIF | ✅ |
| GIF | ✅ |
| JPEG XL | ✅ |
| Auto format | ✅ |
| Quality | ✅ |
Notes
- imgix-grammar, calibrated on its own — Gumlet’s parameters look like imgix’s, but several diverge in ways that were measured against rendered pixels rather than read from docs. The provider is standalone (not a shared base with imgix), so each behaviour below is Gumlet-specific.
- URL signing — optional; requires both
token(the source secret) and asigner. Gumlet’s scheme ismd5(token + path + query)in hex, so the signer isHashUrlSigner(algorithm: Algorithm::Md5, encoding: SignatureEncoding::Hex). With only one of the two configured, URLs are emitted unsigned. - Gamma — refused. Neither slider is usable:
gamis fully inert, andgammaonly shifts a few units non-monotonically in the wrong direction, sogamma()throwsUnsupportedManipulatorrather than emit an unreliable parameter. - Contrast — Gumlet’s parameter is the long
contrast(0…100); the imgixconalias is silently ignored. It only ever increases contrast — a negative value renders identically to its positive twin — so there is no contrast-reduction primitive and a negativecontrast()throws. Use a local provider to reduce contrast. - Pad fill — the pad bar colour is
fill=solid+fill-color, notbg. A barebgleaves the pad bars white. (bgis still the parameter forBackgroundcompositing — the two do not share a slot.) - Pure-white background — an exact pure-white
background('#ffffff')is nudged to#fffffe(a hair off white, visually indistinguishable). Gumlet silently drops a pure-white background on alpha-preserving output — it keeps the transparency instead of compositing — andfffffecomposites correctly. Only exact pure white is touched; every other colour passes through unchanged. Pad bars (fill-color=ffffff) are not affected. - Trim — the tolerance is the value of
trimitself (a 1…99 similarity percentage). Chainsaw’s 0…100 tolerance clamps into that range (0 lifts to 1). An optional custom match colour is emitted astrim-color. - Blur —
blur = radius(Gumlet’s 0…100 slider renders a gaussian sigma of aboutradius/2). It is silently dropped when the output codec is WebP or AVIF — the parameter is ignored and the hard edge stays — so blur only renders for JPEG/PNG output. - Invert and the alpha channel —
negate()(Gumlet’sinvert=true) inverts the alpha channel along with the colours. A source that carries an alpha channel is destroyed: its transparency is swapped (opaque areas turn transparent and transparent areas turn opaque). The discriminator is the presence of an alpha channel, not visual opacity — a fully-opaque RGBA image would have its all-opaque alpha inverted to fully transparent. Sources with no alpha channel (JPEG, plain RGB PNG) invert fine. No parameter both inverts the colours and keeps the alpha channel, so use a local provider to invert an image that has one. - Format negotiation —
format=autonegotiates a modern codec (AVIF/WebP) from the request’sAcceptheader. Gumlet varies onAccepteven without aformatparameter, so a modern browser can receive AVIF/WebP by default. Concrete formats pass through by value, including JPEG XL (format=jxl→image/jxl). - Source formats — Gumlet decodes the full raster set, AVIF input included (transcoded to JPEG by default).
- Watermark — Gumlet uses its
overlaygrammar (not imgix’smark-*). All nine anchor positions are supported. Sizing is percent-only (a 0…1 fraction of the output); pixel sizing throws.- Opacity (alpha) — supported for a same-origin
PathSourceoverlay. The overlay URL is itself a Gumlet URL, so a non-default alpha is baked into it as a nestedopacity(Chainsaw’s 0…100 maps directly), and the mark composites semi-transparently. AUrlSourceoverlay is external and cannot be transformed, so a non-default alpha on it is refused. - Padding needs the top-left anchor —
overlay_top/overlay_leftare absolute pixel offsets from the top-left that override the position, so padding is only expressible withPosition::TopLeft; padding at any other anchor throws. - No inter-tile gap — a tiled overlay covers the whole output and has no gap control, so a requested tile gap throws.
- Absolute URL required — the overlay is fetched from an absolute URL. A same-origin
PathSourceoverlay is resolved against the provider host, and aUrlSourcepasses through as-is. On a secure source the same-origin overlay is signed automatically when atoken+signerare configured (the signature covers the nestedopacitywhen present); an externalUrlSourceoverlay is left verbatim.
- Opacity (alpha) — supported for a same-origin