Skip to main content

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 {