use libwebp_sys as sys;
use std::mem;
use std::os::raw::*;
use std::panic::{RefUnwindSafe, UnwindSafe};
use std::ptr::{self, NonNull};
use std::slice;
use crate::boxed::{wrap_bytes, WebpBox, WebpYuvBox};
use crate::error::WebPSimpleError;
#[allow(non_snake_case)]
pub fn WebPGetDecoderVersion() -> u32 {
(unsafe { sys::WebPGetDecoderVersion() }) as u32
}
#[allow(non_snake_case)]
pub fn WebPGetInfo(data: &[u8]) -> Result<(u32, u32), WebPSimpleError> {
let mut width: c_int = 0;
let mut height: c_int = 0;
let result = unsafe { sys::WebPGetInfo(data.as_ptr(), data.len(), &mut width, &mut height) };
if result != 0 {
Ok((width as u32, height as u32))
} else {
Err(WebPSimpleError)
}
}
#[allow(non_snake_case)]
pub fn WebPDecodeRGBA(data: &[u8]) -> Result<(u32, u32, WebpBox<[u8]>), WebPSimpleError> {
let mut width: c_int = 0;
let mut height: c_int = 0;
let result = unsafe { sys::WebPDecodeRGBA(data.as_ptr(), data.len(), &mut width, &mut height) };
let buf = (unsafe { wrap_bytes(result, || width as usize * height as usize * 4) })?;
Ok((width as u32, height as u32, buf))
}
#[allow(non_snake_case)]
pub fn WebPDecodeARGB(data: &[u8]) -> Result<(u32, u32, WebpBox<[u8]>), WebPSimpleError> {
let mut width: c_int = 0;
let mut height: c_int = 0;
let result = unsafe { sys::WebPDecodeARGB(data.as_ptr(), data.len(), &mut width, &mut height) };
let buf = (unsafe { wrap_bytes(result, || width as usize * height as usize * 4) })?;
Ok((width as u32, height as u32, buf))
}
#[allow(non_snake_case)]
pub fn WebPDecodeBGRA(data: &[u8]) -> Result<(u32, u32, WebpBox<[u8]>), WebPSimpleError> {
let mut width: c_int = 0;
let mut height: c_int = 0;
let result = unsafe { sys::WebPDecodeBGRA(data.as_ptr(), data.len(), &mut width, &mut height) };
let buf = (unsafe { wrap_bytes(result, || width as usize * height as usize * 4) })?;
Ok((width as u32, height as u32, buf))
}
#[allow(non_snake_case)]
pub fn WebPDecodeRGB(data: &[u8]) -> Result<(u32, u32, WebpBox<[u8]>), WebPSimpleError> {
let mut width: c_int = 0;
let mut height: c_int = 0;
let result = unsafe { sys::WebPDecodeRGB(data.as_ptr(), data.len(), &mut width, &mut height) };
let buf = (unsafe { wrap_bytes(result, || width as usize * height as usize * 3) })?;
Ok((width as u32, height as u32, buf))
}
#[allow(non_snake_case)]
pub fn WebPDecodeBGR(data: &[u8]) -> Result<(u32, u32, WebpBox<[u8]>), WebPSimpleError> {
let mut width: c_int = 0;
let mut height: c_int = 0;
let result = unsafe { sys::WebPDecodeBGR(data.as_ptr(), data.len(), &mut width, &mut height) };
let buf = (unsafe { wrap_bytes(result, || width as usize * height as usize * 3) })?;
Ok((width as u32, height as u32, buf))
}
#[allow(non_snake_case)]
pub fn WebPDecodeYUV(data: &[u8]) -> Result<(u32, u32, u32, u32, WebpYuvBox), WebPSimpleError> {
let mut width: c_int = 0;
let mut height: c_int = 0;
let mut u: *mut u8 = ptr::null_mut();
let mut v: *mut u8 = ptr::null_mut();
let mut stride: c_int = 0;
let mut uv_stride: c_int = 0;
let result = unsafe {
sys::WebPDecodeYUV(
data.as_ptr(),
data.len(),
&mut width,
&mut height,
&mut u,
&mut v,
&mut stride,
&mut uv_stride,
)
};
if !result.is_null() {
let y_len = height as usize * stride as usize;
let uv_len = (height as usize + 1) / 2 * uv_stride as usize;
let buf = unsafe {
WebpYuvBox::from_raw_yuv(
slice::from_raw_parts_mut(result, y_len),
slice::from_raw_parts_mut(u, uv_len),
slice::from_raw_parts_mut(v, uv_len),
)
};
Ok((
width as u32,
height as u32,
stride as u32,
uv_stride as u32,
buf,
))
} else {
Err(WebPSimpleError)
}
}
#[allow(non_snake_case)]
pub fn WebPDecodeRGBAInto(
data: &[u8],
output_buffer: &mut [u8],
output_stride: u32,
) -> Result<(), WebPSimpleError> {
assert!(output_stride as c_int >= 0);
assert_eq!(output_stride as c_int as u32, output_stride);
let result = unsafe {
sys::WebPDecodeRGBAInto(
data.as_ptr(),
data.len(),
output_buffer.as_mut_ptr(),
output_buffer.len(),
output_stride as c_int,
)
};
if !result.is_null() {
Ok(())
} else {
Err(WebPSimpleError)
}
}
#[allow(non_snake_case)]
pub fn WebPDecodeARGBInto(
data: &[u8],
output_buffer: &mut [u8],
output_stride: u32,
) -> Result<(), WebPSimpleError> {
assert!(output_stride as c_int >= 0);
assert_eq!(output_stride as c_int as u32, output_stride);
let result = unsafe {
sys::WebPDecodeARGBInto(
data.as_ptr(),
data.len(),
output_buffer.as_mut_ptr(),
output_buffer.len(),
output_stride as c_int,
)
};
if !result.is_null() {
Ok(())
} else {
Err(WebPSimpleError)
}
}
#[allow(non_snake_case)]
pub fn WebPDecodeBGRAInto(
data: &[u8],
output_buffer: &mut [u8],
output_stride: u32,
) -> Result<(), WebPSimpleError> {
assert!(output_stride as c_int >= 0);
assert_eq!(output_stride as c_int as u32, output_stride);
let result = unsafe {
sys::WebPDecodeBGRAInto(
data.as_ptr(),
data.len(),
output_buffer.as_mut_ptr(),
output_buffer.len(),
output_stride as c_int,
)
};
if !result.is_null() {
Ok(())
} else {
Err(WebPSimpleError)
}
}
#[allow(non_snake_case)]
pub fn WebPDecodeRGBInto(
data: &[u8],
output_buffer: &mut [u8],
output_stride: u32,
) -> Result<(), WebPSimpleError> {
assert!(output_stride as c_int >= 0);
assert_eq!(output_stride as c_int as u32, output_stride);
let result = unsafe {
sys::WebPDecodeRGBInto(
data.as_ptr(),
data.len(),
output_buffer.as_mut_ptr(),
output_buffer.len(),
output_stride as c_int,
)
};
if !result.is_null() {
Ok(())
} else {
Err(WebPSimpleError)
}
}
#[allow(non_snake_case)]
pub fn WebPDecodeBGRInto(
data: &[u8],
output_buffer: &mut [u8],
output_stride: u32,
) -> Result<(), WebPSimpleError> {
assert!(output_stride as c_int >= 0);
assert_eq!(output_stride as c_int as u32, output_stride);
let result = unsafe {
sys::WebPDecodeBGRInto(
data.as_ptr(),
data.len(),
output_buffer.as_mut_ptr(),
output_buffer.len(),
output_stride as c_int,
)
};
if !result.is_null() {
Ok(())
} else {
Err(WebPSimpleError)
}
}
#[allow(non_snake_case)]
pub fn WebPDecodeYUVInto(
data: &[u8],
luma: &mut [u8],
luma_stride: u32,
u: &mut [u8],
u_stride: u32,
v: &mut [u8],
v_stride: u32,
) -> Result<(), WebPSimpleError> {
assert!(luma_stride as c_int >= 0);
assert_eq!(luma_stride as c_int as u32, luma_stride);
assert!(u_stride as c_int >= 0);
assert_eq!(u_stride as c_int as u32, u_stride);
assert!(v_stride as c_int >= 0);
assert_eq!(v_stride as c_int as u32, v_stride);
let result = unsafe {
sys::WebPDecodeYUVInto(
data.as_ptr(),
data.len(),
luma.as_mut_ptr(),
luma.len(),
luma_stride as c_int,
u.as_mut_ptr(),
u.len(),
u_stride as c_int,
v.as_mut_ptr(),
v.len(),
v_stride as c_int,
)
};
if !result.is_null() {
Ok(())
} else {
Err(WebPSimpleError)
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum WEBP_CSP_MODE {
MODE_RGB = 0,
MODE_RGBA = 1,
MODE_BGR = 2,
MODE_BGRA = 3,
MODE_ARGB = 4,
MODE_RGBA_4444 = 5,
MODE_RGB_565 = 6,
MODE_rgbA = 7,
MODE_bgrA = 8,
MODE_Argb = 9,
MODE_rgbA_4444 = 10,
MODE_YUV = 11,
MODE_YUVA = 12,
}
impl WEBP_CSP_MODE {
pub fn from_raw(raw: sys::WEBP_CSP_MODE) -> Self {
use self::WEBP_CSP_MODE::*;
match raw {
sys::MODE_RGB => MODE_RGB,
sys::MODE_RGBA => MODE_RGBA,
sys::MODE_BGR => MODE_BGR,
sys::MODE_BGRA => MODE_BGRA,
sys::MODE_ARGB => MODE_ARGB,
sys::MODE_RGBA_4444 => MODE_RGBA_4444,
sys::MODE_RGB_565 => MODE_RGB_565,
sys::MODE_rgbA => MODE_rgbA,
sys::MODE_bgrA => MODE_bgrA,
sys::MODE_Argb => MODE_Argb,
sys::MODE_rgbA_4444 => MODE_rgbA_4444,
sys::MODE_YUV => MODE_YUV,
sys::MODE_YUVA => MODE_YUVA,
_ => panic!("WEBP_CSP_MODE::from_raw: unknown value {:?}", raw),
}
}
pub fn into_raw(self) -> sys::WEBP_CSP_MODE {
use self::WEBP_CSP_MODE::*;
match self {
MODE_RGB => sys::MODE_RGB,
MODE_RGBA => sys::MODE_RGBA,
MODE_BGR => sys::MODE_BGR,
MODE_BGRA => sys::MODE_BGRA,
MODE_ARGB => sys::MODE_ARGB,
MODE_RGBA_4444 => sys::MODE_RGBA_4444,
MODE_RGB_565 => sys::MODE_RGB_565,
MODE_rgbA => sys::MODE_rgbA,
MODE_bgrA => sys::MODE_bgrA,
MODE_Argb => sys::MODE_Argb,
MODE_rgbA_4444 => sys::MODE_rgbA_4444,
MODE_YUV => sys::MODE_YUV,
MODE_YUVA => sys::MODE_YUVA,
}
}
}
#[allow(non_snake_case)]
pub fn WebPIsPremultipliedMode(mode: WEBP_CSP_MODE) -> bool {
use self::WEBP_CSP_MODE::*;
match mode {
MODE_rgbA | MODE_bgrA | MODE_Argb | MODE_rgbA_4444 => true,
MODE_RGB | MODE_RGBA | MODE_BGR | MODE_BGRA | MODE_ARGB | MODE_RGBA_4444 | MODE_RGB_565
| MODE_YUV | MODE_YUVA => false,
}
}
#[allow(non_snake_case)]
pub fn WebPIsAlphaMode(mode: WEBP_CSP_MODE) -> bool {
use self::WEBP_CSP_MODE::*;
match mode {
MODE_RGBA | MODE_BGRA | MODE_ARGB | MODE_RGBA_4444 | MODE_rgbA | MODE_bgrA | MODE_Argb
| MODE_rgbA_4444 | MODE_YUVA => true,
MODE_RGB | MODE_BGR | MODE_RGB_565 | MODE_YUV => false,
}
}
#[allow(non_snake_case)]
pub fn WebPIsRGBMode(mode: WEBP_CSP_MODE) -> bool {
use self::WEBP_CSP_MODE::*;
match mode {
MODE_RGB | MODE_RGBA | MODE_BGR | MODE_BGRA | MODE_ARGB | MODE_RGBA_4444 | MODE_RGB_565
| MODE_rgbA | MODE_bgrA | MODE_Argb | MODE_rgbA_4444 => true,
MODE_YUV | MODE_YUVA => false,
}
}
#[allow(non_camel_case_types)]
#[must_use]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum VP8StatusCode {
VP8_STATUS_OK = 0,
VP8_STATUS_OUT_OF_MEMORY = 1,
VP8_STATUS_INVALID_PARAM = 2,
VP8_STATUS_BITSTREAM_ERROR = 3,
VP8_STATUS_UNSUPPORTED_FEATURE = 4,
VP8_STATUS_SUSPENDED = 5,
VP8_STATUS_USER_ABORT = 6,
VP8_STATUS_NOT_ENOUGH_DATA = 7,
}
impl VP8StatusCode {
pub fn from_raw(raw: sys::VP8StatusCode) -> Self {
use self::VP8StatusCode::*;
match raw {
sys::VP8_STATUS_OK => VP8_STATUS_OK,
sys::VP8_STATUS_OUT_OF_MEMORY => VP8_STATUS_OUT_OF_MEMORY,
sys::VP8_STATUS_INVALID_PARAM => VP8_STATUS_INVALID_PARAM,
sys::VP8_STATUS_BITSTREAM_ERROR => VP8_STATUS_BITSTREAM_ERROR,
sys::VP8_STATUS_UNSUPPORTED_FEATURE => VP8_STATUS_UNSUPPORTED_FEATURE,
sys::VP8_STATUS_SUSPENDED => VP8_STATUS_SUSPENDED,
sys::VP8_STATUS_USER_ABORT => VP8_STATUS_USER_ABORT,
sys::VP8_STATUS_NOT_ENOUGH_DATA => VP8_STATUS_NOT_ENOUGH_DATA,
_ => panic!("VP8StatusCode::from_raw: unknown value {:?}", raw),
}
}
pub fn into_raw(self) -> sys::WEBP_CSP_MODE {
use self::VP8StatusCode::*;
match self {
VP8_STATUS_OK => sys::VP8_STATUS_OK,
VP8_STATUS_OUT_OF_MEMORY => sys::VP8_STATUS_OUT_OF_MEMORY,
VP8_STATUS_INVALID_PARAM => sys::VP8_STATUS_INVALID_PARAM,
VP8_STATUS_BITSTREAM_ERROR => sys::VP8_STATUS_BITSTREAM_ERROR,
VP8_STATUS_UNSUPPORTED_FEATURE => sys::VP8_STATUS_UNSUPPORTED_FEATURE,
VP8_STATUS_SUSPENDED => sys::VP8_STATUS_SUSPENDED,
VP8_STATUS_USER_ABORT => sys::VP8_STATUS_USER_ABORT,
VP8_STATUS_NOT_ENOUGH_DATA => sys::VP8_STATUS_NOT_ENOUGH_DATA,
}
}
}
#[derive(Debug)]
pub struct WebPIDecoder(NonNull<sys::WebPIDecoder>);
unsafe impl Send for WebPIDecoder {}
unsafe impl Sync for WebPIDecoder {}
impl UnwindSafe for WebPIDecoder {}
impl RefUnwindSafe for WebPIDecoder {}
impl Drop for WebPIDecoder {
fn drop(&mut self) {
unsafe {
sys::WebPIDelete(self.0.as_ptr());
}
}
}
impl WebPIDecoder {
pub unsafe fn from_raw(raw: NonNull<sys::WebPIDecoder>) -> Self {
WebPIDecoder(raw)
}
pub fn into_raw(self) -> NonNull<sys::WebPIDecoder> {
let ret = self.0;
mem::forget(self);
ret
}
pub fn as_ptr(&self) -> *const sys::WebPIDecoder {
unsafe { self.0.as_ref() }
}
pub fn as_mut_ptr(&mut self) -> *mut sys::WebPIDecoder {
unsafe { self.0.as_mut() }
}
}
#[allow(non_snake_case)]
pub fn WebPINewDecoder() -> WebPIDecoder {
let result = unsafe { sys::WebPINewDecoder(ptr::null_mut()) };
if let Some(result) = NonNull::new(result) {
unsafe { WebPIDecoder::from_raw(result) }
} else {
panic!("WebPINewDecoder: allocation failed");
}
}
#[allow(non_snake_case)]
pub fn WebPINewRGB(csp: WEBP_CSP_MODE) -> WebPIDecoder {
assert!(WebPIsRGBMode(csp), "Not an RGB mode: {:?}", csp);
let result = unsafe { sys::WebPINewRGB(csp.into_raw(), ptr::null_mut(), 0, 0) };
if let Some(result) = NonNull::new(result) {
unsafe { WebPIDecoder::from_raw(result) }
} else {
panic!("WebPINewRGB: allocation failed");
}
}
#[allow(non_snake_case)]
pub fn WebPINewYUVA() -> WebPIDecoder {
let result = unsafe {
sys::WebPINewYUVA(
ptr::null_mut(),
0,
0,
ptr::null_mut(),
0,
0,
ptr::null_mut(),
0,
0,
ptr::null_mut(),
0,
0,
)
};
if let Some(result) = NonNull::new(result) {
unsafe { WebPIDecoder::from_raw(result) }
} else {
panic!("WebPINewYUVA: allocation failed");
}
}
#[allow(non_snake_case)]
pub fn WebPIAppend(idec: &mut WebPIDecoder, data: &[u8]) -> VP8StatusCode {
if data.is_empty() {
panic!("WebPIAppend: appending an empty slice is not supported for now");
}
let result = unsafe { sys::WebPIAppend(idec.as_mut_ptr(), data.as_ptr(), data.len()) };
VP8StatusCode::from_raw(result)
}
#[derive(Debug)]
pub struct WebPIDecGetRGBResult<'a> {
pub buf: &'a [u8],
pub last_y: u32,
pub width: u32,
pub height: u32,
pub stride: u32,
}
#[allow(non_snake_case)]
pub fn WebPIDecGetRGB(idec: &WebPIDecoder) -> Result<WebPIDecGetRGBResult<'_>, WebPSimpleError> {
let mut last_y: c_int = 0;
let mut width: c_int = 0;
let mut height: c_int = 0;
let mut stride: c_int = 0;
let result = unsafe {
sys::WebPIDecGetRGB(
idec.as_ptr(),
&mut last_y,
&mut width,
&mut height,
&mut stride,
)
};
if !result.is_null() {
let len = stride as usize * last_y as usize;
let buf = unsafe { slice::from_raw_parts(result, len) };
Ok(WebPIDecGetRGBResult {
buf,
last_y: last_y as u32,
width: width as u32,
height: height as u32,
stride: stride as u32,
})
} else {
Err(WebPSimpleError)
}
}
#[derive(Debug)]
pub struct WebPIDecGetYUVAResult<'a> {
pub luma: &'a [u8],
pub last_y: u32,
pub u: &'a [u8],
pub v: &'a [u8],
pub a: Option<&'a [u8]>,
pub width: u32,
pub height: u32,
pub stride: u32,
pub uv_stride: u32,
pub a_stride: u32,
}
#[allow(non_snake_case)]
pub fn WebPIDecGetYUVA(idec: &WebPIDecoder) -> Result<WebPIDecGetYUVAResult<'_>, WebPSimpleError> {
let mut last_y: c_int = 0;
let mut u: *mut u8 = ptr::null_mut();
let mut v: *mut u8 = ptr::null_mut();
let mut a: *mut u8 = ptr::null_mut();
let mut width: c_int = 0;
let mut height: c_int = 0;
let mut stride: c_int = 0;
let mut uv_stride: c_int = 0;
let mut a_stride: c_int = 0;
let result = unsafe {
sys::WebPIDecGetYUVA(
idec.as_ptr(),
&mut last_y,
&mut u,
&mut v,
&mut a,
&mut width,
&mut height,
&mut stride,
&mut uv_stride,
&mut a_stride,
)
};
if !result.is_null() {
let luma_len = stride as usize * last_y as usize;
let luma = unsafe { slice::from_raw_parts(result, luma_len) };
let uv_len = uv_stride as usize * ((last_y as usize + 1) / 2);
let u = unsafe { slice::from_raw_parts(u as *const u8, uv_len) };
let v = unsafe { slice::from_raw_parts(v as *const u8, uv_len) };
let a = if !a.is_null() {
let a_len = a_stride as usize * last_y as usize;
Some(unsafe { slice::from_raw_parts(a as *const u8, a_len) })
} else {
None
};
Ok(WebPIDecGetYUVAResult {
luma,
last_y: last_y as u32,
u,
v,
a,
width: width as u32,
height: height as u32,
stride: stride as u32,
uv_stride: uv_stride as u32,
a_stride: a_stride as u32,
})
} else {
Err(WebPSimpleError)
}
}
#[cfg(test)]
mod tests {
use rand::prelude::*;
use super::*;
fn lena() -> Vec<u8> {
include_bytes!("lena.webp").to_vec()
}
#[test]
#[allow(non_snake_case)]
fn test_WebPDecodeRGBA() {
let (width, height, buf) = WebPDecodeRGBA(&lena()).unwrap();
assert_eq!(width, 128);
assert_eq!(height, 128);
assert_eq!(
&buf[..24],
&[
226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113, 255,
223, 155, 109, 255, 223, 155, 109, 255,
]
);
}
#[test]
#[allow(non_snake_case)]
fn test_WebPDecodeARGB() {
let (width, height, buf) = WebPDecodeARGB(&lena()).unwrap();
assert_eq!(width, 128);
assert_eq!(height, 128);
assert_eq!(
&buf[..24],
&[
255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113,
255, 223, 155, 109, 255, 223, 155, 109,
]
);
}
#[test]
#[allow(non_snake_case)]
fn test_WebPDecodeBGRA() {
let (width, height, buf) = WebPDecodeBGRA(&lena()).unwrap();
assert_eq!(width, 128);
assert_eq!(height, 128);
assert_eq!(
&buf[..24],
&[
113, 158, 226, 255, 113, 158, 226, 255, 113, 158, 226, 255, 113, 158, 226, 255,
109, 155, 223, 255, 109, 155, 223, 255,
]
);
}
#[test]
#[allow(non_snake_case)]
fn test_WebPDecodeRGB() {
let (width, height, buf) = WebPDecodeRGB(&lena()).unwrap();
assert_eq!(width, 128);
assert_eq!(height, 128);
assert_eq!(
&buf[..24],
&[
226, 158, 113, 226, 158, 113, 226, 158, 113, 226, 158, 113, 223, 155, 109, 223,
155, 109, 223, 155, 109, 223, 155, 109,
]
);
}
#[test]
#[allow(non_snake_case)]
fn test_WebPDecodeBGR() {
let (width, height, buf) = WebPDecodeBGR(&lena()).unwrap();
assert_eq!(width, 128);
assert_eq!(height, 128);
assert_eq!(
&buf[..24],
&[
113, 158, 226, 113, 158, 226, 113, 158, 226, 113, 158, 226, 109, 155, 223, 109,
155, 223, 109, 155, 223, 109, 155, 223,
]
);
}
#[test]
#[allow(non_snake_case)]
fn test_WebPDecodeYUV() {
let (width, height, stride, uv_stride, buf) = WebPDecodeYUV(&lena()).unwrap();
assert_eq!(width, 128);
assert_eq!(height, 128);
assert!(stride >= 128);
assert!(uv_stride >= 64);
assert_eq!(&buf.y()[..6], &[165, 165, 165, 165, 162, 162]);
assert_eq!(&buf.u()[..6], &[98, 98, 98, 98, 98, 98]);
assert_eq!(&buf.v()[..6], &[161, 161, 161, 161, 161, 161]);
}
#[test]
#[allow(non_snake_case)]
fn test_WebPDecodeRGBAInto() {
let mut buf = vec![0; 128 * 128 * 4];
WebPDecodeRGBAInto(&lena(), &mut buf, 128 * 4).unwrap();
assert_eq!(
&buf[..24],
&[
226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113, 255,
223, 155, 109, 255, 223, 155, 109, 255,
]
);
}
#[test]
#[allow(non_snake_case)]
fn test_WebPDecodeARGBInto() {
let mut buf = vec![0; 128 * 128 * 4];
WebPDecodeARGBInto(&lena(), &mut buf, 128 * 4).unwrap();
assert_eq!(
&buf[..24],
&[
255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113,
255, 223, 155, 109, 255, 223, 155, 109,
]
);
}
#[test]
#[allow(non_snake_case)]
fn test_WebPDecodeBGRAInto() {
let mut buf = vec![0; 128 * 128 * 4];
WebPDecodeBGRAInto(&lena(), &mut buf, 128 * 4).unwrap();
assert_eq!(
&buf[..24],
&[
113, 158, 226, 255, 113, 158, 226, 255, 113, 158, 226, 255, 113, 158, 226, 255,
109, 155, 223, 255, 109, 155, 223, 255,
]
);
}
#[test]
#[allow(non_snake_case)]
fn test_WebPDecodeRGBInto() {
let mut buf = vec![0; 128 * 128 * 3];
WebPDecodeRGBInto(&lena(), &mut buf, 128 * 3).unwrap();
assert_eq!(
&buf[..24],
&[
226, 158, 113, 226, 158, 113, 226, 158, 113, 226, 158, 113, 223, 155, 109, 223,
155, 109, 223, 155, 109, 223, 155, 109,
]
);
}
#[test]
#[allow(non_snake_case)]
fn test_WebPDecodeBGRInto() {
let mut buf = vec![0; 128 * 128 * 3];
WebPDecodeBGRInto(&lena(), &mut buf, 128 * 3).unwrap();
assert_eq!(
&buf[..24],
&[
113, 158, 226, 113, 158, 226, 113, 158, 226, 113, 158, 226, 109, 155, 223, 109,
155, 223, 109, 155, 223, 109, 155, 223
],
);
}
#[test]
#[allow(non_snake_case)]
fn test_WebPDecodeYUVInto() {
let mut luma = vec![0; 128 * 128];
let mut u = vec![0; 64 * 64];
let mut v = vec![0; 64 * 64];
WebPDecodeYUVInto(&lena(), &mut luma, 128, &mut u, 64, &mut v, 64).unwrap();
assert_eq!(&luma[..6], &[165, 165, 165, 165, 162, 162]);
assert_eq!(&u[..6], &[98, 98, 98, 98, 98, 98]);
assert_eq!(&v[..6], &[161, 161, 161, 161, 161, 161]);
}
#[allow(unused)]
fn test_auto_traits() {
fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
fn is_unwind_safe<T: UnwindSafe>() {}
fn is_ref_unwind_safe<T: RefUnwindSafe>() {}
is_send::<WebPIDecoder>();
is_sync::<WebPIDecoder>();
is_unwind_safe::<WebPIDecoder>();
is_ref_unwind_safe::<WebPIDecoder>();
}
#[test]
#[allow(non_snake_case)]
fn test_WebPINewDecoder() {
let _idec = WebPINewDecoder();
}
#[test]
fn test_incr_argb() {
let data = lena();
let mut rng = rand::thread_rng();
for _ in 0..50 {
let mut idec = WebPINewRGB(WEBP_CSP_MODE::MODE_ARGB);
let mut idx = 0;
while idx < data.len() {
let write_len = std::cmp::min(rng.gen_range(1, 64), data.len() - idx);
let result = WebPIAppend(&mut idec, &data[idx..idx + write_len]);
idx += write_len;
if result == VP8StatusCode::VP8_STATUS_OK {
break;
} else if result == VP8StatusCode::VP8_STATUS_SUSPENDED {
if let Ok(result) = WebPIDecGetRGB(&mut idec) {
if result.last_y >= 1 {
assert_eq!(
&result.buf[..24],
&[
255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113,
255, 226, 158, 113, 255, 223, 155, 109, 255, 223, 155, 109,
]
);
}
}
} else {
panic!("Unexpected status: {:?}", result);
}
}
let result = WebPIDecGetRGB(&mut idec).unwrap();
assert_eq!(result.width, 128);
assert_eq!(result.height, 128);
assert_eq!(result.last_y, 128);
assert_eq!(
&result.buf[..24],
&[
255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113,
255, 223, 155, 109, 255, 223, 155, 109,
]
);
}
}
#[test]
fn test_incr_yuva() {
let data = lena();
let mut rng = rand::thread_rng();
for _ in 0..50 {
let mut idec = WebPINewYUVA();
let mut idx = 0;
while idx < data.len() {
let write_len = std::cmp::min(rng.gen_range(1, 64), data.len() - idx);
let result = WebPIAppend(&mut idec, &data[idx..idx + write_len]);
idx += write_len;
if result == VP8StatusCode::VP8_STATUS_OK {
break;
} else if result == VP8StatusCode::VP8_STATUS_SUSPENDED {
if let Ok(result) = WebPIDecGetYUVA(&mut idec) {
if result.last_y >= 1 {
assert_eq!(&result.luma[..6], &[165, 165, 165, 165, 162, 162]);
assert_eq!(&result.u[..6], &[98, 98, 98, 98, 98, 98]);
assert_eq!(&result.v[..6], &[161, 161, 161, 161, 161, 161]);
}
}
} else {
panic!("Unexpected status: {:?}", result);
}
}
let result = WebPIDecGetYUVA(&mut idec).unwrap();
assert_eq!(result.width, 128);
assert_eq!(result.height, 128);
assert_eq!(result.last_y, 128);
assert_eq!(&result.luma[..6], &[165, 165, 165, 165, 162, 162]);
assert_eq!(&result.u[..6], &[98, 98, 98, 98, 98, 98]);
assert_eq!(&result.v[..6], &[161, 161, 161, 161, 161, 161]);
}
}
}