Skip to content

Commit

Permalink
Switch to using the Derive API for Clap
Browse files Browse the repository at this point in the history
This is the recommended approach in the Clap docs, and I'm not doing
anything complicated enough to require the Builder API.  Let's simplify!
  • Loading branch information
alexwlchan committed Jun 17, 2024
1 parent d0b8a83 commit 0a6530f
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 76 deletions.
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ edition = "2018"

[dependencies]
assert_cmd = "2.0.14"
clap = "4.5.7"
clap = { version = "4.5.7", features = ["derive"] }
regex = "1.10.5"

[dependencies.kmeans_colors]
Expand Down
47 changes: 0 additions & 47 deletions src/cli.rs

This file was deleted.

22 changes: 13 additions & 9 deletions src/get_image_colors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,22 @@
//
// It returns a Vec<Lab>, which can be passed to the k-means process.

use std::ffi::OsStr;
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;

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)
pub fn get_image_colors(path: &PathBuf) -> Vec<Lab> {
let image_bytes = match path.extension().and_then(OsStr::to_str) {
Some("gif") => get_bytes_for_gif(&path),
Some("GIF") => get_bytes_for_gif(&path),
_ => get_bytes_for_non_gif(&path),
};

let lab: Vec<Lab> = from_component_slice::<Srgba<u8>>(&image_bytes)
Expand All @@ -30,7 +32,7 @@ pub fn get_image_colors(path: &str) -> Vec<Lab> {
lab
}

fn get_bytes_for_non_gif(path: &str) -> Vec<u8> {
fn get_bytes_for_non_gif(path: &PathBuf) -> Vec<u8> {
let img = match image::open(&path) {
Ok(im) => im,
Err(e) => {
Expand Down Expand Up @@ -59,7 +61,7 @@ fn get_bytes_for_non_gif(path: &str) -> Vec<u8> {
resized_img.into_rgba8().into_raw()
}

fn get_bytes_for_gif(path: &str) -> Vec<u8> {
fn get_bytes_for_gif(path: &PathBuf) -> Vec<u8> {
let f = match File::open(path) {
Ok(im) => im,
Err(e) => {
Expand Down Expand Up @@ -132,6 +134,8 @@ fn get_bytes_for_gif(path: &str) -> Vec<u8> {

#[cfg(test)]
mod test {
use std::path::PathBuf;

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
Expand All @@ -141,11 +145,11 @@ mod test {
// processed correctly.
#[test]
fn it_gets_colors_for_mri_fruit() {
get_image_colors("./src/tests/garlic.gif");
get_image_colors(&PathBuf::from("./src/tests/garlic.gif"));
}

#[test]
fn get_colors_for_webp() {
get_image_colors("./src/tests/purple.webp");
get_image_colors(&PathBuf::from("./src/tests/purple.webp"));
}
}
45 changes: 27 additions & 18 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,53 @@
#![deny(warnings)]

#[macro_use]
extern crate clap;
use std::path::PathBuf;

use clap::Parser;
use palette::{FromColor, Lab, Srgb};

mod cli;
mod find_dominant_colors;
mod get_image_colors;
mod printing;

fn main() {
let matches = cli::app().get_matches();
#[derive(Parser, Debug)]
#[command(version, about, long_about=None)]
struct Cli {
/// path to the image to inspect
path: PathBuf,

/// how many colours to find
#[arg(long="max-colours", default_value_t=5)]
max_colours: usize,

let path = matches
.get_one::<String>("PATH")
.expect("`path` is required");
/// find a single colour that will look best against this background
#[arg(long="best-against-bg")]
background: Option<Srgb<u8>>,

let max_colours: usize = *matches
.get_one::<usize>("MAX_COLOURS")
.expect("`max-colours` is required");
/// just print the hex values, not colour previews
#[arg(long="no-palette")]
no_palette: bool,
}

let lab: Vec<Lab> = get_image_colors::get_image_colors(&path);

let dominant_colors = find_dominant_colors::find_dominant_colors(&lab, max_colours);
fn main() {
let cli = Cli::parse();

let background = matches.get_one::<Srgb<u8>>("BACKGROUND_HEX");
let lab: Vec<Lab> = get_image_colors::get_image_colors(&cli.path);

let selected_colors = match background {
Some(bg) => find_dominant_colors::choose_best_color_for_bg(dominant_colors.clone(), bg),
let dominant_colors = find_dominant_colors::find_dominant_colors(&lab, cli.max_colours);

let selected_colors = match cli.background {
Some(bg) => find_dominant_colors::choose_best_color_for_bg(dominant_colors.clone(), &bg),
None => dominant_colors,
};

//
let rgb_colors = selected_colors
.iter()
.map(|c| Srgb::from_color(*c).into_format())
.collect::<Vec<Srgb<u8>>>();

for c in rgb_colors {
printing::print_color(c, &background, matches.get_flag("no-palette"));
printing::print_color(c, &cli.background, cli.no_palette);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/printing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use palette::Srgb;
//
// See https://alexwlchan.net/2021/04/coloured-squares/
// See: https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797?permalink_comment_id=3857871
pub fn print_color(c: Srgb<u8>, background: &Option<&Srgb<u8>>, no_palette: bool) {
pub fn print_color(c: Srgb<u8>, background: &Option<Srgb<u8>>, no_palette: bool) {
let display_value = format!("#{:02x}{:02x}{:02x}", c.red, c.green, c.blue);

if no_palette {
Expand Down

0 comments on commit 0a6530f

Please sign in to comment.