jxl

jxl is a JPEG XL decoder and lossless Modular encoder written in Ruby without native extensions.

Installation

bundle add jxl

Ruby 3.2 or newer is required. YJIT is recommended for large images.

Decode

require "jxl"

image = JXL.decode(File.binread("input.jxl"), max_pixels: 100_000_000)
File.binwrite("output.png", JXL::IO::PNG.dump(image))

JXL.decode accepts pixel_format, color_space, desired_scale, max_pixels, max_memory, strict, apply_orientation, and render_spot_colors. Packed pixel data is available through Image#to_rgba8, #to_rgba16, and #to_float; pixel_format validates the requested format for API compatibility. Output writers support PNG, PPM/PGM, PAM, PFM, grayscale PGX, and multi-frame NPY.

For incremental input, use JXL::Decoder#feed, drain #next_event, and call #finish at end of input.

decoder = JXL::Decoder.new.subscribe(:basic_info, :frame, :full_image)
File.open("input.jxl", "rb") { |file| decoder.feed(chunk) while (chunk = file.read(65_536)) }
decoder.finish
loop do
  event = decoder.next_event
  break if event.nil? || event.type == :full_image
end

The command-line decoder is also available:

djxl input.jxl output.png

Encode

The encoder writes lossless RGB Modular codestreams using RCT6, a Gradient predictor, and prefix entropy coding.

bytes = JXL.encode(image, bits_per_sample: 8)
File.binwrite("output.jxl", bytes)

The CLI accepts binary PPM/PGM and non-interlaced 8-bit PNG input:

cjxl input.png output.jxl

Development

bundle exec rake
bundle exec rake fuzz:truncate
bundle exec rake bench

Set JXL_CONFORMANCE_CASES to the conformance suite's main_level5.txt to enable full reference comparisons. After running the official conformance runner with --results, print its measured results with:

JXL_CONFORMANCE_RESULTS=results.json bundle exec rake conformance:report

Support

Version 1.0 decodes Level 5 raw codestreams and jxlc/jxlp containers, including Modular and VarDCT, progressive frames, animation and blending, all transform strategies, restoration filters, image features, extra channels, orientation, standardized transfer functions, and embedded ICC profiles. The lossless encoder writes RGB Modular codestreams that round-trip through this gem and libjxl.

The current upstream Level 5 conformance manifest has 23 cases; all 23 pass the official runner in lax pixel mode. JPEG bitstream reconstruction from jbrd and Brotli-compressed brob metadata are optional next-version features. Preview rendering is not exposed, the event decoder buffers the complete compressed image before emitting frame pixels, and strict: false only replaces non-finite decoded samples; structural corruption still raises JXL::Error.

License

MIT