Provider Support Matrix

Chainsaw ships with ten providers. Each provider supports a different subset of the available manipulators. Unsupported manipulators throw UnsupportedManipulator at URL-generation time.

Providers at a glance

Provider Type Pricing URL style Signing
Intervention Local processing OSS (free) n/a (filesystem) n/a
Imagine Local processing OSS (free) n/a (filesystem) n/a
Cloudflare URL grammar Freemium SaaS /cdn-cgi/image/w=…,h=…/source Cloudflare-managed
Cloudinary URL grammar Freemium SaaS /image/upload/w_…,h_…/source HMAC (s--…--)
ImageKit URL grammar Freemium SaaS /source?tr=w-…,h-…,c-maintain_ratio HMAC-SHA1 (&ik-s=…)
imgix URL grammar Paid SaaS /source?w=…&h=…&fit=crop MD5 (&s=…)
imgproxy URL grammar OSS (self-hosted) /rs:…/w:…/h:…/plain/source HMAC (path signature)
Thumbor URL grammar OSS (self-hosted) /hmac/WxH/filters:…/source HMAC (path prefix)
Imagor URL grammar OSS (self-hosted) /fit-in/WxH/filters:…/source HMAC (path prefix)
wsrv.nl URL grammar Free (public) ?url=…&w=…&h=…&output=webp n/a (public service)

Portability baseline

If your presets stick to the manipulators below, switching providers is a configuration change — no provider will throw UnsupportedManipulator:

  • Resize: Width, Height, Cover (and its crop() alias), ManualCrop, Contain, Pad, Stretch
  • Encoding: JPEG, PNG, WebP, AVIF, Quality
  • Filters: Blur, Sharpen, Greyscale
  • Decoration: Background, Flip, Rotate (quarter-turns), AutoOrient

“Portable” here means the manipulator is accepted by every provider — not that output is pixel-identical. Numeric ranges and algorithms differ between backends (e.g. Blur radius, Quality scales, AVIF encoder settings), so expect visual differences when switching providers even within the baseline. Run visual regression if that matters to you.

Precision notes

  • Sharpen(0..100) — backend granularity varies widely. Cloudflare quantizes to 11 steps (0..10), imgproxy Pro to ~10 sigma steps, Thumbor to 11 amount steps. Expect visible banding at small mid-range deltas on these backends. imgix, Cloudinary, Imagor and wsrv.nl preserve the full 0…100 precision.
  • Gamma(0.1..9.99) — Chainsaw uses a multiplier (1.0 = unchanged). Cloudinary and imgix natively take a percentage, so the providers translate via pct = round((gamma - 1) * 100) and clamp to each backend’s percentage window (Cloudinary -50..150, imgix -100..100). Large multipliers saturate rather than extrapolate.

Manipulation support

Legend: ✅ = supported, ❌ = not supported.

Resize & crop

Manipulator Cloudflare Cloudinary Imagekit Imagine Imagor Imgix Imgproxy Intervention Thumbor Wserv
Width
Height
Scale
Cover
ManualCrop
Contain
Pad
Stretch
CropToRatio
PadToRatio
Trim

Filters & effects

Manipulator Cloudflare Cloudinary Imagekit Imagine Imagor Imgix Imgproxy Intervention Thumbor Wserv
Blur
Sharpen
Brightness
Contrast
Gamma
Greyscale
Sepia
Pixelate
Saturation
Hue
Negate

Decoration & orientation

Manipulator Cloudflare Cloudinary Imagekit Imagine Imagor Imgix Imgproxy Intervention Thumbor Wserv
Background
Border
Flip
Rotate
AutoOrient

Watermark sub-matrix

Source types:

Source Intervention Imagine Cloudflare Cloudinary ImageKit imgix imgproxy (free) imgproxy (Pro) Thumbor Imagor wsrv
WatermarkFromUrl
WatermarkFromServerDefault ✅¹

Size units ($sizeUnit):

Unit Intervention Imagine Cloudflare Cloudinary ImageKit imgix imgproxy (free) imgproxy (Pro) Thumbor Imagor wsrv
Unit::Pixel ✅² ✅²
Unit::Percent ✅¹⁰ ✅⁸

Padding units ($paddingUnit):

Unit Intervention Imagine Cloudflare Cloudinary ImageKit imgix imgproxy (free) imgproxy (Pro) Thumbor Imagor wsrv
Unit::Pixel ✅⁹
Unit::Percent ✅³ ✅³ ✅⁴ ✅¹⁰ ❌⁵ ✅⁶ ✅⁶ ✅⁷ ✅⁷

¹ Only key === 'default' (matches the server’s IMGPROXY_WATERMARK_URL). Custom keys require Pro.
² Converts pixels → ratio using the output image width (set via upstream Width/Crop). Without upstream output dims, throws UnsupportedManipulator.
³ Computed locally from base image dims.
⁴ Native via decimal x_0.1 / y_0.05 per Cloudinary docs.
⁵ Imgix mark-x/mark-y/mark-pad are integer-only per docs; throws UnsupportedManipulator.
⁶ Native via relative offset (imgproxy treats |v| < 1 as percent of image dims).
⁷ Native via Xp notation (Thumbor / Imagor docs: “20p” = 20% of image width).
⁸ Converts percent → pixels using the output image dims (set via upstream Width/Crop/Contain). Imgix’s native mark-w=0..1 is a fraction of the watermark source, not the output image — without upstream output dims, throws UnsupportedManipulator.
⁹ Symmetric only (paddingX === paddingY); emits mark-pad. Imgix mark-x / mark-y are absolute pixel offsets that override mark-align, so asymmetric padding from the alignment edge has no clean imgix equivalent — throws UnsupportedManipulator.
¹⁰ Native via ImageKit arithmetic expressions (bw_mul_0.25 = 25% of base width) per ImageKit’s imgix migration guide.

Special

Manipulator Cloudflare Cloudinary Imagekit Imagine Imagor Imgix Imgproxy Intervention Thumbor Wserv
BlurHash
ThumbHash
Dither

Encoding

Every provider supports format conversion and quality control through the Encoding value object.

Capability Intervention Imagine Cloudflare Cloudinary ImageKit imgix imgproxy Thumbor Imagor wsrv
JPEG
PNG ❌¹
WebP
AVIF
GIF ❌¹ ❌²
Auto format ✅³ ✅³ ❌⁴ ❌⁴ ❌⁴ ❌⁴
Quality

¹ Cloudflare’s URL API has no format=png|gif value — an explicit PNG/GIF request is silently ignored and the source format passes through.
² ImageKit does not output GIF — an explicit request throws UnsupportedOperation.
³ Origin-side, resolved by an AutoFormatStrategyInterface you inject — see Advanced > Format negotiation. The CDN columns negotiate edge-side (format=auto / f_auto / f-auto / auto=format).
Format::Auto is silently ignored — set an explicit format or compose a <picture> with typed sources.