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