yunter 0.1.0

convert from one color-space to another
Documentation
use num_traits::Float;
use rgb::Rgb;
use xyz::Xyz;

#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Hash, Default)]
pub struct Lab<T: Float = f32> {
    pub l: T,
    pub a: T,
    pub b: T,
}

impl<T: Float> Lab<T> {
    pub fn new(l: T, a: T, b: T) -> Self {
        Lab { l, a, b }
    }

    pub fn from_rgb(rgb: Rgb) -> Self {
        rgb.to_lab()
    }

    pub fn from_xyz(xyz: Xyz<T>) -> Self {
        xyz.to_lab()
    }

    pub fn to_rgb(self) -> Rgb {
        self.to_xyz().to_rgb()
    }

    pub fn to_xyz(self) -> Xyz<T> {
        let y = (self.l + T::from(16.0).unwrap()) / T::from(116.0).unwrap();
        let x = self.a / T::from(500.0).unwrap() + y;
        let z = y - self.b / T::from(200.0).unwrap();

        let white_ref = [
            T::from(95.047).unwrap(),
            T::from(100.000).unwrap(),
            T::from(108.883).unwrap()
        ];
        let x3 = x * x * x;
        let z3 = z * z * z;

        Xyz {
            data: [
                white_ref[0] * pivot_lab_xyz(x, x3),
                white_ref[1] * pivot_l_lab_xyz(self.l, y),
                white_ref[2] * pivot_lab_xyz(z, z3)
            ]
        }
    }
}

impl<T: Float> From<Rgb> for Lab<T> {
    fn from(rgb: Rgb) -> Self {
        Lab::from_rgb(rgb)
    }
}

impl<T: Float> From<Xyz<T>> for Lab<T> {
    fn from(xyz: Xyz<T>) -> Self {
        Lab::from_xyz(xyz)
    }
}

fn pivot_lab_xyz<T: Float>(n: T, n3: T) -> T {
    let epsilon = T::from(0.008856).unwrap();
    let kappa = T::from(7.787).unwrap();
    if n3 > epsilon {
        n3
    } else {
        (n - T::from(16.0).unwrap() / T::from(116.0).unwrap()) / kappa
    }
}

fn pivot_l_lab_xyz<T: Float>(l: T, y: T) -> T {
    let epsilon = T::from(0.008856).unwrap();
    let kappa = T::from(903.3).unwrap();
    if l > epsilon * kappa {
        y * y * y
    } else {
        l / kappa
    }
}

#[cfg(test)]
mod tests {
    use lab::Lab;
    use rgb::Rgb;
    use xyz::Xyz;

    #[test]
    fn lab_to_xyz_simple() {
        let lab = Lab { l: 46.97063877033799,
                        a: 80.39955582611775,
                        b: -45.78947040551107 };
        let xyz: Xyz = lab.into();
        assert_eq!(xyz.data[0], 33.113674);
        assert_eq!(xyz.data[1], 15.997065);
        assert_eq!(xyz.data[2], 50.057648);
    }

    #[test]
    fn lab_to_xyz_simple3() {
        let lab = Lab { l: 7.417381,
                        a: 1.6188575,
                        b: 5.2350793 };
        let xyz: Xyz = lab.into();
        assert_eq!(xyz.data[0], 0.8199973);
        assert_eq!(xyz.data[1], 0.82114255);
        assert_eq!(xyz.data[2], 0.52809083);
    }

    #[test]
    fn lab_to_rgb_simple() {
        let lab = Lab { l: 46.97063877033799, a: 80.39955582611775, b: -45.78947040551107 };
        let rgb: Rgb = lab.into();
        assert_eq!(rgb.data[0], 200);
        assert_eq!(rgb.data[1], 0);
        assert_eq!(rgb.data[2], 190);
    }

    #[test]
    fn lab_to_rgb_simple2() {
        let lab = Lab { l: 8.112699908516632,
                        a: 12.557465203893239,
                        b: 0.05391983803255673 };
        let rgb: Rgb = lab.into();
        assert_eq!(rgb.data[0], 39);
        assert_eq!(rgb.data[1], 17);
        assert_eq!(rgb.data[2], 24);
    }

    #[test]
    fn lab_to_rgb_simple3() {
        let lab = Lab { l: 7.417381,
                        a: 1.6188575,
                        b: 5.2350793 };
        let rgb: Rgb = lab.into();
        assert_eq!(rgb.data[0], 27);
        assert_eq!(rgb.data[1], 21);
        assert_eq!(rgb.data[2], 13);
    }
}