/src/image/src/codecs/webp/decoder.rs
Line | Count | Source |
1 | | use std::io::{BufRead, Read, Seek}; |
2 | | |
3 | | use crate::buffer::ConvertBuffer; |
4 | | use crate::error::{DecodingError, ImageError, ImageResult}; |
5 | | use crate::metadata::Orientation; |
6 | | use crate::{ |
7 | | AnimationDecoder, ColorType, Delay, Frame, Frames, ImageDecoder, ImageFormat, RgbImage, Rgba, |
8 | | RgbaImage, |
9 | | }; |
10 | | |
11 | | /// WebP Image format decoder. |
12 | | /// |
13 | | /// Supports both lossless and lossy WebP images. |
14 | | pub struct WebPDecoder<R> { |
15 | | inner: image_webp::WebPDecoder<R>, |
16 | | orientation: Option<Orientation>, |
17 | | } |
18 | | |
19 | | impl<R: BufRead + Seek> WebPDecoder<R> { |
20 | | /// Create a new `WebPDecoder` from the Reader `r`. |
21 | 4.24k | pub fn new(r: R) -> ImageResult<Self> { |
22 | | Ok(Self { |
23 | 4.24k | inner: image_webp::WebPDecoder::new(r).map_err(ImageError::from_webp_decode)?, |
24 | 4.12k | orientation: None, |
25 | | }) |
26 | 4.24k | } |
27 | | |
28 | | /// Returns true if the image as described by the bitstream is animated. |
29 | 0 | pub fn has_animation(&self) -> bool { |
30 | 0 | self.inner.is_animated() |
31 | 0 | } |
32 | | |
33 | | /// Sets the background color if the image is an extended and animated webp. |
34 | 0 | pub fn set_background_color(&mut self, color: Rgba<u8>) -> ImageResult<()> { |
35 | 0 | self.inner |
36 | 0 | .set_background_color(color.0) |
37 | 0 | .map_err(ImageError::from_webp_decode) |
38 | 0 | } |
39 | | } |
40 | | |
41 | | impl<R: BufRead + Seek> ImageDecoder for WebPDecoder<R> { |
42 | 20.6k | fn dimensions(&self) -> (u32, u32) { |
43 | 20.6k | self.inner.dimensions() |
44 | 20.6k | } |
45 | | |
46 | 16.4k | fn color_type(&self) -> ColorType { |
47 | 16.4k | if self.inner.has_alpha() { |
48 | 11.3k | ColorType::Rgba8 |
49 | | } else { |
50 | 5.09k | ColorType::Rgb8 |
51 | | } |
52 | 16.4k | } |
53 | | |
54 | 4.12k | fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> { |
55 | 4.12k | assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes())); |
56 | | |
57 | 4.12k | self.inner |
58 | 4.12k | .read_image(buf) |
59 | 4.12k | .map_err(ImageError::from_webp_decode) |
60 | 4.12k | } |
61 | | |
62 | 4.12k | fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> { |
63 | 4.12k | (*self).read_image(buf) |
64 | 4.12k | } |
65 | | |
66 | 0 | fn icc_profile(&mut self) -> ImageResult<Option<Vec<u8>>> { |
67 | 0 | self.inner |
68 | 0 | .icc_profile() |
69 | 0 | .map_err(ImageError::from_webp_decode) |
70 | 0 | } |
71 | | |
72 | 0 | fn exif_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> { |
73 | 0 | let exif = self |
74 | 0 | .inner |
75 | 0 | .exif_metadata() |
76 | 0 | .map_err(ImageError::from_webp_decode)?; |
77 | | |
78 | | self.orientation = Some( |
79 | 0 | exif.as_ref() |
80 | 0 | .and_then(|exif| Orientation::from_exif_chunk(exif)) |
81 | 0 | .unwrap_or(Orientation::NoTransforms), |
82 | | ); |
83 | | |
84 | 0 | Ok(exif) |
85 | 0 | } |
86 | | |
87 | 0 | fn xmp_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> { |
88 | 0 | self.inner |
89 | 0 | .xmp_metadata() |
90 | 0 | .map_err(ImageError::from_webp_decode) |
91 | 0 | } |
92 | | |
93 | 0 | fn orientation(&mut self) -> ImageResult<Orientation> { |
94 | | // `exif_metadata` caches the orientation, so call it if `orientation` hasn't been set yet. |
95 | 0 | if self.orientation.is_none() { |
96 | 0 | let _ = self.exif_metadata()?; |
97 | 0 | } |
98 | 0 | Ok(self.orientation.unwrap()) |
99 | 0 | } |
100 | | } |
101 | | |
102 | | impl<'a, R: 'a + BufRead + Seek> AnimationDecoder<'a> for WebPDecoder<R> { |
103 | 0 | 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 | 0 | fn next(&mut self) -> Option<Self::Item> { |
112 | 0 | if self.current == self.decoder.inner.num_frames() { |
113 | 0 | return None; |
114 | 0 | } |
115 | 0 | self.current += 1; |
116 | 0 | let (width, height) = self.decoder.inner.dimensions(); |
117 | | |
118 | 0 | let (img, delay) = if self.decoder.inner.has_alpha() { |
119 | 0 | let mut img = RgbaImage::new(width, height); |
120 | 0 | match self.decoder.inner.read_frame(&mut img) { |
121 | 0 | Ok(delay) => (img, delay), |
122 | 0 | Err(image_webp::DecodingError::NoMoreFrames) => return None, |
123 | 0 | Err(e) => return Some(Err(ImageError::from_webp_decode(e))), |
124 | | } |
125 | | } else { |
126 | 0 | let mut img = RgbImage::new(width, height); |
127 | 0 | match self.decoder.inner.read_frame(&mut img) { |
128 | 0 | Ok(delay) => (img.convert(), delay), |
129 | 0 | Err(image_webp::DecodingError::NoMoreFrames) => return None, |
130 | 0 | Err(e) => return Some(Err(ImageError::from_webp_decode(e))), |
131 | | } |
132 | | }; |
133 | | |
134 | 0 | Some(Ok(Frame::from_parts( |
135 | 0 | img, |
136 | 0 | 0, |
137 | 0 | 0, |
138 | 0 | Delay::from_numer_denom_ms(delay, 1), |
139 | 0 | ))) |
140 | 0 | } |
141 | | } |
142 | | |
143 | 0 | Frames::new(Box::new(FramesInner { |
144 | 0 | decoder: self, |
145 | 0 | current: 0, |
146 | 0 | })) |
147 | 0 | } |
148 | | } |
149 | | |
150 | | impl ImageError { |
151 | 1.92k | fn from_webp_decode(e: image_webp::DecodingError) -> Self { |
152 | 1.92k | match e { |
153 | 111 | image_webp::DecodingError::IoError(e) => ImageError::IoError(e), |
154 | 1.81k | _ => ImageError::Decoding(DecodingError::new(ImageFormat::WebP.into(), e)), |
155 | | } |
156 | 1.92k | } |
157 | | } |
158 | | |
159 | | #[cfg(test)] |
160 | | mod 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 | | } |