Safe wrapper around the libheif-sys crate for parsing heif/heic files.
libheif-dev>= 1.17.0
Minimal supported version of libheif library is 1.17.
But there are some functions in the crate that require a newer version of
libheif library.
You may specify a minimal version of libheif library that is required for you.
To do this, enable the corresponding feature v1_17, v1_18, v1_19 or v1_20.
Example:
[dependencies]
libheif-rs = { version = "2.1", default-features = false, features = ["v1_17"] }There is also the latest feature. It always corresponds to
the maximal supported by the crate version of libheif API.
This feature is enabled by default.
Crate libheif-sys uses pkg-confing command to find installed libheif.
You can also enable embedded-libheif feature to compile libheif from
embedded into libheif-sys crate sources and then link it statically.
Note: Static linked version of libheif doesn't have statically linked
it dependencies, such as libde256, libaom and other.
Crate libheif-sys uses vcpkg crate
to find libheif installed with help of vcpkg.
You can use cargo-vcpkg
to install libheif with help of cargo command:
cargo vcpkg -v buildcargo-vcpkg can fetch and build a vcpkg installation of required
packages from scratch. It merges package requirements specified in
the Cargo.toml of crates in the dependency tree.
You can enable image feature to use functions from integration module
to register decoder hooks for the image crate.
use image::{ColorType, ImageReader};
use libheif_rs::integration::image::register_all_decoding_hooks;
fn main() {
register_all_decoding_hooks();
let reader = ImageReader::open("data/test.heif").unwrap();
let image = reader.decode().unwrap();
assert_eq!(image.width(), 1652);
assert_eq!(image.height(), 1791);
assert!(matches!(image.color(), ColorType::Rgb8));
}use libheif_rs::{
Channel, RgbChroma, ColorSpace, HeifContext, Result,
ItemId, LibHeif
};
fn main() -> Result<()> {
let lib_heif = LibHeif::new();
let ctx = HeifContext::read_from_file("./data/test.heif")?;
let handle = ctx.primary_image_handle()?;
assert_eq!(handle.width(), 1652);
assert_eq!(handle.height(), 1791);
// Get Exif
let mut meta_ids: Vec<ItemId> = vec![0; 1];
let count = handle.metadata_block_ids(&mut meta_ids, b"Exif");
assert_eq!(count, 1);
let exif: Vec<u8> = handle.metadata(meta_ids[0])?;
// Decode the image
let image = lib_heif.decode(
&handle,
ColorSpace::Rgb(RgbChroma::Rgb),
None,
)?;
assert_eq!(
image.color_space(),
Some(ColorSpace::Rgb(RgbChroma::Rgb)),
);
assert_eq!(image.width(), 1652);
assert_eq!(image.height(), 1791);
// Scale the image
let small_img = image.scale(1024, 800, None)?;
assert_eq!(small_img.width(), 1024);
assert_eq!(small_img.height(), 800);
// Get "pixels"
let planes = small_img.planes();
let interleaved_plane = planes.interleaved.unwrap();
assert_eq!(interleaved_plane.width, 1024);
assert_eq!(interleaved_plane.height, 800);
assert!(!interleaved_plane.data.is_empty());
assert!(interleaved_plane.stride > 0);
Ok(())
}use tempfile::NamedTempFile;
use libheif_rs::{
Channel, RgbChroma, ColorSpace, CompressionFormat,
EncoderQuality, HeifContext, Image, Result, LibHeif
};
fn main() -> Result<()> {
let width = 640;
let height = 480;
let mut image = Image::new(
width,
height,
ColorSpace::Rgb(RgbChroma::C444)
)?;
image.create_plane(Channel::R, width, height, 8)?;
image.create_plane(Channel::G, width, height, 8)?;
image.create_plane(Channel::B, width, height, 8)?;
let planes = image.planes_mut();
let plane_r = planes.r.unwrap();
let stride = plane_r.stride;
let data_r = plane_r.data;
let data_g = planes.g.unwrap().data;
let data_b = planes.b.unwrap().data;
// Fill data of planes by some "pixels"
for y in 0..height {
let mut pixel_index = stride * y as usize;
for x in 0..width {
let color = ((x * y) as u32).to_le_bytes();
data_r[pixel_index] = color[0];
data_g[pixel_index] = color[1];
data_b[pixel_index] = color[2];
pixel_index += 1;
}
}
// Encode image and save it into file.
let lib_heif = LibHeif::new();
let mut context = HeifContext::new()?;
let mut encoder = lib_heif.encoder_for_format(
CompressionFormat::Av1,
)?;
encoder.set_quality(EncoderQuality::LossLess)?;
context.encode_image(&image, &mut encoder, None)?;
let tmp_file = NamedTempFile::new().unwrap();
context.write_to_file(tmp_file.path().to_str().unwrap())?;
Ok(())
}