1use libwebp_sys as sys;
2use std::mem;
3use std::os::raw::*;
4use std::panic::{RefUnwindSafe, UnwindSafe};
5use std::ptr::{self, NonNull};
6use std::slice;
7
8use crate::boxed::{wrap_bytes, WebpBox, WebpYuvBox};
9use crate::error::WebPSimpleError;
10
11#[allow(non_snake_case)]
24pub fn WebPGetDecoderVersion() -> u32 {
25 (unsafe { sys::WebPGetDecoderVersion() }) as u32
26}
27
28#[allow(non_snake_case)]
49pub fn WebPGetInfo(data: &[u8]) -> Result<(u32, u32), WebPSimpleError> {
50 let mut width: c_int = 0;
51 let mut height: c_int = 0;
52 let result = unsafe { sys::WebPGetInfo(data.as_ptr(), data.len(), &mut width, &mut height) };
53 if result != 0 {
54 Ok((width as u32, height as u32))
55 } else {
56 Err(WebPSimpleError)
57 }
58}
59
60#[allow(non_snake_case)]
103pub fn WebPDecodeRGBA(data: &[u8]) -> Result<(u32, u32, WebpBox<[u8]>), WebPSimpleError> {
104 let mut width: c_int = 0;
105 let mut height: c_int = 0;
106 let result = unsafe { sys::WebPDecodeRGBA(data.as_ptr(), data.len(), &mut width, &mut height) };
107 let buf = (unsafe { wrap_bytes(result, || width as usize * height as usize * 4) })?;
108 Ok((width as u32, height as u32, buf))
109}
110
111#[allow(non_snake_case)]
116pub fn WebPDecodeARGB(data: &[u8]) -> Result<(u32, u32, WebpBox<[u8]>), WebPSimpleError> {
117 let mut width: c_int = 0;
118 let mut height: c_int = 0;
119 let result = unsafe { sys::WebPDecodeARGB(data.as_ptr(), data.len(), &mut width, &mut height) };
120 let buf = (unsafe { wrap_bytes(result, || width as usize * height as usize * 4) })?;
121 Ok((width as u32, height as u32, buf))
122}
123
124#[allow(non_snake_case)]
129pub fn WebPDecodeBGRA(data: &[u8]) -> Result<(u32, u32, WebpBox<[u8]>), WebPSimpleError> {
130 let mut width: c_int = 0;
131 let mut height: c_int = 0;
132 let result = unsafe { sys::WebPDecodeBGRA(data.as_ptr(), data.len(), &mut width, &mut height) };
133 let buf = (unsafe { wrap_bytes(result, || width as usize * height as usize * 4) })?;
134 Ok((width as u32, height as u32, buf))
135}
136
137#[allow(non_snake_case)]
143pub fn WebPDecodeRGB(data: &[u8]) -> Result<(u32, u32, WebpBox<[u8]>), WebPSimpleError> {
144 let mut width: c_int = 0;
145 let mut height: c_int = 0;
146 let result = unsafe { sys::WebPDecodeRGB(data.as_ptr(), data.len(), &mut width, &mut height) };
147 let buf = (unsafe { wrap_bytes(result, || width as usize * height as usize * 3) })?;
148 Ok((width as u32, height as u32, buf))
149}
150
151#[allow(non_snake_case)]
157pub fn WebPDecodeBGR(data: &[u8]) -> Result<(u32, u32, WebpBox<[u8]>), WebPSimpleError> {
158 let mut width: c_int = 0;
159 let mut height: c_int = 0;
160 let result = unsafe { sys::WebPDecodeBGR(data.as_ptr(), data.len(), &mut width, &mut height) };
161 let buf = (unsafe { wrap_bytes(result, || width as usize * height as usize * 3) })?;
162 Ok((width as u32, height as u32, buf))
163}
164
165#[allow(non_snake_case)]
213pub fn WebPDecodeYUV(data: &[u8]) -> Result<(u32, u32, u32, u32, WebpYuvBox), WebPSimpleError> {
214 let mut width: c_int = 0;
215 let mut height: c_int = 0;
216 let mut u: *mut u8 = ptr::null_mut();
217 let mut v: *mut u8 = ptr::null_mut();
218 let mut stride: c_int = 0;
219 let mut uv_stride: c_int = 0;
220 let result = unsafe {
221 sys::WebPDecodeYUV(
222 data.as_ptr(),
223 data.len(),
224 &mut width,
225 &mut height,
226 &mut u,
227 &mut v,
228 &mut stride,
229 &mut uv_stride,
230 )
231 };
232 if !result.is_null() {
233 let y_len = height as usize * stride as usize;
234 let uv_len = (height as usize + 1) / 2 * uv_stride as usize;
235 let buf = unsafe {
236 WebpYuvBox::from_raw_yuv(
237 slice::from_raw_parts_mut(result, y_len),
238 slice::from_raw_parts_mut(u, uv_len),
239 slice::from_raw_parts_mut(v, uv_len),
240 )
241 };
242 Ok((
243 width as u32,
244 height as u32,
245 stride as u32,
246 uv_stride as u32,
247 buf,
248 ))
249 } else {
250 Err(WebPSimpleError)
251 }
252}
253
254#[allow(non_snake_case)]
304pub fn WebPDecodeRGBAInto(
305 data: &[u8],
306 output_buffer: &mut [u8],
307 output_stride: u32,
308) -> Result<(), WebPSimpleError> {
309 assert!(output_stride as c_int >= 0);
310 assert_eq!(output_stride as c_int as u32, output_stride);
311 let result = unsafe {
312 sys::WebPDecodeRGBAInto(
313 data.as_ptr(),
314 data.len(),
315 output_buffer.as_mut_ptr(),
316 output_buffer.len(),
317 output_stride as c_int,
318 )
319 };
320 if !result.is_null() {
321 Ok(())
322 } else {
323 Err(WebPSimpleError)
324 }
325}
326
327#[allow(non_snake_case)]
332pub fn WebPDecodeARGBInto(
333 data: &[u8],
334 output_buffer: &mut [u8],
335 output_stride: u32,
336) -> Result<(), WebPSimpleError> {
337 assert!(output_stride as c_int >= 0);
338 assert_eq!(output_stride as c_int as u32, output_stride);
339 let result = unsafe {
340 sys::WebPDecodeARGBInto(
341 data.as_ptr(),
342 data.len(),
343 output_buffer.as_mut_ptr(),
344 output_buffer.len(),
345 output_stride as c_int,
346 )
347 };
348 if !result.is_null() {
349 Ok(())
350 } else {
351 Err(WebPSimpleError)
352 }
353}
354
355#[allow(non_snake_case)]
360pub fn WebPDecodeBGRAInto(
361 data: &[u8],
362 output_buffer: &mut [u8],
363 output_stride: u32,
364) -> Result<(), WebPSimpleError> {
365 assert!(output_stride as c_int >= 0);
366 assert_eq!(output_stride as c_int as u32, output_stride);
367 let result = unsafe {
368 sys::WebPDecodeBGRAInto(
369 data.as_ptr(),
370 data.len(),
371 output_buffer.as_mut_ptr(),
372 output_buffer.len(),
373 output_stride as c_int,
374 )
375 };
376 if !result.is_null() {
377 Ok(())
378 } else {
379 Err(WebPSimpleError)
380 }
381}
382
383#[allow(non_snake_case)]
390pub fn WebPDecodeRGBInto(
391 data: &[u8],
392 output_buffer: &mut [u8],
393 output_stride: u32,
394) -> Result<(), WebPSimpleError> {
395 assert!(output_stride as c_int >= 0);
396 assert_eq!(output_stride as c_int as u32, output_stride);
397 let result = unsafe {
398 sys::WebPDecodeRGBInto(
399 data.as_ptr(),
400 data.len(),
401 output_buffer.as_mut_ptr(),
402 output_buffer.len(),
403 output_stride as c_int,
404 )
405 };
406 if !result.is_null() {
407 Ok(())
408 } else {
409 Err(WebPSimpleError)
410 }
411}
412
413#[allow(non_snake_case)]
420pub fn WebPDecodeBGRInto(
421 data: &[u8],
422 output_buffer: &mut [u8],
423 output_stride: u32,
424) -> Result<(), WebPSimpleError> {
425 assert!(output_stride as c_int >= 0);
426 assert_eq!(output_stride as c_int as u32, output_stride);
427 let result = unsafe {
428 sys::WebPDecodeBGRInto(
429 data.as_ptr(),
430 data.len(),
431 output_buffer.as_mut_ptr(),
432 output_buffer.len(),
433 output_stride as c_int,
434 )
435 };
436 if !result.is_null() {
437 Ok(())
438 } else {
439 Err(WebPSimpleError)
440 }
441}
442
443#[allow(non_snake_case)]
487pub fn WebPDecodeYUVInto(
488 data: &[u8],
489 luma: &mut [u8],
490 luma_stride: u32,
491 u: &mut [u8],
492 u_stride: u32,
493 v: &mut [u8],
494 v_stride: u32,
495) -> Result<(), WebPSimpleError> {
496 assert!(luma_stride as c_int >= 0);
497 assert_eq!(luma_stride as c_int as u32, luma_stride);
498 assert!(u_stride as c_int >= 0);
499 assert_eq!(u_stride as c_int as u32, u_stride);
500 assert!(v_stride as c_int >= 0);
501 assert_eq!(v_stride as c_int as u32, v_stride);
502 let result = unsafe {
503 sys::WebPDecodeYUVInto(
504 data.as_ptr(),
505 data.len(),
506 luma.as_mut_ptr(),
507 luma.len(),
508 luma_stride as c_int,
509 u.as_mut_ptr(),
510 u.len(),
511 u_stride as c_int,
512 v.as_mut_ptr(),
513 v.len(),
514 v_stride as c_int,
515 )
516 };
517 if !result.is_null() {
518 Ok(())
519 } else {
520 Err(WebPSimpleError)
521 }
522}
523
524#[allow(non_camel_case_types)]
525#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
526pub enum WEBP_CSP_MODE {
527 MODE_RGB = 0,
528 MODE_RGBA = 1,
529 MODE_BGR = 2,
530 MODE_BGRA = 3,
531 MODE_ARGB = 4,
532 MODE_RGBA_4444 = 5,
533 MODE_RGB_565 = 6,
534 MODE_rgbA = 7,
536 MODE_bgrA = 8,
538 MODE_Argb = 9,
540 MODE_rgbA_4444 = 10,
542 MODE_YUV = 11,
544 MODE_YUVA = 12, }
546
547impl WEBP_CSP_MODE {
548 pub fn from_raw(raw: sys::WEBP_CSP_MODE) -> Self {
549 use self::WEBP_CSP_MODE::*;
550
551 match raw {
552 sys::MODE_RGB => MODE_RGB,
553 sys::MODE_RGBA => MODE_RGBA,
554 sys::MODE_BGR => MODE_BGR,
555 sys::MODE_BGRA => MODE_BGRA,
556 sys::MODE_ARGB => MODE_ARGB,
557 sys::MODE_RGBA_4444 => MODE_RGBA_4444,
558 sys::MODE_RGB_565 => MODE_RGB_565,
559 sys::MODE_rgbA => MODE_rgbA,
560 sys::MODE_bgrA => MODE_bgrA,
561 sys::MODE_Argb => MODE_Argb,
562 sys::MODE_rgbA_4444 => MODE_rgbA_4444,
563 sys::MODE_YUV => MODE_YUV,
564 sys::MODE_YUVA => MODE_YUVA,
565 _ => panic!("WEBP_CSP_MODE::from_raw: unknown value {:?}", raw),
566 }
567 }
568
569 pub fn into_raw(self) -> sys::WEBP_CSP_MODE {
570 use self::WEBP_CSP_MODE::*;
571
572 match self {
573 MODE_RGB => sys::MODE_RGB,
574 MODE_RGBA => sys::MODE_RGBA,
575 MODE_BGR => sys::MODE_BGR,
576 MODE_BGRA => sys::MODE_BGRA,
577 MODE_ARGB => sys::MODE_ARGB,
578 MODE_RGBA_4444 => sys::MODE_RGBA_4444,
579 MODE_RGB_565 => sys::MODE_RGB_565,
580 MODE_rgbA => sys::MODE_rgbA,
581 MODE_bgrA => sys::MODE_bgrA,
582 MODE_Argb => sys::MODE_Argb,
583 MODE_rgbA_4444 => sys::MODE_rgbA_4444,
584 MODE_YUV => sys::MODE_YUV,
585 MODE_YUVA => sys::MODE_YUVA,
586 }
587 }
588}
589
590#[allow(non_snake_case)]
591pub fn WebPIsPremultipliedMode(mode: WEBP_CSP_MODE) -> bool {
592 use self::WEBP_CSP_MODE::*;
593
594 match mode {
595 MODE_rgbA | MODE_bgrA | MODE_Argb | MODE_rgbA_4444 => true,
596 MODE_RGB | MODE_RGBA | MODE_BGR | MODE_BGRA | MODE_ARGB | MODE_RGBA_4444 | MODE_RGB_565
597 | MODE_YUV | MODE_YUVA => false,
598 }
599}
600
601#[allow(non_snake_case)]
602pub fn WebPIsAlphaMode(mode: WEBP_CSP_MODE) -> bool {
603 use self::WEBP_CSP_MODE::*;
604
605 match mode {
606 MODE_RGBA | MODE_BGRA | MODE_ARGB | MODE_RGBA_4444 | MODE_rgbA | MODE_bgrA | MODE_Argb
607 | MODE_rgbA_4444 | MODE_YUVA => true,
608 MODE_RGB | MODE_BGR | MODE_RGB_565 | MODE_YUV => false,
609 }
610}
611
612#[allow(non_snake_case)]
613pub fn WebPIsRGBMode(mode: WEBP_CSP_MODE) -> bool {
614 use self::WEBP_CSP_MODE::*;
615
616 match mode {
617 MODE_RGB | MODE_RGBA | MODE_BGR | MODE_BGRA | MODE_ARGB | MODE_RGBA_4444 | MODE_RGB_565
618 | MODE_rgbA | MODE_bgrA | MODE_Argb | MODE_rgbA_4444 => true,
619 MODE_YUV | MODE_YUVA => false,
620 }
621}
622
623#[allow(non_camel_case_types)]
690#[must_use]
691#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
692pub enum VP8StatusCode {
693 VP8_STATUS_OK = 0,
694 VP8_STATUS_OUT_OF_MEMORY = 1,
695 VP8_STATUS_INVALID_PARAM = 2,
696 VP8_STATUS_BITSTREAM_ERROR = 3,
697 VP8_STATUS_UNSUPPORTED_FEATURE = 4,
698 VP8_STATUS_SUSPENDED = 5,
699 VP8_STATUS_USER_ABORT = 6,
700 VP8_STATUS_NOT_ENOUGH_DATA = 7,
701}
702
703impl VP8StatusCode {
704 pub fn from_raw(raw: sys::VP8StatusCode) -> Self {
705 use self::VP8StatusCode::*;
706
707 match raw {
708 sys::VP8_STATUS_OK => VP8_STATUS_OK,
709 sys::VP8_STATUS_OUT_OF_MEMORY => VP8_STATUS_OUT_OF_MEMORY,
710 sys::VP8_STATUS_INVALID_PARAM => VP8_STATUS_INVALID_PARAM,
711 sys::VP8_STATUS_BITSTREAM_ERROR => VP8_STATUS_BITSTREAM_ERROR,
712 sys::VP8_STATUS_UNSUPPORTED_FEATURE => VP8_STATUS_UNSUPPORTED_FEATURE,
713 sys::VP8_STATUS_SUSPENDED => VP8_STATUS_SUSPENDED,
714 sys::VP8_STATUS_USER_ABORT => VP8_STATUS_USER_ABORT,
715 sys::VP8_STATUS_NOT_ENOUGH_DATA => VP8_STATUS_NOT_ENOUGH_DATA,
716 _ => panic!("VP8StatusCode::from_raw: unknown value {:?}", raw),
717 }
718 }
719
720 pub fn into_raw(self) -> sys::WEBP_CSP_MODE {
721 use self::VP8StatusCode::*;
722
723 match self {
724 VP8_STATUS_OK => sys::VP8_STATUS_OK,
725 VP8_STATUS_OUT_OF_MEMORY => sys::VP8_STATUS_OUT_OF_MEMORY,
726 VP8_STATUS_INVALID_PARAM => sys::VP8_STATUS_INVALID_PARAM,
727 VP8_STATUS_BITSTREAM_ERROR => sys::VP8_STATUS_BITSTREAM_ERROR,
728 VP8_STATUS_UNSUPPORTED_FEATURE => sys::VP8_STATUS_UNSUPPORTED_FEATURE,
729 VP8_STATUS_SUSPENDED => sys::VP8_STATUS_SUSPENDED,
730 VP8_STATUS_USER_ABORT => sys::VP8_STATUS_USER_ABORT,
731 VP8_STATUS_NOT_ENOUGH_DATA => sys::VP8_STATUS_NOT_ENOUGH_DATA,
732 }
733 }
734}
735
736#[derive(Debug)]
737pub struct WebPIDecoder(NonNull<sys::WebPIDecoder>);
738
739unsafe impl Send for WebPIDecoder {}
740unsafe impl Sync for WebPIDecoder {}
741impl UnwindSafe for WebPIDecoder {}
742impl RefUnwindSafe for WebPIDecoder {}
743
744impl Drop for WebPIDecoder {
745 fn drop(&mut self) {
746 unsafe {
747 sys::WebPIDelete(self.0.as_ptr());
748 }
749 }
750}
751
752impl WebPIDecoder {
753 pub unsafe fn from_raw(raw: NonNull<sys::WebPIDecoder>) -> Self {
754 WebPIDecoder(raw)
755 }
756
757 pub fn into_raw(self) -> NonNull<sys::WebPIDecoder> {
758 let ret = self.0;
759 mem::forget(self);
760 ret
761 }
762
763 pub fn as_ptr(&self) -> *const sys::WebPIDecoder {
764 unsafe { self.0.as_ref() }
765 }
766
767 pub fn as_mut_ptr(&mut self) -> *mut sys::WebPIDecoder {
768 unsafe { self.0.as_mut() }
769 }
770}
771
772#[allow(non_snake_case)]
774pub fn WebPINewDecoder() -> WebPIDecoder {
775 let result = unsafe { sys::WebPINewDecoder(ptr::null_mut()) };
776 if let Some(result) = NonNull::new(result) {
777 unsafe { WebPIDecoder::from_raw(result) }
778 } else {
779 panic!("WebPINewDecoder: allocation failed");
780 }
781}
782
783#[allow(non_snake_case)]
785pub fn WebPINewRGB(csp: WEBP_CSP_MODE) -> WebPIDecoder {
786 assert!(WebPIsRGBMode(csp), "Not an RGB mode: {:?}", csp);
787 let result = unsafe { sys::WebPINewRGB(csp.into_raw(), ptr::null_mut(), 0, 0) };
788 if let Some(result) = NonNull::new(result) {
789 unsafe { WebPIDecoder::from_raw(result) }
790 } else {
791 panic!("WebPINewRGB: allocation failed");
792 }
793}
794
795#[allow(non_snake_case)]
797pub fn WebPINewYUVA() -> WebPIDecoder {
798 let result = unsafe {
799 sys::WebPINewYUVA(
800 ptr::null_mut(),
801 0,
802 0,
803 ptr::null_mut(),
804 0,
805 0,
806 ptr::null_mut(),
807 0,
808 0,
809 ptr::null_mut(),
810 0,
811 0,
812 )
813 };
814 if let Some(result) = NonNull::new(result) {
815 unsafe { WebPIDecoder::from_raw(result) }
816 } else {
817 panic!("WebPINewYUVA: allocation failed");
818 }
819}
820
821#[allow(non_snake_case)]
822pub fn WebPIAppend(idec: &mut WebPIDecoder, data: &[u8]) -> VP8StatusCode {
823 if data.is_empty() {
824 panic!("WebPIAppend: appending an empty slice is not supported for now");
827 }
828 let result = unsafe { sys::WebPIAppend(idec.as_mut_ptr(), data.as_ptr(), data.len()) };
829 VP8StatusCode::from_raw(result)
830}
831
832#[derive(Debug)]
840pub struct WebPIDecGetRGBResult<'a> {
841 pub buf: &'a [u8],
842 pub last_y: u32,
843 pub width: u32,
844 pub height: u32,
845 pub stride: u32,
846}
847
848#[allow(non_snake_case)]
849pub fn WebPIDecGetRGB(idec: &WebPIDecoder) -> Result<WebPIDecGetRGBResult<'_>, WebPSimpleError> {
850 let mut last_y: c_int = 0;
851 let mut width: c_int = 0;
852 let mut height: c_int = 0;
853 let mut stride: c_int = 0;
854 let result = unsafe {
855 sys::WebPIDecGetRGB(
856 idec.as_ptr(),
857 &mut last_y,
858 &mut width,
859 &mut height,
860 &mut stride,
861 )
862 };
863 if !result.is_null() {
864 let len = stride as usize * last_y as usize;
866 let buf = unsafe { slice::from_raw_parts(result, len) };
867 Ok(WebPIDecGetRGBResult {
868 buf,
869 last_y: last_y as u32,
870 width: width as u32,
871 height: height as u32,
872 stride: stride as u32,
873 })
874 } else {
875 Err(WebPSimpleError)
876 }
877}
878
879#[derive(Debug)]
880pub struct WebPIDecGetYUVAResult<'a> {
881 pub luma: &'a [u8],
882 pub last_y: u32,
883 pub u: &'a [u8],
884 pub v: &'a [u8],
885 pub a: Option<&'a [u8]>,
886 pub width: u32,
887 pub height: u32,
888 pub stride: u32,
889 pub uv_stride: u32,
890 pub a_stride: u32,
891}
892
893#[allow(non_snake_case)]
894pub fn WebPIDecGetYUVA(idec: &WebPIDecoder) -> Result<WebPIDecGetYUVAResult<'_>, WebPSimpleError> {
895 let mut last_y: c_int = 0;
896 let mut u: *mut u8 = ptr::null_mut();
897 let mut v: *mut u8 = ptr::null_mut();
898 let mut a: *mut u8 = ptr::null_mut();
899 let mut width: c_int = 0;
900 let mut height: c_int = 0;
901 let mut stride: c_int = 0;
902 let mut uv_stride: c_int = 0;
903 let mut a_stride: c_int = 0;
904 let result = unsafe {
905 sys::WebPIDecGetYUVA(
906 idec.as_ptr(),
907 &mut last_y,
908 &mut u,
909 &mut v,
910 &mut a,
911 &mut width,
912 &mut height,
913 &mut stride,
914 &mut uv_stride,
915 &mut a_stride,
916 )
917 };
918 if !result.is_null() {
919 let luma_len = stride as usize * last_y as usize;
921 let luma = unsafe { slice::from_raw_parts(result, luma_len) };
922 let uv_len = uv_stride as usize * ((last_y as usize + 1) / 2);
924 let u = unsafe { slice::from_raw_parts(u as *const u8, uv_len) };
925 let v = unsafe { slice::from_raw_parts(v as *const u8, uv_len) };
926 let a = if !a.is_null() {
928 let a_len = a_stride as usize * last_y as usize;
929 Some(unsafe { slice::from_raw_parts(a as *const u8, a_len) })
930 } else {
931 None
932 };
933 Ok(WebPIDecGetYUVAResult {
934 luma,
935 last_y: last_y as u32,
936 u,
937 v,
938 a,
939 width: width as u32,
940 height: height as u32,
941 stride: stride as u32,
942 uv_stride: uv_stride as u32,
943 a_stride: a_stride as u32,
944 })
945 } else {
946 Err(WebPSimpleError)
947 }
948}
949
950#[cfg(test)]
951mod tests {
952 use rand::prelude::*;
953
954 use super::*;
955
956 fn lena() -> Vec<u8> {
957 include_bytes!("lena.webp").to_vec()
958 }
959
960 #[test]
961 #[allow(non_snake_case)]
962 fn test_WebPDecodeRGBA() {
963 let (width, height, buf) = WebPDecodeRGBA(&lena()).unwrap();
964 assert_eq!(width, 128);
965 assert_eq!(height, 128);
966 assert_eq!(
967 &buf[..24],
968 &[
969 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113, 255,
970 223, 155, 109, 255, 223, 155, 109, 255,
971 ]
972 );
973 }
974
975 #[test]
976 #[allow(non_snake_case)]
977 fn test_WebPDecodeARGB() {
978 let (width, height, buf) = WebPDecodeARGB(&lena()).unwrap();
979 assert_eq!(width, 128);
980 assert_eq!(height, 128);
981 assert_eq!(
982 &buf[..24],
983 &[
984 255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113,
985 255, 223, 155, 109, 255, 223, 155, 109,
986 ]
987 );
988 }
989
990 #[test]
991 #[allow(non_snake_case)]
992 fn test_WebPDecodeBGRA() {
993 let (width, height, buf) = WebPDecodeBGRA(&lena()).unwrap();
994 assert_eq!(width, 128);
995 assert_eq!(height, 128);
996 assert_eq!(
997 &buf[..24],
998 &[
999 113, 158, 226, 255, 113, 158, 226, 255, 113, 158, 226, 255, 113, 158, 226, 255,
1000 109, 155, 223, 255, 109, 155, 223, 255,
1001 ]
1002 );
1003 }
1004
1005 #[test]
1006 #[allow(non_snake_case)]
1007 fn test_WebPDecodeRGB() {
1008 let (width, height, buf) = WebPDecodeRGB(&lena()).unwrap();
1009 assert_eq!(width, 128);
1010 assert_eq!(height, 128);
1011 assert_eq!(
1012 &buf[..24],
1013 &[
1014 226, 158, 113, 226, 158, 113, 226, 158, 113, 226, 158, 113, 223, 155, 109, 223,
1015 155, 109, 223, 155, 109, 223, 155, 109,
1016 ]
1017 );
1018 }
1019
1020 #[test]
1021 #[allow(non_snake_case)]
1022 fn test_WebPDecodeBGR() {
1023 let (width, height, buf) = WebPDecodeBGR(&lena()).unwrap();
1024 assert_eq!(width, 128);
1025 assert_eq!(height, 128);
1026 assert_eq!(
1027 &buf[..24],
1028 &[
1029 113, 158, 226, 113, 158, 226, 113, 158, 226, 113, 158, 226, 109, 155, 223, 109,
1030 155, 223, 109, 155, 223, 109, 155, 223,
1031 ]
1032 );
1033 }
1034
1035 #[test]
1036 #[allow(non_snake_case)]
1037 fn test_WebPDecodeYUV() {
1038 let (width, height, stride, uv_stride, buf) = WebPDecodeYUV(&lena()).unwrap();
1039 assert_eq!(width, 128);
1040 assert_eq!(height, 128);
1041 assert!(stride >= 128);
1042 assert!(uv_stride >= 64);
1043 assert_eq!(&buf.y()[..6], &[165, 165, 165, 165, 162, 162]);
1044 assert_eq!(&buf.u()[..6], &[98, 98, 98, 98, 98, 98]);
1045 assert_eq!(&buf.v()[..6], &[161, 161, 161, 161, 161, 161]);
1046 }
1047
1048 #[test]
1049 #[allow(non_snake_case)]
1050 fn test_WebPDecodeRGBAInto() {
1051 let mut buf = vec![0; 128 * 128 * 4];
1052 WebPDecodeRGBAInto(&lena(), &mut buf, 128 * 4).unwrap();
1053 assert_eq!(
1054 &buf[..24],
1055 &[
1056 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113, 255,
1057 223, 155, 109, 255, 223, 155, 109, 255,
1058 ]
1059 );
1060 }
1061
1062 #[test]
1063 #[allow(non_snake_case)]
1064 fn test_WebPDecodeARGBInto() {
1065 let mut buf = vec![0; 128 * 128 * 4];
1066 WebPDecodeARGBInto(&lena(), &mut buf, 128 * 4).unwrap();
1067 assert_eq!(
1068 &buf[..24],
1069 &[
1070 255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113,
1071 255, 223, 155, 109, 255, 223, 155, 109,
1072 ]
1073 );
1074 }
1075
1076 #[test]
1077 #[allow(non_snake_case)]
1078 fn test_WebPDecodeBGRAInto() {
1079 let mut buf = vec![0; 128 * 128 * 4];
1080 WebPDecodeBGRAInto(&lena(), &mut buf, 128 * 4).unwrap();
1081 assert_eq!(
1082 &buf[..24],
1083 &[
1084 113, 158, 226, 255, 113, 158, 226, 255, 113, 158, 226, 255, 113, 158, 226, 255,
1085 109, 155, 223, 255, 109, 155, 223, 255,
1086 ]
1087 );
1088 }
1089
1090 #[test]
1091 #[allow(non_snake_case)]
1092 fn test_WebPDecodeRGBInto() {
1093 let mut buf = vec![0; 128 * 128 * 3];
1094 WebPDecodeRGBInto(&lena(), &mut buf, 128 * 3).unwrap();
1095 assert_eq!(
1096 &buf[..24],
1097 &[
1098 226, 158, 113, 226, 158, 113, 226, 158, 113, 226, 158, 113, 223, 155, 109, 223,
1099 155, 109, 223, 155, 109, 223, 155, 109,
1100 ]
1101 );
1102 }
1103
1104 #[test]
1105 #[allow(non_snake_case)]
1106 fn test_WebPDecodeBGRInto() {
1107 let mut buf = vec![0; 128 * 128 * 3];
1108 WebPDecodeBGRInto(&lena(), &mut buf, 128 * 3).unwrap();
1109 assert_eq!(
1110 &buf[..24],
1111 &[
1112 113, 158, 226, 113, 158, 226, 113, 158, 226, 113, 158, 226, 109, 155, 223, 109,
1113 155, 223, 109, 155, 223, 109, 155, 223
1114 ],
1115 );
1116 }
1117
1118 #[test]
1119 #[allow(non_snake_case)]
1120 fn test_WebPDecodeYUVInto() {
1121 let mut luma = vec![0; 128 * 128];
1122 let mut u = vec![0; 64 * 64];
1123 let mut v = vec![0; 64 * 64];
1124 WebPDecodeYUVInto(&lena(), &mut luma, 128, &mut u, 64, &mut v, 64).unwrap();
1125 assert_eq!(&luma[..6], &[165, 165, 165, 165, 162, 162]);
1126 assert_eq!(&u[..6], &[98, 98, 98, 98, 98, 98]);
1127 assert_eq!(&v[..6], &[161, 161, 161, 161, 161, 161]);
1128 }
1129
1130 #[allow(unused)]
1131 fn test_auto_traits() {
1132 fn is_send<T: Send>() {}
1133 fn is_sync<T: Sync>() {}
1134 fn is_unwind_safe<T: UnwindSafe>() {}
1135 fn is_ref_unwind_safe<T: RefUnwindSafe>() {}
1136
1137 is_send::<WebPIDecoder>();
1138 is_sync::<WebPIDecoder>();
1139 is_unwind_safe::<WebPIDecoder>();
1140 is_ref_unwind_safe::<WebPIDecoder>();
1141 }
1142
1143 #[test]
1144 #[allow(non_snake_case)]
1145 fn test_WebPINewDecoder() {
1146 let _idec = WebPINewDecoder();
1147 }
1148
1149 #[test]
1150 fn test_incr_argb() {
1151 let data = lena();
1152 let mut rng = rand::thread_rng();
1153 for _ in 0..50 {
1154 let mut idec = WebPINewRGB(WEBP_CSP_MODE::MODE_ARGB);
1155 let mut idx = 0;
1156 while idx < data.len() {
1157 let write_len = std::cmp::min(rng.gen_range(1, 64), data.len() - idx);
1159 let result = WebPIAppend(&mut idec, &data[idx..idx + write_len]);
1160 idx += write_len;
1161 if result == VP8StatusCode::VP8_STATUS_OK {
1162 break;
1163 } else if result == VP8StatusCode::VP8_STATUS_SUSPENDED {
1164 if let Ok(result) = WebPIDecGetRGB(&mut idec) {
1165 if result.last_y >= 1 {
1166 assert_eq!(
1167 &result.buf[..24],
1168 &[
1169 255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113,
1170 255, 226, 158, 113, 255, 223, 155, 109, 255, 223, 155, 109,
1171 ]
1172 );
1173 }
1174 }
1175 } else {
1176 panic!("Unexpected status: {:?}", result);
1177 }
1178 }
1179 let result = WebPIDecGetRGB(&mut idec).unwrap();
1180 assert_eq!(result.width, 128);
1181 assert_eq!(result.height, 128);
1182 assert_eq!(result.last_y, 128);
1183 assert_eq!(
1184 &result.buf[..24],
1185 &[
1186 255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113, 255, 226, 158, 113,
1187 255, 223, 155, 109, 255, 223, 155, 109,
1188 ]
1189 );
1190 }
1191 }
1192
1193 #[test]
1194 fn test_incr_yuva() {
1195 let data = lena();
1196 let mut rng = rand::thread_rng();
1197 for _ in 0..50 {
1198 let mut idec = WebPINewYUVA();
1199 let mut idx = 0;
1200 while idx < data.len() {
1201 let write_len = std::cmp::min(rng.gen_range(1, 64), data.len() - idx);
1203 let result = WebPIAppend(&mut idec, &data[idx..idx + write_len]);
1204 idx += write_len;
1205 if result == VP8StatusCode::VP8_STATUS_OK {
1206 break;
1207 } else if result == VP8StatusCode::VP8_STATUS_SUSPENDED {
1208 if let Ok(result) = WebPIDecGetYUVA(&mut idec) {
1209 if result.last_y >= 1 {
1210 assert_eq!(&result.luma[..6], &[165, 165, 165, 165, 162, 162]);
1211 assert_eq!(&result.u[..6], &[98, 98, 98, 98, 98, 98]);
1212 assert_eq!(&result.v[..6], &[161, 161, 161, 161, 161, 161]);
1213 }
1214 }
1215 } else {
1216 panic!("Unexpected status: {:?}", result);
1217 }
1218 }
1219 let result = WebPIDecGetYUVA(&mut idec).unwrap();
1220 assert_eq!(result.width, 128);
1221 assert_eq!(result.height, 128);
1222 assert_eq!(result.last_y, 128);
1223 assert_eq!(&result.luma[..6], &[165, 165, 165, 165, 162, 162]);
1224 assert_eq!(&result.u[..6], &[98, 98, 98, 98, 98, 98]);
1225 assert_eq!(&result.v[..6], &[161, 161, 161, 161, 161, 161]);
1226 }
1227 }
1228}