How JPEG XL went from "obsolete" to the future of web images - and the honor of being part of its comeback
Live Demo: JXL Animation
Here's a live example of JXL animation support - the implementation shown in the video above. No browser currently supports JXL animations natively, so this uses a WASM polyfill:
Background
In October 2022, Google removed JPEG XL from Chromium, citing "insufficient ecosystem interest." In November 2025, Chrome's Architecture Tech Leads announced: "We would welcome contributions to integrate a performant and memory-safe JPEG XL decoder in Chromium."
What Changed
Rick Byers' announcement on behalf of Chrome ATLs outlined the ecosystem developments:
- Safari shipped JPEG XL support - Apple implemented the format
- Firefox updated their position - Mozilla signaled support pending a Rust decoder
- PDF standardization - JPEG XL designated as the preferred format for HDR content in PDF
- Developer interest - Bug upvotes, Interop proposals, and survey data indicated demand
The ecosystem evolved between 2022 and 2025.
JPEG XL Features
JPEG XL offers several technical improvements over existing formats:
- 30-50% better compression than JPEG at equivalent quality
- Lossless JPEG transcoding with ~20% size reduction
- Progressive decoding - images load incrementally
- Modern capabilities - HDR, wide gamut, alpha channels, and animations
- Browser support - Safari has implemented it, Firefox is working on it, and it's part of the PDF specification
Implementation Approach
Following Rick's announcement, the implementation work began.
Phase 1: C++ Implementation
The initial approach used the reference implementation - libjxl in C++. Using the previous Chromium JPEG XL code as a blueprint, the implementation was updated to the latest spec:
CL 7170439 - Full implementation with animation support
// Integrated libjxl decoder with Blink's image pipeline
class JXLImageDecoder : public ImageDecoder {
// Handle standard decoding
void Decode(const uint8_t* data, size_t length);
// Animation support
size_t FrameCount() const override;
cc::ImageHeaderMetadata MakeMetadataForDecodeAcceleration() const override;
};
Status: Feature complete, demo video here.
The feedback requested using Rust for memory safety.
Phase 2: Rust Implementation
Chromium is moving toward memory-safe code. The pivot to jxl-rs, a pure Rust JPEG XL decoder, aligned with this direction.
CL 7184969 - Rust-based implementation using jxl-rs
// Memory-safe decoder via CXX bindings
pub fn decode_jxl(data: &[u8]) -> Result<DecodedImage> {
let decoder = JxlDecoder::builder()
.build()?;
decoder.decode_to_image(data)
}
The Rust decoder required performance optimization. The jxl-rs community has been working on improvements:
- PR #491 MERGED - HDR color profile handling (PQ/HLG transfer functions)
- PR #492 MERGED - Remove unnecessary
allow_unsaferequirement - PR #493 MERGED - Rectangle bounds checking improvements
- PR #494 MERGED - Precision level matching libjxl C++ version
- PR #506 IN PROGRESS - Major performance improvements bringing jxl-rs nearly on par with C++ libjxl
- PR #509 IN PROGRESS - WASM polyfill implementation for browsers without native JXL support
PR #506 improves decode performance through parallel VarDCT decoding and AVX2+FMA SIMD optimizations:
| Image | Size | Before PR #506 | After PR #506 | C++ libjxl | Speedup |
|---|---|---|---|---|---|
| bike | 2048×2560 | 265ms | 198ms | 170ms | +34% |
| progressive | 4064×2704 | 694ms | 560ms | 450ms | +24% |
| blendmodes | 1024×1024 | 115ms | 85ms | 266ms | +35% |
The gap narrowed from 56% slower to 4% slower than C++. PR #509 provides a WebAssembly-based polyfill for browsers without native support.
Current Status
The implementation includes:
✅ Standard image decoding - JPEG XL images render correctly
✅ ICC color profiles - Proper color management
✅ Animations - Multi-frame JXL support
✅ Alpha/transparency - Full alpha channel support
✅ Wide gamut - Display-P3 and other color spaces
✅ HDR support - PQ/HLG transfer functions (PR #491 MERGED)
Requirements for Shipping
Chrome's requirements:
- Performant decoder - Performance optimizations are ongoing
- Memory-safe implementation - Rust provides memory safety
- Long-term maintenance - The jxl-rs community is active
Format Diversity
Different image formats serve different needs:
- WebP - General-purpose replacement for JPEG/PNG
- AVIF - Photo compression with AV1-based encoding
- JPEG XL - Lossless JPEG transcoding, progressive decode, animations, HDR
Having multiple format options allows developers to choose based on their specific requirements.
Acknowledgments
Special thanks to Luca Versari (veluca93) for reviewing and merging upstream PRs and managing jxl-rs releases. The collaboration and responsiveness from the jxl-rs maintainers has been instrumental in making this implementation possible.
Implementation Details
Status: 🚧 In active development
- C++ Implementation: CL 7170439 - Abandoned in favor of Rust
- Rust Implementation: CL 7184969 - Active development
- Tracking Bug: 462919304
- Design Document: JPEG XL in Chromium
Upstream Work:
Demo:
Links: