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
13pub struct WebPDecoder<R> {
17 inner: image_webp::WebPDecoder<R>,
18 orientation: Option<Orientation>,
19}
20
21impl<R: BufRead + Seek> WebPDecoder<R> {
22 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 pub fn has_animation(&self) -> bool {
32 self.inner.is_animated()
33 }
34
35 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 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}