Skip to content

Commit

Permalink
Merge pull request #36 from alexwlchan/get-image-colors
Browse files Browse the repository at this point in the history
Rename 'get_bytes' to 'get_image_colors'
  • Loading branch information
alexwlchan authored May 12, 2024
2 parents 078fc68 + 13869b3 commit 16cc283
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 20 deletions.
35 changes: 30 additions & 5 deletions src/get_bytes.rs → src/get_image_colors.rs
Original file line number Diff line number Diff line change
@@ -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) => {
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -107,15 +132,15 @@ 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
//
// I don't remember how I got these images, but for some reason they
// 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");
}
}
18 changes: 3 additions & 15 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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;
Expand Down

0 comments on commit 16cc283

Please sign in to comment.