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