use std::ffi::{c_int, c_void};
use anyhow::{ensure, Result};
#[link(name = "webp", kind = "dylib")]
extern "C" {
fn WebPEncodeLosslessRGBA(
rgba: *const u8,
width: c_int,
height: c_int,
stride: c_int,
output: *mut *mut u8,
) -> usize;
fn WebPFree(ptr: *mut c_void);
}
pub fn webp_encode_lossless_rgba(rgba: &[u8], width: usize, height: usize) -> Result<EncodedImage> {
unsafe {
ensure!(width < 16384 && height < 16384);
ensure!(width > 0 && height > 0);
ensure!(rgba.len() == width * height * 4);
let mut ptr = std::ptr::null_mut();
let len = WebPEncodeLosslessRGBA(
rgba.as_ptr(),
width as c_int,
height as c_int,
(width * 4) as c_int,
&mut ptr,
);
ensure!(len != 0);
ensure!(!ptr.is_null());
Ok(EncodedImage { ptr, len })
}
}
pub struct EncodedImage {
ptr: *mut u8,
len: usize,
}
impl EncodedImage {
pub fn webp_file(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
}
}
impl Drop for EncodedImage {
fn drop(&mut self) {
unsafe {
WebPFree(self.ptr as *mut c_void);
}
}
}
unsafe impl Send for EncodedImage {}
unsafe impl Sync for EncodedImage {}