Image Processing Pipeline
This document zooms in on the transformation phase that runs after imgforge validates a request. Use it alongside Processing Options to design URLs and reason about how directives interact inside libvips.
Pipeline visualization
┌─────────────────────────────────────────────────────────────────────────────┐
│ Image Processing Pipeline │
└─────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────┐
│ Parsed Directives │ → User request with processing options
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ 1. Plan │ → Normalize defaults (quality→85, auto_rotate→true)
│ Normalization │ Missing dimensions→0 (preserve aspect ratio)
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ 2. DPR Scaling │ → Multiply dimensions by device-pixel-ratio
│ (if dpr present) │ Affects width, height, padding before limits
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ 3. Image Loading │ → libvips ingests source buffer
│ (libvips) │ Color profile conversion + EXIF orientation
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ 4. Geometry │ → Crop (absolute coords) → Resize (fit/fill/force)
│ Transforms │ Gravity affects crop window & fill positioning
│ │ Upscaling blocked unless enlarge:true
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ 5. Canvas │ → Padding + extend + background (post-resize)
│ Adjustments │ Padding inherits DPR scaling
│ │ Alpha flattening for JPEG/non-alpha formats
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ 6. Effects & │ → Blur/sharpen/pixelate/zoom
│ Safeguards │ min_width/min_height checks → upscale if needed
│ │ Watermark loading & compositing
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ 7. Encoding │ → Format conversion (JPEG/WebP/AVIF/PNG)
│ (libvips) │ Quality compression (default 85)
│ │ Metadata stripping
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ Processed Image │ → Ready for response & caching
└──────────────────────┘High-level flow
- Plan normalization – Parsed directives are expanded into a structured plan with explicit defaults. Missing widths or heights default to
0, which allows imgforge to preserve aspect ratio. Quality defaults to85, backgrounds default to transparent/black depending on the target format, and EXIF auto-rotation starts enabled. - Device-pixel-ratio scaling – When
dpris present, imgforge multiplies all linear dimensions (width, height, padding) before any transformations take place. This scaling happens before limit checks so a largedprcan trip resolution safeguards. - Image loading – libvips ingests the source buffer, performs color-profile conversion when required, and applies EXIF orientation unless
auto_rotate:falsewas specified. - Geometry transforms – Crops execute first, followed by explicit resizing directives (
resize,size,width,height) using the activeresizing_type. Gravity influences how libvips positions the crop window and fill canvas. Upscaling is blocked unlessenlarge:truewas provided globally or through the specific directive. - Canvas adjustments – Padding, extend, and background directives run after resizing so they operate on the final viewport. Padding values inherit
dprscaling. When outputting formats without alpha channels (e.g., JPEG), backgrounds are flattened against the target color. - Effects & safeguards – Blur, sharpen, pixelate, and zoom run after geometry changes. Minimum dimension checks (
min_width,min_height) can trigger an additional upscale when the image still falls short. Watermarks load at this stage, clamped by the canvas size, and will fail with a descriptive error if the watermark image cannot be fetched or decoded. - Encoding – The final libvips image is encoded into the desired format. Explicit
formatdirectives override the implicit format derived from@extension. Compression quality honours thequalitydirective, falling back to85for JPEG/WebP and libvips defaults for other codecs. Metadata stripping follows libvips defaults.
Inter-option nuances
- Resizing + padding – Padding is additive. A
resize:fit:800:600followed bypadding:20yields an 840×640 canvas before background flattening. Remember to scale padding expectations when usingdpr. - Crop vs. gravity – An explicit
crop:x:y:width:heightignores gravity because coordinates are absolute. Gravity only matters for implicit crops triggered byfillresizing or watermark positioning. - Zoom and minimums –
zoommultiplies the dimensions produced by resizing. Minimum width/height run afterward, so a zoom factor under 1.0 can still be clamped upward bymin_widthormin_height. - Watermark precedence – If both
watermark_urlandIMGFORGE_WATERMARK_PATHare available, the URL-specific asset wins. Repeated watermark directives use the last occurrence. - Concurrency and
rawmode – Settingrawskips the global semaphore, but the transformation order remains identical. Use it sparingly for high-priority jobs.
Failure modes
- Invalid numerical values (negative widths, NaNs, out-of-range blur sigma) surface as
400 Bad Requestbefore libvips runs. - Oversized outputs—after applying
dpr, padding, and minimum dimensions—trigger the megapixel guard or source file size checks if derivatives exceed the thresholds. - Watermark downloads share the same timeout and size limits as primary sources; failures stop the request unless a fallback watermark path exists.
Observability
image_processing_duration_secondsmeasures time spent inside this pipeline.processed_images_total{format="..."}tracks throughput per output format.- Logging includes a request ID. Combine it with the detailed stages in Request Lifecycle when debugging complex transformations.
Use this pipeline map when troubleshooting visual discrepancies, designing new directives, or reasoning about how multiple options compose.