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 color_space::{WhitePoint};
use num_traits::{Float, NumCast, cast, zero};
use xyz::{Xyz, ToXyz};
use std::ops::{Add, Mul};
#[derive(Clone, Copy, Debug)]
pub struct Lab<T, Wp>{
pub l: T,
pub a: T,
pub b: T,
pub white_point: Wp,
}
impl<T, Wp: WhitePoint> Lab<T, Wp>{
pub fn new(l: T, a: T, b: T) -> Lab<T, Wp>{
Lab { l, a, b, white_point: Wp::default() }
}
}
impl<T: Copy, Wp: WhitePoint> Lab<T, Wp>{
pub fn brightness(&self) -> T {
self.l
}
}
impl<T: Float, Wp: WhitePoint> Lab<T, Wp>{
pub fn chromacity(&self) -> T {
(self.a.powi(2) + self.b.powi(2)).sqrt()
}
pub fn hue(&self) -> T {
let h = self.b.atan2(self.a);
if h < zero() {
h + cast(std::f64::consts::TAU).unwrap()
}else{
h
}
}
pub fn offset_chromacity(&self, chroma_offset: T) -> Lab<T, Wp>{
let current_croma = self.chromacity();
let offset_a = self.a / current_croma * chroma_offset;
let offset_b = self.b / current_croma * chroma_offset;
Lab::new(
self.l,
self.a + offset_a,
self.b + offset_b,
)
}
}
pub trait ToLab {
type WhitePoint: WhitePoint;
fn to_lab<T: Channel>(&self) -> Lab<T, Self::WhitePoint>;
}
impl<T: Channel + Float + NumCast, Wp: WhitePoint> ToXyz for Lab<T, Wp> {
type WhitePoint = Wp;
fn to_xyz<U: Channel + Float>(&self) -> Xyz<U, Wp> {
let fy = (self.l + cast(16).unwrap()) / cast(116).unwrap();
let fx = self.a / cast(500).unwrap() + fy;
let fz = fy - self.b / cast(200).unwrap();
let fxcb=fx*fx*fx;
let fzcb=fz*fz*fz;
let mut xyz = [fxcb, cast(0.).unwrap(), fzcb];
let eps= cast(216.0 / 24389.).unwrap();
if fxcb <= eps {
xyz[0] = (cast::<f64,T>(108.0).unwrap() * fx / cast(841).unwrap()) - cast::<f64,T>(432.0).unwrap() / cast(24389.).unwrap()
};
if fzcb <= eps{
xyz[2] = (cast::<f64,T>(108.0).unwrap() * fz / cast(841).unwrap()) - cast::<f64,T>(432.0).unwrap() / cast(24389.).unwrap()
}
if self.l > cast(8.).unwrap() {
xyz[1]=fy.powi(3)
}else{
xyz[1]=self.l * cast(27.0).unwrap() / cast(24389).unwrap();
}
xyz[0] = xyz[0] * Wp::xyz().x;
xyz[1] = xyz[1] * Wp::xyz().y;
xyz[2] = xyz[2] * Wp::xyz().z;
Xyz::new(xyz[0].to_channel(), xyz[1].to_channel(), xyz[2].to_channel())
}
}
impl<T: Channel + Float + NumCast, Wp: WhitePoint> Add for Lab<T,Wp>{
type Output = Lab<T, Wp>;
fn add(self, other: Lab<T, Wp>) -> Lab<T, Wp> {
Lab::new(self.l + other.l, self.a + other.a, self.b + other.b)
}
}
impl<T: Channel + Float + NumCast, Wp: WhitePoint> Mul<T> for Lab<T,Wp>{
type Output = Lab<T, Wp>;
fn mul(self, other: T) -> Lab<T, Wp> {
Lab::new(self.l * other, self.a * other, self.b * other)
}
}