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//! # 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 = gif::DecodeOptions::new();
59        decoder.set_color_output(ColorOutput::RGBA);
60
61        Ok(GifDecoder {
62            reader: decoder.read_info(r).map_err(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 = 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(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, height) = decoder.dimensions();
246        let 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(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(u32::from(frame.delay) * 10, 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) => 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 @ Format(_) => {
617                ImageError::Decoding(DecodingError::new(ImageFormat::Gif.into(), err))
618            }
619            Io(io_err) => ImageError::IoError(io_err),
620        }
621    }
622
623    fn from_encoding(err: gif::EncodingError) -> ImageError {
624        use gif::EncodingError::*;
625        match err {
626            err @ Format(_) => {
627                ImageError::Encoding(EncodingError::new(ImageFormat::Gif.into(), err))
628            }
629            Io(io_err) => 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}