diff --git a/src/codecs/webp/decoder.rs b/src/codecs/webp/decoder.rs index 4395b76140..da50c471a5 100644 --- a/src/codecs/webp/decoder.rs +++ b/src/codecs/webp/decoder.rs @@ -321,16 +321,35 @@ impl<'a, R: 'a + Read> ImageDecoder<'a> for WebPDecoder { } fn read_image(self, buf: &mut [u8]) -> ImageResult<()> { - assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes())); - match &self.image { WebPImage::Lossy(vp8_frame) => { + assert_eq!( + buf.len(), + vp8_frame.get_buf_size(), + "Buffer size mismatch, got {} but need {}", + buf.len(), + vp8_frame.get_buf_size() + ); vp8_frame.fill_rgb(buf); } WebPImage::Lossless(lossless_frame) => { + assert_eq!( + buf.len(), + lossless_frame.get_buf_size(), + "Buffer size mismatch, got {} but need {}", + buf.len(), + lossless_frame.get_buf_size() + ); lossless_frame.fill_rgba(buf); } WebPImage::Extended(extended) => { + assert_eq!( + buf.len(), + extended.get_buf_size(), + "Buffer size mismatch, got {} but need {}", + buf.len(), + extended.get_buf_size() + ); extended.fill_buf(buf); } } diff --git a/src/codecs/webp/extended.rs b/src/codecs/webp/extended.rs index d3a5e0090b..fe7d48c529 100644 --- a/src/codecs/webp/extended.rs +++ b/src/codecs/webp/extended.rs @@ -93,10 +93,10 @@ impl ExtendedImage { pub(crate) fn color_type(&self) -> ColorType { match &self.image { - ExtendedImageData::Animation { frames, .. } => &frames[0].image, - ExtendedImageData::Static(image) => image, + // animation frames are always rendered to RGBA8 (see into_frames() function below) + ExtendedImageData::Animation { .. } => ColorType::Rgba8, + ExtendedImageData::Static(image) => image.color_type(), } - .color_type() } pub(crate) fn into_frames<'a>(self) -> Frames<'a> { @@ -147,6 +147,54 @@ impl ExtendedImage { Frames::new(Box::new(frame_iter)) } + pub(crate) fn as_frames<'a>(&'a self) -> Frames<'a> { + struct FrameIterator<'a> { + image: &'a ExtendedImage, + index: usize, + canvas: RgbaImage, + } + + impl<'a> Iterator for FrameIterator<'a> { + type Item = ImageResult; + + fn next(&mut self) -> Option { + if let ExtendedImageData::Animation { frames, anim_info } = &self.image.image { + let frame = frames.get(self.index); + match frame { + Some(anim_image) => { + self.index += 1; + ExtendedImage::draw_subimage( + &mut self.canvas, + anim_image, + anim_info.background_color, + ) + } + None => None, + } + } else { + None + } + } + } + + let width = self.info.canvas_width; + let height = self.info.canvas_height; + let background_color = + if let ExtendedImageData::Animation { ref anim_info, .. } = self.image { + anim_info.background_color + } else { + Rgba([0, 0, 0, 0]) + }; + + let frame_iter = FrameIterator { + image: &self, + index: 0, + canvas: RgbaImage::from_pixel(width, height, background_color), + }; + + Frames::new(Box::new(frame_iter)) + } + pub(crate) fn read_extended_chunks( reader: &mut R, mut info: WebPExtendedInfo, @@ -324,19 +372,27 @@ impl ExtendedImage { pub(crate) fn fill_buf(&self, buf: &mut [u8]) { match &self.image { // will always have at least one frame - ExtendedImageData::Animation { frames, .. } => &frames[0].image, - ExtendedImageData::Static(image) => image, + ExtendedImageData::Animation { .. } => { + let frame = self.as_frames().nth(0).unwrap().ok().unwrap(); + buf.copy_from_slice(frame.buffer()); + } + ExtendedImageData::Static(image) => image.fill_buf(buf), } - .fill_buf(buf); } pub(crate) fn get_buf_size(&self) -> usize { match &self.image { // will always have at least one frame - ExtendedImageData::Animation { frames, .. } => &frames[0].image, - ExtendedImageData::Static(image) => image, + ExtendedImageData::Animation { .. } => self + .as_frames() + .nth(0) + .unwrap() + .ok() + .unwrap() + .buffer() + .len(), + ExtendedImageData::Static(image) => image.get_buf_size(), } - .get_buf_size() } } diff --git a/tests/reference/webp/extended_images/anim.webp.f6449d24.png b/tests/reference/webp/extended_images/anim.webp.f6449d24.png deleted file mode 100644 index daf1dc0fd7..0000000000 Binary files a/tests/reference/webp/extended_images/anim.webp.f6449d24.png and /dev/null differ diff --git a/tests/reference/webp/extended_images/anim.webp.f9f4035e.png b/tests/reference/webp/extended_images/anim.webp.f9f4035e.png new file mode 100644 index 0000000000..75ed60c105 Binary files /dev/null and b/tests/reference/webp/extended_images/anim.webp.f9f4035e.png differ