All formats

jpeg2k

LanguageRust
LicenseMIT OR Apache-2.0 (OpenJPEG is BSD-2-Clause)
Repositorygithub.com/Neopallium/jpeg2k
Documentationdocs.rs/jpeg2k
Depends onopenjpeg-sys (builds OpenJPEG from source with a C compiler); optional image crate
Read / writeyes / limited (re-save a loaded image); JP2 and J2K

jpeg2k wraps OpenJPEG with a safe API. Image::from_file or Image::from_bytes decode a file, DecodeParameters select a reduction factor, quality layers or a decode area, and the image feature converts the result to image::DynamicImage. Each component is also available as raw i32 samples with its bit depth, for 12-bit and 16-bit data.

The crate can save an Image it loaded back to JPEG 2000 (save_as_file), but it has no constructor from your own pixel buffer, so it isn’t a general encoder. Releases are infrequent; it depends on image 0.25, so use the same version in your project.

Installation#

Shell
cargo add jpeg2k
cargo add image

Default features are image, threads, file-io and openjpeg-sys. To avoid C code, disable default features and enable openjp2, a Rust port of OpenJPEG: cargo add jpeg2k --no-default-features --features openjp2,image,file-io.

Basic usage: convert JPEG 2000 to PNG#

Rust
use image::DynamicImage;
use jpeg2k::Image;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let jp2 = Image::from_file("in.jp2")?;
    println!(
        "{} x {}, {} components, color space {:?}",
        jp2.width(),
        jp2.height(),
        jp2.num_components(),
        jp2.color_space()
    );

    let img = DynamicImage::try_from(&jp2)?;
    img.save("out.png")?;
    Ok(())
}

How to decode at reduced resolution or a region#

Rust
use jpeg2k::{DecodeArea, DecodeParameters, Image};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let params = DecodeParameters::new()
        .reduce(2)                                            // 1/4 width and height
        .layers(1)                                            // first quality layer only
        .decode_area(Some(DecodeArea::new(0, 0, 2048, 2048))); // full-resolution coordinates
    let jp2 = Image::from_file_with("big.jp2", params)?;
    println!("decoded {} x {}", jp2.width(), jp2.height());
    Ok(())
}

How to read raw component samples#

Rust
let jp2 = jpeg2k::Image::from_file("ct.j2k")?;
for comp in jp2.components() {
    println!(
        "{} x {}, {} bits, signed: {}",
        comp.width(),
        comp.height(),
        comp.precision(),
        comp.is_signed()
    );
    let samples: &[i32] = comp.data();   // width * height samples
    println!("first sample: {}", samples[0]);
}

How to get interleaved 8-bit or 16-bit pixels#

get_pixels interleaves the components and reports the pixel layout:

Rust
use jpeg2k::{Image, ImagePixelData};

let jp2 = Image::from_file("in.jp2")?;
let pixels = jp2.get_pixels(Some(255))?;  // alpha value to use when there's no alpha channel
match pixels.data {
    ImagePixelData::Rgb8(bytes) => println!("RGB8, {} bytes", bytes.len()),
    ImagePixelData::L16(words) => println!("16-bit gray, {} samples", words.len()),
    _ => println!("{:?} format", pixels.format),
}

Tips#