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//! use std::io::BufReader;
14//! # fn main() -> std::io::Result<()> {
15//! // Decode a gif into frames
16//! let file_in = BufReader::new(File::open("foo.gif")?);
17//! let mut decoder = GifDecoder::new(file_in).unwrap();
18//! let frames = decoder.into_frames();
19//! let frames = frames.collect_frames().expect("error decoding gif");
20//!
21//! // Encode frames into a gif and save to a file
22//! let mut file_out = File::open("out.gif")?;
23//! let mut encoder = GifEncoder::new(file_out);
24//! encoder.encode_frames(frames.into_iter());
25//! # Ok(())
26//! # }
27//! ```
28#![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
51/// GIF decoder
52pub struct GifDecoder<R: Read> {
53 reader: gif::Decoder<R>,
54 limits: Limits,
55}
56
57impl<R: Read> GifDecoder<R> {
58 /// Creates a new decoder that decodes the input steam `r`
59 pub fn new(r: R) -> ImageResult<GifDecoder<R>> {
60 let mut decoder: DecodeOptions = gif::DecodeOptions::new();
61 decoder.set_color_output(color:ColorOutput::RGBA);
62
63 Ok(GifDecoder {
64 reader: decoder.read_info(r).map_err(op:ImageError::from_decoding)?,
65 limits: Limits::no_limits(),
66 })
67 }
68}
69
70/// Wrapper struct around a `Cursor<Vec<u8>>`
71#[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(x: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 // If the frame matches the logical screen, or, as a more general case,
136 // fits into it and touches its left and right borders, then
137 // we can directly write it into the buffer without causing line wraparound.
138 let line_length = usize::try_from(width)
139 .unwrap()
140 .checked_mul(self.color_type().bytes_per_pixel() as usize)
141 .unwrap();
142
143 // isolate the portion of the buffer to read the frame data into.
144 // the chunks above and below it are going to be zeroed.
145 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 // this is only necessary in case the buffer is not zeroed
153 for b in blank_top {
154 *b = 0;
155 }
156 // fill the middle section with the frame data
157 self.reader
158 .read_into_buffer(buf)
159 .map_err(ImageError::from_decoding)?;
160 // this is only necessary in case the buffer is not zeroed
161 for b in blank_bottom {
162 *b = 0;
163 }
164 } else {
165 // If the frame does not match the logical screen, read into an extra buffer
166 // and 'insert' the frame from left/top to logical screen width/height.
167 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 // `buffer_size` uses wrapping arithmetic, thus might not report the
186 // correct storage requirement if the result does not fit in `usize`.
187 // `ImageBuffer::from_raw` detects overflow and reports by returning `None`.
188 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 // this is only necessary in case the buffer is not zeroed
211 *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: u32, height: u32) = decoder.dimensions();
237 let limits: Limits = decoder.limits.clone();
238
239 // intentionally ignore the background color for web compatibility
240
241 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 // The iterator always produces RGBA8 images
256 const COLOR_TYPE: ColorType = ColorType::Rgba8;
257
258 // Allocate the buffer for the previous frame.
259 // This is done here and not in the constructor because
260 // the constructor cannot return an error when the allocation limit is exceeded.
261 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 // Bind to a variable to avoid repeated `.unwrap()` calls
275 let non_disposed_frame = self.non_disposed_frame.as_mut().unwrap();
276
277 // begin looping over each frame
278
279 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 // no more frames
285 return None;
286 }
287 }
288 Err(err) => return Some(Err(ImageError::from_decoding(err))),
289 };
290
291 // All allocations we do from now on will be freed at the end of this function.
292 // Therefore, do not count them towards the persistent limits.
293 // Instead, create a local instance of `Limits` for this function alone
294 // which will be dropped along with all the buffers when they go out of scope.
295 let mut local_limits = self.limits.clone();
296
297 // Check the allocation we're about to perform against the limits
298 if let Err(e) = local_limits.reserve_buffer(frame.width, frame.height, COLOR_TYPE) {
299 return Some(Err(e));
300 }
301 // Allocate the buffer now that the limits allowed it
302 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 // create the image buffer from the raw frame.
308 // `buffer_size` uses wrapping arithmetic, thus might not report the
309 // correct storage requirement if the result does not fit in `usize`.
310 // on the other hand, `ImageBuffer::from_raw` detects overflow and
311 // reports by returning `None`.
312 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 // blend the current frame with the non-disposed frame, then update
325 // the non-disposed frame according to the disposal method.
326 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 // do not dispose
339 // (keep pixels from this frame)
340 // note: the `Any` disposal method is underspecified in the GIF
341 // spec, but most viewers treat it identically to `Keep`
342 *previous = *current;
343 }
344 DisposalMethod::Background => {
345 // restore to background color
346 // (background shows through transparent pixels in the next frame)
347 *previous = Rgba([0, 0, 0, 0]);
348 }
349 DisposalMethod::Previous => {
350 // restore to previous
351 // (dispose frames leaving the last none disposal frame)
352 }
353 }
354 }
355
356 // if `frame_buffer`'s frame exactly matches the entire image, then
357 // use it directly, else create a new buffer to hold the composited
358 // image.
359 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 // Check limits before allocating the buffer
369 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 // out of bounds, return pixel from previous frame
383 *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(iterator: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 // frame.delay is in units of 10ms so frame.delay*10 is in ms
421 delay: animation::Delay::from_ratio(Ratio::new(numerator:u32::from(frame.delay) * 10, denominator:1)),
422 }
423 }
424}
425
426/// Number of repetitions for a GIF animation
427#[derive(Clone, Copy, Debug)]
428pub enum Repeat {
429 /// Finite number of repetitions
430 Finite(u16),
431 /// Looping GIF
432 Infinite,
433}
434
435impl Repeat {
436 pub(crate) fn to_gif_enum(self) -> gif::Repeat {
437 match self {
438 Repeat::Finite(n: u16) => gif::Repeat::Finite(n),
439 Repeat::Infinite => gif::Repeat::Infinite,
440 }
441 }
442}
443
444/// GIF encoder.
445pub 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 /// Creates a new GIF encoder with a speed of 1. This prioritizes quality over performance at any cost.
454 pub fn new(w: W) -> GifEncoder<W> {
455 Self::new_with_speed(w, 1)
456 }
457
458 /// Create a new GIF encoder, and has the speed parameter `speed`. See
459 /// [`Frame::from_rgba_speed`](https://docs.rs/gif/latest/gif/struct.Frame.html#method.from_rgba_speed)
460 /// for more information.
461 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 /// Set the repeat behaviour of the encoded GIF
475 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 /// Encode a single image.
486 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 /// Encode one frame of animation.
509 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 /// Encodes Frames.
515 /// Consider using `try_encode_frames` instead to encode an `animation::Frames` like iterator.
516 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 /// Try to encode a collection of `ImageResult<animation::Frame>` objects.
527 /// Use this function to encode an `animation::Frames` like iterator.
528 /// Whenever an `Err` item is encountered, that value is returned without further actions.
529 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 // get the delay before converting img_frame
544 let frame_delay = img_frame.delay().into_ratio().to_integer();
545 // convert img_frame into RgbaImage
546 let mut rbga_frame = img_frame.into_buffer();
547 let (width, height) = self.gif_dimensions(rbga_frame.width(), rbga_frame.height())?;
548
549 // Create the gif::Frame from the animation::Frame
550 let mut frame = Frame::from_rgba_speed(width, height, &mut rbga_frame, self.speed);
551 // Saturate the conversion to u16::MAX instead of returning an error as that
552 // would require a new special cased variant in ParameterErrorKind which most
553 // likely couldn't be reused for other cases. This isn't a bad trade-off given
554 // that the current algorithm is already lossy.
555 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 // TODO: this is not very idiomatic yet. Should return an EncodingError.
568 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: DecodingError @ Format(_) => {
605 ImageError::Decoding(DecodingError::new(format:ImageFormat::Gif.into(), err))
606 }
607 Io(io_err: Error) => ImageError::IoError(io_err),
608 }
609 }
610
611 fn from_encoding(err: gif::EncodingError) -> ImageError {
612 use gif::EncodingError::*;
613 match err {
614 err: EncodingError @ Format(_) => {
615 ImageError::Encoding(EncodingError::new(format:ImageFormat::Gif.into(), err))
616 }
617 Io(io_err: Error) => 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 // This is a gif with 10x10 logical screen, but a 16x16 frame + 6px offset inside.
629 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}
644