Skip to content

Commit 9f6724b

Browse files
authored
Merge pull request #71 from alexwlchan/static-webp-bug
Fix a bug when getting colours for a non-animated WebP
2 parents bca18d1 + 81bb194 commit 9f6724b

6 files changed

+57
-7
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## v1.4.1 - 2024-11-06
4+
5+
* Fix a bug introduced in v1.3.0 where getting colours for non-animated WebP images would fail with an assertion error.
6+
37
## v1.4.0 - 2024-10-05
48

59
* `dominant_colours` will now skip printing terminal colours if it detects it's not running in a tty. This makes it slightly easier to use in automated environments, because you don't need to pass the `--no-palette` flag.

Cargo.lock

+2-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
[package]
22
name = "dominant_colours"
3-
version = "1.4.0"
3+
version = "1.4.1"
44
edition = "2018"
55

66
[dependencies]
77
assert_cmd = "2.0.16"
88
clap = { version = "4.5.20", features = ["derive"] }
9+
image-webp = "0.2.0"
910
regex = "1.11.1"
1011

1112
[dependencies.kmeans_colors]

src/find_dominant_colors.rs

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ pub fn find_dominant_colors(lab: &Vec<Lab>, max_colors: usize) -> Vec<Lab> {
1010
let verbose = false;
1111
let seed: u64 = 0;
1212

13+
assert!(lab.len() > 0);
14+
1315
let result = get_kmeans_hamerly(max_colors, max_iterations, converge, verbose, lab, seed);
1416

1517
result.centroids

src/get_image_colors.rs

+45-5
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub fn get_image_colors(path: &PathBuf) -> Result<Vec<Lab>, GetImageColorsErr> {
3030
get_bytes_for_animated_image(decoder)
3131
}
3232

33-
ImageFormat::WebP => {
33+
ImageFormat::WebP if is_animated_webp(path) => {
3434
let decoder = WebPDecoder::new(reader)?;
3535
get_bytes_for_animated_image(decoder)
3636
}
@@ -49,6 +49,7 @@ pub fn get_image_colors(path: &PathBuf) -> Result<Vec<Lab>, GetImageColorsErr> {
4949
Ok(lab)
5050
}
5151

52+
#[derive(Debug)]
5253
pub enum GetImageColorsErr {
5354
IoError(std::io::Error),
5455
ImageError(image::ImageError),
@@ -94,6 +95,22 @@ fn get_format(path: &PathBuf) -> Result<ImageFormat, GetImageColorsErr> {
9495
}
9596
}
9697

98+
/// Returns true if a WebP file is animated, and false otherwise.
99+
///
100+
/// This function assumes that the file exists and can be opened.
101+
fn is_animated_webp(path: &PathBuf) -> bool {
102+
let f = File::open(path).unwrap();
103+
let reader = BufReader::new(f);
104+
105+
match image_webp::WebPDecoder::new(reader) {
106+
// num_frames() returns the number of frames in the animation,
107+
// or zero if the image is not animated.
108+
// See https://docs.rs/image-webp/0.2.0/image_webp/struct.WebPDecoder.html#method.num_frames
109+
Ok(decoder) => decoder.num_frames() > 0,
110+
Err(_) => false,
111+
}
112+
}
113+
97114
fn get_bytes_for_static_image(img: DynamicImage) -> Vec<u8> {
98115
// Resize the image after we open it. For this tool I'd rather get a good answer
99116
// quickly than a great answer slower.
@@ -117,6 +134,7 @@ fn get_bytes_for_static_image(img: DynamicImage) -> Vec<u8> {
117134

118135
fn get_bytes_for_animated_image<'a>(decoder: impl AnimationDecoder<'a>) -> Vec<u8> {
119136
let frames: Vec<Frame> = decoder.into_frames().collect_frames().unwrap();
137+
assert!(frames.len() > 0);
120138

121139
// If the image is animated, we want to make sure we look at multiple
122140
// frames when choosing the dominant colour.
@@ -187,12 +205,34 @@ mod test {
187205
// caused v1.1.2 to fall over. This is a test that they can still be
188206
// processed correctly.
189207
#[test]
190-
fn it_gets_colors_for_mri_fruit() {
191-
assert!(get_image_colors(&PathBuf::from("./src/tests/garlic.gif")).is_ok());
208+
fn it_gets_colors_for_animated_gif() {
209+
let colors = get_image_colors(&PathBuf::from("./src/tests/garlic.gif"));
210+
211+
assert!(colors.is_ok());
212+
assert!(colors.unwrap().len() > 0);
192213
}
193214

194215
#[test]
195-
fn get_colors_for_webp() {
196-
assert!(get_image_colors(&PathBuf::from("./src/tests/purple.webp")).is_ok());
216+
fn get_colors_for_static_gif() {
217+
let colors = get_image_colors(&PathBuf::from("./src/tests/yellow.gif"));
218+
219+
assert!(colors.is_ok());
220+
assert!(colors.unwrap().len() > 0);
221+
}
222+
223+
#[test]
224+
fn get_colors_for_static_webp() {
225+
let colors = get_image_colors(&PathBuf::from("./src/tests/purple.webp"));
226+
227+
assert!(colors.is_ok());
228+
assert!(colors.unwrap().len() > 0);
229+
}
230+
231+
#[test]
232+
fn get_colors_for_animated_webp() {
233+
let colors = get_image_colors(&PathBuf::from("./src/tests/animated_squares.webp"));
234+
235+
assert!(colors.is_ok());
236+
assert!(colors.unwrap().len() > 0);
197237
}
198238
}

src/main.rs

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ fn main() {
4040
}
4141
};
4242

43+
assert!(lab.len() > 0);
44+
4345
let dominant_colors = find_dominant_colors::find_dominant_colors(&lab, cli.max_colours);
4446

4547
let selected_colors = match cli.background {

0 commit comments

Comments
 (0)