1use crate::quant::Rgb;
4
5#[derive(Clone, Copy, Debug, PartialEq)]
7pub struct Lab {
8 pub l: f32,
10 pub a: f32,
12 pub b: f32,
14}
15
16impl From<Rgb> for Lab {
17 fn from(rgb: Rgb) -> Self {
18 rgb_to_lab(rgb.r, rgb.g, rgb.b)
19 }
20}
21
22pub fn rgb_to_lab(r: u8, g: u8, b: u8) -> Lab {
24 let mut r = r as f32 / 255.0;
26 let mut g = g as f32 / 255.0;
27 let mut b = b as f32 / 255.0;
28
29 r = if r > 0.04045 {
30 ((r + 0.055) / 1.055).powf(2.4)
31 } else {
32 r / 12.92
33 };
34 g = if g > 0.04045 {
35 ((g + 0.055) / 1.055).powf(2.4)
36 } else {
37 g / 12.92
38 };
39 b = if b > 0.04045 {
40 ((b + 0.055) / 1.055).powf(2.4)
41 } else {
42 b / 12.92
43 };
44
45 let x = r * 0.4124 + g * 0.3576 + b * 0.1805;
46 let y = r * 0.2126 + g * 0.7152 + b * 0.0722;
47 let z = r * 0.0193 + g * 0.1192 + b * 0.9505;
48
49 let x = x / 0.95047;
51 let y = y / 1.00000;
52 let z = z / 1.08883;
53
54 let f = |t: f32| {
55 if t > 0.008856 {
56 t.powf(1.0 / 3.0)
57 } else {
58 7.787 * t + 16.0 / 116.0
59 }
60 };
61
62 Lab {
63 l: 116.0 * f(y) - 16.0,
64 a: 500.0 * (f(x) - f(y)),
65 b: 200.0 * (f(y) - f(z)),
66 }
67}
68
69pub fn lab_distance_sq(c1: Lab, c2: Lab) -> f32 {
71 let dl = c1.l - c2.l;
72 let da = c1.a - c2.a;
73 let db = c1.b - c2.b;
74 dl * dl + da * da + db * db
75}