ImagekitProvider

Generates ImageKit transformation URLs. SaaS image CDN in the same family as imgix and Cloudinary, with strong AI/object-aware crop primitives on the free tier.

use Timber\Chainsaw\Provider\Imagekit\ImagekitProvider;

$provider = new ImagekitProvider(
    urlEndpoint: 'https://ik.imagekit.io/your-account',
);

Output: {urlEndpoint}/{source}?tr=w-300,h-200,c-maintain_ratio&ik-s={signature}

Source modes

ImagekitProvider auto-detects between two modes based on whether a SourceLocator is supplied:

  • Account-origin mode – pass a SourceLocator (typically FlysystemSourceAdapter) to rewrite relative paths to fetchable URLs. ImageKit’s dashboard must be configured with the matching origin (S3, web folder, custom). Mirrors the imgix workflow.
  • Web proxy mode – no SourceLocator. Absolute http(s) source URLs are appended directly to the endpoint: https://ik.imagekit.io/your-account/https://example.com/photo.jpg. Useful for ad-hoc remote sources; no dashboard origin config needed.

URL signing

Optional signed URLs via UrlSignerInterface. ImageKit uses HMAC-SHA1 (lowercase hex) over path + query + expiryTimestamp. Wire it with HmacUrlSigner configured for hex output:

use Timber\Chainsaw\Provider\Imagekit\ImagekitProvider;
use Timber\Chainsaw\Signer\Algorithm;
use Timber\Chainsaw\Signer\SignatureEncoding;
use Timber\Chainsaw\Signer\HmacUrlSigner;

$provider = new ImagekitProvider(
    urlEndpoint: 'https://ik.imagekit.io/your-account',
    signer: new HmacUrlSigner(
        key: 'your-private-api-key',
        algorithm: Algorithm::Sha1,
        encoding: SignatureEncoding::Hex,
    ),
);

Output (default, no TTL): {urlEndpoint}/{source}?tr=…&ik-s={hex-signature}. ImageKit’s official SDK always appends a 9999999999 sentinel timestamp to the signed payload but omits the ik-t query parameter when no expiry is configured — the server replays the sentinel during signature verification. The provider mirrors this so signed URLs stay deterministic and CDN-cacheable.

Opt into a TTL by passing expirySeconds:

$provider = new ImagekitProvider(
    urlEndpoint: 'https://ik.imagekit.io/your-account',
    signer: $signer,
    expirySeconds: 300, // 5-minute TTL
);

The URL gains &ik-t=<unix-timestamp> and the signature covers path + query + timestamp. Signatures drift per second, so cache hit rates drop accordingly.

The timestamp comes from an optional PSR-20 clock (clock: constructor parameter); by default the system time is used. Inject a fixed clock (for example symfony/clock’s MockClock) to make signed-TTL URLs deterministic in tests.

Signing is required only when “Restrict Unsigned URLs” is enabled in the ImageKit dashboard. The default is off, so unsigned URLs work out of the box.

Manipulation support

Legend: ✅ = implemented in Chainsaw, ⚠️ = supported with caveats, ❌ = not available on this CDN.

Resize & crop

Manipulation Chainsaw Availability
Width Free tier
Height Free tier
Scale No scale-by-factor primitive; use width()/height()
Cover ⚠️ All anchors except Focal (named positions only on fo-)
ManualCrop Free tier (cm-extract)
Contain Maps c-at_max_enlarge (upscale) / c-at_max (no-upscale)
Pad Maps cm-pad_resize / cm-pad_resize_no_enlarge
Stretch Maps c-force
CropToRatio Maps ar-w-h,c-maintain_ratio
PadToRatio Maps ar-w-h,cm-pad_resize
Trim t-true (auto) or t-<1..99> (threshold)
Smart crop Anchor::smart() / Anchor::entropy() / Anchor::attention() all map to fo-auto
Face crop Anchor::face()fo-face
Object-aware crop Anchor::object('car')fo-car; full COCO label set

Filters & effects

Manipulation Chainsaw Availability
Blur bl- = round(radius × 0.55) → emits 1…55 (σ anchor; ImageKit accepts 1…100); blur(0) is a no-op
Sharpen e-sharpen (auto) or e-sharpen-<0..100>; see notes
Greyscale e-grayscale
Brightness Not documented in ImageKit’s URL API
Contrast e-contrast is a boolean auto-enhance only, no level control
Gamma Not documented in ImageKit’s URL API
Saturation Not documented in ImageKit’s URL API
Hue Not documented in ImageKit’s URL API
Sepia Not documented (could approximate via e-colorize, deferred)
Pixelate Not documented
Negate / Invert Not documented

