Add a couple of tests for background picking
- ID
76bab5d- date
2024-05-12 12:48:38+00:00- author
Alex Chan <alex@alexwlchan.net>- parent
c523110- message
Add a couple of tests for background picking- changed files
4 files, 81 additions, 31 deletions
Changed files
src/find_dominant_colors.rs (2228) → src/find_dominant_colors.rs (2737)
diff --git a/src/find_dominant_colors.rs b/src/find_dominant_colors.rs
index a437a4c..2e03315 100644
--- a/src/find_dominant_colors.rs
+++ b/src/find_dominant_colors.rs
@@ -1,5 +1,5 @@
use kmeans_colors::get_kmeans_hamerly;
-use palette::{color_difference::Wcag21RelativeContrast, FromColor, Hsl, Lab, Srgb};
+use palette::{color_difference::Wcag21RelativeContrast, FromColor, Lab, Srgb};
pub fn find_dominant_colors(lab: &Vec<Lab>, max_colors: usize) -> Vec<Lab> {
// This is based on code from the kmeans-colors binary, but with a bunch of
@@ -40,18 +40,42 @@ pub fn choose_best_color_for_bg(colors: Vec<Lab>, background: &Srgb<u8>) -> Vec<
// Filter for colors which meet the min contrast ratio
let allowed_colors: Vec<Srgb<f32>> = extended_colors
.into_iter()
- .filter(|c| background.has_min_contrast_text(*c))
+ .filter(|c| background.has_min_contrast_graphics(*c))
.collect();
// Now pick the color with the highest saturation among the remaining.
let best_color: Srgb<f32> = allowed_colors
.into_iter()
.max_by(|color_a, color_b| {
- let saturation_a = Hsl::new_srgb(color_a.red, color_a.green, color_a.blue).saturation;
- let saturation_b = Hsl::new_srgb(color_b.red, color_b.green, color_b.blue).saturation;
- saturation_a.partial_cmp(&saturation_b).unwrap()
+ saturation(color_a)
+ .partial_cmp(&saturation(color_b))
+ .unwrap()
})
.unwrap();
vec![Lab::from_color(best_color)]
}
+
+// Based on https://filmentor.academy/en/blogs/news/die-wunderbare-welt-der-mathematik-fur-farben
+fn saturation(c: &Srgb<f32>) -> f32 {
+ let min_rgb: f32 = vec![c.red, c.green, c.blue]
+ .into_iter()
+ .min_by(|a, b| a.partial_cmp(b).unwrap())
+ .unwrap();
+ let max_rgb: f32 = vec![c.red, c.green, c.blue]
+ .into_iter()
+ .max_by(|a, b| a.partial_cmp(b).unwrap())
+ .unwrap();
+
+ if min_rgb == max_rgb {
+ return 0.0;
+ }
+
+ let luminosity: f32 = 0.5 * (min_rgb + max_rgb);
+
+ if luminosity == 1.0 {
+ 0.0
+ } else {
+ (max_rgb - min_rgb) / (1.0 - (2.0 * luminosity - 1.0).abs())
+ }
+}
src/main.rs (8239) → src/main.rs (8024)
diff --git a/src/main.rs b/src/main.rs
index 3323a51..4d4ecbf 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,6 +8,7 @@ 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();
@@ -37,32 +38,7 @@ fn main() {
.collect::<Vec<Srgb<u8>>>();
for c in rgb_colors {
- print_color(c, &background, matches.get_flag("no-palette"));
- }
-}
-
-// Print the colours to the terminal, using ANSI escape codes to
-// apply formatting if desired.
-//
-// See https://alexwlchan.net/2021/04/coloured-squares/
-// See: https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797?permalink_comment_id=3857871
-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 {
- println!("{}", display_value);
- } else {
- // If a background colour is specified, print it behind the
- // hex strings.
- match background {
- Some(bg) => print!("\x1B[48;2;{};{};{}m", bg.red, bg.green, bg.blue),
- _ => (),
- };
-
- println!(
- "\x1B[38;2;{};{};{}m▇ {}\x1B[0m",
- c.red, c.green, c.blue, display_value
- );
+ printing::print_color(c, &background, matches.get_flag("no-palette"));
}
}
@@ -245,6 +221,30 @@ mod tests {
);
}
+ #[test]
+ fn it_chooses_the_right_color_for_a_dark_background() {
+ let output = get_success(&[
+ "src/tests/stripes.png",
+ "--max-colours=5",
+ "--best-against-bg=#222",
+ "--no-palette"
+ ]);
+
+ assert_eq!(output.stdout, "#d4fb79\n");
+ }
+
+ #[test]
+ fn it_chooses_the_right_color_for_a_light_background() {
+ let output = get_success(&[
+ "src/tests/stripes.png",
+ "--max-colours=5",
+ "--best-against-bg=#fff",
+ "--no-palette"
+ ]);
+
+ assert_eq!(output.stdout, "#a35c00\n");
+ }
+
struct DcOutput {
exit_code: i32,
stdout: String,
src/printing.rs (0) → src/printing.rs (881)
diff --git a/src/printing.rs b/src/printing.rs
new file mode 100644
index 0000000..8cc5441
--- /dev/null
+++ b/src/printing.rs
@@ -0,0 +1,26 @@
+use palette::Srgb;
+
+// Print the colours to the terminal, using ANSI escape codes to
+// apply formatting if desired.
+//
+// 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) {
+ let display_value = format!("#{:02x}{:02x}{:02x}", c.red, c.green, c.blue);
+
+ if no_palette {
+ println!("{}", display_value);
+ } else {
+ // If a background colour is specified, print it behind the
+ // hex strings.
+ match background {
+ Some(bg) => print!("\x1B[48;2;{};{};{}m", bg.red, bg.green, bg.blue),
+ _ => (),
+ };
+
+ println!(
+ "\x1B[38;2;{};{};{}m▇ {}\x1B[0m",
+ c.red, c.green, c.blue, display_value
+ );
+ }
+}
src/tests/stripes.png (0) → src/tests/stripes.png (1778)
diff --git a/src/tests/stripes.png b/src/tests/stripes.png
new file mode 100644
index 0000000..ccf56e5
Binary files /dev/null and b/src/tests/stripes.png differ