Image Conversion
Overview
On-the-fly image-to-WebP conversion via a Rust Lua filter. Content negotiation is based on the Accept header: when a client accepts image/webp and the response is an eligible image (JPEG, PNG, or GIF first-frame), the response is buffered, decoded, re-encoded as WebP, and emitted with updated Content-Type and Vary headers.
How It Works
The same URL serves WebP or the original image transparently. No rewrite rules or src link replacement is needed — the browser’s Accept header determines which format is served.
Client (Chrome) -> Accept: image/webp -> WebP response
Client (IE) -> Accept: image/* -> JPEG response
Encoding Strategy
| Source | Encoding | Reason |
|---|---|---|
| PNG | Lossless WebP | PNG is lossless, so lossless WebP preserves quality |
| JPEG | Lossy WebP | JPEG is already lossy, lossy WebP at quality 80 typically gives better ratio |
| GIF | Lossy WebP (first frame) | Only the first frame is converted (see Animated GIF below) |
Size Guard
If the WebP output is not smaller than the original, the original bytes are served instead. This ensures conversion never increases the response size.
Configuration
Global Toggle
| Setting | Default | Description |
|---|---|---|
img_2_webp_enabled | off | Master switch for image conversion |
Per-Backend Options
| Setting | Default | Description |
|---|---|---|
img_2_webp_enabled | off | Enable for this backend |
img_2_webp_quality | 80 | WebP quality for lossy encoding (1-100) |
img_2_webp_max_size | 10MB | Skip conversion if image is larger |
img_2_webp_max_dim | 4096 | Skip conversion if either dimension exceeds this |
img_2_webp_source_types | jpeg,png,gif | Source types to convert |
Caching Integration
The filter emits Vary: Accept so caches create separate entries for WebP and original responses. HAProxy’s memory cache auto-enables process-vary when image conversion is active. The disk cache caches the converted WebP output.
Without Vary: Accept, a cache might serve a WebP response to a client that doesn’t support WebP. coreX Manager handles this automatically — you don’t need to configure anything extra.
Filter Ordering
The image conversion filter is emitted after compression so the WebP output is not re-compressed. The full filter order is:
cache -> resp_transform -> compression -> image_conversion
FCGI Limitation
The image conversion filter is skipped for FastCGI backends due to an HAProxy 3.4 bug.
Animated GIF
The current version converts only the first frame of animated GIFs to a static WebP. Animated GIF to animated WebP is future work. If you serve animated GIFs, consider excluding gif from img_2_webp_source_types to avoid losing animation.
Step-by-Step: Enable Image Conversion
- Navigate to Settings > Global Options
- Enable
img_2_webp_enabled - Save
Step-by-Step: Configure Per-Backend
- Navigate to Core > Backends and open the backend serving images
- Scroll to Image Conversion
- Enable
img_2_webp_enabled - Set
img_2_webp_qualityto80(good balance) - Set
img_2_webp_max_sizeto10MB(skip very large images) - Set
img_2_webp_max_dimto4096(skip very large dimensions) - Set
img_2_webp_source_typestojpeg,png(exclude gif if you have animated GIFs) - Save and Apply
Verification
-
Test with WebP support:
curl -k -H "Accept: image/webp" -sI https://localhost/photo.jpg | grep -i content-typeExpect
content-type: image/webp. -
Test without WebP support:
curl -k -H "Accept: image/*" -sI https://localhost/photo.jpg | grep -i content-typeExpect
content-type: image/jpeg(original format). -
Check Vary header:
curl -k -sI https://localhost/photo.jpg | grep -i varyExpect
vary: Accept. -
Compare sizes:
curl -k -H "Accept: image/webp" -s https://localhost/photo.jpg | wc -c curl -k -H "Accept: image/*" -s https://localhost/photo.jpg | wc -cThe WebP response should be smaller (if not, the original is served due to the size guard).
-
Test with a browser:
- Open your site in Chrome or Firefox
- Open DevTools > Network
- Filter by images
- Verify JPEG/PNG images are served as WebP
Next Steps
- Caching — Cache converted WebP images
- Compression — Configure response compression
- Response Transforms — Modify response bodies