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