use crate::{
Cielab,
Cielch,
Srgb
};
use super::{
Ciexyz,
D65,
};
pub(super) const FROM_SRGB_CONVERSION_MATRIX: [f32; 9] = {
let xr = 506752f32 / 1228815f32;
let xg = 87881f32 / 245763f32;
let xb = 12673f32 / 70218f32;
let yr = 87098f32 / 409605f32;
let yg = 175762f32 / 245763f32;
let yb = 12673f32 / 175545f32;
let zr = 7918f32 / 409605f32;
let zg = 87881f32 / 737289f32;
let zb = 1001167f32 / 1053270f32;
[xr, xg, xb, yr, yg, yb, zr, zg, zb]
};
impl From<Srgb> for Ciexyz {
fn from(srgb: Srgb) -> Self {
let lr = srgb.linear_red();
let lg = srgb.linear_green();
let lb = srgb.linear_blue();
let [xr, xg, xb, yr, yg, yb, zr, zg, zb] = FROM_SRGB_CONVERSION_MATRIX;
let x = lr * xr + lg * xg + lb * xb;
let y = lr * yr + lg * yg + lb * yb;
let z = lr * zr + lg * zg + lb * zb;
Self(x, y, z)
}
}
impl From<Cielab> for Ciexyz {
fn from(cielab: Cielab) -> Self {
let delta = 6f32 / 29f32;
let f = |t| match t > delta {
true => f32::powf(t, 3f32),
false => 3f32 * f32::powf(delta, 2f32) * (t - 4f32 / 29f32),
};
let p = (cielab.lightness() + 16f32) / 116f32;
let x = D65.x() * f(p + cielab.a() / 500f32);
let y = D65.y() * f(p);
let z = D65.z() * f(p - cielab.b() / 200f32);
Self(x, y, z)
}
}
impl From<Cielch> for Ciexyz {
fn from(cielch: Cielch) -> Self {
let cielab: Cielab = cielch.into();
Self::from(cielab)
}
}