Skip to main content

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;