1use crate::*;
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5pub struct Rgb {
6 pub r: u8,
8 pub g: u8,
10 pub b: u8,
12}
13
14impl Rgb {
15 pub const fn new(r: u8, g: u8, b: u8) -> Self {
17 Self { r, g, b }
18 }
19 pub const fn is_grey(self) -> bool {
20 self.r == self.g && self.g == self.b
21 }
22 #[inline]
23 pub fn nearest_ansi_in_range(self, min: u8, max: u8) -> AnsiColor {
24 let mut best = AnsiColor { code: min };
25 let mut smallest_distance: f32 = self.distance_to(best.to_rgb());
26 for code in min+1..=max {
27 let color = AnsiColor { code };
28 let distance = self.distance_to(color.to_rgb());
29 if distance < smallest_distance {
30 best = color;
31 smallest_distance = distance;
32 }
33 }
34 best
35 }
36 pub fn to_ansi(self) -> AnsiColor {
41 if self.r == self.g && self.g == self.b {
42 AnsiColor { code: GREY_TO_ANSI[self.r as usize] }
43 } else if self.r < 108 {
44 if self.r < 41 {
45 self.nearest_ansi_in_range(17, 51)
46 } else {
47 self.nearest_ansi_in_range(52, 87)
48 }
49 } else if self.r < 195 {
50 if self.r < 151 {
51 self.nearest_ansi_in_range(88, 123)
52 } else {
53 self.nearest_ansi_in_range(124, 159)
54 }
55 } else {
56 if self.r < 235 {
57 self.nearest_ansi_in_range(160, 195)
58 } else {
59 self.nearest_ansi_in_range(196, 230)
60 }
61 }
62 }
63 pub fn mix(c1: Self, w1: f32, c2: Self, w2: f32) -> Self {
64 debug_assert!(w1 + w2 > 0.0);
65 let (r1, g1, b1) = c1.parts();
66 let (r2, g2, b2) = c2.parts();
67 let r = (w1 * r1 + w2 * r2) / (w1 + w2);
68 let g = (w1 * g1 + w2 * g2) / (w1 + w2);
69 let b = (w1 * b1 + w2 * b2) / (w1 + w2);
70 (r, g, b).into()
71 }
72 #[allow(clippy::float_cmp)]
73 pub fn to_hsl(self) -> Hsl {
74 let (r, g, b) = (self.rp(), self.gp(), self.bp());
75 let min = r.min(g).min(b);
76 let max = r.max(g).max(b);
77
78 let l = 0.5 * (max + min);
79
80 if min == max {
81 return Hsl::new(0.0, 0.0, l);
83 }
84
85 let h = if max == r {
86 60.0 * (g - b) / (max - min)
87 } else if max == g {
88 60.0 * (b - r) / (max - min) + 120.0
89 } else if max == b {
90 60.0 * (r - g) / (max - min) + 240.0
91 } else {
92 0.0
93 };
94 let h = (h + 360.0) % 360.0;
95
96 let s = if 0.0 < l && l <= 0.5 {
97 (max - min) / (2.0 * l)
98 } else {
99 (max - min) / (2.0 - 2.0 * l)
100 };
101
102 Hsl { h, s, l }
103 }
104 pub fn rp(self) -> f32 {
106 self.r as f32 / 256f32
107 }
108 pub fn gp(self) -> f32 {
110 self.g as f32 / 256f32
111 }
112 pub fn bp(self) -> f32 {
114 self.b as f32 / 256f32
115 }
116 pub fn parts(self) -> (f32, f32, f32) {
117 (self.rp(), self.gp(), self.bp())
118 }
119 pub fn luma(self) -> f32 {
124 0.2627 * self.rp() + 0.6780 * self.gp() + 0.0593 * self.bp()
125 }
126 #[inline(always)]
130 pub fn distance_to<O: Into<Rgb>>(self, other: O) -> f32 {
131 let other = other.into();
132 let r_sum = self.r as f32 + other.r as f32;
133 let r = self.r as f32 - other.r as f32;
134 let g = self.g as f32 - other.g as f32;
135 let b = self.b as f32 - other.b as f32;
136 (1024.0 + r_sum) * r * r + 2048.0 * g * g + (1534.0 - r_sum) * b * b
137 }
138}
139
140pub fn r255(v: f32) -> u8 {
141 (v * 255.0) as u8
142}
143
144impl From<(f32, f32, f32)> for Rgb {
145 fn from(c: (f32, f32, f32)) -> Self {
147 debug_assert!(c.0 <= 1.0);
148 debug_assert!(c.1 <= 1.0);
149 debug_assert!(c.2 <= 1.0);
150 Rgb::new(r255(c.0), r255(c.1), r255(c.2))
151 }
152}
153
154pub const GREY_TO_ANSI: &[u8] = &[
155 16,
156 16,
157 16,
158 16,
159 16,
160 232,
161 232,
162 232,
163 232,
164 232,
165 232,
166 232,
167 232,
168 232,
169 233,
170 233,
171 233,
172 233,
173 233,
174 233,
175 233,
176 233,
177 233,
178 233,
179 234,
180 234,
181 234,
182 234,
183 234,
184 234,
185 234,
186 234,
187 234,
188 234,
189 235,
190 235,
191 235,
192 235,
193 235,
194 235,
195 235,
196 235,
197 235,
198 235,
199 236,
200 236,
201 236,
202 236,
203 236,
204 236,
205 236,
206 236,
207 236,
208 236,
209 237,
210 237,
211 237,
212 237,
213 237,
214 237,
215 237,
216 237,
217 237,
218 237,
219 238,
220 238,
221 238,
222 238,
223 238,
224 238,
225 238,
226 238,
227 238,
228 238,
229 239,
230 239,
231 239,
232 239,
233 239,
234 239,
235 239,
236 239,
237 239,
238 239,
239 240,
240 240,
241 240,
242 240,
243 240,
244 240,
245 240,
246 240,
247 59,
248 59,
249 59,
250 59,
251 241,
252 241,
253 241,
254 241,
255 242,
256 242,
257 242,
258 242,
259 242,
260 242,
261 242,
262 242,
263 242,
264 242,
265 242,
266 243,
267 243,
268 243,
269 243,
270 243,
271 243,
272 243,
273 243,
274 243,
275 243,
276 243,
277 243,
278 243,
279 244,
280 244,
281 244,
282 244,
283 244,
284 244,
285 244,
286 244,
287 102,
288 102,
289 102,
290 102,
291 102,
292 245,
293 245,
294 245,
295 245,
296 245,
297 245,
298 245,
299 246,
300 246,
301 246,
302 246,
303 246,
304 246,
305 246,
306 246,
307 246,
308 246,
309 247,
310 247,
311 247,
312 247,
313 247,
314 247,
315 247,
316 247,
317 247,
318 247,
319 248,
320 248,
321 248,
322 248,
323 248,
324 248,
325 248,
326 248,
327 145,
328 145,
329 145,
330 145,
331 145,
332 249,
333 249,
334 249,
335 249,
336 249,
337 249,
338 249,
339 250,
340 250,
341 250,
342 250,
343 250,
344 250,
345 250,
346 250,
347 250,
348 250,
349 251,
350 251,
351 251,
352 251,
353 251,
354 251,
355 251,
356 251,
357 251,
358 251,
359 252,
360 252,
361 252,
362 252,
363 252,
364 252,
365 252,
366 252,
367 188,
368 188,
369 188,
370 188,
371 188,
372 253,
373 253,
374 253,
375 253,
376 253,
377 253,
378 253,
379 254,
380 254,
381 254,
382 254,
383 254,
384 254,
385 254,
386 254,
387 254,
388 254,
389 255,
390 255,
391 255,
392 255,
393 255,
394 255,
395 255,
396 255,
397 255,
398 255,
399 255,
400 255,
401 255,
402 231,
403 231,
404 231,
405 231,
406 231,
407 231,
408 231,
409 231,
410 231,
411];
412
413