1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#![allow(clippy::many_single_char_names)]

pub use self::data::AvifData;
pub use self::encoder::Encoder;
pub use self::error::Error;
pub use self::format::YuvFormat;
pub use self::image::AvifImage;
pub use self::rgb::RgbPixels;
use libavif_sys as sys;

mod data;
mod encoder;
mod error;
mod format;
mod image;
mod rgb;

/// Very efficiently detects AVIF files
///
/// returns true if the file header matches the AVIF type
/// Does not necessarily confirm that the file can actually
/// be decoded.
///
/// Generally requires no more than 64 bytes to make
/// this determination.
pub fn is_avif(avif_bytes: &[u8]) -> bool {
    let raw = sys::avifROData {
        data: avif_bytes.as_ptr(),
        size: avif_bytes.len(),
    };
    unsafe { sys::avifPeekCompatibleFileType(&raw) == 1 }
}

pub fn decode(avif_bytes: &[u8]) -> Result<AvifImage, Error> {
    let raw = sys::avifROData {
        data: avif_bytes.as_ptr(),
        size: avif_bytes.len(),
    };

    let mut image = AvifImage::empty();
    unsafe {
        let decoder = sys::avifDecoderCreate();
        let result = sys::avifDecoderRead(decoder, image.inner_mut(), &raw);
        sys::avifDecoderDestroy(decoder);
        Error::code(result)?;

        Ok(image)
    }
}

/// Decode into RGB pixels
pub fn decode_rgb(avif_bytes: &[u8]) -> Result<RgbPixels, Error> {
    decode(avif_bytes).map(Into::into)
}

/// Encode an 8 bit per channel RGB or RGBA image
pub fn encode_rgb8(width: u32, height: u32, rgb: &[u8]) -> Result<AvifData<'static>, Error> {
    let rgb = RgbPixels::new(width, height, rgb)?;
    let image = rgb.to_image(YuvFormat::Yuv444);

    let mut encoder = Encoder::new();
    encoder.set_max_threads(1);
    encoder.set_quantizer(20);
    encoder.encode(&image)
}