Decoding JPEG XL images embedded in PDF documents using the pure Rust decoder jxl-rs
๐งช PROOF OF CONCEPT
JXL-in-PDF decoding for standalone PDFium builds
Background
With JPEG XL landing in Chromium via the Rust decoder jxl-rs, it's natural to ask: what about PDF?
JPEG XL is poised to become the preferred format for HDR images in PDF (per ISO 32000-2:2020 discussions). While the PDF spec doesn't yet have a standardized filter name, this experiment uses /JXLDecode as a bring-up name to prove the concept works.
The Challenge
PDFium is Chromium's PDF renderer, but it's also used standalone (e.g., in other browsers, document viewers, server-side rendering). The challenge:
- Rust integration โ PDFium's standalone build needed Rust toolchain support
- Alpha handling โ JXL images can have alpha, but PDF expects a separate
/SMask - Animation โ JXL supports animation, but PDF image XObjects are static
Implementation
Approach
- Rust-only decoder: Uses
jxl-rsvia Chromium's CXX bridge wrapper - No C++ libjxl: Memory-safe by design, aligns with Chromium's direction
- Synthesized SMask: Decoder extracts alpha and creates an internal soft mask
- Frame 0 only: For animated JXL, only the first frame is rendered
Build Integration
Added a new GN flag for standalone builds:
# In pdfium.gni
declare_args() {
pdf_enable_rust_jxl = false
}
The decoder glue lives in core/fxcodec/jxl/:
core/fxcodec/jxl/
โโโ BUILD.gn
โโโ DEPS
โโโ jxl_decoder.cc
โโโ jxl_decoder.h
โโโ jxl_rs_stub.cc
Decoder Flow
// In cpdf_dib.cpp
bool CPDF_DIB::LoadJxlBitmap(pdfium::span<const uint8_t> data) {
auto info = pdfium::jxl::ParseInfo(data);
if (!info) return false;
auto decoded = pdfium::jxl::DecodeFrame0(data, info->width, info->height);
if (!decoded) return false;
// Extract RGB
// If has_alpha: synthesize SMask via jpx_inline_data_ mechanism
return true;
}
The integration hooks into CreateDecoder() to handle the /JXLDecode filter:
if (decoder == "JXLDecode") {
return LoadJxlBitmap(src_span) ? LoadState::kSuccess : LoadState::kFail;
}
Demo Artifacts
Sample PDFs with embedded JXL images, rendered by the patched PDFium:
Zoltan (RGB Photo)
Large RGB JPEG XL embedded in PDF.
Dice (Alpha)
RGBA JPEG XL with transparency. PDFium synthesizes an /SMask and composites over a checkerboard background (baked into the PDF to visualize alpha).
Animated Icons (Frame 0)
Animated RGBA JPEG XL. PDFium decodes only the first frame.
Code Changes
IN REVIEW CL 142070 โ Add experimental JXLDecode support via Rust jxl-rs
Building
To build PDFium with JXL support:
# In args.gn
enable_rust = true
pdf_enable_rust_jxl = true
# Requires rust_revision pointing to a version with jxl-rs v0.3 wrapper
Related
- JPEG XL Returns to Chrome โ The Chromium/Blink implementation
- jxl-rs โ The pure Rust JPEG XL decoder
- PDFium โ Google's PDF rendering library
This is an experimental feature exploring JXL-in-PDF before standardization. The filter name /JXLDecode is a placeholder and may change.