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
use crate::{ FromRgb, ToRgb, approx };
use crate::rgb::Rgb;
#[derive(Copy, Clone, Debug, Default)]
pub struct Xyz {
pub x: f64,
pub y: f64,
pub z: f64,
}
impl Xyz {
#[inline]
pub fn new(x: f64, y: f64, z: f64) -> Self {
Self { x, y, z }
}
}
impl PartialEq for Xyz {
fn eq(&self, other: &Self) -> bool {
approx(self.x, other.x) &&
approx(self.y, other.y) &&
approx(self.z, other.z)
}
}
fn srgb_to_linear(val: f64) -> f64 {
if val <= 0.04045 {
val / 12.92
} else {
((val + 0.055) / 1.055).powf(2.4)
}
}
impl FromRgb for Xyz {
fn from_rgb(rgb: &Rgb) -> Self {
let r = srgb_to_linear(rgb.r / 255.0);
let g = srgb_to_linear(rgb.g / 255.0);
let b = srgb_to_linear(rgb.b / 255.0);
Self::new(
(0.4124 * r + 0.3576 * g + 0.1805 * b) * 100.0,
(0.2126 * r + 0.7152 * g + 0.0722 * b) * 100.0,
(0.0193 * r + 0.1192 * g + 0.9505 * b) * 100.0
)
}
}
impl ToRgb for Xyz {
fn to_rgb(&self) -> Rgb {
let x = self.x / 100.0;
let y = self.y / 100.0;
let z = self.z / 100.0;
let r = x * 3.2404542 + y * -1.5371385 + z * -0.4985314;
let g = x * -0.9692660 + y * 1.8760108 + z * 0.0415560;
let b = x * 0.0556434 + y * -0.2040259 + z * 1.0572252;
let r = 255.0 * if r > 0.0031308 { 1.055 * r.powf(1.0 / 2.4) - 0.055 } else { 12.92 * r };
let g = 255.0 * if g > 0.0031308 { 1.055 * g.powf(1.0 / 2.4) - 0.055 } else { 12.92 * g };
let b = 255.0 * if b > 0.0031308 { 1.055 * b.powf(1.0 / 2.4) - 0.055 } else { 12.92 * b };
Rgb::new(r, g, b)
}
}