Skip to main content

image/codecs/webp/
decoder.rs

1use std::io::{BufRead, Read, Seek};
2
3use image_webp::LoopCount;
4
5use crate::buffer::ConvertBuffer;
6use crate::error::{DecodingError, ImageError, ImageResult};
7use crate::metadata::Orientation;
8use crate::{
9    AnimationDecoder, ColorType, Delay, Frame, Frames, ImageDecoder, ImageFormat, RgbImage, Rgba,
10    RgbaImage,
11};
12
13/// WebP Image format decoder.
14///
15/// Supports both lossless and lossy WebP images.
16pub struct WebPDecoder<R> {
17    inner: image_webp::WebPDecoder<R>,
18    orientation: Option<Orientation>,
19}
20
21impl<R: BufRead + Seek> WebPDecoder<R> {
22    /// Create a new `WebPDecoder` from the Reader `r`.
23    pub fn new(r: R) -> ImageResult<Self> {
24        Ok(Self {
25            inner: image_webp::WebPDecoder::new(r).map_err(ImageError::from_webp_decode)?,
26            orientation: None,
27        })
28    }
29
30    /// Returns true if the image as described by the bitstream is animated.
31    pub fn has_animation(&self) -> bool {
32        self.inner.is_animated()
33    }
34
35    /// Sets the background color if the image is an extended and animated webp.
36    pub fn set_background_color(&mut self, color: Rgba<u8>) -> ImageResult<()> {
37        self.inner
38            .set_background_color(color.0)
39            .map_err(ImageError::from_webp_decode)
40    }
41}
42
43impl<R: BufRead + Seek> ImageDecoder for WebPDecoder<R> {
44    fn dimensions(&self) -> (u32, u32) {
45        self.inner.dimensions()
46    }
47
48    fn color_type(&self) -> ColorType {
49        if self.inner.has_alpha() {
50            ColorType::Rgba8
51        } else {
52            ColorType::Rgb8
53        }
54    }
55
56    fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
57        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
58
59        self.inner
60            .read_image(buf)
61            .map_err(ImageError::from_webp_decode)
62    }
63
64    fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
65        (*self).read_image(buf)
66    }
67
68    fn icc_profile(&mut self) -> ImageResult<Option<Vec<u8>>> {
69        self.inner
70            .icc_profile()
71            .map_err(ImageError::from_webp_decode)
72    }
73
74    fn exif_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
75        let exif = self
76            .inner
77            .exif_metadata()
78            .map_err(ImageError::from_webp_decode)?;
79
80        self.orientation = Some(
81            exif.as_ref()
82                .and_then(|exif| Orientation::from_exif_chunk(exif))
83                .unwrap_or(Orientation::NoTransforms),
84        );
85
86        Ok(exif)
87    }
88
89    fn xmp_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
90        self.inner
91            .xmp_metadata()
92            .map_err(ImageError::from_webp_decode)
93    }
94
95    fn orientation(&mut self) -> ImageResult<Orientation> {
96        // `exif_metadata` caches the orientation, so call it if `orientation` hasn't been set yet.
97        if self.orientation.is_none() {
98            let _ = self.exif_metadata()?;
99        }
100        Ok(self.orientation.unwrap())
101    }
102}
103
104impl<'a, R: 'a + BufRead + Seek> AnimationDecoder<'a> for WebPDecoder<R> {
105    fn loop_count(&self) -> crate::metadata::LoopCount {
106        match self.inner.loop_count() {
107            LoopCount::Forever => crate::metadata::LoopCount::Infinite,
108            LoopCount::Times(n) => crate::metadata::LoopCount::Finite(n.into()),
109        }
110    }
111
112    fn into_frames(self) -> Frames<'a> {
113        struct FramesInner<R: Read + Seek> {
114            decoder: WebPDecoder<R>,
115            current: u32,
116        }
117        impl<R: BufRead + Seek> Iterator for FramesInner<R> {
118            type Item = ImageResult<Frame>;
119
120            fn next(&mut self) -> Option<Self::Item> {
121                if self.current == self.decoder.inner.num_frames() {
122                    return None;
123                }
124                self.current += 1;
125                let (width, height) = self.decoder.inner.dimensions();
126
127                let (img, delay) = if self.decoder.inner.has_alpha() {
128                    let mut img = RgbaImage::new(width, height);
129                    match self.decoder.inner.read_frame(&mut img) {
130                        Ok(delay) => (img, delay),
131                        Err(image_webp::DecodingError::NoMoreFrames) => return None,
132                        Err(e) => return Some(Err(ImageError::from_webp_decode(e))),
133                    }
134                } else {
135                    let mut img = RgbImage::new(width, height);
136                    match self.decoder.inner.read_frame(&mut img) {
137                        Ok(delay) => (img.convert(), delay),
138                        Err(image_webp::DecodingError::NoMoreFrames) => return None,
139                        Err(e) => return Some(Err(ImageError::from_webp_decode(e))),
140                    }
141                };
142
143                Some(Ok(Frame::from_parts(
144                    img,
145                    0,
146                    0,
147                    Delay::from_numer_denom_ms(delay, 1),
148                )))
149            }
150        }
151
152        Frames::new(Box::new(FramesInner {
153            decoder: self,
154            current: 0,
155        }))
156    }
157}
158
159impl ImageError {
160    fn from_webp_decode(e: image_webp::DecodingError) -> Self {
161        match e {
162            image_webp::DecodingError::IoError(e) => ImageError::IoError(e),
163            _ => ImageError::Decoding(DecodingError::new(ImageFormat::WebP.into(), e)),
164        }
165    }
166}
167
168#[cfg(test)]
169mod tests {
170    use super::*;
171
172    #[test]
173    fn add_with_overflow_size() {
174        let bytes = vec![
175            0x52, 0x49, 0x46, 0x46, 0xaf, 0x37, 0x80, 0x47, 0x57, 0x45, 0x42, 0x50, 0x6c, 0x64,
176            0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x7e, 0x73, 0x00, 0x06, 0x00, 0x00, 0x00,
177            0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
178            0x40, 0xfb, 0xff, 0xff, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
179            0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49,
180            0x49, 0x54, 0x55, 0x50, 0x4c, 0x54, 0x59, 0x50, 0x45, 0x33, 0x37, 0x44, 0x4d, 0x46,
181        ];
182
183        let data = std::io::Cursor::new(bytes);
184
185        let _ = WebPDecoder::new(data);
186    }
187}