Integrating JPEG XL in Chromium with jxl-rs

โšก Chromium ๐Ÿ”ง Rust / C++ ๐Ÿ‘ค Helmut Januschka

Why Chromium selected a Rust decoder, how it was integrated, and how it reached default enablement.

Status: โœ… Enabled by Default in Chrome 155

Whoop whoop: enabled by default!

Starting with Chrome Canary >=155.0.8040.0, JPEG XL decoding and image/jxl advertising are enabled without changing a flag. The default-enable CL has landed. Read the one-year follow-up for the hardening, fuzzing, and parallel-decoding work that prepared the rollout.

The Story

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?

Why JPEG XL?

Implementation

Phase 1: C++ (Abandoned)

Initial approach used libjxl in C++. Feature complete with animation support, but feedback requested Rust for memory safety.

ABANDONED CL 7170439 โ€” C++ implementation (superseded by Rust)

Phase 2: Rust (Current)

Pivoted to jxl-rs, a pure Rust decoder. Memory-safe and aligned with Chromium's direction.

MERGED CL 7201443 - Add jxl-rs to third_party

Blink integration:

  1. MERGED CL 7320482 โ€” Add JXL infrastructure: enums and build flag
  2. MERGED CL 7319379 โ€” Add JXL image decoder using jxl-rs
  3. MERGED CL 7184969 - Wire up the JXL decoder

The Rust decoder also needed performance work for browser workloads. Representative measurements from that period:

Image Before After C++ libjxl Change
bike (2048ร—2560) 265ms 198ms 170ms +34%
progressive (4064ร—2704) 694ms 560ms 450ms +24%
blendmodes (1024ร—1024) 115ms 85ms 266ms +35%
Selected upstream jxl-rs changes

SIMD Optimizations:

  • MERGED #585 SIMD table lookup with shuffle
  • MERGED #537 SIMD F32 to U8/U16 conversions
  • MERGED #536 SIMD transfer functions
  • MERGED #535 SIMD upsampling (2x, 4x, 8x)
  • MERGED #533 SIMD min and store_interleaved
  • MERGED #532 SIMD noise convolution
  • MERGED #530 SIMD chroma upsampling
  • MERGED #529 SIMD YCbCr to RGB

Performance:

  • MERGED #600 SinglePropertyLookup for table-based routing
  • MERGED #583 Optimize EPF sigma for modular encoding
  • MERGED #581 Cache default quantization tables
  • MERGED #538 Flattened modular trees
  • MERGED #526 Weighted predictor cache locality
  • MERGED #525 Cache natural coefficient orders
  • MERGED #524 Precompute cosines in spline rendering

API & Integration:

  • MERGED #594 Bump version to 0.2.2
  • MERGED #587 Bump version to 0.2.1
  • MERGED #586 Fix rendering bugs
  • MERGED #574 Add premultiply_output option
  • MERGED #556 FFI-friendly API for Chromium
  • MERGED #540 Benchmark CI stage
  • MERGED #496 Remaining decoder API methods
  • MERGED #495 Preview frame API
  • MERGED #494 Fix spline DISTANCE_EXP
  • MERGED #493 Fix rect bounds check
  • MERGED #492 Remove zerocopy dependency
  • MERGED #491 HDR tone mapping
  • MERGED #533 Add min and store_interleaved

Current Status

โœ… Standard image decoding
โœ… ICC color profiles
โœ… Animations (multi-frame)
โœ… Alpha/transparency
โœ… Wide gamut (Display-P3)
โœ… HDR support (PQ/HLG)

Chromium rolls:


Testing Without Native Support

The jxl-rs-polyfill provides a WASM fallback for testing JPEG XL on browsers without native decoding.

Basic usage:

<script src="https://cdn.jsdelivr.net/npm/jxl-rs-polyfill/dist/auto.js"></script>

The script detects native support before installing its fallback. It covers common <img>, CSS background, <picture>, and SVG cases; the WASM payload is approximately 540 KB gzipped.

More usage examples โ†’

NPM:

npm install jxl-rs-polyfill
import { JXLPolyfill } from 'jxl-rs-polyfill';
const polyfill = new JXLPolyfill();
await polyfill.start();

Programmatic decoding:

import { decodeJxlToPng } from 'jxl-rs-polyfill';
const pngBytes = await decodeJxlToPng(jxlBytes);

โ†’ GitHub: jxl-rs-polyfill


Live Demo

JXL animation support โ€” no browser supports JXL animations natively yet, so this uses the WASM polyfill:

Animated JXL Demo


Acknowledgments

Special thanks to Luca Versari (veluca93) for reviewing PRs and managing jxl-rs releases. The collaboration from jxl-rs maintainers made this possible.


Resources: