1#![deny(warnings)]
2
3use core::fmt;
4mod a98_rgb;
5mod channels;
6mod color_space;
7mod conversion;
8mod display_p3;
9mod distance;
10mod gamut;
11mod hex;
12mod hsb;
13mod hsl;
14mod hwb;
15mod lab;
16mod lch;
17mod linear_rgb;
18mod mix;
19mod named;
20mod oklab;
21mod oklch;
22mod prophoto_rgb;
23mod rec2020;
24mod round;
25mod srgb;
26#[cfg(test)]
27mod tests;
28mod wcag;
29mod xyzd50;
30mod xyzd65;
31
32pub use a98_rgb::A98Rgb;
33pub use channels::{Channel, PolarLayout, ToAlpha};
34pub use color_space::ColorSpace;
35pub use display_p3::DisplayP3;
36pub use distance::ColorDistance;
37pub use gamut::Gamut;
38pub use hex::Hex;
39pub use hsb::Hsv;
40pub use hsl::Hsl;
41pub use hwb::Hwb;
42pub use lab::Lab;
43pub use lch::Lch;
44pub use linear_rgb::LinearRgb;
45pub use mix::{ColorMix, ColorMixPolar, HueInterpolation, mix_channels};
46pub use named::{Named, ToNamedError};
47pub use oklab::Oklab;
48pub use oklch::Oklch;
49pub use prophoto_rgb::ProphotoRgb;
50pub use rec2020::Rec2020;
51pub use round::PerceptualRound;
52pub use srgb::Srgb;
53pub use wcag::{WcagColorContrast, WcagLevel};
54pub use xyzd50::XyzD50;
55pub use xyzd65::XyzD65;
56
57#[derive(Debug, Clone, Copy, PartialEq)]
58pub enum Color {
59 A98Rgb(A98Rgb),
60 DisplayP3(DisplayP3),
61 Hsv(Hsv),
62 Hsl(Hsl),
63 Hex(Hex),
64 Hwb(Hwb),
65 Lab(Lab),
66 Lch(Lch),
67 LinearRgb(LinearRgb),
68 Named(Named),
69 Oklab(Oklab),
70 Oklch(Oklch),
71 ProphotoRgb(ProphotoRgb),
72 Rec2020(Rec2020),
73 Srgb(Srgb),
74 XyzD50(XyzD50),
75 XyzD65(XyzD65),
76}
77
78impl fmt::Display for Color {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 match self {
81 Self::A98Rgb(a) => fmt::Display::fmt(a, f),
82 Self::DisplayP3(d) => fmt::Display::fmt(d, f),
83 Self::Hex(h) => fmt::Display::fmt(h, f),
84 Self::Hsv(h) => fmt::Display::fmt(h, f),
85 Self::Hsl(h) => fmt::Display::fmt(h, f),
86 Self::Hwb(h) => fmt::Display::fmt(h, f),
87 Self::Lab(l) => fmt::Display::fmt(l, f),
88 Self::Lch(l) => fmt::Display::fmt(l, f),
89 Self::LinearRgb(l) => fmt::Display::fmt(l, f),
90 Self::Named(n) => fmt::Display::fmt(n, f),
91 Self::Oklab(o) => fmt::Display::fmt(o, f),
92 Self::Oklch(o) => fmt::Display::fmt(o, f),
93 Self::ProphotoRgb(p) => fmt::Display::fmt(p, f),
94 Self::Rec2020(r) => fmt::Display::fmt(r, f),
95 Self::Srgb(s) => fmt::Display::fmt(s, f),
96 Self::XyzD50(x) => fmt::Display::fmt(x, f),
97 Self::XyzD65(x) => fmt::Display::fmt(x, f),
98 }
99 }
100}
101
102impl Color {
103 pub fn with_alpha(self, alpha: f32) -> Self {
108 match self {
109 Color::A98Rgb(mut c) => {
110 c.alpha = alpha;
111 Color::A98Rgb(c)
112 }
113 Color::DisplayP3(mut c) => {
114 c.alpha = alpha;
115 Color::DisplayP3(c)
116 }
117 Color::Hsv(mut c) => {
118 c.alpha = alpha;
119 Color::Hsv(c)
120 }
121 Color::Hsl(mut c) => {
122 c.alpha = alpha;
123 Color::Hsl(c)
124 }
125 Color::Hex(h) => {
126 let mut srgb: Srgb = h.into();
127 srgb.alpha = alpha;
128 Color::Srgb(srgb)
129 }
130 Color::Hwb(mut c) => {
131 c.alpha = alpha;
132 Color::Hwb(c)
133 }
134 Color::Lab(mut c) => {
135 c.alpha = alpha;
136 Color::Lab(c)
137 }
138 Color::Lch(mut c) => {
139 c.alpha = alpha;
140 Color::Lch(c)
141 }
142 Color::LinearRgb(mut c) => {
143 c.alpha = alpha;
144 Color::LinearRgb(c)
145 }
146 Color::Named(n) => {
147 let mut srgb: Srgb = n.into();
148 srgb.alpha = alpha;
149 Color::Srgb(srgb)
150 }
151 Color::Oklab(mut c) => {
152 c.alpha = alpha;
153 Color::Oklab(c)
154 }
155 Color::Oklch(mut c) => {
156 c.alpha = alpha;
157 Color::Oklch(c)
158 }
159 Color::ProphotoRgb(mut c) => {
160 c.alpha = alpha;
161 Color::ProphotoRgb(c)
162 }
163 Color::Rec2020(mut c) => {
164 c.alpha = alpha;
165 Color::Rec2020(c)
166 }
167 Color::Srgb(mut c) => {
168 c.alpha = alpha;
169 Color::Srgb(c)
170 }
171 Color::XyzD50(mut c) => {
172 c.alpha = alpha;
173 Color::XyzD50(c)
174 }
175 Color::XyzD65(mut c) => {
176 c.alpha = alpha;
177 Color::XyzD65(c)
178 }
179 }
180 }
181}
182
183impl ToAlpha for Color {
184 fn to_alpha(&self) -> f32 {
185 match self {
186 Color::A98Rgb(a) => a.to_alpha(),
187 Color::DisplayP3(d) => d.to_alpha(),
188 Color::Hex(h) => h.to_alpha(),
189 Color::Hsv(h) => h.to_alpha(),
190 Color::Hsl(h) => h.to_alpha(),
191 Color::Hwb(h) => h.to_alpha(),
192 Color::Lab(l) => l.to_alpha(),
193 Color::Lch(l) => l.to_alpha(),
194 Color::LinearRgb(l) => l.to_alpha(),
195 Color::Named(n) => n.to_alpha(),
196 Color::Oklab(o) => o.to_alpha(),
197 Color::Oklch(o) => o.to_alpha(),
198 Color::ProphotoRgb(p) => p.to_alpha(),
199 Color::Rec2020(r) => r.to_alpha(),
200 Color::Srgb(s) => s.to_alpha(),
201 Color::XyzD50(x) => x.to_alpha(),
202 Color::XyzD65(x) => x.to_alpha(),
203 }
204 }
205}
206
207impl From<A98Rgb> for Color {
208 fn from(c: A98Rgb) -> Self {
209 Color::A98Rgb(c)
210 }
211}
212impl From<DisplayP3> for Color {
213 fn from(c: DisplayP3) -> Self {
214 Color::DisplayP3(c)
215 }
216}
217impl From<Hsl> for Color {
218 fn from(c: Hsl) -> Self {
219 Color::Hsl(c)
220 }
221}
222impl From<Hwb> for Color {
223 fn from(c: Hwb) -> Self {
224 Color::Hwb(c)
225 }
226}
227impl From<Lab> for Color {
228 fn from(c: Lab) -> Self {
229 Color::Lab(c)
230 }
231}
232impl From<Lch> for Color {
233 fn from(c: Lch) -> Self {
234 Color::Lch(c)
235 }
236}
237impl From<LinearRgb> for Color {
238 fn from(c: LinearRgb) -> Self {
239 Color::LinearRgb(c)
240 }
241}
242impl From<Oklab> for Color {
243 fn from(c: Oklab) -> Self {
244 Color::Oklab(c)
245 }
246}
247impl From<Oklch> for Color {
248 fn from(c: Oklch) -> Self {
249 Color::Oklch(c)
250 }
251}
252impl From<ProphotoRgb> for Color {
253 fn from(c: ProphotoRgb) -> Self {
254 Color::ProphotoRgb(c)
255 }
256}
257impl From<Rec2020> for Color {
258 fn from(c: Rec2020) -> Self {
259 Color::Rec2020(c)
260 }
261}
262impl From<Srgb> for Color {
263 fn from(c: Srgb) -> Self {
264 Color::Srgb(c)
265 }
266}
267impl From<XyzD50> for Color {
268 fn from(c: XyzD50) -> Self {
269 Color::XyzD50(c)
270 }
271}
272impl From<XyzD65> for Color {
273 fn from(c: XyzD65) -> Self {
274 Color::XyzD65(c)
275 }
276}
277
278impl From<Color> for XyzD65 {
279 fn from(value: Color) -> Self {
280 match value {
281 Color::A98Rgb(a) => a.into(),
282 Color::DisplayP3(d) => d.into(),
283 Color::Hex(h) => h.into(),
284 Color::Hsv(h) => h.into(),
285 Color::Hsl(h) => h.into(),
286 Color::Hwb(h) => h.into(),
287 Color::Lab(l) => l.into(),
288 Color::Lch(l) => l.into(),
289 Color::LinearRgb(l) => l.into(),
290 Color::Named(n) => n.into(),
291 Color::Oklab(o) => o.into(),
292 Color::Oklch(o) => o.into(),
293 Color::ProphotoRgb(p) => p.into(),
294 Color::Rec2020(r) => r.into(),
295 Color::Srgb(s) => s.into(),
296 Color::XyzD50(x) => x.into(),
297 Color::XyzD65(x) => x,
298 }
299 }
300}
301
302pub const COLOR_EPSILON: f64 = 0.0072;
303
304pub fn round_dp(f: f64, d: u32) -> f64 {
305 let factor = 10u32.pow(d) as f64;
306 (f * factor).round() / factor
307}