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