#heic #heif #libheif

libheif-rs

Safe wrapper around the libheif-sys crate for parsing heif/heic files

20 releases (breaking)

0.15.1 Oct 21, 2022
0.15.0 May 12, 2021
0.14.0 Mar 17, 2021
0.11.0 Sep 26, 2020
0.6.0 Jul 17, 2019

#38 in Images

Download history 90/week @ 2022-10-14 196/week @ 2022-10-21 183/week @ 2022-10-28 156/week @ 2022-11-04 205/week @ 2022-11-11 218/week @ 2022-11-18 241/week @ 2022-11-25 190/week @ 2022-12-02 207/week @ 2022-12-09 184/week @ 2022-12-16 178/week @ 2022-12-23 192/week @ 2022-12-30 135/week @ 2023-01-06 119/week @ 2023-01-13 197/week @ 2023-01-20 232/week @ 2023-01-27

697 downloads per month
Used in 7 crates (5 directly)

MIT license

1.5MB
1K SLoC

libheif-rs

Safe wrapper around the libheif-sys crate for parsing heif/heic files.

CHANGELOG

System dependencies

  • libheif-dev >= 1.12.0

Examples

Read HEIF file

use libheif_rs::{Channel, RgbChroma, ColorSpace, HeifContext, Result, ItemId};

fn main() -> Result<()> {
    let ctx = HeifContext::read_from_file("./data/test.heic")?;
    let handle = ctx.primary_image_handle()?;
    assert_eq!(handle.width(), 3024);
    assert_eq!(handle.height(), 4032);

    // Get Exif
    let mut meta_ids: Vec<ItemId> = vec![0; 1];
    let count = handle.metadata_block_ids("Exif", &mut meta_ids);
    assert_eq!(count, 1);
    let exif: Vec<u8> = handle.metadata(meta_ids[0])?;

    // Decode the image
    let image = handle.decode(ColorSpace::Rgb(RgbChroma::Rgb), false)?;
    assert_eq!(image.color_space(), Some(ColorSpace::Rgb(RgbChroma::Rgb)));
    assert_eq!(image.width(Channel::Interleaved)?, 3024);
    assert_eq!(image.height(Channel::Interleaved)?, 4032);

    // Scale the image
    let small_img = image.scale(1024, 800, None)?;
    assert_eq!(small_img.width(Channel::Interleaved)?, 1024);
    assert_eq!(small_img.height(Channel::Interleaved)?, 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(())
}

Write HEIF file

use tempfile::NamedTempFile;
use libheif_rs::{
    Channel, RgbChroma, ColorSpace, CompressionFormat, EncoderQuality, HeifContext,
    Image, Result
};

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 row_start = stride * y as usize;
        for x in 0..width {
            let color = (x * y) as u32;
            data_r[row_start] = ((color & 0x00_ff_00_00) >> 16) as u8;
            data_g[row_start] = ((color & 0x00_00_ff_00) >> 8) as u8;
            data_b[row_start] = (color & 0x00_00_00_ff) as u8;
            row_start += 1;
        }
    }

    // Encode image and save it into file.
    let mut context = HeifContext::new()?;
    let mut encoder = context.encoder_for_format(CompressionFormat::Hevc)?;
    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())?;

    Ok(())
}

Dependencies

~3MB
~17K SLoC