Merge pull request #36 from alexwlchan/get-image-colors
- ID
16cc283- date
2024-05-12 09:50:02+00:00- author
Alex Chan <alex@alexwlchan.net>- parents
078fc68,13869b3- message
Merge pull request #36 from alexwlchan/get-image-colors Rename 'get_bytes' to 'get_image_colors'- changed files
2 files, 33 additions, 20 deletions
Changed files
src/get_bytes.rs (4362) → src/get_image_colors.rs (5109)
diff --git a/src/get_bytes.rs b/src/get_image_colors.rs
similarity index 86%
rename from src/get_bytes.rs
rename to src/get_image_colors.rs
index f028477..42ff9e9 100644
--- a/src/get_bytes.rs
+++ b/src/get_image_colors.rs
@@ -1,11 +1,36 @@
+// This file exports a single function, which is used to read the
+// pixel data from an image.
+//
+// This includes resizing the image to a smaller size (~400×400) for
+// faster downstream computations.
+//
+// It returns a Vec<Lab>, which can be passed to the k-means process.
+
use std::fs::File;
use std::io::BufReader;
use image::codecs::gif::GifDecoder;
use image::imageops::FilterType;
use image::{AnimationDecoder, DynamicImage, Frame};
+use palette::cast::from_component_slice;
+use palette::{IntoColor, Lab, Srgba};
+
+pub fn get_image_colors(path: &str) -> Vec<Lab> {
+ let image_bytes = if path.to_lowercase().ends_with(".gif") {
+ get_bytes_for_gif(&path)
+ } else {
+ get_bytes_for_non_gif(&path)
+ };
+
+ let lab: Vec<Lab> = from_component_slice::<Srgba<u8>>(&image_bytes)
+ .iter()
+ .map(|x| x.into_format::<_, f32>().into_color())
+ .collect();
+
+ lab
+}
-pub fn get_bytes_for_image(path: &str) -> Vec<u8> {
+fn get_bytes_for_non_gif(path: &str) -> Vec<u8> {
let img = match image::open(&path) {
Ok(im) => im,
Err(e) => {
@@ -34,7 +59,7 @@ pub fn get_bytes_for_image(path: &str) -> Vec<u8> {
resized_img.into_rgba8().into_raw()
}
-pub fn get_bytes_for_gif(path: &str) -> Vec<u8> {
+fn get_bytes_for_gif(path: &str) -> Vec<u8> {
let f = match File::open(path) {
Ok(im) => im,
Err(e) => {
@@ -107,7 +132,7 @@ pub fn get_bytes_for_gif(path: &str) -> Vec<u8> {
#[cfg(test)]
mod test {
- use crate::get_bytes;
+ use crate::get_image_colors::get_image_colors;
// This image comes from https://stacks.wellcomecollection.org/peering-through-mri-scans-of-fruit-and-veg-part-1-a2e8b07bde6f
//
@@ -115,7 +140,7 @@ mod test {
// caused v1.1.2 to fall over. This is a test that they can still be
// processed correctly.
#[test]
- fn it_gets_bytes_for_mri_fruit() {
- get_bytes::get_bytes_for_gif("./src/tests/garlic.gif");
+ fn it_gets_colors_for_mri_fruit() {
+ get_image_colors("./src/tests/garlic.gif");
}
}
src/main.rs (8383) → src/main.rs (7921)
diff --git a/src/main.rs b/src/main.rs
index e0e8d1f..3fb70f0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,11 +4,10 @@
extern crate clap;
use kmeans_colors::get_kmeans_hamerly;
-use palette::cast::from_component_slice;
-use palette::{FromColor, IntoColor, Lab, Srgb, Srgba};
+use palette::{FromColor, Lab, Srgb};
mod cli;
-mod get_bytes;
+mod get_image_colors;
fn main() {
let matches = cli::app().get_matches();
@@ -21,22 +20,11 @@ fn main() {
.get_one::<usize>("MAX-COLOURS")
.expect("`max-colours` is required");
- // There's different code for fetching bytes from GIF images because
- // GIFs are often animated, and we want a selection of frames.
- let img_bytes = if path.to_lowercase().ends_with(".gif") {
- get_bytes::get_bytes_for_gif(&path)
- } else {
- get_bytes::get_bytes_for_image(&path)
- };
+ let lab: Vec<Lab> = get_image_colors::get_image_colors(&path);
// This is based on code from the kmeans-colors binary, but with a bunch of
// the options stripped out.
// See https://github.com/okaneco/kmeans-colors/blob/0.5.0/src/bin/kmeans_colors/app.rs
- let lab: Vec<Lab> = from_component_slice::<Srgba<u8>>(&img_bytes)
- .iter()
- .map(|x| x.into_format::<_, f32>().into_color())
- .collect();
-
let max_iterations = 20;
let converge = 1.0;
let verbose = false;