Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 60 additions & 22 deletions src/codecs/webp/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,34 +118,63 @@ impl<'a, R: 'a + BufRead + Seek> AnimationDecoder<'a> for WebPDecoder<R> {
type Item = ImageResult<Frame>;

fn next(&mut self) -> Option<Self::Item> {
if self.current == self.decoder.inner.num_frames() {
let is_animated = self.decoder.inner.is_animated();
let num_frames = if is_animated {
self.decoder.inner.num_frames()
} else {
1
};
if self.current == num_frames {
return None;
}
self.current += 1;
let (width, height) = self.decoder.inner.dimensions();

let (img, delay) = if self.decoder.inner.has_alpha() {
let mut img = RgbaImage::new(width, height);
match self.decoder.inner.read_frame(&mut img) {
Ok(delay) => (img, delay),
Err(image_webp::DecodingError::NoMoreFrames) => return None,
Err(e) => return Some(Err(ImageError::from_webp_decode(e))),
}
if is_animated {
let (img, delay) = if self.decoder.inner.has_alpha() {
let mut img = RgbaImage::new(width, height);
match self.decoder.inner.read_frame(&mut img) {
Ok(delay) => (img, delay),
Err(image_webp::DecodingError::NoMoreFrames) => return None,
Err(e) => return Some(Err(ImageError::from_webp_decode(e))),
}
} else {
let mut img = RgbImage::new(width, height);
match self.decoder.inner.read_frame(&mut img) {
Ok(delay) => (img.convert(), delay),
Err(image_webp::DecodingError::NoMoreFrames) => return None,
Err(e) => return Some(Err(ImageError::from_webp_decode(e))),
}
};

Some(Ok(Frame::from_parts(
img,
0,
0,
Delay::from_numer_denom_ms(delay, 1),
)))
} else {
let mut img = RgbImage::new(width, height);
match self.decoder.inner.read_frame(&mut img) {
Ok(delay) => (img.convert(), delay),
Err(image_webp::DecodingError::NoMoreFrames) => return None,
Err(e) => return Some(Err(ImageError::from_webp_decode(e))),
}
};

Some(Ok(Frame::from_parts(
img,
0,
0,
Delay::from_numer_denom_ms(delay, 1),
)))
let img = if self.decoder.inner.has_alpha() {
let mut img = RgbaImage::new(width, height);
match self.decoder.inner.read_image(&mut img) {
Ok(()) => img,
Err(e) => return Some(Err(ImageError::from_webp_decode(e))),
}
} else {
let mut img = RgbImage::new(width, height);
match self.decoder.inner.read_image(&mut img) {
Ok(()) => img.convert(),
Err(e) => return Some(Err(ImageError::from_webp_decode(e))),
}
};

Some(Ok(Frame::from_parts(
img,
0,
0,
Delay::from_numer_denom_ms(0, 1),
)))
}
}
}

Expand Down Expand Up @@ -184,4 +213,13 @@ mod tests {

let _ = WebPDecoder::new(data);
}

#[test]
fn into_frames_non_animated() {
let data = std::fs::read("tests/images/webp/lossy_images/simple-rgb.webp").unwrap();
let decoder = WebPDecoder::new(std::io::Cursor::new(data)).unwrap();
assert!(!decoder.has_animation());
let frames: Vec<_> = decoder.into_frames().collect_frames().unwrap();
assert_eq!(frames.len(), 1);
}
}
9 changes: 6 additions & 3 deletions tests/regression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,12 @@ fn check_webp_frames_regressions() {
for path in glob::glob(pattern).unwrap().filter_map(Result::ok) {
let bytes = fs::read(&path).unwrap();
let cursor = Cursor::new(&bytes);
let frame_count = image_webp::WebPDecoder::new(cursor.clone())
.unwrap()
.num_frames() as usize;
let raw_decoder = image_webp::WebPDecoder::new(cursor.clone()).unwrap();
let frame_count = if raw_decoder.is_animated() {
raw_decoder.num_frames() as usize
} else {
1
};
let decoder = WebPDecoder::new(cursor).unwrap();
// The `take` guards against a potentially infinitely running iterator.
// Since we take `frame_count + 1`, we can assume that the last iteration already returns `None`.
Expand Down
Loading