Skip to main content

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 >93 can cause VP8_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_headers phase
  • Image processing happens in on_http_response_body phase
  • 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

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):

  1. HTTP trailers support → Add metrics headers, size comparison

Medium Term (Waiting on Community):

  1. Pure Rust lossy WebP → Quality control for WebP

Long Term (Potential):

  1. Parallel processing → Process multiple operations faster
  2. 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

OperationPerformanceStatus
WebP encoding<2 seconds✅ Excellent
Image resize<100ms✅ Excellent
Image crop<100ms✅ Excellent
Format detection<1ms✅ Excellent

Overall: WebP + Resize + Crop = Production Ready