Skip to main content

chromashift/
chromaticity.rs

1use crate::Matrix3;
2
3/// A CIE 1931 xy chromaticity: a colour's hue and purity with its luminance factored out.
4///
5/// Used for the white point of an [`RgbSpace`](crate::RgbSpace).
6///
7/// ```
8/// # use chromashift::Chromaticity;
9/// let [x, y, z] = Chromaticity::D65.xyz();
10/// assert_eq!(y, 1.0);
11/// assert!((x - 0.9504559).abs() < 1e-6);
12/// ```
13#[derive(Debug, Clone, Copy, PartialEq)]
14pub struct Chromaticity {
15	pub x: f64,
16	pub y: f64,
17}
18
19impl Chromaticity {
20	/// The D65 white point, as used by CSS Color 4: <https://drafts.csswg.org/css-color-4/#d65>
21	pub const D65: Self = Self::new(0.3127, 0.3290);
22
23	/// The D50 white point, as used by CSS Color 4: <https://drafts.csswg.org/css-color-4/#d50>
24	pub const D50: Self = Self::new(0.3457, 0.3585);
25
26	const BRADFORD: Matrix3 =
27		Matrix3([[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]);
28
29	pub const fn new(x: f64, y: f64) -> Self {
30		Self { x, y }
31	}
32
33	/// This chromaticity as CIE XYZ, normalised to `Y = 1`.
34	pub const fn xyz(self) -> [f64; 3] {
35		[self.x / self.y, 1.0, (1.0 - self.x - self.y) / self.y]
36	}
37
38	/// The Bradford chromatic adaptation matrix taking CIE XYZ relative to `self` to XYZ relative to `other`.
39	///
40	/// <https://en.wikipedia.org/wiki/LMS_color_space#Bradford's_spectrally_sharpened_matrix_(LLAB,_CIECAM97s)>
41	///
42	/// ```
43	/// # use chromashift::Chromaticity;
44	/// let m = Chromaticity::D65.adapt_to(Chromaticity::D50);
45	/// assert!((m.0[0][0] - 1.0479297925449969).abs() < 1e-12);
46	/// ```
47	pub const fn adapt_to(self, other: Self) -> Matrix3 {
48		if self.x == other.x && self.y == other.y {
49			return Matrix3::IDENTITY;
50		}
51		let source = Self::BRADFORD.transform(self.xyz());
52		let dest = Self::BRADFORD.transform(other.xyz());
53		let scale = Matrix3::diagonal([dest[0] / source[0], dest[1] / source[1], dest[2] / source[2]]);
54		Self::BRADFORD.then(&scale).then(&Self::BRADFORD.inverse())
55	}
56}