1//! Decoding of GIF Images
2//!
3//! GIF (Graphics Interchange Format) is an image format that supports lossless compression.
4//!
5//! # Related Links
6//! * <http://www.w3.org/Graphics/GIF/spec-gif89a.txt> - The GIF Specification
7//!
8//! # Examples
9//! ```rust,no_run
10//! use image::codecs::gif::{GifDecoder, GifEncoder};
11//! use image::{ImageDecoder, AnimationDecoder};
12//! use std::fs::File;
13//! # fn main() -> std::io::Result<()> {
14//! // Decode a gif into frames
15//! let file_in = File::open("foo.gif")?;
16//! let mut decoder = GifDecoder::new(file_in).unwrap();
17//! let frames = decoder.into_frames();
18//! let frames = frames.collect_frames().expect("error decoding gif");
19//!
20//! // Encode frames into a gif and save to a file
21//! let mut file_out = File::open("out.gif")?;
22//! let mut encoder = GifEncoder::new(file_out);
23//! encoder.encode_frames(frames.into_iter());
24//! # Ok(())
25//! # }
26//! ```
27#![allow(clippy::while_let_loop)]
28
29use std::io::{self, Cursor, Read, Write};
30use std::marker::PhantomData;
31use std::mem;
32
33use gif::ColorOutput;
34use gif::{DisposalMethod, Frame};
35
36use crate::animation::{self, Ratio};
37use crate::color::{ColorType, Rgba};
38use crate::error::LimitError;
39use crate::error::LimitErrorKind;
40use crate::error::{
41 DecodingError, EncodingError, ImageError, ImageResult, ParameterError, ParameterErrorKind,
42 UnsupportedError, UnsupportedErrorKind,
43};
44use crate::image::{self, AnimationDecoder, ImageDecoder, ImageFormat};
45use crate::io::Limits;
46use crate::traits::Pixel;
47use crate::ImageBuffer;
48
49/// GIF decoder
50pub struct GifDecoder<R: Read> {
51 reader: gif::Decoder<R>,
52 limits: Limits,
53}
54
55impl<R: Read> GifDecoder<R> {
56 /// Creates a new decoder that decodes the input steam `r`
57 pub fn new(r: R) -> ImageResult<GifDecoder<R>> {
58 let mut decoder: DecodeOptions = gif::DecodeOptions::new();
59 decoder.set_color_output(color:ColorOutput::RGBA);
60
61 Ok(GifDecoder {
62 reader: decoder.read_info(r).map_err(op:ImageError::from_decoding)?,
63 limits: Limits::no_limits(),
64 })
65 }
66
67 /// Creates a new decoder that decodes the input steam `r`, using limits `limits`
68 #[deprecated(since = "0.24.8", note = "Use `new` followed by `set_limits` instead")]
69 pub fn with_limits(r: R, limits: Limits) -> ImageResult<GifDecoder<R>> {
70 let mut decoder: GifDecoder = Self::new(r)?;
71 // call `.set_limits()` instead of just setting the field directly
72 // so that we raise an error in case they are exceeded
73 decoder.set_limits(limits)?;
74 Ok(decoder)
75 }
76}
77
78/// Wrapper struct around a `Cursor<Vec<u8>>`
79pub struct GifReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
80impl<R> Read for GifReader<R> {
81 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
82 self.0.read(buf)
83 }
84 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
85 if self.0.position() == 0 && buf.is_empty() {
86 mem::swap(x:buf, self.0.get_mut());
87 Ok(buf.len())
88 } else {
89 self.0.read_to_end(buf)
90 }
91 }
92}
93
94impl<'a, R: 'a + Read> ImageDecoder<'a> for GifDecoder<R> {
95 type Reader = GifReader<R>;
96
97 fn dimensions(&self) -> (u32, u32) {
98 (
99 u32::from(self.reader.width()),
100 u32::from(self.reader.height()),
101 )
102 }
103
104 fn color_type(&self) -> ColorType {
105 ColorType::Rgba8
106 }
107
108 fn into_reader(self) -> ImageResult<Self::Reader> {
109 Ok(GifReader(
110 Cursor::new(image::decoder_to_vec(self)?),
111 PhantomData,
112 ))
113 }
114
115 fn set_limits(&mut self, limits: Limits) -> ImageResult<()> {
116 limits.check_support(&crate::io::LimitSupport::default())?;
117
118 let (width, height) = self.dimensions();
119 limits.check_dimensions(width, height)?;
120
121 self.limits = limits;
122
123 Ok(())
124 }
125
126 fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
127 assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
128
129 let frame = match self
130 .reader
131 .next_frame_info()
132 .map_err(ImageError::from_decoding)?
133 {
134 Some(frame) => FrameInfo::new_from_frame(frame),
135 None => {
136 return Err(ImageError::Parameter(ParameterError::from_kind(
137 ParameterErrorKind::NoMoreData,
138 )))
139 }
140 };
141
142 let (width, height) = self.dimensions();
143
144 if frame.left == 0
145 && frame.width == width
146 && (frame.top as u64 + frame.height as u64 <= height as u64)
147 {
148 // If the frame matches the logical screen, or, as a more general case,
149 // fits into it and touches its left and right borders, then
150 // we can directly write it into the buffer without causing line wraparound.
151 let line_length = usize::try_from(width)
152 .unwrap()
153 .checked_mul(self.color_type().bytes_per_pixel() as usize)
154 .unwrap();
155
156 // isolate the portion of the buffer to read the frame data into.
157 // the chunks above and below it are going to be zeroed.
158 let (blank_top, rest) =
159 buf.split_at_mut(line_length.checked_mul(frame.top as usize).unwrap());
160 let (buf, blank_bottom) =
161 rest.split_at_mut(line_length.checked_mul(frame.height as usize).unwrap());
162
163 debug_assert_eq!(buf.len(), self.reader.buffer_size());
164
165 // this is only necessary in case the buffer is not zeroed
166 for b in blank_top {
167 *b = 0;
168 }
169 // fill the middle section with the frame data
170 self.reader
171 .read_into_buffer(buf)
172 .map_err(ImageError::from_decoding)?;
173 // this is only necessary in case the buffer is not zeroed
174 for b in blank_bottom {
175 *b = 0;
176 }
177 } else {
178 // If the frame does not match the logical screen, read into an extra buffer
179 // and 'insert' the frame from left/top to logical screen width/height.
180 let buffer_size = (frame.width as usize)
181 .checked_mul(frame.height as usize)
182 .and_then(|s| s.checked_mul(4))
183 .ok_or(ImageError::Limits(LimitError::from_kind(
184 LimitErrorKind::InsufficientMemory,
185 )))?;
186
187 self.limits.reserve_usize(buffer_size)?;
188 let mut frame_buffer = vec![0; buffer_size];
189 self.limits.free_usize(buffer_size);
190
191 self.reader
192 .read_into_buffer(&mut frame_buffer[..])
193 .map_err(ImageError::from_decoding)?;
194
195 let frame_buffer = ImageBuffer::from_raw(frame.width, frame.height, frame_buffer);
196 let image_buffer = ImageBuffer::from_raw(width, height, buf);
197
198 // `buffer_size` uses wrapping arithmetic, thus might not report the
199 // correct storage requirement if the result does not fit in `usize`.
200 // `ImageBuffer::from_raw` detects overflow and reports by returning `None`.
201 if frame_buffer.is_none() || image_buffer.is_none() {
202 return Err(ImageError::Unsupported(
203 UnsupportedError::from_format_and_kind(
204 ImageFormat::Gif.into(),
205 UnsupportedErrorKind::GenericFeature(format!(
206 "Image dimensions ({}, {}) are too large",
207 frame.width, frame.height
208 )),
209 ),
210 ));
211 }
212
213 let frame_buffer = frame_buffer.unwrap();
214 let mut image_buffer = image_buffer.unwrap();
215
216 for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
217 let frame_x = x.wrapping_sub(frame.left);
218 let frame_y = y.wrapping_sub(frame.top);
219
220 if frame_x < frame.width && frame_y < frame.height {
221 *pixel = *frame_buffer.get_pixel(frame_x, frame_y);
222 } else {
223 // this is only necessary in case the buffer is not zeroed
224 *pixel = Rgba([0, 0, 0, 0]);
225 }
226 }
227 }
228
229 Ok(())
230 }
231}
232
233struct GifFrameIterator<R: Read> {
234 reader: gif::Decoder<R>,
235
236 width: u32,
237 height: u32,
238
239 non_disposed_frame: Option<ImageBuffer<Rgba<u8>, Vec<u8>>>,
240 limits: Limits,
241}
242
243impl<R: Read> GifFrameIterator<R> {
244 fn new(decoder: GifDecoder<R>) -> GifFrameIterator<R> {
245 let (width: u32, height: u32) = decoder.dimensions();
246 let limits: Limits = decoder.limits.clone();
247
248 // intentionally ignore the background color for web compatibility
249
250 GifFrameIterator {
251 reader: decoder.reader,
252 width,
253 height,
254 non_disposed_frame: None,
255 limits,
256 }
257 }
258}
259
260impl<R: Read> Iterator for GifFrameIterator<R> {
261 type Item = ImageResult<animation::Frame>;
262
263 fn next(&mut self) -> Option<ImageResult<animation::Frame>> {
264 // The iterator always produces RGBA8 images
265 const COLOR_TYPE: ColorType = ColorType::Rgba8;
266
267 // Allocate the buffer for the previous frame.
268 // This is done here and not in the constructor because
269 // the constructor cannot return an error when the allocation limit is exceeded.
270 if self.non_disposed_frame.is_none() {
271 if let Err(e) = self
272 .limits
273 .reserve_buffer(self.width, self.height, COLOR_TYPE)
274 {
275 return Some(Err(e));
276 }
277 self.non_disposed_frame = Some(ImageBuffer::from_pixel(
278 self.width,
279 self.height,
280 Rgba([0, 0, 0, 0]),
281 ));
282 }
283 // Bind to a variable to avoid repeated `.unwrap()` calls
284 let non_disposed_frame = self.non_disposed_frame.as_mut().unwrap();
285
286 // begin looping over each frame
287
288 let frame = match self.reader.next_frame_info() {
289 Ok(frame_info) => {
290 if let Some(frame) = frame_info {
291 FrameInfo::new_from_frame(frame)
292 } else {
293 // no more frames
294 return None;
295 }
296 }
297 Err(err) => return Some(Err(ImageError::from_decoding(err))),
298 };
299
300 // All allocations we do from now on will be freed at the end of this function.
301 // Therefore, do not count them towards the persistent limits.
302 // Instead, create a local instance of `Limits` for this function alone
303 // which will be dropped along with all the buffers when they go out of scope.
304 let mut local_limits = self.limits.clone();
305
306 // Check the allocation we're about to perform against the limits
307 if let Err(e) = local_limits.reserve_buffer(frame.width, frame.height, COLOR_TYPE) {
308 return Some(Err(e));
309 }
310 // Allocate the buffer now that the limits allowed it
311 let mut vec = vec![0; self.reader.buffer_size()];
312 if let Err(err) = self.reader.read_into_buffer(&mut vec) {
313 return Some(Err(ImageError::from_decoding(err)));
314 }
315
316 // create the image buffer from the raw frame.
317 // `buffer_size` uses wrapping arithmetic, thus might not report the
318 // correct storage requirement if the result does not fit in `usize`.
319 // on the other hand, `ImageBuffer::from_raw` detects overflow and
320 // reports by returning `None`.
321 let mut frame_buffer = match ImageBuffer::from_raw(frame.width, frame.height, vec) {
322 Some(frame_buffer) => frame_buffer,
323 None => {
324 return Some(Err(ImageError::Unsupported(
325 UnsupportedError::from_format_and_kind(
326 ImageFormat::Gif.into(),
327 UnsupportedErrorKind::GenericFeature(format!(
328 "Image dimensions ({}, {}) are too large",
329 frame.width, frame.height
330 )),
331 ),
332 )))
333 }
334 };
335
336 // blend the current frame with the non-disposed frame, then update
337 // the non-disposed frame according to the disposal method.
338 fn blend_and_dispose_pixel(
339 dispose: DisposalMethod,
340 previous: &mut Rgba<u8>,
341 current: &mut Rgba<u8>,
342 ) {
343 let pixel_alpha = current.channels()[3];
344 if pixel_alpha == 0 {
345 *current = *previous;
346 }
347
348 match dispose {
349 DisposalMethod::Any | DisposalMethod::Keep => {
350 // do not dispose
351 // (keep pixels from this frame)
352 // note: the `Any` disposal method is underspecified in the GIF
353 // spec, but most viewers treat it identically to `Keep`
354 *previous = *current;
355 }
356 DisposalMethod::Background => {
357 // restore to background color
358 // (background shows through transparent pixels in the next frame)
359 *previous = Rgba([0, 0, 0, 0]);
360 }
361 DisposalMethod::Previous => {
362 // restore to previous
363 // (dispose frames leaving the last none disposal frame)
364 }
365 }
366 }
367
368 // if `frame_buffer`'s frame exactly matches the entire image, then
369 // use it directly, else create a new buffer to hold the composited
370 // image.
371 let image_buffer = if (frame.left, frame.top) == (0, 0)
372 && (self.width, self.height) == frame_buffer.dimensions()
373 {
374 for (x, y, pixel) in frame_buffer.enumerate_pixels_mut() {
375 let previous_pixel = non_disposed_frame.get_pixel_mut(x, y);
376 blend_and_dispose_pixel(frame.disposal_method, previous_pixel, pixel);
377 }
378 frame_buffer
379 } else {
380 // Check limits before allocating the buffer
381 if let Err(e) = local_limits.reserve_buffer(self.width, self.height, COLOR_TYPE) {
382 return Some(Err(e));
383 }
384 ImageBuffer::from_fn(self.width, self.height, |x, y| {
385 let frame_x = x.wrapping_sub(frame.left);
386 let frame_y = y.wrapping_sub(frame.top);
387 let previous_pixel = non_disposed_frame.get_pixel_mut(x, y);
388
389 if frame_x < frame_buffer.width() && frame_y < frame_buffer.height() {
390 let mut pixel = *frame_buffer.get_pixel(frame_x, frame_y);
391 blend_and_dispose_pixel(frame.disposal_method, previous_pixel, &mut pixel);
392 pixel
393 } else {
394 // out of bounds, return pixel from previous frame
395 *previous_pixel
396 }
397 })
398 };
399
400 Some(Ok(animation::Frame::from_parts(
401 image_buffer,
402 0,
403 0,
404 frame.delay,
405 )))
406 }
407}
408
409impl<'a, R: Read + 'a> AnimationDecoder<'a> for GifDecoder<R> {
410 fn into_frames(self) -> animation::Frames<'a> {
411 animation::Frames::new(iterator:Box::new(GifFrameIterator::new(self)))
412 }
413}
414
415struct FrameInfo {
416 left: u32,
417 top: u32,
418 width: u32,
419 height: u32,
420 disposal_method: DisposalMethod,
421 delay: animation::Delay,
422}
423
424impl FrameInfo {
425 fn new_from_frame(frame: &Frame) -> FrameInfo {
426 FrameInfo {
427 left: u32::from(frame.left),
428 top: u32::from(frame.top),
429 width: u32::from(frame.width),
430 height: u32::from(frame.height),
431 disposal_method: frame.dispose,
432 // frame.delay is in units of 10ms so frame.delay*10 is in ms
433 delay: animation::Delay::from_ratio(Ratio::new(numerator:u32::from(frame.delay) * 10, denominator:1)),
434 }
435 }
436}
437
438/// Number of repetitions for a GIF animation
439#[derive(Clone, Copy, Debug)]
440pub enum Repeat {
441 /// Finite number of repetitions
442 Finite(u16),
443 /// Looping GIF
444 Infinite,
445}
446
447impl Repeat {
448 pub(crate) fn to_gif_enum(&self) -> gif::Repeat {
449 match self {
450 Repeat::Finite(n: &u16) => gif::Repeat::Finite(*n),
451 Repeat::Infinite => gif::Repeat::Infinite,
452 }
453 }
454}
455
456/// GIF encoder.
457pub struct GifEncoder<W: Write> {
458 w: Option<W>,
459 gif_encoder: Option<gif::Encoder<W>>,
460 speed: i32,
461 repeat: Option<Repeat>,
462}
463
464impl<W: Write> GifEncoder<W> {
465 /// Creates a new GIF encoder with a speed of 1. This prioritizes quality over performance at any cost.
466 pub fn new(w: W) -> GifEncoder<W> {
467 Self::new_with_speed(w, 1)
468 }
469
470 /// Create a new GIF encoder, and has the speed parameter `speed`. See
471 /// [`Frame::from_rgba_speed`](https://docs.rs/gif/latest/gif/struct.Frame.html#method.from_rgba_speed)
472 /// for more information.
473 pub fn new_with_speed(w: W, speed: i32) -> GifEncoder<W> {
474 assert!(
475 (1..=30).contains(&speed),
476 "speed needs to be in the range [1, 30]"
477 );
478 GifEncoder {
479 w: Some(w),
480 gif_encoder: None,
481 speed,
482 repeat: None,
483 }
484 }
485
486 /// Set the repeat behaviour of the encoded GIF
487 pub fn set_repeat(&mut self, repeat: Repeat) -> ImageResult<()> {
488 if let Some(ref mut encoder) = self.gif_encoder {
489 encoder
490 .set_repeat(repeat.to_gif_enum())
491 .map_err(ImageError::from_encoding)?;
492 }
493 self.repeat = Some(repeat);
494 Ok(())
495 }
496
497 /// Encode a single image.
498 pub fn encode(
499 &mut self,
500 data: &[u8],
501 width: u32,
502 height: u32,
503 color: ColorType,
504 ) -> ImageResult<()> {
505 let (width, height) = self.gif_dimensions(width, height)?;
506 match color {
507 ColorType::Rgb8 => self.encode_gif(Frame::from_rgb(width, height, data)),
508 ColorType::Rgba8 => {
509 self.encode_gif(Frame::from_rgba(width, height, &mut data.to_owned()))
510 }
511 _ => Err(ImageError::Unsupported(
512 UnsupportedError::from_format_and_kind(
513 ImageFormat::Gif.into(),
514 UnsupportedErrorKind::Color(color.into()),
515 ),
516 )),
517 }
518 }
519
520 /// Encode one frame of animation.
521 pub fn encode_frame(&mut self, img_frame: animation::Frame) -> ImageResult<()> {
522 let frame = self.convert_frame(img_frame)?;
523 self.encode_gif(frame)
524 }
525
526 /// Encodes Frames.
527 /// Consider using `try_encode_frames` instead to encode an `animation::Frames` like iterator.
528 pub fn encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
529 where
530 F: IntoIterator<Item = animation::Frame>,
531 {
532 for img_frame in frames {
533 self.encode_frame(img_frame)?;
534 }
535 Ok(())
536 }
537
538 /// Try to encode a collection of `ImageResult<animation::Frame>` objects.
539 /// Use this function to encode an `animation::Frames` like iterator.
540 /// Whenever an `Err` item is encountered, that value is returned without further actions.
541 pub fn try_encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
542 where
543 F: IntoIterator<Item = ImageResult<animation::Frame>>,
544 {
545 for img_frame in frames {
546 self.encode_frame(img_frame?)?;
547 }
548 Ok(())
549 }
550
551 pub(crate) fn convert_frame(
552 &mut self,
553 img_frame: animation::Frame,
554 ) -> ImageResult<Frame<'static>> {
555 // get the delay before converting img_frame
556 let frame_delay = img_frame.delay().into_ratio().to_integer();
557 // convert img_frame into RgbaImage
558 let mut rbga_frame = img_frame.into_buffer();
559 let (width, height) = self.gif_dimensions(rbga_frame.width(), rbga_frame.height())?;
560
561 // Create the gif::Frame from the animation::Frame
562 let mut frame = Frame::from_rgba_speed(width, height, &mut rbga_frame, self.speed);
563 // Saturate the conversion to u16::MAX instead of returning an error as that
564 // would require a new special cased variant in ParameterErrorKind which most
565 // likely couldn't be reused for other cases. This isn't a bad trade-off given
566 // that the current algorithm is already lossy.
567 frame.delay = (frame_delay / 10).try_into().unwrap_or(std::u16::MAX);
568
569 Ok(frame)
570 }
571
572 fn gif_dimensions(&self, width: u32, height: u32) -> ImageResult<(u16, u16)> {
573 fn inner_dimensions(width: u32, height: u32) -> Option<(u16, u16)> {
574 let width = u16::try_from(width).ok()?;
575 let height = u16::try_from(height).ok()?;
576 Some((width, height))
577 }
578
579 // TODO: this is not very idiomatic yet. Should return an EncodingError.
580 inner_dimensions(width, height).ok_or_else(|| {
581 ImageError::Parameter(ParameterError::from_kind(
582 ParameterErrorKind::DimensionMismatch,
583 ))
584 })
585 }
586
587 pub(crate) fn encode_gif(&mut self, mut frame: Frame) -> ImageResult<()> {
588 let gif_encoder;
589 if let Some(ref mut encoder) = self.gif_encoder {
590 gif_encoder = encoder;
591 } else {
592 let writer = self.w.take().unwrap();
593 let mut encoder = gif::Encoder::new(writer, frame.width, frame.height, &[])
594 .map_err(ImageError::from_encoding)?;
595 if let Some(ref repeat) = self.repeat {
596 encoder
597 .set_repeat(repeat.to_gif_enum())
598 .map_err(ImageError::from_encoding)?;
599 }
600 self.gif_encoder = Some(encoder);
601 gif_encoder = self.gif_encoder.as_mut().unwrap()
602 }
603
604 frame.dispose = gif::DisposalMethod::Background;
605
606 gif_encoder
607 .write_frame(&frame)
608 .map_err(ImageError::from_encoding)
609 }
610}
611
612impl ImageError {
613 fn from_decoding(err: gif::DecodingError) -> ImageError {
614 use gif::DecodingError::*;
615 match err {
616 err: DecodingError @ Format(_) => {
617 ImageError::Decoding(DecodingError::new(format:ImageFormat::Gif.into(), err))
618 }
619 Io(io_err: Error) => ImageError::IoError(io_err),
620 }
621 }
622
623 fn from_encoding(err: gif::EncodingError) -> ImageError {
624 use gif::EncodingError::*;
625 match err {
626 err: EncodingError @ Format(_) => {
627 ImageError::Encoding(EncodingError::new(format:ImageFormat::Gif.into(), err))
628 }
629 Io(io_err: Error) => ImageError::IoError(io_err),
630 }
631 }
632}
633
634#[cfg(test)]
635mod test {
636 use super::*;
637
638 #[test]
639 fn frames_exceeding_logical_screen_size() {
640 // This is a gif with 10x10 logical screen, but a 16x16 frame + 6px offset inside.
641 let data = vec![
642 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x0A, 0x00, 0x0A, 0x00, 0xF0, 0x00, 0x00, 0x00,
643 0x00, 0x00, 0x0E, 0xFF, 0x1F, 0x21, 0xF9, 0x04, 0x09, 0x64, 0x00, 0x00, 0x00, 0x2C,
644 0x06, 0x00, 0x06, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x02, 0x23, 0x84, 0x8F, 0xA9,
645 0xBB, 0xE1, 0xE8, 0x42, 0x8A, 0x0F, 0x50, 0x79, 0xAE, 0xD1, 0xF9, 0x7A, 0xE8, 0x71,
646 0x5B, 0x48, 0x81, 0x64, 0xD5, 0x91, 0xCA, 0x89, 0x4D, 0x21, 0x63, 0x89, 0x4C, 0x09,
647 0x77, 0xF5, 0x6D, 0x14, 0x00, 0x3B,
648 ];
649
650 let decoder = GifDecoder::new(Cursor::new(data)).unwrap();
651 let mut buf = vec![0u8; decoder.total_bytes() as usize];
652
653 assert!(decoder.read_image(&mut buf).is_ok());
654 }
655}
656