use crate::cie::illumination::Illumination;
use crate::cie::lab::Lab;
use crate::cie::rgb::RGB;
#[macro_export]
macro_rules! illumination {
($xyz:expr, $rgb:expr, $reference:expr) => {
Illumination {
x: $xyz[0],
y: $xyz[1],
z: $xyz[2],
r: $rgb[0],
g: $rgb[1],
b: $rgb[2],
reference: XYZ {
x: $reference[0],
y: $reference[1],
z: $reference[2],
},
}
};
}
#[derive(Clone, Copy)]
pub struct XYZ {
pub x: f32,
pub y: f32,
pub z: f32,
}
impl XYZ {
pub fn lab(self, illumination: Illumination) -> Lab {
let fx = forward(self.x * illumination.reference.x);
let fy = forward(self.y * illumination.reference.y);
let fz = forward(self.z * illumination.reference.z);
let l = (116.0 * fy) - 16.0;
let a = 500.0 * (fx - fy);
let b = 200.0 * (fy - fz);
Lab { l, a, b }
}
pub fn rgb(self, illumination: Illumination) -> RGB {
let r =
illumination.r[0] * self.x + illumination.r[1] * self.y + illumination.r[2] * self.z;
let g =
illumination.g[0] * self.x + illumination.g[1] * self.y + illumination.g[2] * self.z;
let b =
illumination.b[0] * self.x + illumination.b[1] * self.y + illumination.b[2] * self.z;
RGB::new(
(gamma(r) * 255.0).max(0.0).min(255.0) as u8,
(gamma(g) * 255.0).max(0.0).min(255.0) as u8,
(gamma(b) * 255.0).max(0.0).min(255.0) as u8,
)
}
}
fn gamma(v: f32) -> f32 {
if v < 0.0031308 {
v * 12.92
} else {
1.055 * v.powf(1.0 / 2.4) - 0.055
}
}
fn forward(v: f32) -> f32 {
if v > 0.008856451679035631 {
v.powf(1.0 / 3.0)
} else {
v * 7.787037037037037 + 0.13793103448275862
}
}