1#![allow(clippy::excessive_precision)]
9
10pub struct Lab {
12 pub l: f32,
13 pub a: f32,
14 pub b: f32,
15 pub alpha: f32,
16}
17
18pub fn srgb_to_oklab(color: u32) -> Lab {
20 let r = SRGB_TO_RGB_LUT[(color & 0xff) as usize];
21 let g = SRGB_TO_RGB_LUT[((color >> 8) & 0xff) as usize];
22 let b = SRGB_TO_RGB_LUT[((color >> 16) & 0xff) as usize];
23 let alpha = (color >> 24) as f32 * (1.0 / 255.0);
24
25 let l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
26 let m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
27 let s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
28
29 let l_ = cbrtf_est(l);
30 let m_ = cbrtf_est(m);
31 let s_ = cbrtf_est(s);
32
33 Lab {
34 l: 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_,
35 a: 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_,
36 b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_,
37 alpha,
38 }
39}
40
41pub fn oklab_to_srgb(c: Lab) -> u32 {
43 let l_ = c.l + 0.3963377774 * c.a + 0.2158037573 * c.b;
44 let m_ = c.l - 0.1055613458 * c.a - 0.0638541728 * c.b;
45 let s_ = c.l - 0.0894841775 * c.a - 1.2914855480 * c.b;
46
47 let l = l_ * l_ * l_;
48 let m = m_ * m_ * m_;
49 let s = s_ * s_ * s_;
50
51 let r = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
52 let g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
53 let b = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s;
54
55 let r = r.clamp(0.0, 1.0);
56 let g = g.clamp(0.0, 1.0);
57 let b = b.clamp(0.0, 1.0);
58 let alpha = c.alpha.clamp(0.0, 1.0);
59
60 let r = linear_to_srgb(r);
61 let g = linear_to_srgb(g);
62 let b = linear_to_srgb(b);
63 let a = (alpha * 255.0) as u32;
64
65 r | (g << 8) | (b << 16) | (a << 24)
66}
67
68pub fn oklab_blend(dst: u32, src: u32) -> u32 {
70 let dst = srgb_to_oklab(dst);
71 let src = srgb_to_oklab(src);
72
73 let inv_a = 1.0 - src.alpha;
74 let l = src.l + dst.l * inv_a;
75 let a = src.a + dst.a * inv_a;
76 let b = src.b + dst.b * inv_a;
77 let alpha = src.alpha + dst.alpha * inv_a;
78
79 oklab_to_srgb(Lab { l, a, b, alpha })
80}
81
82fn linear_to_srgb(c: f32) -> u32 {
83 (if c > 0.0031308 {
84 255.0 * 1.055 * c.powf(1.0 / 2.4) - 255.0 * 0.055
85 } else {
86 255.0 * 12.92 * c
87 }) as u32
88}
89
90#[inline]
91fn cbrtf_est(a: f32) -> f32 {
92 let u: u32 = f32::to_bits(a); let u = u / 3 + 709921077; let x: f32 = f32::from_bits(u);
100
101 (1.0 / 3.0) * (a / (x * x) + (x + x)) }
108
109#[rustfmt::skip]
110#[allow(clippy::excessive_precision)]
111const SRGB_TO_RGB_LUT: [f32; 256] = [
112 0.0000000000, 0.0003035270, 0.0006070540, 0.0009105810, 0.0012141080, 0.0015176350, 0.0018211619, 0.0021246888, 0.0024282159, 0.0027317430, 0.0030352699, 0.0033465356, 0.0036765069, 0.0040247170, 0.0043914421, 0.0047769533,
113 0.0051815170, 0.0056053917, 0.0060488326, 0.0065120910, 0.0069954102, 0.0074990317, 0.0080231922, 0.0085681248, 0.0091340570, 0.0097212177, 0.0103298230, 0.0109600937, 0.0116122449, 0.0122864870, 0.0129830306, 0.0137020806,
114 0.0144438436, 0.0152085144, 0.0159962922, 0.0168073755, 0.0176419523, 0.0185002182, 0.0193823613, 0.0202885624, 0.0212190095, 0.0221738834, 0.0231533647, 0.0241576303, 0.0251868572, 0.0262412224, 0.0273208916, 0.0284260381,
115 0.0295568332, 0.0307134409, 0.0318960287, 0.0331047624, 0.0343398079, 0.0356013142, 0.0368894450, 0.0382043645, 0.0395462364, 0.0409151986, 0.0423114114, 0.0437350273, 0.0451862030, 0.0466650836, 0.0481718220, 0.0497065634,
116 0.0512694679, 0.0528606549, 0.0544802807, 0.0561284944, 0.0578054339, 0.0595112406, 0.0612460710, 0.0630100295, 0.0648032799, 0.0666259527, 0.0684781820, 0.0703601092, 0.0722718611, 0.0742135793, 0.0761853904, 0.0781874284,
117 0.0802198276, 0.0822827145, 0.0843762159, 0.0865004659, 0.0886556059, 0.0908417329, 0.0930589810, 0.0953074843, 0.0975873619, 0.0998987406, 0.1022417471, 0.1046164930, 0.1070231125, 0.1094617173, 0.1119324341, 0.1144353822,
118 0.1169706732, 0.1195384338, 0.1221387982, 0.1247718409, 0.1274376959, 0.1301364899, 0.1328683347, 0.1356333494, 0.1384316236, 0.1412633061, 0.1441284865, 0.1470272839, 0.1499598026, 0.1529261619, 0.1559264660, 0.1589608639,
119 0.1620294005, 0.1651322246, 0.1682693958, 0.1714410931, 0.1746473908, 0.1778884083, 0.1811642349, 0.1844749898, 0.1878207624, 0.1912016720, 0.1946178079, 0.1980693042, 0.2015562356, 0.2050787061, 0.2086368501, 0.2122307271,
120 0.2158605307, 0.2195262313, 0.2232279778, 0.2269658893, 0.2307400703, 0.2345506549, 0.2383976579, 0.2422811985, 0.2462013960, 0.2501583695, 0.2541521788, 0.2581829131, 0.2622507215, 0.2663556635, 0.2704978585, 0.2746773660,
121 0.2788943350, 0.2831487954, 0.2874408960, 0.2917706966, 0.2961383164, 0.3005438447, 0.3049873710, 0.3094689548, 0.3139887452, 0.3185468316, 0.3231432438, 0.3277781308, 0.3324515820, 0.3371636569, 0.3419144452, 0.3467040956,
122 0.3515326977, 0.3564002514, 0.3613068759, 0.3662526906, 0.3712377846, 0.3762622178, 0.3813261092, 0.3864295185, 0.3915725648, 0.3967553079, 0.4019778669, 0.4072403014, 0.4125427008, 0.4178851545, 0.4232677519, 0.4286905527,
123 0.4341537058, 0.4396572411, 0.4452012479, 0.4507858455, 0.4564110637, 0.4620770514, 0.4677838385, 0.4735315442, 0.4793202281, 0.4851499796, 0.4910208881, 0.4969330430, 0.5028865933, 0.5088814497, 0.5149177909, 0.5209956765,
124 0.5271152258, 0.5332764983, 0.5394796133, 0.5457245708, 0.5520114899, 0.5583404899, 0.5647116303, 0.5711249113, 0.5775805116, 0.5840784907, 0.5906189084, 0.5972018838, 0.6038274169, 0.6104956269, 0.6172066331, 0.6239604354,
125 0.6307572126, 0.6375969648, 0.6444797516, 0.6514056921, 0.6583748460, 0.6653873324, 0.6724432111, 0.6795425415, 0.6866854429, 0.6938719153, 0.7011020184, 0.7083759308, 0.7156936526, 0.7230552435, 0.7304608822, 0.7379105687,
126 0.7454043627, 0.7529423237, 0.7605246305, 0.7681512833, 0.7758223414, 0.7835379243, 0.7912980318, 0.7991028428, 0.8069523573, 0.8148466945, 0.8227858543, 0.8307699561, 0.8387991190, 0.8468732834, 0.8549926877, 0.8631572723,
127 0.8713672161, 0.8796223402, 0.8879231811, 0.8962693810, 0.9046613574, 0.9130986929, 0.9215820432, 0.9301108718, 0.9386858940, 0.9473065734, 0.9559735060, 0.9646862745, 0.9734454751, 0.9822505713, 0.9911022186, 1.0000000000,
128];