All formats

hayro-jpeg2000

LanguageRust (no_std with an allocator)
LicenseMIT OR Apache-2.0
Repositorygithub.com/LaurenzV/hayro
Documentationdocs.rs/hayro-jpeg2000
Depends onpure Rust; optional image and moxcms for the image crate integration
Read / writeyes / 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#

Shell
cargo add hayro-jpeg2000

Default features: std, simd and image (integration with the image crate).

Basic usage: decode to 8-bit pixels#

Rust
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:

Rust
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#

Rust
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.

Rust
let settings = DecodeSettings {
    target_resolution: Some((512, 512)),
    ..DecodeSettings::default()
};
let image = Image::new(&data, &settings)?;

Tips#