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
#[derive(Debug, PartialEq)] pub struct Lab { pub l: f32, pub a: f32, pub b: f32, } impl Lab { pub fn from_rgb(r: u8, g: u8, b: u8) -> Self { let (x, y, z) = { let r = (r as f32) / 255.0; let g = (g as f32) / 255.0; let b = (b as f32) / 255.0; let _rgb: Vec<f32> = [r, g, b].into_iter().map(|&c| { (if c > 0.04045 { ((c + 0.055) / 1.055).powf(2.4) } else { c / 12.92 }) * 100.0 }).collect(); ( _rgb[0]*0.4124 + _rgb[1]*0.3576 + _rgb[2]*0.1805, _rgb[0]*0.2126 + _rgb[1]*0.7152 + _rgb[2]*0.0722, _rgb[0]*0.0193 + _rgb[1]*0.1192 + _rgb[2]*0.9505, ) }; let (l, a, b) = { let _x = x / 95.047; let _y = y / 100.0; let _z = z / 108.883; let _xyz: Vec<f32> = [_x, _y, _z].into_iter().map(|&c| { if c > 0.008856 { c.powf(1.0/3.0) } else { (c * 7.787) + ( 16.0 / 116.0 ) } }).collect(); ( (116.0 * _xyz[1]) - 16.0, 500.0 * (_xyz[0] - _xyz[1]), 200.0 * (_xyz[1] - _xyz[2]), ) }; Lab { l: l, a: a, b: b } } pub fn squared_distance(&self, other: &Lab) -> f32 { (self.l - other.l).powf(2.0) + (self.a - other.a).powf(2.0) + (self.b - other.b).powf(2.0) } } impl From<[u8; 4]> for Lab { fn from(data: [u8; 4]) -> Self { Lab::from_rgb(data[0], data[1], data[2]) } } impl From<[u8; 3]> for Lab { fn from(data: [u8; 3]) -> Self { Lab::from_rgb(data[0], data[1], data[2]) } } #[cfg(test)] mod tests { use super::Lab; #[test] fn test_from_rgb() { let rgb: [u8; 3] = [253, 120, 138]; let lab: Lab = rgb.into(); assert_eq!( lab, Lab { l: 66.6348, a: 52.260696, b: 14.850557 } ); } #[test] fn test_from_rgba() { let rgba: [u8; 4] = [253, 120, 138, 255]; let lab: Lab = rgba.into(); assert_eq!( lab, Lab { l: 66.6348, a: 52.260696, b: 14.850557 } ); } }