Skip to content

Commit 1207aca

Browse files
authored
webp frames iterator is now ending iteration if no more frames are decodable (#2228)
1 parent bc05c8c commit 1207aca

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

src/codecs/webp/decoder.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,16 @@ impl<'a, R: 'a + Read + Seek> AnimationDecoder<'a> for WebPDecoder<R> {
6868
fn into_frames(self) -> Frames<'a> {
6969
struct FramesInner<R: Read + Seek> {
7070
decoder: WebPDecoder<R>,
71+
current: u32,
7172
}
7273
impl<R: Read + Seek> Iterator for FramesInner<R> {
7374
type Item = ImageResult<Frame>;
7475

7576
fn next(&mut self) -> Option<Self::Item> {
77+
if self.current == self.decoder.inner.num_frames() {
78+
return None;
79+
}
80+
self.current += 1;
7681
let (width, height) = self.decoder.inner.dimensions();
7782

7883
let (img, delay) = if self.decoder.inner.has_alpha() {
@@ -98,7 +103,10 @@ impl<'a, R: 'a + Read + Seek> AnimationDecoder<'a> for WebPDecoder<R> {
98103
}
99104
}
100105

101-
Frames::new(Box::new(FramesInner { decoder: self }))
106+
Frames::new(Box::new(FramesInner {
107+
decoder: self,
108+
current: 0,
109+
}))
102110
}
103111
}
104112

tests/regression.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
use std::{fs::File, io::BufReader, path::PathBuf};
1+
use std::{
2+
fs::{self, File},
3+
io::{BufReader, Cursor},
4+
path::PathBuf,
5+
};
6+
7+
#[cfg(feature = "webp")]
8+
use image::{codecs::webp::WebPDecoder, AnimationDecoder};
29

310
const BASE_PATH: [&str; 2] = [".", "tests"];
411
const IMAGE_DIR: &str = "images";
@@ -37,6 +44,30 @@ fn check_regressions() {
3744
let _ = image::open(path);
3845
})
3946
}
47+
/// Check that the WEBP frames iterator returns the right amount of frames.
48+
#[test]
49+
#[cfg(feature = "webp")]
50+
fn check_webp_frames_regressions() {
51+
let path: PathBuf = BASE_PATH
52+
.iter()
53+
.collect::<PathBuf>()
54+
.join(IMAGE_DIR)
55+
.join("webp/extended_images")
56+
.join("*.webp");
57+
let pattern = &*format!("{}", path.display());
58+
for path in glob::glob(pattern).unwrap().filter_map(Result::ok) {
59+
let bytes = fs::read(path).unwrap();
60+
let cursor = Cursor::new(&bytes);
61+
let frame_count = image_webp::WebPDecoder::new(cursor.clone())
62+
.unwrap()
63+
.num_frames() as usize;
64+
let decoder = WebPDecoder::new(cursor).unwrap();
65+
// The `take` guards against a potentially infinitely running iterator.
66+
// Since we take `frame_count + 1`, we can assume that the last iteration already returns `None`.
67+
let actual_frame_count = decoder.into_frames().take(frame_count + 1).count();
68+
assert_eq!(actual_frame_count, frame_count);
69+
}
70+
}
4071

4172
/// Check that BMP files with large values could cause OOM issues are rejected.
4273
///

0 commit comments

Comments
 (0)