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#[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 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 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}