use crate::{
cielab::Cielab,
cielch::Cielch,
ciexyz::Ciexyz,
error::OutOfGamut,
};
use super::{
gamma_compress,
Srgb,
};
const FROM_CIEXYZ_CONVERSION_MATRIX: [f32; 9] = {
let xr = 12831f32 / 3959f32;
let xg = -329f32 / 214f32;
let xb = -1974f32 / 3959f32;
let yr = -851781f32 / 878810f32;
let yg = 1648619f32 / 878810f32;
let yb = 36519f32 / 878810f32;
let zr = 705f32 / 12673f32;
let zg = -2585f32 / 12673f32;
let zb = 705f32 / 667f32;
[xr, xg, xb, yr, yg, yb, zr, zg, zb]
};
impl TryFrom<Ciexyz> for Srgb {
type Error = OutOfGamut;
fn try_from(ciexyz: Ciexyz) -> Result<Self, Self::Error> {
let [xr, xg, xb, yr, yg, yb, zr, zg, zb] = FROM_CIEXYZ_CONVERSION_MATRIX;
let [x, y, z] = [ciexyz.x(), ciexyz.y(), ciexyz.z()];
let lr = x * xr + y * xg + z * xb;
let lg = x * yr + y * yg + z * yb;
let lb = x * zr + y * zg + z * zb;
let [r, g, b] = [lr, lg, lb].map(gamma_compress);
match [r, g, b].iter().all(|x| (0f32..=1f32).contains(x)) {
true => Ok(Self(r, g, b)),
false => Err(OutOfGamut),
}
}
}
impl TryFrom<Cielab> for Srgb {
type Error = OutOfGamut;
fn try_from(cielab: Cielab) -> Result<Self, Self::Error> {
let ciexyz: Ciexyz = cielab.into();
Self::try_from(ciexyz)
}
}
impl TryFrom<Cielch> for Srgb {
type Error = OutOfGamut;
fn try_from(cielch: Cielch) -> Result<Self, Self::Error> {
let ciexyz: Ciexyz = cielch.into();
Self::try_from(ciexyz)
}
}