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::LimitError;
40use crate::error::LimitErrorKind;
41use crate::error::{
42 DecodingError, EncodingError, ImageError, ImageResult, ParameterError, ParameterErrorKind,
43 UnsupportedError, UnsupportedErrorKind,
44};
45use crate::image::{AnimationDecoder, ImageDecoder, ImageFormat};
46use crate::traits::Pixel;
47use crate::ExtendedColorType;
48use crate::ImageBuffer;
49use crate::Limits;
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 read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
220 (*self).read_image(buf)
221 }
222}
223
224struct GifFrameIterator<R: Read> {
225 reader: gif::Decoder<R>,
226
227 width: u32,
228 height: u32,
229
230 non_disposed_frame: Option<ImageBuffer<Rgba<u8>, Vec<u8>>>,
231 limits: Limits,
232}
233
234impl<R: BufRead + Seek> GifFrameIterator<R> {
235 fn new(decoder: GifDecoder<R>) -> GifFrameIterator<R> {
236 let (width, height) = decoder.dimensions();
237 let limits = decoder.limits.clone();
238
239 GifFrameIterator {
242 reader: decoder.reader,
243 width,
244 height,
245 non_disposed_frame: None,
246 limits,
247 }
248 }
249}
250
251impl<R: Read> Iterator for GifFrameIterator<R> {
252 type Item = ImageResult<animation::Frame>;
253
254 fn next(&mut self) -> Option<ImageResult<animation::Frame>> {
255 const COLOR_TYPE: ColorType = ColorType::Rgba8;
257
258 if self.non_disposed_frame.is_none() {
262 if let Err(e) = self
263 .limits
264 .reserve_buffer(self.width, self.height, COLOR_TYPE)
265 {
266 return Some(Err(e));
267 }
268 self.non_disposed_frame = Some(ImageBuffer::from_pixel(
269 self.width,
270 self.height,
271 Rgba([0, 0, 0, 0]),
272 ));
273 }
274 let non_disposed_frame = self.non_disposed_frame.as_mut().unwrap();
276
277 let frame = match self.reader.next_frame_info() {
280 Ok(frame_info) => {
281 if let Some(frame) = frame_info {
282 FrameInfo::new_from_frame(frame)
283 } else {
284 return None;
286 }
287 }
288 Err(err) => return Some(Err(ImageError::from_decoding(err))),
289 };
290
291 let mut local_limits = self.limits.clone();
296
297 if let Err(e) = local_limits.reserve_buffer(frame.width, frame.height, COLOR_TYPE) {
299 return Some(Err(e));
300 }
301 let mut vec = vec![0; self.reader.buffer_size()];
303 if let Err(err) = self.reader.read_into_buffer(&mut vec) {
304 return Some(Err(ImageError::from_decoding(err)));
305 }
306
307 let Some(mut frame_buffer) = ImageBuffer::from_raw(frame.width, frame.height, vec) else {
313 return Some(Err(ImageError::Unsupported(
314 UnsupportedError::from_format_and_kind(
315 ImageFormat::Gif.into(),
316 UnsupportedErrorKind::GenericFeature(format!(
317 "Image dimensions ({}, {}) are too large",
318 frame.width, frame.height
319 )),
320 ),
321 )));
322 };
323
324 fn blend_and_dispose_pixel(
327 dispose: DisposalMethod,
328 previous: &mut Rgba<u8>,
329 current: &mut Rgba<u8>,
330 ) {
331 let pixel_alpha = current.channels()[3];
332 if pixel_alpha == 0 {
333 *current = *previous;
334 }
335
336 match dispose {
337 DisposalMethod::Any | DisposalMethod::Keep => {
338 *previous = *current;
343 }
344 DisposalMethod::Background => {
345 *previous = Rgba([0, 0, 0, 0]);
348 }
349 DisposalMethod::Previous => {
350 }
353 }
354 }
355
356 let image_buffer = if (frame.left, frame.top) == (0, 0)
360 && (self.width, self.height) == frame_buffer.dimensions()
361 {
362 for (x, y, pixel) in frame_buffer.enumerate_pixels_mut() {
363 let previous_pixel = non_disposed_frame.get_pixel_mut(x, y);
364 blend_and_dispose_pixel(frame.disposal_method, previous_pixel, pixel);
365 }
366 frame_buffer
367 } else {
368 if let Err(e) = local_limits.reserve_buffer(self.width, self.height, COLOR_TYPE) {
370 return Some(Err(e));
371 }
372 ImageBuffer::from_fn(self.width, self.height, |x, y| {
373 let frame_x = x.wrapping_sub(frame.left);
374 let frame_y = y.wrapping_sub(frame.top);
375 let previous_pixel = non_disposed_frame.get_pixel_mut(x, y);
376
377 if frame_x < frame_buffer.width() && frame_y < frame_buffer.height() {
378 let mut pixel = *frame_buffer.get_pixel(frame_x, frame_y);
379 blend_and_dispose_pixel(frame.disposal_method, previous_pixel, &mut pixel);
380 pixel
381 } else {
382 *previous_pixel
384 }
385 })
386 };
387
388 Some(Ok(animation::Frame::from_parts(
389 image_buffer,
390 0,
391 0,
392 frame.delay,
393 )))
394 }
395}
396
397impl<'a, R: BufRead + Seek + 'a> AnimationDecoder<'a> for GifDecoder<R> {
398 fn into_frames(self) -> animation::Frames<'a> {
399 animation::Frames::new(Box::new(GifFrameIterator::new(self)))
400 }
401}
402
403struct FrameInfo {
404 left: u32,
405 top: u32,
406 width: u32,
407 height: u32,
408 disposal_method: DisposalMethod,
409 delay: animation::Delay,
410}
411
412impl FrameInfo {
413 fn new_from_frame(frame: &Frame) -> FrameInfo {
414 FrameInfo {
415 left: u32::from(frame.left),
416 top: u32::from(frame.top),
417 width: u32::from(frame.width),
418 height: u32::from(frame.height),
419 disposal_method: frame.dispose,
420 delay: animation::Delay::from_ratio(Ratio::new(u32::from(frame.delay) * 10, 1)),
422 }
423 }
424}
425
426#[derive(Clone, Copy, Debug)]
428pub enum Repeat {
429 Finite(u16),
431 Infinite,
433}
434
435impl Repeat {
436 pub(crate) fn to_gif_enum(self) -> gif::Repeat {
437 match self {
438 Repeat::Finite(n) => gif::Repeat::Finite(n),
439 Repeat::Infinite => gif::Repeat::Infinite,
440 }
441 }
442}
443
444pub struct GifEncoder<W: Write> {
446 w: Option<W>,
447 gif_encoder: Option<gif::Encoder<W>>,
448 speed: i32,
449 repeat: Option<Repeat>,
450}
451
452impl<W: Write> GifEncoder<W> {
453 pub fn new(w: W) -> GifEncoder<W> {
455 Self::new_with_speed(w, 1)
456 }
457
458 pub fn new_with_speed(w: W, speed: i32) -> GifEncoder<W> {
462 assert!(
463 (1..=30).contains(&speed),
464 "speed needs to be in the range [1, 30]"
465 );
466 GifEncoder {
467 w: Some(w),
468 gif_encoder: None,
469 speed,
470 repeat: None,
471 }
472 }
473
474 pub fn set_repeat(&mut self, repeat: Repeat) -> ImageResult<()> {
476 if let Some(ref mut encoder) = self.gif_encoder {
477 encoder
478 .set_repeat(repeat.to_gif_enum())
479 .map_err(ImageError::from_encoding)?;
480 }
481 self.repeat = Some(repeat);
482 Ok(())
483 }
484
485 pub fn encode(
487 &mut self,
488 data: &[u8],
489 width: u32,
490 height: u32,
491 color: ExtendedColorType,
492 ) -> ImageResult<()> {
493 let (width, height) = self.gif_dimensions(width, height)?;
494 match color {
495 ExtendedColorType::Rgb8 => self.encode_gif(Frame::from_rgb(width, height, data)),
496 ExtendedColorType::Rgba8 => {
497 self.encode_gif(Frame::from_rgba(width, height, &mut data.to_owned()))
498 }
499 _ => Err(ImageError::Unsupported(
500 UnsupportedError::from_format_and_kind(
501 ImageFormat::Gif.into(),
502 UnsupportedErrorKind::Color(color),
503 ),
504 )),
505 }
506 }
507
508 pub fn encode_frame(&mut self, img_frame: animation::Frame) -> ImageResult<()> {
510 let frame = self.convert_frame(img_frame)?;
511 self.encode_gif(frame)
512 }
513
514 pub fn encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
517 where
518 F: IntoIterator<Item = animation::Frame>,
519 {
520 for img_frame in frames {
521 self.encode_frame(img_frame)?;
522 }
523 Ok(())
524 }
525
526 pub fn try_encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
530 where
531 F: IntoIterator<Item = ImageResult<animation::Frame>>,
532 {
533 for img_frame in frames {
534 self.encode_frame(img_frame?)?;
535 }
536 Ok(())
537 }
538
539 pub(crate) fn convert_frame(
540 &mut self,
541 img_frame: animation::Frame,
542 ) -> ImageResult<Frame<'static>> {
543 let frame_delay = img_frame.delay().into_ratio().to_integer();
545 let mut rbga_frame = img_frame.into_buffer();
547 let (width, height) = self.gif_dimensions(rbga_frame.width(), rbga_frame.height())?;
548
549 let mut frame = Frame::from_rgba_speed(width, height, &mut rbga_frame, self.speed);
551 frame.delay = (frame_delay / 10).try_into().unwrap_or(u16::MAX);
556
557 Ok(frame)
558 }
559
560 fn gif_dimensions(&self, width: u32, height: u32) -> ImageResult<(u16, u16)> {
561 fn inner_dimensions(width: u32, height: u32) -> Option<(u16, u16)> {
562 let width = u16::try_from(width).ok()?;
563 let height = u16::try_from(height).ok()?;
564 Some((width, height))
565 }
566
567 inner_dimensions(width, height).ok_or_else(|| {
569 ImageError::Parameter(ParameterError::from_kind(
570 ParameterErrorKind::DimensionMismatch,
571 ))
572 })
573 }
574
575 pub(crate) fn encode_gif(&mut self, mut frame: Frame) -> ImageResult<()> {
576 let gif_encoder;
577 if let Some(ref mut encoder) = self.gif_encoder {
578 gif_encoder = encoder;
579 } else {
580 let writer = self.w.take().unwrap();
581 let mut encoder = gif::Encoder::new(writer, frame.width, frame.height, &[])
582 .map_err(ImageError::from_encoding)?;
583 if let Some(ref repeat) = self.repeat {
584 encoder
585 .set_repeat(repeat.to_gif_enum())
586 .map_err(ImageError::from_encoding)?;
587 }
588 self.gif_encoder = Some(encoder);
589 gif_encoder = self.gif_encoder.as_mut().unwrap();
590 }
591
592 frame.dispose = DisposalMethod::Background;
593
594 gif_encoder
595 .write_frame(&frame)
596 .map_err(ImageError::from_encoding)
597 }
598}
599
600impl ImageError {
601 fn from_decoding(err: gif::DecodingError) -> ImageError {
602 use gif::DecodingError::*;
603 match err {
604 err @ Format(_) => {
605 ImageError::Decoding(DecodingError::new(ImageFormat::Gif.into(), err))
606 }
607 Io(io_err) => ImageError::IoError(io_err),
608 }
609 }
610
611 fn from_encoding(err: gif::EncodingError) -> ImageError {
612 use gif::EncodingError::*;
613 match err {
614 err @ Format(_) => {
615 ImageError::Encoding(EncodingError::new(ImageFormat::Gif.into(), err))
616 }
617 Io(io_err) => ImageError::IoError(io_err),
618 }
619 }
620}
621
622#[cfg(test)]
623mod test {
624 use super::*;
625
626 #[test]
627 fn frames_exceeding_logical_screen_size() {
628 let data = vec![
630 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x0A, 0x00, 0x0A, 0x00, 0xF0, 0x00, 0x00, 0x00,
631 0x00, 0x00, 0x0E, 0xFF, 0x1F, 0x21, 0xF9, 0x04, 0x09, 0x64, 0x00, 0x00, 0x00, 0x2C,
632 0x06, 0x00, 0x06, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x02, 0x23, 0x84, 0x8F, 0xA9,
633 0xBB, 0xE1, 0xE8, 0x42, 0x8A, 0x0F, 0x50, 0x79, 0xAE, 0xD1, 0xF9, 0x7A, 0xE8, 0x71,
634 0x5B, 0x48, 0x81, 0x64, 0xD5, 0x91, 0xCA, 0x89, 0x4D, 0x21, 0x63, 0x89, 0x4C, 0x09,
635 0x77, 0xF5, 0x6D, 0x14, 0x00, 0x3B,
636 ];
637
638 let decoder = GifDecoder::new(Cursor::new(data)).unwrap();
639 let mut buf = vec![0u8; decoder.total_bytes() as usize];
640
641 assert!(decoder.read_image(&mut buf).is_ok());
642 }
643}