v155 · graphics · image formats

JPEG XL decoding support (image/jxl)

Chrome 155 decodes JPEG XL, using jxl-rs — a memory-safe decoder written in Rust rather than the C++ one that was reverted in 2023. The format brings progressive decoding, wide gamut, high bit depth and animation; the safety of the decoder is what made it shippable this time.

concepts

  1. Decode probe

    Four ways to ask whether this browser decodes JPEG XL — an <img>, createImageBitmap, a canvas draw, and the Accept header the browser sends — run against a real .jxl file. They do not always agree, and the disagreement is the interesting part.

  2. Format showdown

    One source image encoded as JPEG XL, AVIF, WebP and JPEG, with real byte counts and decode timings measured in your browser. No claims from a blog post — the files are in this repo and the numbers come from your machine.

  3. Serving it safely

    How to actually ship it: a <picture> with a JXL source and fallbacks, and a readout of which source the browser chose. Includes the mistakes that make the fallback never fire.

why it shipped

Chromium had a JPEG XL decoder behind a flag and removed it in 2023, citing the maintenance burden of another C++ image parser — the class of code where a malformed file becomes a memory-safety bug, and where the attack surface is every image on the web. The format's technical case was never really the problem.

jxl-rs changes that calculation: a pure-Rust decoder, memory-safe by construction, so a malformed file is a decode error rather than a vulnerability. This is a decode-only shipment — Chrome reads JPEG XL, it does not write it.

the API

<!-- Content negotiation, so older browsers never see the .jxl -->
<picture>
  <source srcset="photo.jxl" type="image/jxl">
  <source srcset="photo.avif" type="image/avif">
  <img src="photo.jpg" alt="…" width="960" height="600">
</picture>

// Feature detection, if you need it in script: decode a tiny file and
// see whether it produces pixels. There is no format registry to ask.
const supported = await createImageBitmap(jxlBlob).then(() => true, () => false);

references