use failure::Fail;
use heif_sys::*;
use std::ffi;
use std::mem;
use std::ptr;
mod test;
#[derive(Debug, Fail)]
#[repr(C)]
pub enum HeifError {
#[fail(display = "Input does not exist")]
InputDoesNotExist = 1,
#[fail(display = "Invalid Input")]
InvalidInput = 2,
#[fail(display = "Unsupported File Type")]
UnsupportedFiletype = 3,
#[fail(display = "Unsupported Feature")]
UnsupportedFeature = 4,
#[fail(display = "Usage Error")]
UsageHeifError = 5,
#[fail(display = "Memory Allocation Error")]
MemoryAllocationHeifError = 6,
#[fail(display = "Decoder Plugin Error")]
DecoderPluginHeifError = 7,
#[fail(display = "Encoder Plugin Error")]
EncoderPluginHeifError = 8,
#[fail(display = "Encoding Error")]
EncodingHeifError = 9,
#[fail(display = "Failed to create context")]
ContexCreateFailed,
#[fail(display = "Unknown Error")]
Unknown,
}
pub fn err_message(err: heif_error) -> String {
unsafe { ffi::CStr::from_ptr(err.message) }
.to_str()
.unwrap()
.to_owned()
}
pub fn err_result(err: heif_error) -> Result<(), HeifError> {
if err.code == 0 {
Ok(())
} else if err.code > 0 && err.code < 10 {
Err(unsafe { mem::transmute(err.code) })
} else {
Err(HeifError::Unknown)
}
}
#[derive(Debug)]
#[repr(C)]
pub enum ColorSpace {
Undefined = 99,
YCbCr = 0,
Rgb = 1,
Monochrome = 2,
}
#[derive(Debug)]
#[repr(C)]
pub enum Chroma {
Undefined = 99,
Monochrome = 0,
C420 = 1,
C422 = 2,
C444 = 3,
InterleavedRgb = 10,
InterleavedRgba = 11,
}
#[derive(Debug)]
#[repr(C)]
pub enum Channel {
Y = 0,
Cb = 1,
Cr = 2,
R = 3,
G = 4,
B = 5,
Alpha = 6,
Interleaved = 10,
}
#[derive(Debug)]
pub struct DecodeOptions {
inner: *mut heif_decoding_options,
}
impl DecodeOptions {
pub fn new() -> DecodeOptions {
DecodeOptions {
inner: unsafe { heif_decoding_options_alloc() },
}
}
}
impl Drop for DecodeOptions {
fn drop(&mut self) {
unsafe { heif_decoding_options_free(self.inner) };
}
}
pub struct ImageHandle {
inner: *mut heif_image_handle,
}
impl ImageHandle {
pub fn width(&self) -> u32 {
unsafe { heif_image_handle_get_width(self.inner) as _ }
}
pub fn height(&self) -> u32 {
unsafe { heif_image_handle_get_width(self.inner) as _ }
}
pub fn has_alpha_channel(&self) -> bool {
unsafe {
if heif_image_handle_has_alpha_channel(self.inner) == 0 {
false
} else {
true
}
}
}
pub fn decode(&self, options: &DecodeOptions) -> Result<Image, HeifError> {
unsafe {
let mut image = Box::new(mem::uninitialized());
let err = heif_decode_image(
self.inner,
&mut *image,
heif_colorspace_heif_colorspace_undefined, heif_chroma_heif_chroma_undefined, options.inner,
);
err_result(err)?;
Ok(Image { inner: *image })
}
}
}
pub struct Context {
inner: *mut heif_context,
}
impl Context {
pub fn new() -> Result<Context, HeifError> {
let ctx = unsafe { heif_context_alloc() };
if ctx == ptr::null_mut() {
Err(HeifError::ContexCreateFailed)
} else {
Ok(Context { inner: ctx })
}
}
pub fn read_from_bytes(&self, bytes: &[u8]) -> Result<(), HeifError> {
let err = unsafe {
heif_context_read_from_memory_without_copy(
self.inner,
bytes.as_ptr() as _,
bytes.len(),
ptr::null(),
)
};
err_result(err)
}
pub fn read_from_file(&mut self, name: &str) -> Result<(), HeifError> {
let c_name = ffi::CString::new(name).unwrap();
let err = unsafe { heif_context_read_from_file(self.inner, c_name.as_ptr(), ptr::null()) };
err_result(err)
}
pub fn write_to_file(&self, name: &str) {
unsafe {
let c_name = ffi::CString::new(name).unwrap();
heif_context_write_to_file(self.inner, c_name.as_ptr());
}
}
pub fn get_number_of_top_level_images(&mut self) -> usize {
unsafe { heif_context_get_number_of_top_level_images(self.inner) as _ }
}
pub fn get_primary_image_handle(&self) -> Result<ImageHandle, HeifError> {
unsafe {
let mut handle = Box::new(mem::uninitialized());
let err = heif_context_get_primary_image_handle(self.inner, &mut *handle);
err_result(err)?;
Ok(ImageHandle { inner: *handle })
}
}
pub fn get_encoder_for_format(&mut self) -> Result<Encoder, HeifError> {
let mut encoder = Box::new(unsafe { mem::uninitialized() });
let err = unsafe {
heif_context_get_encoder_for_format(
self.inner,
heif_compression_format_heif_compression_HEVC,
&mut *encoder,
)
};
err_result(err)?;
Ok(Encoder { inner: *encoder })
}
}
impl Drop for Context {
fn drop(&mut self) {
unsafe { heif_context_free(self.inner) };
}
}
pub struct Encoder {
inner: *mut heif_encoder,
}
impl Encoder {
pub fn set_lossy_quality(&mut self, value: usize) -> Result<(), HeifError> {
let err = unsafe { heif_encoder_set_lossy_quality(self.inner, value as _) };
err_result(err)
}
}
pub struct Image {
inner: *mut heif_image,
}
impl Image {
pub fn new(width: u32, height: u32, colorspace: u32, chroma: u32) -> Result<Image, HeifError> {
let mut image = Image {
inner: unsafe { mem::uninitialized() },
};
let err = unsafe {
heif_image_create(
width as _,
height as _,
colorspace,
chroma,
&mut image.inner,
)
};
err_result(err)?;
Ok(image)
}
pub fn get_plane(&self, channel: Channel) -> (&mut [u8], u32) {
unsafe {
let mut stride: i32 = 1;
let data = heif_image_get_plane(self.inner, channel as _, &mut stride as _);
let height = self.height() as usize;
let size = height * (stride as usize);
use std::slice;
let bytes = slice::from_raw_parts_mut(data, size);
(bytes, stride as _)
}
}
pub fn width(&self) -> u32 {
unsafe { heif_image_get_width(self.inner, heif_channel_heif_channel_Y) as _ }
}
pub fn height(&self) -> u32 {
unsafe { heif_image_get_height(self.inner, heif_channel_heif_channel_Y) as _ }
}
pub fn get_chroma_format(&self) -> Chroma {
unsafe { mem::transmute(heif_image_get_chroma_format(self.inner)) }
}
pub fn get_color_space(&self) -> ColorSpace {
unsafe { mem::transmute(heif_image_get_colorspace(self.inner)) }
}
}