use crate::lab::Lab;
use crate::rgb::RGB;
#[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 {
r: (gamma(r) * 255.0).max(0.0).min(255.0),
g: (gamma(g) * 255.0).max(0.0).min(255.0),
b: (gamma(b) * 255.0).max(0.0).min(255.0),
}
}
}
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
}
}
#[derive(Clone, Copy)]
pub struct Illumination {
pub(crate) x: [f32; 3],
pub(crate) y: [f32; 3],
pub(crate) z: [f32; 3],
pub(crate) r: [f32; 3],
pub(crate) g: [f32; 3],
pub(crate) b: [f32; 3],
pub(crate) reference: XYZ,
}