1#![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
49pub struct GifDecoder<R: Read> {
51 reader: gif::Decoder<R>,
52 limits: Limits,
53}
54
55impl<R: Read> GifDecoder<R> {
56 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 #[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 decoder.set_limits(limits)?;
74 Ok(decoder)
75 }
76}
77
78pub 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 let line_length = usize::try_from(width)
152 .unwrap()
153 .checked_mul(self.color_type().bytes_per_pixel() as usize)
154 .unwrap();
155
156 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 for b in blank_top {
167 *b = 0;
168 }
169 self.reader
171 .read_into_buffer(buf)
172 .map_err(ImageError::from_decoding)?;
173 for b in blank_bottom {
175 *b = 0;
176 }
177 } else {
178 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 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 *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 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 const COLOR_TYPE: ColorType = ColorType::Rgba8;
266
267 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 let non_disposed_frame = self.non_disposed_frame.as_mut().unwrap();
285
286 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 return None;
295 }
296 }
297 Err(err) => return Some(Err(ImageError::from_decoding(err))),
298 };
299
300 let mut local_limits = self.limits.clone();
305
306 if let Err(e) = local_limits.reserve_buffer(frame.width, frame.height, COLOR_TYPE) {
308 return Some(Err(e));
309 }
310 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 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 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 *previous = *current;
355 }
356 DisposalMethod::Background => {
357 *previous = Rgba([0, 0, 0, 0]);
360 }
361 DisposalMethod::Previous => {
362 }
365 }
366 }
367
368 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 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 *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 delay: animation::Delay::from_ratio(Ratio::new(u32::from(frame.delay) * 10, 1)),
434 }
435 }
436}
437
438#[derive(Clone, Copy, Debug)]
440pub enum Repeat {
441 Finite(u16),
443 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
456pub 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 pub fn new(w: W) -> GifEncoder<W> {
467 Self::new_with_speed(w, 1)
468 }
469
470 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 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 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 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 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 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 let frame_delay = img_frame.delay().into_ratio().to_integer();
557 let mut rbga_frame = img_frame.into_buffer();
559 let (width, height) = self.gif_dimensions(rbga_frame.width(), rbga_frame.height())?;
560
561 let mut frame = Frame::from_rgba_speed(width, height, &mut rbga_frame, self.speed);
563 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 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 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}