hayro-jpeg2000
| Language | Rust (no_std with an allocator) |
|---|---|
| License | MIT OR Apache-2.0 |
| Repository | github.com/LaurenzV/hayro |
| Documentation | docs.rs/hayro-jpeg2000 |
| Depends on | pure Rust; optional image and moxcms for the image crate integration |
| Read / write | yes / no; JP2 and raw codestreams (.j2c, .j2k), most of Part 1 and some Part 2 color spaces |
hayro-jpeg2000 is the JPEG 2000 decoder of hayro, a Rust PDF renderer, published as its own crate. It was tested on more than 20,000 JPEG 2000 images taken from real PDF files and passes most of the OpenJPEG conformance suite. Unsafe code is forbidden in the crate; with the default simd feature it uses the fearless_simd crate, and turning that off removes all unsafe from the dependency tree.
The output is always 8 bits per sample (higher bit depths are scaled down), in gray, RGB, CMYK or an ICC-based color space, with an optional alpha channel. It’s slower than OpenJPEG and doesn’t encode. Use it when you want a Rust-only build, WebAssembly, or a memory-safe decoder for untrusted PDF images.
Installation#
cargo add hayro-jpeg2000
Default features: std, simd and image (integration with the image crate).
Basic usage: decode to 8-bit pixels#
use hayro_jpeg2000::{DecodeSettings, DecoderContext, Image};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = std::fs::read("in.jp2")?;
let image = Image::new(&data, &DecodeSettings::default())?;
println!(
"{} x {}, {:?}, alpha: {}, original bit depth: {}",
image.width(),
image.height(),
image.color_space(),
image.has_alpha(),
image.original_bit_depth()
);
let mut ctx = DecoderContext::default();
let decoded = image.decode(&mut ctx)?;
let pixels: Vec<u8> = decoded.data_u8(); // interleaved, alpha last
println!("{} bytes", pixels.len());
Ok(())
}
How to convert JPEG 2000 to PNG with the image crate#
With the image feature, register a decoding hook once. After that, image::ImageReader opens JPEG 2000 files like any other format, and CMYK and ICC images are converted to RGB:
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
hayro_jpeg2000::integration::register_decoding_hook();
let img = image::ImageReader::open("in.jp2")?.decode()?;
img.save("out.png")?;
Ok(())
}
Add the png feature of image to your Cargo.toml to save PNG files: cargo add image --no-default-features --features png.
How to read the ICC profile#
use hayro_jpeg2000::{ColorSpace, DecodeSettings, Image};
let data = std::fs::read("in.jp2")?;
let image = Image::new(&data, &DecodeSettings::default())?;
if let ColorSpace::Icc { profile, num_channels } = image.color_space() {
println!("ICC profile: {} bytes, {} channels", profile.len(), num_channels);
}
How to decode a smaller image#
DecodeSettings::target_resolution is a hint: the decoder skips resolution levels it doesn’t need to reach that size.
let settings = DecodeSettings {
target_resolution: Some((512, 512)),
..DecodeSettings::default()
};
let image = Image::new(&data, &settings)?;
Tips#
- Keep
strict: false(the default) for real-world files: many PDFs contain slightly broken codestreams that the lenient mode still decodes. resolve_palette_indices: falsereturns palette indices as a gray image instead of colors.