image/codecs/
gif.rs

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 = 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/// 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(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, height) = decoder.dimensions();
237        let 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(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(u32::from(frame.delay) * 10, 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) => 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 @ 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        // 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}