1use std::io::Cursor;
6use std::sync::Arc;
7use std::time::Duration;
8use std::{cmp, fmt, vec};
9
10use image::codecs::{bmp, gif, ico, jpeg, png, webp};
11use image::error::ImageFormatHint;
12use image::metadata::LoopCount;
13use image::{
14 AnimationDecoder, DynamicImage, ImageDecoder, ImageError, ImageFormat, ImageResult, Limits,
15};
16use log::debug;
17
18use crate::{
19 CorsStatus, ImageFrame, ImageMetadata, PixelFormat, RasterImage, Repeat,
20 rgba8_premultiply_inplace,
21};
22
23enum GenericImageDecoder<'a> {
24 Apng(Box<png::ApngDecoder<Cursor<&'a [u8]>>>),
25 Png(Box<png::PngDecoder<Cursor<&'a [u8]>>>),
26 Gif(Box<gif::GifDecoder<Cursor<&'a [u8]>>>),
27 Webp(Box<webp::WebPDecoder<Cursor<&'a [u8]>>>),
28 Jpeg(Box<jpeg::JpegDecoder<Cursor<&'a [u8]>>>),
29 Bmp(Box<bmp::BmpDecoder<Cursor<&'a [u8]>>>),
30 Ico(Box<ico::IcoDecoder<Cursor<&'a [u8]>>>),
31}
32
33impl<'a> std::fmt::Debug for GenericImageDecoder<'a> {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 match self {
36 Self::Apng(_) => f.debug_tuple("Apng").finish(),
37 Self::Png(_) => f.debug_tuple("Png").finish(),
38 Self::Gif(_) => f.debug_tuple("Gif").finish(),
39 Self::Webp(_) => f.debug_tuple("Webp").finish(),
40 Self::Jpeg(_) => f.debug_tuple("Jpeg").finish(),
41 Self::Bmp(_) => f.debug_tuple("Bmp").finish(),
42 Self::Ico(_) => f.debug_tuple("Ico").finish(),
43 }
44 }
45}
46
47impl<'a> image::ImageDecoder for GenericImageDecoder<'a> {
50 fn dimensions(&self) -> (u32, u32) {
51 match self {
52 GenericImageDecoder::Apng(_) => {
53 unreachable!("Animated image should never go into non-animated values")
54 },
55 GenericImageDecoder::Png(d) => d.dimensions(),
56 GenericImageDecoder::Gif(d) => d.dimensions(),
57 GenericImageDecoder::Webp(d) => d.dimensions(),
58 GenericImageDecoder::Jpeg(d) => d.dimensions(),
59 GenericImageDecoder::Bmp(d) => d.dimensions(),
60 GenericImageDecoder::Ico(d) => d.dimensions(),
61 }
62 }
63
64 fn color_type(&self) -> image::ColorType {
65 match self {
66 GenericImageDecoder::Apng(_) => {
67 unreachable!("Animated image should never go into non-animated values")
68 },
69 GenericImageDecoder::Png(d) => d.color_type(),
70 GenericImageDecoder::Gif(d) => d.color_type(),
71 GenericImageDecoder::Webp(d) => d.color_type(),
72 GenericImageDecoder::Jpeg(d) => d.color_type(),
73 GenericImageDecoder::Bmp(d) => d.color_type(),
74 GenericImageDecoder::Ico(d) => d.color_type(),
75 }
76 }
77
78 fn read_image(self, buf: &mut [u8]) -> ImageResult<()>
79 where
80 Self: Sized,
81 {
82 match self {
83 GenericImageDecoder::Apng(_) => {
84 unreachable!("Animated image should never go into non-animated values")
85 },
86 GenericImageDecoder::Png(d) => d.read_image(buf),
87 GenericImageDecoder::Gif(d) => d.read_image(buf),
88 GenericImageDecoder::Webp(d) => d.read_image(buf),
89 GenericImageDecoder::Jpeg(d) => d.read_image(buf),
90 GenericImageDecoder::Bmp(d) => d.read_image(buf),
91 GenericImageDecoder::Ico(d) => d.read_image(buf),
92 }
93 }
94
95 fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
96 match *self {
97 GenericImageDecoder::Apng(_) => {
98 unreachable!("Animated image should never go into non-animated values")
99 },
100 GenericImageDecoder::Png(d) => d.read_image_boxed(buf),
101 GenericImageDecoder::Gif(d) => d.read_image_boxed(buf),
102 GenericImageDecoder::Webp(d) => d.read_image_boxed(buf),
103 GenericImageDecoder::Jpeg(d) => d.read_image_boxed(buf),
104 GenericImageDecoder::Bmp(d) => d.read_image_boxed(buf),
105 GenericImageDecoder::Ico(d) => d.read_image_boxed(buf),
106 }
107 }
108
109 fn icc_profile(&mut self) -> ImageResult<Option<Vec<u8>>> {
110 match self {
111 GenericImageDecoder::Apng(_) => {
112 unreachable!("Animated image should never go into non-animated values")
113 },
114 GenericImageDecoder::Png(d) => d.icc_profile(),
115 GenericImageDecoder::Gif(d) => d.icc_profile(),
116 GenericImageDecoder::Webp(d) => d.icc_profile(),
117 GenericImageDecoder::Jpeg(d) => d.icc_profile(),
118 GenericImageDecoder::Bmp(d) => d.icc_profile(),
119 GenericImageDecoder::Ico(d) => d.icc_profile(),
120 }
121 }
122
123 fn exif_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
124 match self {
125 GenericImageDecoder::Apng(_) => {
126 unreachable!("Animated image should never go into non-animated values")
127 },
128 GenericImageDecoder::Png(d) => d.exif_metadata(),
129 GenericImageDecoder::Gif(d) => d.exif_metadata(),
130 GenericImageDecoder::Webp(d) => d.exif_metadata(),
131 GenericImageDecoder::Jpeg(d) => d.exif_metadata(),
132 GenericImageDecoder::Bmp(d) => d.exif_metadata(),
133 GenericImageDecoder::Ico(d) => d.exif_metadata(),
134 }
135 }
136
137 fn xmp_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
138 match self {
139 GenericImageDecoder::Apng(_) => {
140 unreachable!("Animated image should never go into non-animated values")
141 },
142 GenericImageDecoder::Png(d) => d.xmp_metadata(),
143 GenericImageDecoder::Gif(d) => d.xmp_metadata(),
144 GenericImageDecoder::Webp(d) => d.xmp_metadata(),
145 GenericImageDecoder::Jpeg(d) => d.xmp_metadata(),
146 GenericImageDecoder::Bmp(d) => d.xmp_metadata(),
147 GenericImageDecoder::Ico(d) => d.xmp_metadata(),
148 }
149 }
150
151 fn iptc_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
152 match self {
153 GenericImageDecoder::Apng(_) => {
154 unreachable!("Animated image should never go into non-animated values")
155 },
156 GenericImageDecoder::Png(d) => d.iptc_metadata(),
157 GenericImageDecoder::Gif(d) => d.iptc_metadata(),
158 GenericImageDecoder::Webp(d) => d.iptc_metadata(),
159 GenericImageDecoder::Jpeg(d) => d.iptc_metadata(),
160 GenericImageDecoder::Bmp(d) => d.iptc_metadata(),
161 GenericImageDecoder::Ico(d) => d.iptc_metadata(),
162 }
163 }
164}
165
166impl<'a> AnimationDecoder<'a> for GenericImageDecoder<'a> {
168 fn into_frames(self) -> image::Frames<'a> {
169 match self {
170 GenericImageDecoder::Apng(decoder) => decoder.into_frames(),
171 GenericImageDecoder::Gif(decoder) => decoder.into_frames(),
172 GenericImageDecoder::Webp(decoder) => decoder.into_frames(),
173 _ => unreachable!("Should never decode these images with animated decoder"),
174 }
175 }
176
177 fn loop_count(&self) -> LoopCount {
178 match self {
179 GenericImageDecoder::Apng(decoder) => decoder.loop_count(),
180 GenericImageDecoder::Gif(decoder) => decoder.loop_count(),
181 GenericImageDecoder::Webp(decoder) => decoder.loop_count(),
182 _ => unreachable!("Should never decode these images with animated decoder"),
183 }
184 }
185}
186
187#[derive(Debug)]
188pub(crate) struct DefaultImageDecoder<'a> {
190 decoder: GenericImageDecoder<'a>,
191}
192
193pub(crate) trait ServoImageDecoder<'a>: Sized + std::fmt::Debug {
195 fn make_decoder(format: ImageFormat, buffer: &'a [u8]) -> ImageResult<Self>;
197 fn is_animated(&self) -> bool;
198 fn decoder(self) -> impl ImageDecoder;
200 fn animated_decoder(self) -> impl AnimationDecoder<'a>;
202}
203
204impl<'a> ServoImageDecoder<'a> for DefaultImageDecoder<'a> {
205 fn make_decoder(format: ImageFormat, buffer: &'a [u8]) -> ImageResult<Self> {
206 let reader = Cursor::new(buffer);
207 let decoder = match format {
208 ImageFormat::Png => {
209 let limits = Limits::default();
210 let png_decoder = png::PngDecoder::with_limits(reader, limits)?;
211 if png_decoder.is_apng().unwrap_or_default() {
212 let decoder = png_decoder.apng()?;
213 GenericImageDecoder::Apng(Box::new(decoder))
214 } else {
215 GenericImageDecoder::Png(Box::new(png_decoder))
216 }
217 },
218 ImageFormat::Gif => GenericImageDecoder::Gif(Box::new(gif::GifDecoder::new(reader)?)),
219 ImageFormat::WebP => {
220 GenericImageDecoder::Webp(Box::new(webp::WebPDecoder::new(reader)?))
221 },
222 ImageFormat::Jpeg => {
223 GenericImageDecoder::Jpeg(Box::new(jpeg::JpegDecoder::new(reader)?))
224 },
225 ImageFormat::Bmp => GenericImageDecoder::Bmp(Box::new(bmp::BmpDecoder::new(reader)?)),
226 ImageFormat::Ico => GenericImageDecoder::Ico(Box::new(ico::IcoDecoder::new(reader)?)),
227 _ => {
228 return Err(ImageError::Unsupported(
229 ImageFormatHint::Exact(format).into(),
230 ));
231 },
232 };
233 Ok(DefaultImageDecoder { decoder })
234 }
235
236 fn is_animated(&self) -> bool {
237 match &self.decoder {
238 GenericImageDecoder::Apng(_) | GenericImageDecoder::Gif(_) => true,
239 GenericImageDecoder::Webp(decoder) => decoder.has_animation(),
240 GenericImageDecoder::Png(_) |
241 GenericImageDecoder::Jpeg(_) |
242 GenericImageDecoder::Bmp(_) |
243 GenericImageDecoder::Ico(_) => false,
244 }
245 }
246
247 fn decoder(self) -> impl ImageDecoder {
248 self.decoder
249 }
250
251 fn animated_decoder(self) -> impl AnimationDecoder<'a> {
252 self.decoder
253 }
254}
255
256pub(crate) fn decode_static_image(
257 cors_status: CorsStatus,
258 mut image_decoder: impl ImageDecoder,
259) -> Option<RasterImage> {
260 let orientation = image_decoder.orientation();
261
262 let Ok(mut dynamic_image) = DynamicImage::from_decoder(image_decoder) else {
263 debug!("Image decoding error");
264 return None;
265 };
266
267 if let Ok(orientation) = orientation {
268 dynamic_image.apply_orientation(orientation);
269 }
270
271 let mut rgba = dynamic_image.into_rgba8();
272
273 let is_opaque = rgba8_premultiply_inplace(&mut rgba);
277
278 let frame = ImageFrame {
279 delay: None,
280 byte_range: 0..rgba.len(),
281 width: rgba.width(),
282 height: rgba.height(),
283 };
284 Some(RasterImage {
285 metadata: ImageMetadata {
286 width: rgba.width(),
287 height: rgba.height(),
288 },
289 format: PixelFormat::RGBA8,
290 frames: vec![frame],
291 bytes: Arc::new(rgba.into_vec()),
292 id: None,
293 cors_status,
294 is_opaque,
295 loop_count: None,
296 })
297}
298
299pub(crate) fn decode_animated_image<'a, T>(
300 cors_status: CorsStatus,
301 animated_image_decoder: T,
302) -> Option<RasterImage>
303where
304 T: AnimationDecoder<'a>,
305{
306 let mut width = 0;
307 let mut height = 0;
308
309 let mut frame_data = vec![];
313 let mut total_number_of_bytes = 0;
314 let mut is_opaque = true;
315 let loop_count = match animated_image_decoder.loop_count() {
316 LoopCount::Finite(repeat_time) => Repeat::Finite(repeat_time),
317 LoopCount::Infinite => Repeat::Infinite,
318 };
319 let frames: Vec<ImageFrame> = animated_image_decoder
320 .into_frames()
321 .map_while(|decoded_frame| {
322 let mut animated_frame = match decoded_frame {
323 Ok(decoded_frame) => decoded_frame,
324 Err(error) => {
325 debug!("decode Animated frame error: {error}");
326 return None;
327 },
328 };
329
330 is_opaque = rgba8_premultiply_inplace(animated_frame.buffer_mut()) && is_opaque;
334
335 let frame_start = total_number_of_bytes;
336 total_number_of_bytes += animated_frame.buffer().len();
337
338 let frame_width = animated_frame.buffer().width();
340 let frame_height = animated_frame.buffer().height();
341 width = cmp::max(width, frame_width);
342 height = cmp::max(height, frame_height);
343
344 let frame = ImageFrame {
345 byte_range: frame_start..total_number_of_bytes,
346 delay: Some(Duration::from(animated_frame.delay())),
347 width: frame_width,
348 height: frame_height,
349 };
350
351 frame_data.push(animated_frame);
352
353 Some(frame)
354 })
355 .collect();
356
357 if frames.is_empty() {
358 debug!("Animated Image decoding error");
359 return None;
360 }
361
362 let mut bytes = Vec::with_capacity(total_number_of_bytes);
364 for frame in frame_data {
365 bytes.extend_from_slice(frame.buffer());
366 }
367
368 Some(RasterImage {
369 metadata: ImageMetadata { width, height },
370 cors_status,
371 frames,
372 id: None,
373 format: PixelFormat::RGBA8,
374 bytes: Arc::new(bytes),
375 is_opaque,
376 loop_count: Some(loop_count),
377 })
378}