libwebp_sys/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![allow(
3    non_snake_case,
4    clippy::missing_safety_doc,
5    clippy::result_unit_err,
6    clippy::derivable_impls
7)]
8// bindgen --default-enum-style=rust --distrust-clang-mangling --use-core --impl-debug --allowlist-function='[wW][eE][bB].*' --allowlist-var='[wW][eE][bB].*' --allowlist-type='[wW][eE][bB].*' --no-layout-tests wrap.h -- -I./vendor > src/ffi.rs
9
10#[cfg(feature = "std")]
11use std as core;
12
13#[allow(non_camel_case_types)]
14mod ffi;
15pub use ffi::*;
16
17pub fn WebPMuxNew() -> *mut WebPMux {
18    unsafe { WebPNewInternal(ffi::WEBP_MUX_ABI_VERSION as _) }
19}
20
21pub fn WebPGetMuxABIVersion() -> core::ffi::c_int {
22    WEBP_MUX_ABI_VERSION as _
23}
24
25pub fn WebPGetDemuxABIVersion() -> core::ffi::c_int {
26    ffi::WEBP_DEMUX_ABI_VERSION as _
27}
28
29pub unsafe fn WebPInitDecoderConfig(config: *mut WebPDecoderConfig) -> bool {
30    unsafe { WebPInitDecoderConfigInternal(config, ffi::WEBP_DECODER_ABI_VERSION as _) != 0 }
31}
32
33impl WebPDecoderConfig {
34    pub fn new() -> Result<Self, ()> {
35        unsafe {
36            let mut out = core::mem::MaybeUninit::uninit();
37            if WebPInitDecoderConfig(out.as_mut_ptr()) {
38                Ok(out.assume_init())
39            } else {
40                Err(())
41            }
42        }
43    }
44}
45
46pub unsafe fn WebPInitConfig(config: *mut WebPConfig) -> bool {
47    unsafe {
48        WebPConfigInitInternal(
49            config,
50            WebPPreset::WEBP_PRESET_DEFAULT,
51            75.0,
52            ffi::WEBP_DECODER_ABI_VERSION as _,
53        ) != 0
54    }
55}
56
57impl WebPConfig {
58    pub fn new() -> Result<Self, ()> {
59        unsafe {
60            let mut out = core::mem::MaybeUninit::uninit();
61            if WebPInitConfig(out.as_mut_ptr()) {
62                Ok(out.assume_init())
63            } else {
64                Err(())
65            }
66        }
67    }
68
69    pub fn new_with_preset(preset: WebPPreset, quality: f32) -> Result<Self, ()> {
70        unsafe {
71            let mut out = core::mem::MaybeUninit::uninit();
72            if WebPConfigInitInternal(
73                out.as_mut_ptr(),
74                preset,
75                quality,
76                ffi::WEBP_DECODER_ABI_VERSION as _,
77            ) != 0
78            {
79                Ok(out.assume_init())
80            } else {
81                Err(())
82            }
83        }
84    }
85}
86
87pub unsafe fn WebPPictureInit(config: *mut WebPPicture) -> bool {
88    unsafe { WebPPictureInitInternal(config, ffi::WEBP_DECODER_ABI_VERSION as _) != 0 }
89}
90
91impl WebPPicture {
92    pub fn new() -> Result<Self, ()> {
93        unsafe {
94            let mut out = core::mem::MaybeUninit::uninit();
95            if WebPPictureInit(out.as_mut_ptr()) {
96                Ok(out.assume_init())
97            } else {
98                Err(())
99            }
100        }
101    }
102}
103
104pub unsafe fn WebPGetFeatures(
105    arg1: *const u8,
106    arg2: usize,
107    arg3: *mut WebPBitstreamFeatures,
108) -> VP8StatusCode {
109    unsafe { WebPGetFeaturesInternal(arg1, arg2, arg3, ffi::WEBP_DECODER_ABI_VERSION as _) }
110}
111
112pub fn WebPDataInit(data: &mut WebPData) {
113    *data = WebPData {
114        bytes: core::ptr::null_mut(),
115        size: 0,
116    }
117}
118
119impl Default for WebPData {
120    fn default() -> Self {
121        Self {
122            bytes: core::ptr::null(),
123            size: 0,
124        }
125    }
126}
127
128pub unsafe fn WebPDataClear(data: &mut WebPData) {
129    unsafe {
130        WebPFree(data.bytes as *mut _);
131    }
132    WebPDataInit(data);
133}
134
135pub unsafe fn WebPAnimDecoderOptionsInit(arg1: *mut WebPAnimDecoderOptions) -> core::ffi::c_int {
136    unsafe { WebPAnimDecoderOptionsInitInternal(arg1, ffi::WEBP_DEMUX_ABI_VERSION as _) }
137}
138
139pub unsafe fn WebPAnimDecoderNew(
140    arg1: *const WebPData,
141    arg2: *const WebPAnimDecoderOptions,
142) -> *mut WebPAnimDecoder {
143    unsafe { WebPAnimDecoderNewInternal(arg1, arg2, ffi::WEBP_DEMUX_ABI_VERSION as _) }
144}
145
146impl Default for WebPAnimInfo {
147    fn default() -> Self {
148        WebPAnimInfo {
149            canvas_width: 0,
150            canvas_height: 0,
151            loop_count: 0,
152            bgcolor: 0,
153            frame_count: 0,
154            pad: [0u32; 4usize],
155        }
156    }
157}
158
159#[cfg(all(test, feature = "std"))]
160mod tests {
161    use super::*;
162    use std::fs::File;
163    use std::io::prelude::*;
164    use std::slice;
165
166    #[test]
167    fn test_webp() {
168        let mut width = 0;
169        let mut height = 0;
170        let mut buf = Vec::new();
171        let len = File::open("./tests/test1.webp")
172            .unwrap()
173            .read_to_end(&mut buf)
174            .unwrap();
175
176        unsafe {
177            WebPGetInfo(buf.as_ptr(), len, &mut width, &mut height);
178        }
179        assert!(width == 1000);
180        assert!(height == 1000);
181    }
182
183    #[test]
184    fn test_webp_encode_lossless() {
185        let mut buf = Vec::new();
186        let len = File::open("./tests/test1_1000x1000.bif")
187            .unwrap()
188            .read_to_end(&mut buf)
189            .unwrap();
190        assert_eq!(4000000, len);
191
192        let mut out_buf = std::ptr::null_mut();
193        unsafe {
194            let l = WebPEncodeLosslessRGBA(buf.as_ptr(), 1000, 1000, 1000 * 4, &mut out_buf);
195            let out = slice::from_raw_parts(out_buf, l);
196
197            assert_eq!(b"RIFF", &out[0..4]);
198            assert_eq!(b"WEBP", &out[8..12]);
199        }
200    }
201
202    #[test]
203    fn test_webp_encode() {
204        let mut buf = Vec::new();
205        let len = File::open("./tests/test1_1000x1000.bif")
206            .unwrap()
207            .read_to_end(&mut buf)
208            .unwrap();
209        assert_eq!(4000000, len);
210
211        let mut out_buf = std::ptr::null_mut();
212        unsafe {
213            let l = WebPEncodeRGBA(buf.as_ptr(), 1000, 1000, 1000 * 4, 90_f32, &mut out_buf);
214            let out = slice::from_raw_parts(out_buf, l);
215
216            assert_eq!(b"RIFF", &out[0..4]);
217            assert_eq!(b"WEBP", &out[8..12]);
218        }
219    }
220
221    #[test]
222    fn test_webp_encode_advanced() {
223        use std::ffi::c_void;
224
225        let mut buf = Vec::new();
226        let len = File::open("./tests/test1_1000x1000.bif")
227            .unwrap()
228            .read_to_end(&mut buf)
229            .unwrap();
230        assert_eq!(4000000, len);
231
232        unsafe {
233            let config = WebPConfig::new().unwrap();
234            let mut picture = WebPPicture::new().unwrap();
235            picture.use_argb = 1;
236            picture.argb = buf.as_ptr() as *mut u32;
237            picture.width = 1000;
238            picture.height = 1000;
239            picture.argb_stride = 1000;
240
241            let mut out = vec![];
242
243            unsafe extern "C" fn writer_function(
244                data: *const u8,
245                data_size: usize,
246                picture: *const WebPPicture,
247            ) -> ::std::ffi::c_int {
248                unsafe {
249                    let out: &mut Vec<u8> = &mut *((*picture).custom_ptr as *mut std::vec::Vec<u8>);
250                    out.extend_from_slice(std::slice::from_raw_parts(data, data_size));
251                }
252                0
253            }
254
255            picture.writer = Some(writer_function);
256            picture.custom_ptr = &mut out as *mut _ as *mut c_void;
257
258            assert_eq!(WebPEncode(&config, &mut picture), 0);
259
260            assert_eq!(b"RIFF", &out[0..4]);
261            assert_eq!(b"WEBP", &out[8..12]);
262        }
263    }
264
265    #[test]
266    fn test_webp_decode() {
267        let mut buf = Vec::new();
268        let len = File::open("./tests/test1.webp")
269            .unwrap()
270            .read_to_end(&mut buf)
271            .unwrap();
272        let mut width = 0;
273        let mut height = 0;
274
275        unsafe {
276            WebPGetInfo(buf.as_ptr(), len, &mut width, &mut height);
277            assert!(width == 1000);
278            assert!(height == 1000);
279
280            let decode_buf = WebPDecodeRGBA(buf.as_ptr(), len, &mut width, &mut height);
281
282            let mut out_buf = std::ptr::null_mut();
283            let l = WebPEncodeRGBA(decode_buf, width, height, width * 4, 90_f32, &mut out_buf);
284            let out = slice::from_raw_parts(out_buf, l);
285
286            assert_eq!(b"RIFF", &out[0..4]);
287            assert_eq!(b"WEBP", &out[8..12]);
288        }
289    }
290
291    #[test]
292    fn config_debug() {
293        let _ = format!("{:?}", WebPDecoderConfig::new().unwrap());
294    }
295
296    #[test]
297    fn poke() {
298        unsafe {
299            assert_eq!(67072, WebPGetEncoderVersion());
300
301            let mut data = ::std::ptr::null_mut();
302            let rgb = [1u8, 2, 3];
303            // `stride` corresponds to the number of bytes needed to jump from one row to the next.
304            // For RGB, this is 3 * width.
305            // For RGBA, this is 4 * width.
306            let size = WebPEncodeRGB(rgb.as_ptr(), 1, 1, 3, 50., &mut data);
307            assert!(size > 0);
308            assert!(!data.is_null());
309            let mut w = 0;
310            let mut h = 0;
311            let decoded = WebPDecodeRGBA(data, size, &mut w, &mut h);
312            assert_eq!(1, w);
313            assert_eq!(1, h);
314            assert!(!decoded.is_null());
315            WebPFree(data as *mut _);
316            WebPFree(decoded as *mut _);
317        }
318    }
319
320    #[test]
321    fn test_decode_anim() {
322        let mut buf = Vec::new();
323        let len = File::open("./tests/test_anim.webp")
324            .unwrap()
325            .read_to_end(&mut buf)
326            .unwrap();
327
328        unsafe {
329            let mut width = 0;
330            let mut height = 0;
331            WebPGetInfo(buf.as_ptr(), len, &mut width, &mut height);
332            assert!(width == 400);
333            assert!(height == 400);
334
335            let data = WebPData {
336                bytes: buf.as_ptr(),
337                size: len,
338            };
339
340            let mut options = std::mem::zeroed();
341            // WebPAnimDecoderOptionsInitInternal(&mut options, WebPGetDemuxABIVersion());
342            // let decoder = WebPAnimDecoderNewInternal(&data, &options, WebPGetDemuxABIVersion());
343            WebPAnimDecoderOptionsInit(&mut options);
344            let decoder = WebPAnimDecoderNew(&data, &options);
345
346            let mut anim_info = WebPAnimInfo::default();
347            WebPAnimDecoderGetInfo(decoder, &mut anim_info);
348
349            while WebPAnimDecoderHasMoreFrames(decoder) > 0 {
350                let mut frame_buf = std::ptr::null_mut();
351                let mut timestamp = 0;
352                WebPAnimDecoderGetNext(decoder, &mut frame_buf as *mut *mut u8, &mut timestamp);
353            }
354
355            WebPAnimDecoderDelete(decoder);
356        }
357    }
358}