Image Stack Limitations
This document describes current limitations in the FastEdge/proxy-wasm Image Stack implementation.
🚨 Critical Limitations
1. WebP Lossy Encoding Limits (WASI Memory Constraints)
Status: ⚠️ Lossy Supported with Safeguards
Problem:
- WebP lossy encoding now runs through libwebp inside WASI, but qualities above ~93 dramatically increase temporary memory usage.
- WASI modules have a limited linear-memory budget. Large images + quality
>93can causeVP8_ENC_ERROR_OUT_OF_MEMORY, which previously crashed the module.
Impact:
?quality=95&fmt=webp→ Quality automatically clamped to 93 (warning logged).- PNG sources +
PNG_LOSSLESS=true→ Always encoded lossless (quality ignored), matching the previous behavior.
Future Resolution:
- Larger WASI memory limits or Wasm GC could allow higher qualities safely.
- If FastEdge exposes more linear memory, the clamp can be relaxed.
2. Response Headers Cannot Be Set in Body Phase
Status: ⚠️ Architectural Limitation (proxy-wasm)
Problem:
- Headers must be set in
on_http_response_headersphase - Image processing happens in
on_http_response_bodyphase - Cannot add headers after processing (already sent to client)
Missing Headers:
- ❌
X-Img-Origin-Size(need body to know size) - ❌
X-Img-Saved-Bytes(need to compare original vs processed) - ❌
X-Img-Processing-Time(need to measure encoding time) - ❌
Img-Skip-Reason(determined during processing)
Available Headers:
- ✅
Content-Type(known from format selection) - ✅
Vary(known from query parameters) - ✅
X-Img-Operations(known from query parameters) - ✅
Transfer-Encoding: chunked
Metrics Available in Logs:
✓ Encoding successful
Original size: 123456 bytes
Processed size: 45678 bytes
Saved: 77778 bytes (63.0% reduction)
Workaround:
- Metrics logged to console (accessible in FastEdge logs)
- Monitor via log aggregation
Future Resolution:
- HTTP trailers support (when GCore implements)
- Can add headers after body with trailers
3. Size Comparison Disabled (Header/Body Conflict)
Status: ⚠️ By Design (prevents corruption)
Problem:
- Cannot compare processed vs original size in body phase
- Headers already committed to format in header phase
- Changing decision would cause format mismatch → corruption
Example of what would break:
Headers sent: Content-Type: image/webp
Body decision: "Processed larger, serve original JPEG"
Result: Browser tries to decode JPEG as WebP → Broken image
Current Behavior:
- ✅ Always serves processed image
- ⚠️ Even if processed is larger than original
- 📊 Logs warning: "Processed image is X bytes larger"
Impact:
Rare cases where processed > original:
- Already heavily compressed images
- Very small images (WebP overhead)
- Quality settings too high
Workaround:
- WebP is almost always smaller (
>95%of cases) - For rare cases, slightly larger file is acceptable vs corruption
Future Resolution:
- HTTP trailers (can change Content-Type after body)
- Or accept this tradeoff
⚠️ Operational Limitations
4. Image Upscaling Not Supported
Status: ✅ Rejected and skipped
Problem:
- Upscaling degrades quality (interpolation artifacts)
Current Behavior:
?width=2000 // Original: 1000×1000
→ Resize skipped
⚠️ Warning logged: "Resize failed"
Recommendation:
- Image Stack is for optimization (downscaling)
- Don't request dimensions larger than original
- Check original dimensions before using resize
5. Crop Cannot Exceed Original Dimensions
Status: ✅ Logical limitation (not a bug)
Problem:
- Crop extracts a portion of image
- Cannot extract more pixels than exist
- This is expected behavior
Example:
Original: 1000×1000 pixels
?crop=1500,1500 ← Impossible!
Behavior:
- Validation happens during processing
- Error logged, crop skipped
📋 Recommended Configuration
For Production (Current Limitations):
# Format conversion
CONVERT_TO_WEBP=true # WebP lossy (quality capped at 93)
# Quality
QUALITY_PRESET=high # 95% (will be clamped for WebP if >93)
# PNG behavior
PNG_LOSSLESS=true # Keep PNG lossless
# File types
FORMATS_TO_TRANSFORM=jpg,jpeg,png
🔮 Future Roadmap
Short Term (Waiting on Platform):
- HTTP trailers support → Add metrics headers, size comparison
Medium Term (Waiting on Community):
- Pure Rust lossy WebP → Quality control for WebP
Long Term (Potential):
- Parallel processing → Process multiple operations faster
- Caching processed images → Avoid reprocessing
✅ What Works Well
Despite limitations, these features work reliably:
- ✅ WebP conversion - Fast, reliable, good compression
- ✅ Format detection - Accept header parsing
- ✅ Quality control - Works for WebP and JPEG
- ✅ Image resizing - All modes (fit, bounds, cover, force)
- ✅ Image cropping - All modes (aspect ratio, dimensions, anchors)
- ✅ Error handling - Graceful fallback to original
- ✅ Comprehensive logging - Detailed metrics in logs
- ✅ Browser compatibility - Automatic format selection
- ✅ Configuration - Flexible environment variables
📊 Performance Summary
| Operation | Performance | Status |
|---|---|---|
| WebP encoding | <2 seconds | ✅ Excellent |
| Image resize | <100ms | ✅ Excellent |
| Image crop | <100ms | ✅ Excellent |
| Format detection | <1ms | ✅ Excellent |
Overall: WebP + Resize + Crop = Production Ready