color/
xyz.rs

1// Copyright 2013 The color-rs developers. For a full listing of the authors,
2// refer to the AUTHORS file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use channel::Channel;
17use num_traits::Float;
18use rgb::{Rgb, ToRgb};
19use yxy::{Yxy, ToYxy};
20use color_space::{D65, WhitePoint, MatrixColorSpace, Srgb, TransferFunction};
21use num_traits::{zero, NumCast, cast};
22// use srgb::{Srgb, ToSrgb};
23use lab::{Lab, ToLab};
24
25#[derive(Clone, Copy, Debug)]
26pub struct Xyz<T = f32, Wp = D65>
27where T: Channel + Float
28{
29    pub x: T,
30    pub y: T,
31    pub z: T,
32    pub white_point: Wp,
33}
34
35impl<T: Channel + Float, Wp: WhitePoint> Xyz<T,Wp> {
36    pub fn new(x: T, y: T, z: T) -> Xyz<T,Wp> {
37        Xyz{
38            x,
39            y,
40            z,
41            white_point: Wp::default(),
42        }
43    }
44}
45
46pub trait ToXyz {
47    type WhitePoint: WhitePoint;
48    fn to_xyz<T: Channel + Float + std::fmt::Debug>(&self) -> Xyz<T, Self::WhitePoint>;
49}
50
51impl<T: Channel + Float + Clone> ToRgb for Xyz<T, D65> {
52    type Standard = Srgb;
53    fn to_rgb<U: Channel>(&self) -> Rgb<U, Srgb> {
54        let rgb = Srgb::to_rgb_matrix() * self.clone().into();
55        Rgb::new(
56            Srgb::from_linear(rgb[0]).to_channel(),
57            Srgb::from_linear(rgb[1]).to_channel(),
58            Srgb::from_linear(rgb[2]).to_channel(),
59        )
60    }
61}
62
63impl<T: Channel + Float + NumCast, Wp: WhitePoint> ToLab for Xyz<T, Wp> {
64    type WhitePoint = Wp;
65    fn to_lab<U:Channel>(&self) -> Lab<U, Wp> {
66        let mut xyz = [self.x / Wp::xyz().x , self.y / Wp::xyz().y, self.z / Wp::xyz().z];
67        for i in 0..3 {
68            if xyz[i] > cast::<_, T>(216.0).unwrap() / cast(24389.).unwrap() {// See BruceLindbloom.com
69                xyz[i] = xyz[i].cbrt()
70            }else{
71                let k = cast::<_, T>(24389.0).unwrap() / cast(27).unwrap(); // See BruceLindbloom.com
72                xyz[i] = (cast::<_, T>(16.0).unwrap() + k * xyz[i]) / cast(116).unwrap()
73            }
74        }
75
76        return Lab::new(
77            (cast::<_, T>(116.0).unwrap() * xyz[1] - cast(16).unwrap()).to_channel(),
78            (cast::<_, T>(500).unwrap() * (xyz[0] - xyz[1])).to_channel(),
79            (cast::<_, T>(200).unwrap() * (xyz[1] - xyz[2])).to_channel()
80        )
81    }
82}
83
84impl<T: Channel + Float, Wp: WhitePoint> ToYxy for Xyz<T, Wp> {
85    type WhitePoint = Wp;
86    fn to_yxy<U: Channel + Float>(&self) -> Yxy<U, Wp> {
87        let sum = self.x + self.y + self.z;
88        let x;
89        let y;
90        let luma = self.y;
91        if sum < zero() || sum > zero() {
92            x = self.x / sum;
93            y = self.y / sum;
94        }else{
95            x = zero();
96            y = zero();
97        }
98        Yxy{x: x.to_channel(), y: y.to_channel(), luma: luma.to_channel(), white_point: Wp::default()}
99    }
100}