1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use libwebp_sys::*;

use crate::shared::PixelLayout;
use crate::AnimFrame;

pub struct AnimDecoder<'a> {
    data: &'a [u8],
}
impl<'a> AnimDecoder<'a> {
    pub fn new(data: &'a [u8]) -> Self {
        Self { data }
    }
    pub fn decode(&self) -> Result<DecodeAnimImage, String> {
        unsafe { self.decode_internal(true) }
    }
    unsafe fn decode_internal(&self, mut has_alpha: bool) -> Result<DecodeAnimImage, String> {
        let mut dec_options: WebPAnimDecoderOptions = std::mem::zeroed();
        dec_options.color_mode = if has_alpha {
            WEBP_CSP_MODE::MODE_RGBA
        } else {
            WEBP_CSP_MODE::MODE_RGB
        };
        let ok = WebPAnimDecoderOptionsInitInternal(&mut dec_options, WebPGetDemuxABIVersion());
        if ok == 0 {
            return Err(String::from("option init error"));
        }
        match dec_options.color_mode {
            WEBP_CSP_MODE::MODE_RGBA | WEBP_CSP_MODE::MODE_RGB => {}
            _ => return Err(String::from("unsupport color mode")),
        }
        has_alpha = dec_options.color_mode == WEBP_CSP_MODE::MODE_RGBA;
        let webp_data = WebPData {
            bytes: self.data.as_ptr(),
            size: self.data.len(),
        };
        let dec = WebPAnimDecoderNewInternal(&webp_data, &dec_options, WebPGetDemuxABIVersion());
        if dec.is_null() {
            return Err(String::from("null_decoder"));
        }
        let mut anim_info: WebPAnimInfo = std::mem::zeroed();
        let ok = WebPAnimDecoderGetInfo(dec, &mut anim_info);
        if ok == 0 {
            return Err(String::from("null info"));
        }
        let width = anim_info.canvas_width;
        let height = anim_info.canvas_height;
        let mut list: Vec<DecodeAnimFrame> = vec![];
        while WebPAnimDecoderHasMoreFrames(dec) > 0 {
            let mut buf: *mut u8 = std::ptr::null_mut();
            let mut timestamp: std::os::raw::c_int = 0;
            let ok = WebPAnimDecoderGetNext(dec, &mut buf, &mut timestamp);
            if ok != 0 {
                let len = (if has_alpha { 4 } else { 3 } * width * height) as usize;
                let mut img = Vec::with_capacity(len);
                img.set_len(len);
                buf.copy_to(img.as_mut_ptr(), len);
                let layout = if has_alpha {
                    PixelLayout::Rgba
                } else {
                    PixelLayout::Rgb
                };
                let frame = DecodeAnimFrame {
                    img,
                    width,
                    height,
                    layout,
                    timestamp,
                };
                list.push(frame);
            }
        }
        WebPAnimDecoderReset(dec);
        //let demuxer:WebPDemuxer=WebPAnimDecoderGetDemuxer(dec);
        // ... (Do something using 'demuxer'; e.g. get EXIF/XMP/ICC data).
        WebPAnimDecoderDelete(dec);
        let mut anim = DecodeAnimImage::from(list);
        anim.loop_count = anim_info.loop_count;
        anim.bg_color = anim_info.bgcolor;
        Ok(anim)
    }
}
struct DecodeAnimFrame {
    img: Vec<u8>,
    width: u32,
    height: u32,
    layout: PixelLayout,
    timestamp: i32,
}
pub struct DecodeAnimImage {
    frames: Vec<DecodeAnimFrame>,
    pub loop_count: u32,
    pub bg_color: u32,
}
impl From<Vec<DecodeAnimFrame>> for DecodeAnimImage {
    fn from(frames: Vec<DecodeAnimFrame>) -> Self {
        DecodeAnimImage {
            frames,
            loop_count: 0,
            bg_color: 0,
        }
    }
}
impl DecodeAnimImage {
    #[inline]
    pub fn get_frame(&self, index: usize) -> Option<AnimFrame> {
        let f = self.frames.get(index)?;
        Some(AnimFrame::new(
            &f.img,
            f.layout,
            f.width,
            f.height,
            f.timestamp,
            None,
        ))
    }
    #[inline]
    pub fn get_frames(&self, index: core::ops::Range<usize>) -> Option<Vec<AnimFrame>> {
        let dec_frames = self.frames.get(index)?;
        let mut frames = Vec::with_capacity(dec_frames.len());
        for f in dec_frames {
            frames.push(AnimFrame::new(
                &f.img,
                f.layout,
                f.width,
                f.height,
                f.timestamp,
                None,
            ));
        }
        Some(frames)
    }
    pub fn len(&self) -> usize {
        self.frames.len()
    }
    pub fn has_animation(&self) -> bool {
        self.len() > 1
    }
    pub fn sort_by_time_stamp(&mut self) {
        self.frames.sort_by(|a, b| a.timestamp.cmp(&b.timestamp));
    }
}
impl<'a> IntoIterator for &'a DecodeAnimImage {
    type Item = AnimFrame<'a>;
    type IntoIter = std::vec::IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        let fs = self.get_frames(0..self.frames.len());
        if let Some(v) = fs {
            v.into_iter()
        } else {
            vec![].into_iter()
        }
    }
}