jpeg2k
| Language | Rust |
|---|---|
| License | MIT OR Apache-2.0 (OpenJPEG is BSD-2-Clause) |
| Repository | github.com/Neopallium/jpeg2k |
| Documentation | docs.rs/jpeg2k |
| Depends on | openjpeg-sys (builds OpenJPEG from source with a C compiler); optional image crate |
| Read / write | yes / 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#
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#
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#
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#
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:
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#
Image::from_bytes(&buf)decodes from memory; the format (JP2 or J2K) is detected from the first bytes.- With default features, building needs a C compiler because
openjpeg-syscompiles OpenJPEG; on Windows use the MSVC toolchain.