Skip to main content

chromashift/
lib.rs

1use core::fmt;
2mod channels;
3mod chromaticity;
4mod color_space;
5mod conversion;
6mod distance;
7mod gamut;
8mod hex;
9mod hsb;
10mod hsl;
11mod hwb;
12mod interpolation_space;
13mod lab;
14mod lch;
15mod matrix;
16mod mix;
17mod named;
18mod oklab;
19mod oklch;
20mod rgb;
21mod rgb_space;
22mod round;
23mod srgb;
24#[cfg(test)]
25mod tests;
26mod transfer;
27mod wcag;
28mod xyz;
29
30pub use channels::{Channel, ToAlpha};
31pub use chromaticity::Chromaticity;
32pub use color_space::ColorSpace;
33pub use distance::ColorDistance;
34pub use gamut::Gamut;
35pub use hex::Hex;
36pub use hsb::Hsv;
37pub use hsl::Hsl;
38pub use hwb::Hwb;
39pub use interpolation_space::{HueInterpolation, InterpolationSpace};
40pub use lab::Lab;
41pub use lch::Lch;
42pub use matrix::Matrix3;
43pub use mix::ColorMix;
44pub use named::{Named, ToNamedError};
45pub use oklab::Oklab;
46pub use oklch::Oklch;
47pub use rgb::{A98Rgb, DisplayP3, LinearRgb, ProphotoRgb, Rec2020, Srgb};
48pub use rgb_space::RgbSpace;
49pub(crate) use round::{Alpha, Number};
50pub use round::{PerceptualRound, round_dp};
51pub use transfer::Transfer;
52pub use wcag::{WcagColorContrast, WcagLevel};
53pub use xyz::{XyzD50, XyzD65};
54
55macro_rules! color {
56	(settable: $($settable:ident),+ $(,)?; via_srgb: $($via_srgb:ident),+ $(,)?;) => {
57		/// Any colour this crate can represent, in the colour space it was authored in.
58		#[derive(Debug, Clone, Copy, PartialEq)]
59		pub enum Color {
60			$($settable($settable),)+
61			$($via_srgb($via_srgb),)+
62		}
63
64		impl Color {
65			/// Returns a copy of this colour with `alpha`, clamped to 0.0-100.0.
66			///
67			/// `Hex` and `Named` colours are returned as `Srgb`.
68			pub fn with_alpha(self, alpha: f32) -> Self {
69				let alpha = alpha.clamp(0.0, 100.0);
70				match self {
71					$(Self::$settable(mut c) => {
72						c.alpha = alpha;
73						Self::$settable(c)
74					})+
75					$(Self::$via_srgb(c) => {
76						let mut srgb = Srgb::from(c);
77						srgb.alpha = alpha;
78						Self::Srgb(srgb)
79					})+
80				}
81			}
82		}
83
84		impl fmt::Display for Color {
85			fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86				match self {
87					$(Self::$settable(c) => fmt::Display::fmt(c, f),)+
88					$(Self::$via_srgb(c) => fmt::Display::fmt(c, f),)+
89				}
90			}
91		}
92
93		impl ToAlpha for Color {
94			fn to_alpha(&self) -> f32 {
95				match self {
96					$(Self::$settable(c) => c.to_alpha(),)+
97					$(Self::$via_srgb(c) => c.to_alpha(),)+
98				}
99			}
100		}
101
102		impl Color {
103			fn convert<T>(self) -> T
104			where
105				$(T: From<$settable>,)+
106				$(T: From<$via_srgb>,)+
107			{
108				match self {
109					$(Color::$settable(c) => c.into(),)+
110					$(Color::$via_srgb(c) => c.into(),)+
111				}
112			}
113		}
114
115		$(impl From<Color> for $settable {
116			fn from(value: Color) -> Self {
117				value.convert()
118			}
119		})+
120
121		impl From<Color> for Hex {
122			fn from(value: Color) -> Self {
123				value.convert()
124			}
125		}
126
127		$(impl From<$settable> for Color {
128			fn from(c: $settable) -> Self {
129				Color::$settable(c)
130			}
131		})+
132
133		$(impl From<$via_srgb> for Color {
134			fn from(c: $via_srgb) -> Self {
135				Color::$via_srgb(c)
136			}
137		})+
138	};
139}
140
141color! {
142	settable: A98Rgb, DisplayP3, Hsv, Hsl, Hwb, Lab, Lch, LinearRgb, Oklab, Oklch, ProphotoRgb, Rec2020, Srgb, XyzD50, XyzD65;
143	via_srgb: Hex, Named;
144}
145
146/// The CIE Delta E distance below which two colours are considered perceptually identical.
147pub const COLOR_EPSILON: f64 = 0.0072;