Decoration & orientation

Manipulation Chainsaw Availability
Background Bare hex bg-RRGGBB[AA] (alpha as trailing 2 hex digits)
Border All BorderType variants; b-<width>_<color>
Flip fl-h / fl-v
Rotate Arbitrary degrees, including negatives (rt-N45 = -45°)
AutoOrient rt-auto
Watermark WatermarkFromSource only; px and percent units

Special

Manipulation Chainsaw Availability
BlurHash Local-pixel manipulator; ImageKit emits images, not hash strings
ThumbHash Same as BlurHash
Dither Not documented

Encoding

Format Supported
JPEG
PNG
WebP
AVIF
GIF
Auto format
Quality

Notes

  • URL grammar – ImageKit uses a single tr= query parameter with comma-separated key-value transformations: ?tr=w-300,h-200,c-maintain_ratio. Different from imgix’s individual query params.
  • Hex encoding – bare RRGGBB (no #, no %23 prefix, no rgb: prefix). 8-digit RRGGBBAA for alpha. Different scheme from every other Chainsaw provider.
  • Crop modes – ImageKit splits “fit” across two axes: c- (mode: maintain_ratio, at_max, force, at_max_enlarge) × cm- (strategy: extract, pad_resize, pad_resize_no_enlarge). Chainsaw’s Cover/Contain/Pad/Stretch/ManualCrop map to specific combinations per the imgix migration guide.
  • Anchor mapping – compass tokens use underscore separator: top_left, bottom_right (not commas as on imgix). Anchor::smart(), Anchor::entropy() and Anchor::attention() all collapse onto ImageKit’s single fo-auto AI crop. Anchor::object('class') accepts any COCO label (person, car, truck, etc.).
  • Focal anchorAnchor::focal(x, y) throws UnsupportedManipulator. ImageKit’s fo- parameter accepts named positions only; there is no native focal-point-as-percent. Users wanting cross-CDN focal parity should stick with Anchor::compass() or switch to AI-driven anchoring (face/smart).
  • Sharpen – the main docs document e-sharpen-<0..100>; ImageKit’s imgix migration guide hints at a ×20 scaling factor (sharp=10e-sharpen-200). Empirical calibration is deferred; expect output to differ from the documented range until verified.
  • Rotate background – arbitrary-angle rotations leave triangular voids. ImageKit has no dedicated rotation-background parameter, so Rotate(degrees, background) emits the colour as the page-level bg- — the same key the Background manipulator uses. If both are stacked, apply order decides (last-write wins, matching Cloudinary’s pattern).
  • Border – all three BorderType variants render at the requested output size. Expand emits ImageKit’s native b- (the canvas grows by 2×width per axis). Shrink pre-shrinks the constrained dims so the expanding b- lands back on the requested box (content shrinks to make room). Overlay keeps the subject at full crop scale by chaining a centre cm-extract that trims inward by 2×width before b- grows it back, so the border paints over the outer band rather than resizing the content. Overlay needs both dimensions from an upstream box resize (crop/cover/pad/stretch, or width()+height()) and throws UnsupportedManipulator otherwise. Unit::Percent throws.
  • Watermark – The WatermarkFromSource ref (URL or storage path) is base64url-encoded via ie- to safely pass through ImageKit’s comma/colon-separated grammar. The layer block is its own :-chained step. Positioning uses lap-<anchor> for the edge/corner, with lx/ly shifting the layer relative to that anchor (negative offsets — encoded N<abs> — push inward from right/bottom anchors). Percent sizing works (w-bw_mul_0.25 = 25% of base width); percent padding and asymmetric padding throw UnsupportedManipulator. On centered axes (Position::Top/Bottom/Left/Right/Center) the offset along the centered axis is dropped — padding has no direction there. Server-default registries are not supported; use WatermarkFromSource.
  • Watermark fit – with a width/height box the overlay crop token carries the fit: Containc-at_max (fits inside the box keeping aspect), Stretchc-force (distorts to the box). ImageKit’s cover (c-at_least) overflows the box rather than cropping to it, so Fill and Crop throw UnsupportedManipulator. A single axis scales proportionally and emits no crop token.
  • GIF output – ImageKit’s documented format set is auto|orig|jpg|png|webp|avif. Requesting Format::Gif throws UnsupportedOperation.
  • Free tier – ImageKit’s free tier covers all geometry, encoding, signing, and AI-driven crop (face, smart, object-class). Some advanced AI primitives (background removal, gen-fill, etc.) consume metered “extension units”; those are not currently exposed by Chainsaw.