1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use channel::Channel;
use num_traits::Float;
use rgb::{Rgb, ToRgb};
use yxy::{Yxy, ToYxy};
use color_space::{D65, WhitePoint, MatrixColorSpace, Srgb, TransferFunction};
use num_traits::{zero, NumCast, cast};
use lab::{Lab, ToLab};
#[derive(Clone, Copy, Debug)]
pub struct Xyz<T = f32, Wp = D65>
where T: Channel + Float
{
pub x: T,
pub y: T,
pub z: T,
pub white_point: Wp,
}
impl<T: Channel + Float, Wp: WhitePoint> Xyz<T,Wp> {
pub fn new(x: T, y: T, z: T) -> Xyz<T,Wp> {
Xyz{
x,
y,
z,
white_point: Wp::default(),
}
}
}
pub trait ToXyz {
type WhitePoint: WhitePoint;
fn to_xyz<T: Channel + Float + std::fmt::Debug>(&self) -> Xyz<T, Self::WhitePoint>;
}
impl<T: Channel + Float + Clone> ToRgb for Xyz<T, D65> {
type Standard = Srgb;
fn to_rgb<U: Channel>(&self) -> Rgb<U, Srgb> {
let rgb = Srgb::to_rgb_matrix() * self.clone().into();
Rgb::new(
Srgb::from_linear(rgb[0]).to_channel(),
Srgb::from_linear(rgb[1]).to_channel(),
Srgb::from_linear(rgb[2]).to_channel(),
)
}
}
impl<T: Channel + Float + NumCast, Wp: WhitePoint> ToLab for Xyz<T, Wp> {
type WhitePoint = Wp;
fn to_lab<U:Channel>(&self) -> Lab<U, Wp> {
let mut xyz = [self.x / Wp::xyz().x , self.y / Wp::xyz().y, self.z / Wp::xyz().z];
for i in 0..3 {
if xyz[i] > cast::<_, T>(216.0).unwrap() / cast(24389.).unwrap() {
xyz[i] = xyz[i].cbrt()
}else{
let k = cast::<_, T>(24389.0).unwrap() / cast(27).unwrap();
xyz[i] = (cast::<_, T>(16.0).unwrap() + k * xyz[i]) / cast(116).unwrap()
}
}
return Lab::new(
(cast::<_, T>(116.0).unwrap() * xyz[1] - cast(16).unwrap()).to_channel(),
(cast::<_, T>(500).unwrap() * (xyz[0] - xyz[1])).to_channel(),
(cast::<_, T>(200).unwrap() * (xyz[1] - xyz[2])).to_channel()
)
}
}
impl<T: Channel + Float, Wp: WhitePoint> ToYxy for Xyz<T, Wp> {
type WhitePoint = Wp;
fn to_yxy<U: Channel + Float>(&self) -> Yxy<U, Wp> {
let sum = self.x + self.y + self.z;
let x;
let y;
let luma = self.y;
if sum < zero() || sum > zero() {
x = self.x / sum;
y = self.y / sum;
}else{
x = zero();
y = zero();
}
Yxy{x: x.to_channel(), y: y.to_channel(), luma: luma.to_channel(), white_point: Wp::default()}
}
}