17 releases (9 breaking)
new 0.10.2 | Dec 7, 2024 |
---|---|
0.10.1 | Nov 10, 2024 |
0.9.1 | Oct 12, 2024 |
0.8.1 | Jul 30, 2024 |
0.3.0 | Jun 16, 2023 |
#68 in Images
21,271 downloads per month
Used in 14 crates
(7 directly)
1MB
22K
SLoC
jxl-oxide
jxl-oxide is a JPEG XL decoder written in pure Rust. It's internally organized into a few small crates. This crate acts as a blanket and provides a simple interface made from those crates to decode the actual image.
See the crate-level docs for usage.
lib.rs
:
jxl-oxide is a JPEG XL decoder written in pure Rust. It's internally organized into a few small crates. This crate acts as a blanket and provides a simple interface made from those crates to decode the actual image.
Decoding an image
Decoding a JPEG XL image starts with constructing JxlImage
. First create a builder using
JxlImage::builder
, and use open
to read a file:
let image = JxlImage::builder().open("input.jxl").expect("Failed to read image header");
println!("{:?}", image.image_header()); // Prints the image header
Or, if you're reading from a reader that implements Read
, you can use
read
:
let image = JxlImage::builder().read(reader).expect("Failed to read image header");
println!("{:?}", image.image_header()); // Prints the image header
In async context, you'll probably want to feed byte buffers directly. In this case, create an
image struct with uninitialized state using build_uninit
,
and call feed_bytes
and
try_init
:
#
let mut uninit_image = JxlImage::builder().build_uninit();
let image = loop {
uninit_image.feed_bytes(reader.read().await?);
match uninit_image.try_init()? {
InitializeResult::NeedMoreData(uninit) => {
uninit_image = uninit;
}
InitializeResult::Initialized(image) => {
break image;
}
}
};
println!("{:?}", image.image_header()); // Prints the image header
JxlImage
parses the image header and embedded ICC profile (if there's any). Use
JxlImage::render_frame
to render the image.
use jxl_oxide::{JxlImage, RenderResult};
for keyframe_idx in 0..image.num_loaded_keyframes() {
let render = image.render_frame(keyframe_idx)?;
present_image(render);
}
Color management
jxl-oxide has basic color management support, which enables color transformation between well-known color encodings and parsing simple, matrix-based ICC profiles. However, jxl-oxide alone does not support conversion to and from arbitrary ICC profiles, notably CMYK profiles. This includes converting from embedded ICC profiles.
Use JxlImage::request_color_encoding
or JxlImage::request_icc
to set color encoding of
rendered images. Conversion to and/or from ICC profiles may occur if you do this; in that case,
external CMS need to be set using JxlImage::set_cms
.
let mut image = JxlImage::builder().read(reader).expect("Failed to read image header");
image.set_cms(MyCustomCms);
let color_encoding = EnumColourEncoding::display_p3(RenderingIntent::Perceptual);
image.request_color_encoding(color_encoding);
External CMS is set to Little CMS 2 by default if lcms2
feature is enabled. You can
explicitly disable this by setting CMS to NullCms
.
let mut image = JxlImage::builder().read(reader).expect("Failed to read image header");
image.set_cms(NullCms);
Not using set_cms
for color management
If implementing ColorManagementSystem
is difficult for your use case, color management can be
done separately using ICC profile of rendered images. JxlImage::rendered_icc
returns ICC
profile for further processing.
use jxl_oxide::{JxlImage, RenderResult};
let icc_profile = image.rendered_icc();
for keyframe_idx in 0..image.num_loaded_keyframes() {
let render = image.render_frame(keyframe_idx)?;
present_image_with_cms(render, &icc_profile);
}
Feature flags
rayon
: Enable multithreading with Rayon. (default)image
: Enable integration withimage
crate.lcms2
: Enable integration with Little CMS 2.
Dependencies
~0.6–1.8MB
~35K SLoC