/src/image/src/codecs/webp/decoder.rs
Line | Count | Source |
1 | | use std::io::{BufRead, Seek}; |
2 | | |
3 | | use image_webp::LoopCount; |
4 | | |
5 | | use crate::error::{DecodingError, ImageError, ImageResult, ParameterError, ParameterErrorKind}; |
6 | | use crate::io::{ |
7 | | DecodedAnimationAttributes, DecodedImageAttributes, DecodedMetadataHint, DecoderPreparedImage, |
8 | | FormatAttributes, SequenceControl, |
9 | | }; |
10 | | use crate::{ColorType, Delay, ImageDecoder, ImageFormat, Rgba}; |
11 | | |
12 | | /// WebP Image format decoder. |
13 | | /// |
14 | | /// Supports both lossless and lossy WebP images. |
15 | | pub struct WebPDecoder<R> { |
16 | | inner: image_webp::WebPDecoder<R>, |
17 | | current: u32, |
18 | | } |
19 | | |
20 | | impl<R: BufRead + Seek> WebPDecoder<R> { |
21 | | /// Create a new `WebPDecoder` from the Reader `r`. |
22 | 9.44k | pub fn new(r: R) -> ImageResult<Self> { |
23 | | Ok(Self { |
24 | 9.44k | inner: image_webp::WebPDecoder::new(r).map_err(ImageError::from_webp_decode)?, |
25 | | current: 0, |
26 | | }) |
27 | 9.44k | } |
28 | | |
29 | | /// Returns true if the image as described by the bitstream is animated. |
30 | 0 | pub fn has_animation(&self) -> bool { |
31 | 0 | self.inner.is_animated() |
32 | 0 | } |
33 | | |
34 | | /// Sets the background color if the image is an extended and animated webp. |
35 | 0 | pub fn set_background_color(&mut self, color: Rgba<u8>) -> ImageResult<()> { |
36 | 0 | self.inner |
37 | 0 | .set_background_color(color.0) |
38 | 0 | .map_err(ImageError::from_webp_decode) |
39 | 0 | } |
40 | | } |
41 | | |
42 | | impl<R: BufRead + Seek> ImageDecoder for WebPDecoder<R> { |
43 | 15.9k | fn format_attributes(&self) -> FormatAttributes { |
44 | 15.9k | FormatAttributes { |
45 | 15.9k | // As per extended file format description: |
46 | 15.9k | // <https://developers.google.com/speed/webp/docs/riff_container#extended_file_format> |
47 | 15.9k | icc: DecodedMetadataHint::InHeader, |
48 | 15.9k | exif: DecodedMetadataHint::InHeader, |
49 | 15.9k | xmp: DecodedMetadataHint::InHeader, |
50 | 15.9k | ..FormatAttributes::default() |
51 | 15.9k | } |
52 | 15.9k | } |
53 | | |
54 | 0 | fn animation_attributes(&mut self) -> Option<DecodedAnimationAttributes> { |
55 | 0 | let loop_count = match self.inner.loop_count() { |
56 | 0 | LoopCount::Forever => crate::metadata::LoopCount::Infinite, |
57 | 0 | LoopCount::Times(n) => crate::metadata::LoopCount::Finite(n.into()), |
58 | | }; |
59 | | |
60 | 0 | Some(DecodedAnimationAttributes { loop_count }) |
61 | 0 | } |
62 | | |
63 | 34.7k | fn prepare_image(&mut self) -> ImageResult<DecoderPreparedImage> { |
64 | 34.7k | let (width, height) = self.inner.dimensions(); |
65 | 34.7k | let color = if self.inner.has_alpha() { |
66 | 16.2k | ColorType::Rgba8 |
67 | | } else { |
68 | 18.5k | ColorType::Rgb8 |
69 | | }; |
70 | | |
71 | 34.7k | Ok(DecoderPreparedImage::new(width, height, color)) |
72 | 34.7k | } |
73 | | |
74 | 8.66k | fn read_image(&mut self, buf: &mut [u8]) -> ImageResult<DecodedImageAttributes> { |
75 | 8.66k | let is_animated = self.inner.is_animated(); |
76 | | |
77 | 8.66k | if is_animated && self.current == self.inner.num_frames() { |
78 | 0 | return Err(ImageError::Parameter(ParameterError::from_kind( |
79 | 0 | ParameterErrorKind::NoMoreData, |
80 | 0 | ))); |
81 | 8.66k | } |
82 | | |
83 | 8.66k | let layout = self.prepare_image()?; |
84 | 8.66k | assert_eq!(u64::try_from(buf.len()), Ok(layout.total_bytes())); |
85 | | |
86 | | // `read_frame` panics if the image is not animated. |
87 | 8.66k | let delay = if is_animated { |
88 | 1.50k | let delay = self |
89 | 1.50k | .inner |
90 | 1.50k | .read_frame(buf) |
91 | 1.50k | .map_err(ImageError::from_webp_decode)?; |
92 | 205 | Some(Delay::from_millis(delay)) |
93 | | } else { |
94 | 7.16k | self.inner |
95 | 7.16k | .read_image(buf) |
96 | 7.16k | .map_err(ImageError::from_webp_decode)?; |
97 | 3.39k | None |
98 | | }; |
99 | | |
100 | 3.60k | self.current += 1; |
101 | | |
102 | 3.60k | Ok(DecodedImageAttributes { |
103 | 3.60k | delay, |
104 | 3.60k | ..DecodedImageAttributes::default() |
105 | 3.60k | }) |
106 | 8.66k | } |
107 | | |
108 | 8.71k | fn icc_profile(&mut self) -> ImageResult<Option<Vec<u8>>> { |
109 | 8.71k | self.inner |
110 | 8.71k | .icc_profile() |
111 | 8.71k | .map_err(ImageError::from_webp_decode) |
112 | 8.71k | } |
113 | | |
114 | 8.71k | fn exif_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> { |
115 | 8.71k | let exif = self |
116 | 8.71k | .inner |
117 | 8.71k | .exif_metadata() |
118 | 8.71k | .map_err(ImageError::from_webp_decode)?; |
119 | | |
120 | 8.67k | Ok(exif) |
121 | 8.71k | } |
122 | | |
123 | 8.71k | fn xmp_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> { |
124 | 8.71k | self.inner |
125 | 8.71k | .xmp_metadata() |
126 | 8.71k | .map_err(ImageError::from_webp_decode) |
127 | 8.71k | } |
128 | | |
129 | 0 | fn more_images(&self) -> SequenceControl { |
130 | 0 | if self.current == self.inner.num_frames() { |
131 | 0 | SequenceControl::None |
132 | | } else { |
133 | 0 | SequenceControl::MaybeMore |
134 | | } |
135 | 0 | } |
136 | | } |
137 | | |
138 | | impl ImageError { |
139 | 5.85k | fn from_webp_decode(e: image_webp::DecodingError) -> Self { |
140 | 5.85k | match e { |
141 | 491 | image_webp::DecodingError::IoError(e) => ImageError::IoError(e), |
142 | | image_webp::DecodingError::NoMoreFrames => { |
143 | 0 | ImageError::Parameter(ParameterError::from_kind(ParameterErrorKind::NoMoreData)) |
144 | | } |
145 | 5.35k | _ => ImageError::Decoding(DecodingError::new(ImageFormat::WebP.into(), e)), |
146 | | } |
147 | 5.85k | } |
148 | | } |
149 | | |
150 | | #[cfg(test)] |
151 | | mod tests { |
152 | | use super::*; |
153 | | |
154 | | #[test] |
155 | | fn add_with_overflow_size() { |
156 | | let bytes = vec![ |
157 | | 0x52, 0x49, 0x46, 0x46, 0xaf, 0x37, 0x80, 0x47, 0x57, 0x45, 0x42, 0x50, 0x6c, 0x64, |
158 | | 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x7e, 0x73, 0x00, 0x06, 0x00, 0x00, 0x00, |
159 | | 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, |
160 | | 0x40, 0xfb, 0xff, 0xff, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, |
161 | | 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, |
162 | | 0x49, 0x54, 0x55, 0x50, 0x4c, 0x54, 0x59, 0x50, 0x45, 0x33, 0x37, 0x44, 0x4d, 0x46, |
163 | | ]; |
164 | | |
165 | | let data = std::io::Cursor::new(bytes); |
166 | | |
167 | | let _ = WebPDecoder::new(data); |
168 | | } |
169 | | } |