farbraum/spaces/
xyz.rs

1use crate::illuminate::{D50, D65};
2use crate::spaces::{CieXyz, LinearSrgb, Srgb};
3use crate::{Color, Float, Into};
4
5pub(crate) const K: Float = (29.0 * 29.0 * 29.0) / (3.0 * 3.0 * 3.0);
6pub(crate) const E: Float = (6.0 * 6.0 * 6.0) / (29.0 * 29.0 * 29.0);
7
8// --------------------------------- D50 ---------------------------------
9
10impl Into<CieXyz<D50>> for Color<LinearSrgb> {
11    fn into(self, _: CieXyz<D50>) -> Color<CieXyz<D50>> {
12        let (r, g, b) = self.tuple();
13
14        let x = 0.436074716431 * r + 0.385064915333 * g + 0.143080380986 * b;
15        let y = 0.222504478679 * r + 0.716878600214 * g + 0.060616923407 * b;
16        let z = 0.013932173982 * r + 0.097104523966 * g + 0.714173283533 * b;
17
18        Color::of(x, y, z)
19    }
20}
21
22impl Into<CieXyz<D50>> for Color<Srgb> {
23    fn into(self, s: CieXyz<D50>) -> Color<CieXyz<D50>> {
24        self.into(LinearSrgb).into(s)
25    }
26}
27
28impl Into<LinearSrgb> for Color<CieXyz<D50>> {
29    fn into(self, _: LinearSrgb) -> Color<LinearSrgb> {
30        let (x, y, z) = self.tuple();
31
32        let r = x * 3.1338561 - y * 1.6168667 - 0.4906146 * z;
33        let g = x * -0.9787684 + y * 1.9161415 + 0.033454 * z;
34        let b = x * 0.0719453 - y * 0.2289914 + 1.4052427 * z;
35
36        Color::of(r, g, b)
37    }
38}
39
40impl Into<Srgb> for Color<CieXyz<D50>> {
41    fn into(self, s: Srgb) -> Color<Srgb> {
42        self.into(LinearSrgb).into(s)
43    }
44}
45
46// --------------------------------- D65 ---------------------------------
47
48impl Into<CieXyz<D65>> for Color<CieXyz<D50>> {
49    fn into(self, _: CieXyz<D65>) -> Color<CieXyz<D65>> {
50        let (x, y, z) = self.tuple();
51
52        let x2 = 0.9555766 * x - 0.0230393 * y + 0.0631636 * z;
53        let y2 = -0.0282895 * x + 1.0099416 * y + 0.0210077 * z;
54        let z2 = 0.0122982 * x - 0.020483 * y + 1.3299098 * z;
55
56        Color::of(x2, y2, z2)
57    }
58}
59
60impl Into<CieXyz<D50>> for Color<CieXyz<D65>> {
61    fn into(self, _: CieXyz<D50>) -> Color<CieXyz<D50>> {
62        let (x, y, z) = self.tuple();
63
64        let x2 = 1.0478112 * x + 0.0228866 * y - 0.050127 * z;
65        let y2 = 0.0295424 * x + 0.9904844 * y - 0.0170491 * z;
66        let z2 = -0.0092345 * x + 0.0150436 * y + 0.7521316 * z;
67
68        Color::of(x2, y2, z2)
69    }
70}
71
72impl Into<CieXyz<D65>> for Color<LinearSrgb> {
73    fn into(self, _: CieXyz<D65>) -> Color<CieXyz<D65>> {
74        let (r, g, b) = self.tuple();
75
76        let x = 0.412456432268 * r + 0.35757607628 * g + 0.180437480294 * b;
77        let y = 0.212672846318 * r + 0.715152167155 * g + 0.072174999573 * b;
78        let z = 0.019333904103 * r + 0.119192028243 * g + 0.950304073677 * b;
79
80        Color::of(x, y, z)
81    }
82}
83
84impl Into<CieXyz<D65>> for Color<Srgb> {
85    fn into(self, s: CieXyz<D65>) -> Color<CieXyz<D65>> {
86        self.into(LinearSrgb).into(s)
87    }
88}
89
90impl Into<LinearSrgb> for Color<CieXyz<D65>> {
91    fn into(self, _: LinearSrgb) -> Color<LinearSrgb> {
92        let (x, y, z) = self.tuple();
93
94        let r = x * 3.2404542 - y * 1.5371385 - 0.4985314 * z;
95        let g = x * -0.969266 + y * 1.8760108 + 0.041556 * z;
96        let b = x * 0.0556434 - y * 0.2040259 + 1.0572252 * z;
97
98        Color::of(r, g, b)
99    }
100}
101
102impl Into<Srgb> for Color<CieXyz<D65>> {
103    fn into(self, s: Srgb) -> Color<Srgb> {
104        self.into(LinearSrgb).into(s)
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use crate::illuminate::{D50, D65};
111    use crate::spaces::CieXyz;
112    use crate::test_util::round_trips_srgb;
113
114    #[test]
115    fn test_xyz_roundtrips() {
116        round_trips_srgb::<CieXyz<D50>>();
117        round_trips_srgb::<CieXyz<D65>>();
118    }
119}