image_effects/colour/
utils.rs

1use palette::{Srgb, FromColor, Lch};
2
3use super::comparisons::rgb_weighted_euclidean;
4
5#[inline] pub fn collapse_angle(angle: f32) -> f32 {
6    ((angle % 360.0) + 360.0) % 360.0
7}
8
9pub fn quantize_hue(original_hue: f32, hues: &[f32]) -> f32 {
10    let mut closest_dist = f32::MAX;
11    let pixel_hue = collapse_angle(original_hue);
12    let mut current_hue = pixel_hue;
13
14    for hue in hues.iter() {
15        let normalized = collapse_angle(*hue);
16        let distance = (normalized - pixel_hue).abs();
17        if distance < closest_dist {
18            closest_dist = distance;
19            current_hue = normalized;
20        }
21    }
22
23    current_hue
24}
25
26pub const ONE_BIT: &'static [Srgb] = &[
27    Srgb::new(0.0, 0.0, 0.0),
28    Srgb::new(1.0, 1.0, 1.0),
29];
30
31fn quantize_colour(
32    original: (f32, f32, f32),
33    palette: &[(f32, f32, f32)],
34    distance_fn: fn((f32, f32, f32), (f32, f32, f32)) -> f32,
35) -> (f32, f32, f32) {
36    let mut closest_distance = f32::MAX;
37    let mut current_colour = &original;
38
39    for colour in palette.iter() {
40        let distance = distance_fn(
41            original,
42            *colour,
43        );
44        if distance < closest_distance {
45            current_colour = colour;
46            closest_distance = distance;
47        };
48    }
49
50    *current_colour
51}
52
53pub fn quantize_rgb(original_rgb: Srgb, palette: &[Srgb]) -> Srgb {
54    let srgb = quantize_colour(
55        original_rgb.into_components(),
56        &palette.into_iter().map(|&col| col.into_components()).collect::<Vec<_>>(),
57        rgb_weighted_euclidean
58    );
59
60    Srgb::from_components(srgb)
61}
62
63pub fn compute_rgb_error(main: Srgb, other: Srgb) -> (f32, f32, f32) {
64    (main - other).into_components()
65}
66
67pub fn grayscale_rgb(rgb: Srgb) -> Srgb {
68    let mut lch = Lch::from_color(rgb);
69    lch.chroma = 0.0;
70    Srgb::from_color(lch)
71}
72
73pub fn hexcode_to_srgb(value: &str) -> Srgb {
74    let r = u8::from_str_radix(&value[0..=1], 16);
75    let g = u8::from_str_radix(&value[2..=3], 16);
76    let b = u8::from_str_radix(&value[4..=5], 16);
77
78    if let (Ok(r), Ok(g), Ok(b)) = (r, g, b) {
79        let (r, g, b) = (
80            r as f32 / 255.0,
81            g as f32 / 255.0,
82            b as f32 / 255.0,
83        );
84        Srgb::new(r, g, b)
85    } else {
86        println!(
87            "WARNING! Couldn't convert {} into an RGB value. Returning black.",
88            value
89        );
90        Srgb::new(0.0, 0.0, 0.0)
91    }
92}