Merge pull request #42 from alexwlchan/use-derive
- ID
7bfa5f8- date
2024-06-17 21:36:08+00:00- author
Alex Chan <alex@alexwlchan.net>- parents
d0b8a83,2cb43e3- message
Merge pull request #42 from alexwlchan/use-derive Switch to using the Derive API for Clap- changed files
6 files, 60 additions, 76 deletions
Changed files
Cargo.lock (17574) → Cargo.lock (18035)
diff --git a/Cargo.lock b/Cargo.lock
index e77faf7..5cfb1e6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -150,6 +150,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
dependencies = [
"clap_builder",
+ "clap_derive",
]
[[package]]
@@ -165,6 +166,18 @@ dependencies = [
]
[[package]]
+name = "clap_derive"
+version = "4.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "clap_lex"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -253,6 +266,12 @@ dependencies = [
]
[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
name = "image"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
Cargo.toml (441) → Cargo.toml (478)
diff --git a/Cargo.toml b/Cargo.toml
index 334e5bc..7d0a0ef 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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]
src/cli.rs (1384) → src/cli.rs (0)
diff --git a/src/cli.rs b/src/cli.rs
deleted file mode 100644
index d1c0b87..0000000
--- a/src/cli.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-use clap::{Arg, ArgAction, Command};
-use palette::Srgb;
-
-const VERSION: &str = env!("CARGO_PKG_VERSION");
-
-pub fn app() -> clap::Command {
- Command::new("dominant_colours")
- .version(VERSION)
- .author("Alex Chan <alex@alexwlchan.net>")
- .about("Find the dominant colours in an image")
- .arg(
- Arg::new("PATH")
- .help("path to the image to inspect")
- .required(true)
- .index(1),
- )
- .arg(
- Arg::new("MAX_COLOURS")
- .long("max-colours")
- .help("how many colours to find")
- .value_parser(value_parser!(usize))
- .default_value("5"),
- )
- .arg(
- Arg::new("BACKGROUND_HEX")
- .long("best-against-bg")
- .help("find a single colour that will look best against this background")
- .value_parser(value_parser!(Srgb<u8>)),
- )
- .arg(
- Arg::new("no-palette")
- .long("no-palette")
- .help("Just print the hex values, not colour previews")
- .action(ArgAction::SetTrue),
- )
-}
-
-#[cfg(test)]
-mod tests {
- use crate::cli::app;
-
- // See https://github.com/clap-rs/clap/blob/master/CHANGELOG.md#300---2021-12-31
- #[test]
- fn verify_app() {
- app().debug_assert();
- }
-}
src/get_image_colors.rs (5212) → src/get_image_colors.rs (5394)
diff --git a/src/get_image_colors.rs b/src/get_image_colors.rs
index c69ac00..19ec1b5 100644
--- a/src/get_image_colors.rs
+++ b/src/get_image_colors.rs
@@ -6,8 +6,10 @@
//
// 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;
@@ -15,11 +17,11 @@ 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)
@@ -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) => {
@@ -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) => {
@@ -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
@@ -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"));
}
}
src/main.rs (8365) → src/main.rs (8614)
diff --git a/src/main.rs b/src/main.rs
index 3031a60..18deca9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,44 +1,52 @@
#![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 = "Find the dominant colours in an image", 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);
+fn main() {
+ let cli = Cli::parse();
- let dominant_colors = find_dominant_colors::find_dominant_colors(&lab, max_colours);
+ let lab: Vec<Lab> = get_image_colors::get_image_colors(&cli.path);
- let background = matches.get_one::<Srgb<u8>>("BACKGROUND_HEX");
+ let dominant_colors = find_dominant_colors::find_dominant_colors(&lab, cli.max_colours);
- let selected_colors = match background {
- Some(bg) => find_dominant_colors::choose_best_color_for_bg(dominant_colors.clone(), bg),
+ 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);
}
}
src/printing.rs (881) → src/printing.rs (880)
diff --git a/src/printing.rs b/src/printing.rs
index 8cc5441..8704966 100644
--- a/src/printing.rs
+++ b/src/printing.rs
@@ -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 {