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