From 13869b34734f6a8efb952db64e7eeb75c58b5b3d Mon Sep 17 00:00:00 2001 From: Alex Chan Date: Sun, 12 May 2024 10:48:53 +0100 Subject: [PATCH] Rename 'get_bytes' to 'get_image_colors' This feels like a better abstraction imo. --- src/{get_bytes.rs => get_image_colors.rs} | 35 +++++++++++++++++++---- src/main.rs | 18 ++---------- 2 files changed, 33 insertions(+), 20 deletions(-) rename src/{get_bytes.rs => get_image_colors.rs} (80%) diff --git a/src/get_bytes.rs b/src/get_image_colors.rs similarity index 80% 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, 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 { + 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 = from_component_slice::>(&image_bytes) + .iter() + .map(|x| x.into_format::<_, f32>().into_color()) + .collect(); + + lab +} -pub fn get_bytes_for_image(path: &str) -> Vec { +fn get_bytes_for_non_gif(path: &str) -> Vec { let img = match image::open(&path) { Ok(im) => im, Err(e) => { @@ -34,7 +59,7 @@ pub fn get_bytes_for_image(path: &str) -> Vec { resized_img.into_rgba8().into_raw() } -pub fn get_bytes_for_gif(path: &str) -> Vec { +fn get_bytes_for_gif(path: &str) -> Vec { let f = match File::open(path) { Ok(im) => im, Err(e) => { @@ -107,7 +132,7 @@ pub fn get_bytes_for_gif(path: &str) -> Vec { #[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"); } } 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::("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 = 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 = from_component_slice::>(&img_bytes) - .iter() - .map(|x| x.into_format::<_, f32>().into_color()) - .collect(); - let max_iterations = 20; let converge = 1.0; let verbose = false;