1#![allow(clippy::while_let_loop)]
29
30use alloc::{borrow::ToOwned, boxed::Box, format, vec, vec::Vec};
31use core::marker::PhantomData;
32use core::mem;
33use core::num::NonZeroU32;
34use no_std_io::io::{self, BufRead, Cursor, Read, Seek, Write};
35
36use gif::ColorOutput;
37use gif::{DisposalMethod, Frame};
38
39use crate::animation::{self, Ratio};
40use crate::color::{ColorType, Rgba};
41use crate::error::{
42 DecodingError, EncodingError, ImageError, ImageResult, LimitError, LimitErrorKind,
43 ParameterError, ParameterErrorKind, UnsupportedError, UnsupportedErrorKind,
44};
45use crate::metadata::LoopCount;
46use crate::traits::Pixel;
47use crate::{
48 AnimationDecoder, ExtendedColorType, ImageBuffer, ImageDecoder, ImageEncoder, ImageFormat,
49 Limits,
50};
51
52pub struct GifDecoder<R: Read> {
54 reader: gif::Decoder<R>,
55 limits: Limits,
56}
57
58impl<R: Read> GifDecoder<R> {
59 pub fn new(r: R) -> ImageResult<GifDecoder<R>> {
61 let mut decoder = gif::DecodeOptions::new();
62 decoder.set_color_output(ColorOutput::RGBA);
63
64 Ok(GifDecoder {
65 reader: decoder.read_info(r).map_err(ImageError::from_decoding)?,
66 limits: Limits::no_limits(),
67 })
68 }
69}
70
71#[allow(dead_code)]
73#[deprecated]
74pub struct GifReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
75#[allow(deprecated)]
76impl<R> Read for GifReader<R> {
77 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
78 self.0.read(buf)
79 }
80
81 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
82 if self.0.position() == 0 && buf.is_empty() {
83 mem::swap(buf, self.0.get_mut());
84 Ok(buf.len())
85 } else {
86 self.0.read_to_end(buf)
87 }
88 }
89}
90
91impl<R: BufRead + Seek> ImageDecoder for GifDecoder<R> {
92 fn dimensions(&self) -> (u32, u32) {
93 (
94 u32::from(self.reader.width()),
95 u32::from(self.reader.height()),
96 )
97 }
98
99 fn color_type(&self) -> ColorType {
100 ColorType::Rgba8
101 }
102
103 fn set_limits(&mut self, limits: Limits) -> ImageResult<()> {
104 limits.check_support(&crate::LimitSupport::default())?;
105
106 let (width, height) = self.dimensions();
107 limits.check_dimensions(width, height)?;
108
109 self.limits = limits;
110
111 Ok(())
112 }
113
114 fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
115 assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
116
117 let frame = match self
118 .reader
119 .next_frame_info()
120 .map_err(ImageError::from_decoding)?
121 {
122 Some(frame) => FrameInfo::new_from_frame(frame),
123 None => {
124 return Err(ImageError::Parameter(ParameterError::from_kind(
125 ParameterErrorKind::NoMoreData,
126 )))
127 }
128 };
129
130 let (width, height) = self.dimensions();
131
132 if frame.left == 0
133 && frame.width == width
134 && (u64::from(frame.top) + u64::from(frame.height) <= u64::from(height))
135 {
136 let line_length = usize::try_from(width)
140 .unwrap()
141 .checked_mul(self.color_type().bytes_per_pixel() as usize)
142 .unwrap();
143
144 let (blank_top, rest) =
147 buf.split_at_mut(line_length.checked_mul(frame.top as usize).unwrap());
148 let (buf, blank_bottom) =
149 rest.split_at_mut(line_length.checked_mul(frame.height as usize).unwrap());
150
151 debug_assert_eq!(buf.len(), self.reader.buffer_size());
152
153 for b in blank_top {
155 *b = 0;
156 }
157 self.reader
159 .read_into_buffer(buf)
160 .map_err(ImageError::from_decoding)?;
161 for b in blank_bottom {
163 *b = 0;
164 }
165 } else {
166 let buffer_size = (frame.width as usize)
169 .checked_mul(frame.height as usize)
170 .and_then(|s| s.checked_mul(4))
171 .ok_or(ImageError::Limits(LimitError::from_kind(
172 LimitErrorKind::InsufficientMemory,
173 )))?;
174
175 self.limits.reserve_usize(buffer_size)?;
176 let mut frame_buffer = vec![0; buffer_size];
177 self.limits.free_usize(buffer_size);
178
179 self.reader
180 .read_into_buffer(&mut frame_buffer[..])
181 .map_err(ImageError::from_decoding)?;
182
183 let frame_buffer = ImageBuffer::from_raw(frame.width, frame.height, frame_buffer);
184 let image_buffer = ImageBuffer::from_raw(width, height, buf);
185
186 if frame_buffer.is_none() || image_buffer.is_none() {
190 return Err(ImageError::Unsupported(
191 UnsupportedError::from_format_and_kind(
192 ImageFormat::Gif.into(),
193 UnsupportedErrorKind::GenericFeature(format!(
194 "Image dimensions ({}, {}) are too large",
195 frame.width, frame.height
196 )),
197 ),
198 ));
199 }
200
201 let frame_buffer = frame_buffer.unwrap();
202 let mut image_buffer = image_buffer.unwrap();
203
204 for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
205 let frame_x = x.wrapping_sub(frame.left);
206 let frame_y = y.wrapping_sub(frame.top);
207
208 if frame_x < frame.width && frame_y < frame.height {
209 *pixel = *frame_buffer.get_pixel(frame_x, frame_y);
210 } else {
211 *pixel = Rgba([0, 0, 0, 0]);
213 }
214 }
215 }
216
217 Ok(())
218 }
219
220 fn icc_profile(&mut self) -> ImageResult<Option<Vec<u8>>> {
221 Ok(self.reader.icc_profile().map(Vec::from))
223 }
224
225 fn xmp_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
226 Ok(self.reader.xmp_metadata().map(Vec::from))
228 }
229
230 fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
231 (*self).read_image(buf)
232 }
233}
234
235struct GifFrameIterator<R: Read> {
236 reader: gif::Decoder<R>,
237
238 width: u32,
239 height: u32,
240
241 non_disposed_frame: Option<ImageBuffer<Rgba<u8>, Vec<u8>>>,
242 limits: Limits,
243 is_end: bool,
246}
247
248impl<R: BufRead + Seek> GifFrameIterator<R> {
249 fn new(decoder: GifDecoder<R>) -> GifFrameIterator<R> {
250 let (width, height) = decoder.dimensions();
251 let limits = decoder.limits.clone();
252
253 GifFrameIterator {
256 reader: decoder.reader,
257 width,
258 height,
259 non_disposed_frame: None,
260 limits,
261 is_end: false,
262 }
263 }
264}
265
266impl<R: Read> Iterator for GifFrameIterator<R> {
267 type Item = ImageResult<animation::Frame>;
268
269 fn next(&mut self) -> Option<ImageResult<animation::Frame>> {
270 if self.is_end {
271 return None;
272 }
273
274 const COLOR_TYPE: ColorType = ColorType::Rgba8;
276
277 if self.non_disposed_frame.is_none() {
281 if let Err(e) = self
282 .limits
283 .reserve_buffer(self.width, self.height, COLOR_TYPE)
284 {
285 return Some(Err(e));
286 }
287 self.non_disposed_frame = Some(ImageBuffer::from_pixel(
288 self.width,
289 self.height,
290 Rgba([0, 0, 0, 0]),
291 ));
292 }
293 let non_disposed_frame = self.non_disposed_frame.as_mut().unwrap();
295
296 let frame = match self.reader.next_frame_info() {
299 Ok(frame_info) => {
300 if let Some(frame) = frame_info {
301 FrameInfo::new_from_frame(frame)
302 } else {
303 return None;
305 }
306 }
307 Err(err) => match err {
308 gif::DecodingError::Io(ref e) => {
309 if e.kind() == io::ErrorKind::UnexpectedEof {
310 self.is_end = true;
312 }
313 return Some(Err(ImageError::from_decoding(err)));
314 }
315 _ => {
316 return Some(Err(ImageError::from_decoding(err)));
317 }
318 },
319 };
320
321 let mut local_limits = self.limits.clone();
326
327 if let Err(e) = local_limits.reserve_buffer(frame.width, frame.height, COLOR_TYPE) {
329 return Some(Err(e));
330 }
331 let mut vec = vec![0; self.reader.buffer_size()];
333 if let Err(err) = self.reader.read_into_buffer(&mut vec) {
334 return Some(Err(ImageError::from_decoding(err)));
335 }
336
337 let Some(mut frame_buffer) = ImageBuffer::from_raw(frame.width, frame.height, vec) else {
343 return Some(Err(ImageError::Unsupported(
344 UnsupportedError::from_format_and_kind(
345 ImageFormat::Gif.into(),
346 UnsupportedErrorKind::GenericFeature(format!(
347 "Image dimensions ({}, {}) are too large",
348 frame.width, frame.height
349 )),
350 ),
351 )));
352 };
353
354 fn blend_and_dispose_pixel(
357 dispose: DisposalMethod,
358 previous: &mut Rgba<u8>,
359 current: &mut Rgba<u8>,
360 ) {
361 let pixel_alpha = current.channels()[3];
362 if pixel_alpha == 0 {
363 *current = *previous;
364 }
365
366 match dispose {
367 DisposalMethod::Any | DisposalMethod::Keep => {
368 *previous = *current;
373 }
374 DisposalMethod::Background => {
375 *previous = Rgba([0, 0, 0, 0]);
378 }
379 DisposalMethod::Previous => {
380 }
383 }
384 }
385
386 let image_buffer = if (frame.left, frame.top) == (0, 0)
390 && (self.width, self.height) == frame_buffer.dimensions()
391 {
392 for (x, y, pixel) in frame_buffer.enumerate_pixels_mut() {
393 let previous_pixel = non_disposed_frame.get_pixel_mut(x, y);
394 blend_and_dispose_pixel(frame.disposal_method, previous_pixel, pixel);
395 }
396 frame_buffer
397 } else {
398 if let Err(e) = local_limits.reserve_buffer(self.width, self.height, COLOR_TYPE) {
400 return Some(Err(e));
401 }
402 ImageBuffer::from_fn(self.width, self.height, |x, y| {
403 let frame_x = x.wrapping_sub(frame.left);
404 let frame_y = y.wrapping_sub(frame.top);
405 let previous_pixel = non_disposed_frame.get_pixel_mut(x, y);
406
407 if frame_x < frame_buffer.width() && frame_y < frame_buffer.height() {
408 let mut pixel = *frame_buffer.get_pixel(frame_x, frame_y);
409 blend_and_dispose_pixel(frame.disposal_method, previous_pixel, &mut pixel);
410 pixel
411 } else {
412 *previous_pixel
414 }
415 })
416 };
417
418 Some(Ok(animation::Frame::from_parts(
419 image_buffer,
420 0,
421 0,
422 frame.delay,
423 )))
424 }
425}
426
427impl<'a, R: BufRead + Seek + 'a> AnimationDecoder<'a> for GifDecoder<R> {
428 fn loop_count(&self) -> LoopCount {
429 match self.reader.repeat() {
430 gif::Repeat::Finite(n @ 1..) => {
431 LoopCount::Finite(NonZeroU32::new(n.into()).expect("repeat is non-zero"))
432 }
433 gif::Repeat::Finite(0) | gif::Repeat::Infinite => LoopCount::Infinite,
434 }
435 }
436
437 fn into_frames(self) -> animation::Frames<'a> {
438 animation::Frames::new(Box::new(GifFrameIterator::new(self)))
439 }
440}
441
442struct FrameInfo {
443 left: u32,
444 top: u32,
445 width: u32,
446 height: u32,
447 disposal_method: DisposalMethod,
448 delay: animation::Delay,
449}
450
451impl FrameInfo {
452 fn new_from_frame(frame: &Frame) -> FrameInfo {
453 FrameInfo {
454 left: u32::from(frame.left),
455 top: u32::from(frame.top),
456 width: u32::from(frame.width),
457 height: u32::from(frame.height),
458 disposal_method: frame.dispose,
459 delay: animation::Delay::from_ratio(Ratio::new(u32::from(frame.delay) * 10, 1)),
461 }
462 }
463}
464
465#[derive(Clone, Copy, Debug)]
467pub enum Repeat {
468 Finite(u16),
470 Infinite,
472}
473
474impl Repeat {
475 pub(crate) fn to_gif_enum(self) -> gif::Repeat {
476 match self {
477 Repeat::Finite(n) => gif::Repeat::Finite(n),
478 Repeat::Infinite => gif::Repeat::Infinite,
479 }
480 }
481}
482
483pub struct GifEncoder<W: Write> {
485 w: Option<W>,
486 gif_encoder: Option<gif::Encoder<W>>,
487 speed: i32,
488 repeat: Option<Repeat>,
489}
490
491impl<W: Write> GifEncoder<W> {
492 pub fn new(w: W) -> GifEncoder<W> {
494 Self::new_with_speed(w, 1)
495 }
496
497 pub fn new_with_speed(w: W, speed: i32) -> GifEncoder<W> {
501 assert!(
502 (1..=30).contains(&speed),
503 "speed needs to be in the range [1, 30]"
504 );
505 GifEncoder {
506 w: Some(w),
507 gif_encoder: None,
508 speed,
509 repeat: None,
510 }
511 }
512
513 pub fn set_repeat(&mut self, repeat: Repeat) -> ImageResult<()> {
515 if let Some(ref mut encoder) = self.gif_encoder {
516 encoder
517 .set_repeat(repeat.to_gif_enum())
518 .map_err(ImageError::from_encoding)?;
519 }
520 self.repeat = Some(repeat);
521 Ok(())
522 }
523
524 pub fn encode(
526 &mut self,
527 data: &[u8],
528 width: u32,
529 height: u32,
530 color: ExtendedColorType,
531 ) -> ImageResult<()> {
532 let (width, height) = self.gif_dimensions(width, height)?;
533 match color {
534 ExtendedColorType::Rgb8 => {
535 self.encode_gif(Frame::from_rgb_speed(width, height, data, self.speed))
536 }
537 ExtendedColorType::Rgba8 => self.encode_gif(Frame::from_rgba_speed(
538 width,
539 height,
540 &mut data.to_owned(),
541 self.speed,
542 )),
543 _ => Err(ImageError::Unsupported(
544 UnsupportedError::from_format_and_kind(
545 ImageFormat::Gif.into(),
546 UnsupportedErrorKind::Color(color),
547 ),
548 )),
549 }
550 }
551
552 pub fn encode_frame(&mut self, img_frame: animation::Frame) -> ImageResult<()> {
554 let frame = self.convert_frame(img_frame)?;
555 self.encode_gif(frame)
556 }
557
558 pub fn encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
561 where
562 F: IntoIterator<Item = animation::Frame>,
563 {
564 for img_frame in frames {
565 self.encode_frame(img_frame)?;
566 }
567 Ok(())
568 }
569
570 pub fn try_encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
574 where
575 F: IntoIterator<Item = ImageResult<animation::Frame>>,
576 {
577 for img_frame in frames {
578 self.encode_frame(img_frame?)?;
579 }
580 Ok(())
581 }
582
583 pub(crate) fn convert_frame(
584 &mut self,
585 img_frame: animation::Frame,
586 ) -> ImageResult<Frame<'static>> {
587 let frame_delay = img_frame.delay().into_ratio().to_integer();
589 let mut rbga_frame = img_frame.into_buffer();
591 let (width, height) = self.gif_dimensions(rbga_frame.width(), rbga_frame.height())?;
592
593 let mut frame = Frame::from_rgba_speed(width, height, &mut rbga_frame, self.speed);
595 frame.delay = (frame_delay / 10).try_into().unwrap_or(u16::MAX);
600
601 Ok(frame)
602 }
603
604 fn gif_dimensions(&self, width: u32, height: u32) -> ImageResult<(u16, u16)> {
605 fn inner_dimensions(width: u32, height: u32) -> Option<(u16, u16)> {
606 let width = u16::try_from(width).ok()?;
607 let height = u16::try_from(height).ok()?;
608 Some((width, height))
609 }
610
611 inner_dimensions(width, height).ok_or_else(|| {
613 ImageError::Parameter(ParameterError::from_kind(
614 ParameterErrorKind::DimensionMismatch,
615 ))
616 })
617 }
618
619 pub(crate) fn encode_gif(&mut self, mut frame: Frame) -> ImageResult<()> {
620 let gif_encoder;
621 if let Some(ref mut encoder) = self.gif_encoder {
622 gif_encoder = encoder;
623 } else {
624 let writer = self.w.take().unwrap();
625 let mut encoder = gif::Encoder::new(writer, frame.width, frame.height, &[])
626 .map_err(ImageError::from_encoding)?;
627 if let Some(ref repeat) = self.repeat {
628 encoder
629 .set_repeat(repeat.to_gif_enum())
630 .map_err(ImageError::from_encoding)?;
631 }
632 self.gif_encoder = Some(encoder);
633 gif_encoder = self.gif_encoder.as_mut().unwrap();
634 }
635
636 frame.dispose = DisposalMethod::Background;
637
638 gif_encoder
639 .write_frame(&frame)
640 .map_err(ImageError::from_encoding)
641 }
642}
643impl<W: Write> ImageEncoder for GifEncoder<W> {
644 fn write_image(
645 mut self,
646 buf: &[u8],
647 width: u32,
648 height: u32,
649 color_type: ExtendedColorType,
650 ) -> ImageResult<()> {
651 self.encode(buf, width, height, color_type)
652 }
653}
654
655impl ImageError {
656 fn from_decoding(err: gif::DecodingError) -> ImageError {
657 use gif::DecodingError::*;
658 match err {
659 Io(io_err) => ImageError::IoError(io_err),
660 other => ImageError::Decoding(DecodingError::new(ImageFormat::Gif.into(), other)),
661 }
662 }
663
664 fn from_encoding(err: gif::EncodingError) -> ImageError {
665 use gif::EncodingError::*;
666 match err {
667 Io(io_err) => ImageError::IoError(io_err),
668 other => ImageError::Encoding(EncodingError::new(ImageFormat::Gif.into(), other)),
669 }
670 }
671}
672
673#[cfg(test)]
674mod test {
675 use super::*;
676
677 #[test]
678 fn frames_exceeding_logical_screen_size() {
679 let data = vec![
681 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x0A, 0x00, 0x0A, 0x00, 0xF0, 0x00, 0x00, 0x00,
682 0x00, 0x00, 0x0E, 0xFF, 0x1F, 0x21, 0xF9, 0x04, 0x09, 0x64, 0x00, 0x00, 0x00, 0x2C,
683 0x06, 0x00, 0x06, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x02, 0x23, 0x84, 0x8F, 0xA9,
684 0xBB, 0xE1, 0xE8, 0x42, 0x8A, 0x0F, 0x50, 0x79, 0xAE, 0xD1, 0xF9, 0x7A, 0xE8, 0x71,
685 0x5B, 0x48, 0x81, 0x64, 0xD5, 0x91, 0xCA, 0x89, 0x4D, 0x21, 0x63, 0x89, 0x4C, 0x09,
686 0x77, 0xF5, 0x6D, 0x14, 0x00, 0x3B,
687 ];
688
689 let decoder = GifDecoder::new(Cursor::new(data)).unwrap();
690 let mut buf = vec![0u8; decoder.total_bytes() as usize];
691
692 assert!(decoder.read_image(&mut buf).is_ok());
693 }
694}