1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use crate::*;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Hsl {
pub h: f32,
pub s: f32,
pub l: f32,
}
impl Hsl {
pub fn new(h: f32, s: f32, l: f32) -> Self {
debug_assert!(h>=0.0 && h<360.0);
debug_assert!(s>=0.0 && s<=1.0);
debug_assert!(l>=0.0 && l<=1.0);
Self { h, s, l }
}
pub fn checked(h: f32, s: f32, l: f32) -> Result<Self, CoolorError> {
if !(
h>=0.0 && h<360.0
&& s>=0.0 && s<=1.0
&& l>=0.0 && l<=1.0
) {
Ok(Self { h, s, l })
} else {
Err(CoolorError::InvalidHsl(h, s, l))
}
}
pub fn mix(c1: Self, w1: f32, c2: Self, w2: f32) -> Self {
debug_assert!(w1 + w2 > 0.0);
let h = (w1*c1.h + w2*c2.h) / (w1+w2);
let s = (w1*c1.s + w2*c2.s) / (w1+w2);
let l = (w1*c1.l + w2*c2.l) / (w1+w2);
Self { h, s, l }
}
pub fn to_ansi(self) -> AnsiColor {
self.to_rgb().to_ansi()
}
pub fn to_rgb(self) -> Rgb {
let h = self.h / 360.0;
let s = self.s;
let l = self.l;
let rgb = if s == 0.0 {
(l, l, l)
} else {
let v2 = if l < 0.5 {
l * (1.0 + s)
} else {
l + s - (s * l)
};
let v1 = 2.0 * l - v2;
(
hue_to_rgb_component(v1, v2, h + (1.0 / 3.0)),
hue_to_rgb_component(v1, v2, h),
hue_to_rgb_component(v1, v2, h - (1.0 / 3.0)),
)
};
rgb.into()
}
pub fn delta_h(self, other: Hsl) -> f32 {
(self.h - other.h).abs().min((self.h-360.0).abs())
}
pub fn delta_s(self, other: Hsl) -> f32 {
(self.s - other.s).abs()
}
pub fn delta_l(self, other: Hsl) -> f32 {
(self.l - other.l).abs()
}
pub fn near(self, other: Hsl) -> bool {
(
self.delta_h(other) / 360.0
+ self.delta_s(other)
+ self.delta_l(other)
)
< 0.01
}
}
impl From<AnsiColor> for Hsl {
fn from(ansi: AnsiColor) -> Self {
ansi.to_hsl()
}
}
impl From<Rgb> for Hsl {
fn from(rgb: Rgb) -> Self {
rgb.to_hsl()
}
}
fn hue_to_rgb_component(v1: f32, v2: f32, vh: f32) -> f32 {
let vh = (vh + 1.0) % 1.0;
if 6.0 * vh < 1.0 {
(v1 + (v2 - v1) * 6.0 * vh).min(1.0).max(0.0)
} else if 2.0 * vh < 1.0 {
v2
} else if 3.0 * vh < 2.0 {
(v1 + (v2 - v1) * ((2.0 / 3.0) - vh) * 6.0).min(1.0).max(0.0)
} else {
v1
}
}