use std::ops::Deref;
mod bindings;
#[cfg(test)]
mod test;
#[allow(non_snake_case)]
pub fn WebPEncodeLosslessRGB(rgb: &[u8], width: usize, height: usize) -> Result<Bytes, Error> {
unsafe {
if !(1..=16383).contains(&width) || !(1..=16383).contains(&height) {
return Err(Error::LimitExceeded);
}
if rgb.len() < width * height * 3 {
return Err(Error::TooFewPixels);
}
let mut ptr = std::ptr::null_mut();
let len = bindings::WebPEncodeLosslessRGB(
rgb.as_ptr(),
width as _,
height as _,
(width * 3) as _,
&mut ptr,
);
if len == 0 {
return Err(Error::Unknown);
}
if ptr.is_null() {
return Err(Error::NullPointer);
}
Ok(Bytes { ptr, len })
}
}
#[allow(non_snake_case)]
pub fn WebPEncodeLosslessRGBA(rgba: &[u8], width: usize, height: usize) -> Result<Bytes, Error> {
unsafe {
if !(1..=16383).contains(&width) || !(1..=16383).contains(&height) {
return Err(Error::LimitExceeded);
}
if rgba.len() < width * height * 4 {
return Err(Error::TooFewPixels);
}
let mut ptr = std::ptr::null_mut();
let len = bindings::WebPEncodeLosslessRGBA(
rgba.as_ptr(),
width as _,
height as _,
(width * 4) as _,
&mut ptr,
);
if len == 0 {
return Err(Error::Unknown);
}
if ptr.is_null() {
return Err(Error::NullPointer);
}
Ok(Bytes { ptr, len })
}
}
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("unknown")]
Unknown,
#[error("null pointer")]
NullPointer,
#[error("limit exceeded")]
LimitExceeded,
#[error("too few pixels")]
TooFewPixels,
}
pub struct Bytes {
ptr: *mut u8,
len: usize,
}
unsafe impl Send for Bytes {}
impl Deref for Bytes {
type Target = [u8];
fn deref(&self) -> &Self::Target {
unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
}
}
impl Drop for Bytes {
fn drop(&mut self) {
unsafe {
bindings::WebPFree(self.ptr as _);
}
}
}