1use num_traits::{self, Zero, Saturating, NumCast, Num, Float};
17use std::{borrow::{Borrow, BorrowMut}, ops::{Mul, Div, Add, Sub, Index, IndexMut}};
18use std::marker::PhantomData;
19use std::mem;
20use color_space::{TransferFunction, Srgb, LinearRgb, MatrixColorSpace, D65};
21use angle::*;
22
23use {Color, FloatColor};
24use {Channel, FloatChannel};
25use {Hsv, ToHsv};
26use {Luma, ToLuma};
27use xyz::{Xyz, ToXyz};
28use alpha::{ToRgba, Rgba};
29use std::fmt::{self, Debug};
30
31use crate::{oklab::{OkLab, ToOkLab}, ToHsl, Hsl};
32
33#[derive(Serialize, Deserialize)]
34pub struct Rgb<T = u8, S = Srgb> { pub r: T, pub g: T, pub b: T, standard: PhantomData<S> }
35
36impl<T: Clone,S> Clone for Rgb<T, S>{
37 fn clone(&self) -> Rgb<T, S>{
38 Rgb{ r: self.r.clone(), g: self.g.clone(), b: self.b.clone(), standard: PhantomData }
39 }
40}
41
42impl<T: Copy, S> Copy for Rgb<T, S>{}
43
44impl<N: Clone + PartialEq + Num + NumCast, S> PartialEq for Rgb<N, S>{
45 #[inline]
46 fn eq(&self, other: &Rgb<N, S>) -> bool{
47 self.r.eq(&other.r) && self.g.eq(&other.g) && self.b.eq(&other.b)
48 }
49}
50
51impl<N: Clone + PartialEq + Eq + Num + NumCast, S> Eq for Rgb<N, S>{}
52
53impl<T: Debug, S: Default + Debug> Debug for Rgb<T,S>{
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 f.debug_struct("Rgb")
56 .field("r", &self.r)
57 .field("g", &self.g)
58 .field("b", &self.b)
59 .field("standard", &S::default())
60 .finish()
61 }
62}
63
64#[derive(Serialize, Deserialize)]
65pub struct Rg<T = u8, S = Srgb> { pub r: T, pub g: T, pub standard: PhantomData<S> }
66
67impl<T, S> Rg<T, S>{
68 pub const fn new(r: T, g: T) -> Rg<T,S>{
69 Rg{r, g, standard: PhantomData}
70 }
71}
72
73impl<T: Clone,S> Clone for Rg<T, S>{
74 fn clone(&self) -> Rg<T, S>{
75 Rg{ r: self.r.clone(), g: self.g.clone(), standard: PhantomData }
76 }
77}
78
79impl<T: Copy, S> Copy for Rg<T, S>{}
80
81impl<N: Clone + PartialEq + Num + NumCast, S> PartialEq for Rg<N, S>{
82 #[inline]
83 fn eq(&self, other: &Rg<N, S>) -> bool{
84 self.r.eq(&other.r) && self.g.eq(&other.g)
85 }
86}
87
88impl<N: Clone + PartialEq + Eq + Num + NumCast, S> Eq for Rg<N, S>{}
89
90impl<T: Debug, S: Default + Debug> Debug for Rg<T,S>{
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 f.debug_struct("Rg")
93 .field("r", &self.r)
94 .field("g", &self.g)
95 .field("standard", &S::default())
96 .finish()
97 }
98}
99
100fn cast<T: num_traits::NumCast, U: num_traits::NumCast>(n: T) -> U {
101 num_traits::cast(n).unwrap()
102}
103
104impl<T, S> Rgb<T, S> {
105 #[inline]
106 pub const fn new(r: T, g: T, b: T) -> Rgb<T, S> {
107 Rgb { r: r, g: g, b: b, standard: PhantomData }
108 }
109}
110
111impl<T: Channel, S: TransferFunction> Rgb<T, S> {
112 pub fn from_hex(hex: u32) -> Rgb<T, S> {
113 let r = hex >> 16 & 0xFF;
114 let g = hex >> 8 & 0xFF;
115 let b = hex & 0xFF;
116 Rgb::<u8, S>::new(r as u8, g as u8, b as u8).to_rgb()
117 }
118
119 #[inline]
120 pub fn rg(&self) -> Rg<T, S> {
121 Rg{r: self.r, g: self.g, standard: PhantomData}
122 }
123
124 #[inline]
125 pub fn rb(&self) -> Rg<T, S> {
126 Rg{r: self.r, g: self.b, standard: PhantomData}
127 }
128
129 #[inline]
130 pub fn gr(&self) -> Rg<T, S> {
131 Rg{r: self.g, g: self.r, standard: PhantomData}
132 }
133
134 #[inline]
135 pub fn gb(&self) -> Rg<T, S> {
136 Rg{r: self.g, g: self.b, standard: PhantomData}
137 }
138
139 #[inline]
140 pub fn br(&self) -> Rg<T, S> {
141 Rg{r: self.b, g: self.r, standard: PhantomData}
142 }
143
144 #[inline]
145 pub fn bg(&self) -> Rg<T, S> {
146 Rg{r: self.b, g: self.g, standard: PhantomData}
147 }
148
149 #[inline]
150 pub fn rgb(&self) -> Rgb<T, S> {
151 Rgb{r: self.r, g: self.g, b: self.b, standard: PhantomData}
152 }
153
154 #[inline]
155 pub fn rbg(&self) -> Rgb<T, S> {
156 Rgb{r: self.r, g: self.b, b: self.g, standard: PhantomData}
157 }
158
159 #[inline]
160 pub fn bgr(&self) -> Rgb<T, S> {
161 Rgb{r: self.b, g: self.g, b: self.r, standard: PhantomData}
162 }
163
164 #[inline]
165 pub fn brg(&self) -> Rgb<T, S> {
166 Rgb{r: self.b, g: self.r, b: self.g, standard: PhantomData}
167 }
168
169 #[inline]
170 pub fn grb(&self) -> Rgb<T, S> {
171 Rgb{r: self.g, g: self.r, b: self.b, standard: PhantomData}
172 }
173
174 #[inline]
175 pub fn gbr(&self) -> Rgb<T, S> {
176 Rgb{r: self.g, g: self.b, b: self.r, standard: PhantomData}
177 }
178}
179
180impl<T: Channel, S: TransferFunction> Rgb<T, S> {
181 pub fn to_standard<S2: TransferFunction>(&self) -> Rgb<T, S2>{
182 if std::any::TypeId::of::<S>() != std::any::TypeId::of::<S2>(){
183 let r = S2::from_linear(S::to_linear(self.r.to_nearest_precision_float()));
184 let g = S2::from_linear(S::to_linear(self.g.to_nearest_precision_float()));
185 let b = S2::from_linear(S::to_linear(self.b.to_nearest_precision_float()));
186 Rgb::new(r.to_channel(), g.to_channel(), b.to_channel())
187 }else{
188 Rgb::new(self.r, self.g, self.b)
189 }
190 }
191
192 pub fn to_linear(&self) -> Rgb<T, LinearRgb>{
193 let r = S::to_linear(self.r.to_nearest_precision_float());
194 let g = S::to_linear(self.g.to_nearest_precision_float());
195 let b = S::to_linear(self.b.to_nearest_precision_float());
196 Rgb::new(r.to_channel(), g.to_channel(), b.to_channel())
197 }
198}
199
200#[macro_export]
201macro_rules! rgb{
202 ( $r: expr, $g: expr, $b: expr ) => {
203 $crate::Rgb::<_, $crate::color_space::Srgb>::new( $r, $g, $b )
204 };
205 ( $rg: expr, $b: expr ) => {
206 $crate::Rgb::<_, $crate::color_space::Srgb>::new( $rg.r, $rg.g, $b )
207 };
208 ( $r: expr, $gb: expr ) => {
209 $crate::Rgb::<_, $crate::color_space::Srgb>::new( $r, $gb.r, $gb.g )
210 };
211 ( $num: expr ) => {
212 $crate::Rgb::<_, $crate::color_space::Srgb>::new( $num, $num, $num )
213 };
214}
215
216#[macro_export]
217macro_rules! rgb_linear{
218 ( $r: expr, $g: expr, $b: expr ) => {
219 $crate::Rgb::<_, $crate::color_space::LinearRgb>::new( $r, $g, $b )
220 };
221 ( $rg: expr, $b: expr ) => {
222 $crate::Rgb::<_, $crate::color_space::LinearRgb>::new( $rg.r, $rg.g, $b )
223 };
224 ( $r: expr, $gb: expr ) => {
225 $crate::Rgb::<_, $crate::color_space::LinearRgb>::new( $r, $gb.r, $gb.g )
226 };
227 ( $num: expr ) => {
228 $crate::Rgb::<_, $crate::color_space::LinearRgb>::new( $num, $num, $num )
229 };
230}
231
232impl<T: Channel, S> Color<T> for Rgb<T, S> {
233 #[inline]
235 fn clamp_s(self, lo: T, hi: T) -> Rgb<T, S> {
236 Rgb::new(self.r.clamp(lo, hi),
237 self.g.clamp(lo, hi),
238 self.b.clamp(lo, hi))
239 }
240
241 #[inline]
243 fn clamp_c(self, lo: Rgb<T, S>, hi: Rgb<T, S>) -> Rgb<T, S> {
244 Rgb::new(self.r.clamp(lo.r, hi.r),
245 self.g.clamp(lo.g, hi.g),
246 self.b.clamp(lo.b, hi.b))
247 }
248
249 #[inline]
251 fn inverse(self) -> Rgb<T, S> {
252 Rgb::new(self.r.invert_channel(),
253 self.g.invert_channel(),
254 self.b.invert_channel())
255 }
256
257 #[inline]
258 fn mix(self, other: Self, value: T) -> Self {
259 Rgb::new(self.r.mix(other.r, value),
260 self.g.mix(other.g, value),
261 self.b.mix(other.b, value))
262 }
263}
264
265impl<T: FloatChannel, S> FloatColor<T> for Rgb<T, S> {
266 #[inline]
268 fn saturate(self) -> Rgb<T, S> {
269 Rgb::new(self.r.saturate(),
270 self.g.saturate(),
271 self.b.saturate())
272 }
273}
274
275pub trait ToRgb {
276 type Standard: TransferFunction;
277 fn to_rgb<U:Channel>(&self) -> Rgb<U, Self::Standard>;
278}
279
280impl ToRgb for u32 {
281 type Standard = Srgb;
282 #[inline]
283 fn to_rgb<U:Channel>(&self) -> Rgb<U, Srgb> {
284 let r: u8 = cast((*self >> 16) & 0xff);
285 let g: u8 = cast((*self >> 8) & 0xff);
286 let b: u8 = cast((*self >> 0) & 0xff);
287 let r: U = Channel::from(r);
288 let g: U = Channel::from(g);
289 let b: U = Channel::from(b);
290 rgb!(r, g, b)
291 }
292}
293
294impl<T: Channel, S: TransferFunction> ToRgb for Rgb<T,S> {
295 type Standard = S;
296 #[inline]
297 fn to_rgb<U:Channel>(&self) -> Rgb<U,S> {
298 Rgb::new(self.r.to_channel(),
299 self.g.to_channel(),
300 self.b.to_channel())
301 }
302}
303
304impl<T: Channel, S: TransferFunction> ToLuma for Rgb<T, S> {
305 type Standard = S;
306 fn to_luma<U: Channel>(&self) -> Luma<U, S> {
307 Luma::new(Channel::from(
308 self.r.to_nearest_precision_float() * cast::<f32, <T as Channel>::NearestFloat>(0.2126)
309 + self.g.to_nearest_precision_float() * cast::<f32, <T as Channel>::NearestFloat>(0.7152)
310 + self.b.to_nearest_precision_float() * cast::<f32, <T as Channel>::NearestFloat>(0.0722)
311 ))
312 }
313}
314
315impl<T: Channel, S: TransferFunction> ToRgba for Rgb<T, S> {
316 type Standard = S;
317
318 #[inline]
319 fn to_rgba<U: Channel>(&self) -> Rgba<U, S>{
320 Rgba{c: self.to_rgb(), a: 1.0f32.to_channel()}
321 }
322}
323
324impl<T:Channel, S: TransferFunction> ToHsv for Rgb<T, S> {
325 type Standard = S;
326 #[inline]
327 fn to_hsv<U:Channel + NumCast + Num>(&self) -> Hsv<U, S> {
328 let rgb_u = self.to_rgb::<U>();
332
333 let mx = cast(cast::<U,f64>(rgb_u.r).max(cast(rgb_u.g)).max(cast(rgb_u.b)));
334 let mn = cast(cast::<U,f64>(rgb_u.r).min(cast(rgb_u.g)).min(cast(rgb_u.b)));
335 let chr = mx - mn;
336
337 if chr != Zero::zero() {
338 let h =
339 if rgb_u.r == mx { ((rgb_u.g - rgb_u.b) / chr) % cast(6u8) }
340 else if rgb_u.g == mx { ((rgb_u.b - rgb_u.r) / chr) + cast(2u8) }
341 else { ((rgb_u.r - rgb_u.g) / chr) + cast(4u8) }
342 * cast(60u8);
343
344 let s = chr / mx;
345
346 Hsv::new(Deg(h), s, mx)
347
348 } else {
349 Hsv::new(Zero::zero(), Zero::zero(),mx)
350 }
351 }
352}
353
354impl<T:Channel, S: TransferFunction> ToHsl for Rgb<T, S> {
355 type Standard = S;
356 #[inline]
357 fn to_hsl<U:Channel + NumCast + Num>(&self) -> Hsl<U, S> {
358 let rgb_f64 = self.to_rgb::<f64>();
359
360 let mx = rgb_f64.r.channel_max(rgb_f64.g).channel_max(rgb_f64.b);
361 let mn = rgb_f64.r.channel_min(rgb_f64.g).channel_min(rgb_f64.b);
362 let d = mx - mn;
363 let l = (mx + mn) * 0.5;
364 if d != Zero::zero() {
365 let s = if l < 0.5 { d / (mx + mn) } else { d / (2. - mx - mn ) } ;
366 let h =
367 if rgb_f64.r == mx { (rgb_f64.g - rgb_f64.b) / d }
368 else if rgb_f64.g == mx { ((rgb_f64.b - rgb_f64.r) / d) + 2. }
369 else { ((rgb_f64.r - rgb_f64.g) / d) + 4. }
370 * 60.;
371
372 Hsl::new(angle::cast(Deg(h)).unwrap(), Channel::from(s), Channel::from(l))
373 } else {
374 Hsl::new(Zero::zero(), Zero::zero(), Channel::from(l))
375 }
376 }
377}
378
379impl<T: Channel, S: MatrixColorSpace + TransferFunction> ToXyz for Rgb<T, S> {
380 type WhitePoint = D65;
381 fn to_xyz<U: Channel + Float>(&self) -> Xyz<U, D65> {
382 let rgb = self.to_rgb().to_linear();
383 let xyz = S::to_xyz_matrix() * rgb.into();
384 Xyz::new(xyz[0], xyz[1], xyz[2])
385 }
386}
387
388impl <T: Channel + Float + NumCast, S: MatrixColorSpace + TransferFunction> ToOkLab for Rgb<T, S> {
389 fn to_oklab<U: Channel>(&self) -> OkLab<U> {
390 let c: Rgb<T,_> = self.to_rgb().to_linear();
391 let l = cast::<f64, T>(0.4122214708) * c.r + cast::<f64, T>(0.5363325363) * c.g + cast::<f64, T>(0.0514459929) * c.b;
392 let m = cast::<f64, T>(0.2119034982) * c.r + cast::<f64, T>(0.6806995451) * c.g + cast::<f64, T>(0.1073969566) * c.b;
393 let s = cast::<f64, T>(0.0883024619) * c.r + cast::<f64, T>(0.2817188376) * c.g + cast::<f64, T>(0.6299787005) * c.b;
394
395 let l_ = l.cbrt();
396 let m_ = m.cbrt();
397 let s_ = s.cbrt();
398
399 OkLab {
400 l: (cast::<f64, T>(0.2104542553)*l_ + cast::<f64, T>(0.7936177850)*m_ - cast::<f64, T>(0.0040720468)*s_).to_channel(),
401 a: (cast::<f64, T>(1.9779984951)*l_ - cast::<f64, T>(2.4285922050)*m_ + cast::<f64, T>(0.4505937099)*s_).to_channel(),
402 b: (cast::<f64, T>(0.0259040371)*l_ + cast::<f64, T>(0.7827717662)*m_ - cast::<f64, T>(0.8086757660)*s_).to_channel(),
403 }
404 }
405}
406
407impl<T: Channel, S> Mul for Rgb<T, S> {
408 type Output = Rgb<T, S>;
409
410 #[inline]
411 fn mul(self, rhs: Rgb<T, S>) -> Rgb<T, S> {
412 Rgb::new(self.r.normalized_mul(rhs.r),
413 self.g.normalized_mul(rhs.g),
414 self.b.normalized_mul(rhs.b))
415 }
416}
417
418impl<T: Channel + Mul<T,Output=T>, S> Mul<T> for Rgb<T, S> {
419 type Output = Rgb<T, S>;
420
421 #[inline]
422 fn mul(self, rhs: T) -> Rgb<T, S> {
423 Rgb::new(self.r * rhs,
424 self.g * rhs,
425 self.b * rhs)
426 }
427}
428
429
430impl<T: Channel, S> Div for Rgb<T, S> {
431 type Output = Rgb<T, S>;
432
433 #[inline]
434 fn div(self, rhs: Rgb<T, S>) -> Rgb<T, S> {
435 Rgb::new(self.r.normalized_div(rhs.r),
436 self.g.normalized_div(rhs.g),
437 self.b.normalized_div(rhs.b))
438 }
439}
440
441impl<T: Channel + Div<T,Output=T>, S> Div<T> for Rgb<T, S> {
442 type Output = Rgb<T, S>;
443
444 #[inline]
445 fn div(self, rhs: T) -> Rgb<T, S> {
446 Rgb::new(self.r / rhs,
447 self.g / rhs,
448 self.b / rhs)
449 }
450}
451
452impl<T: Channel + Add<T,Output=T>, S> Add for Rgb<T, S> {
453 type Output = Rgb<T, S>;
454
455 #[inline]
456 fn add(self, rhs: Rgb<T, S>) -> Rgb<T, S> {
457 Rgb::new(self.r + rhs.r,
458 self.g + rhs.g,
459 self.b + rhs.b)
460 }
461}
462
463impl<T: Channel + Sub<T,Output=T>, S> Sub for Rgb<T, S> {
464 type Output = Rgb<T, S>;
465
466 #[inline]
467 fn sub(self, rhs: Rgb<T, S>) -> Rgb<T, S> {
468 Rgb::new(self.r - rhs.r,
469 self.g - rhs.g,
470 self.b - rhs.b)
471 }
472}
473
474impl<T: Channel + Saturating, S> Saturating for Rgb<T, S> {
475 fn saturating_add(self, v: Rgb<T, S>) -> Rgb<T, S> {
476 Rgb::new(self.r.saturating_add(v.r),
477 self.g.saturating_add(v.g),
478 self.b.saturating_add(v.b))
479 }
480
481 fn saturating_sub(self, v: Rgb<T, S>) -> Rgb<T, S> {
482 Rgb::new(self.r.saturating_sub(v.r),
483 self.g.saturating_sub(v.g),
484 self.b.saturating_sub(v.b))
485 }
486}
487
488impl<T, S> Index<usize> for Rgb<T, S> {
489 type Output = T;
490 fn index<'a>(&'a self, index: usize) -> &'a T {
491 self.as_ref().index(index)
492 }
493}
494
495impl<T, S> IndexMut<usize> for Rgb<T, S> {
496 fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut T {
497 self.as_mut().index_mut(index)
498 }
499}
500
501impl<T, S> AsRef<[T;3]> for Rgb<T, S> {
502 fn as_ref(&self) -> &[T;3] {
503 unsafe{ mem::transmute(self) }
504 }
505}
506
507impl<T, S> AsMut<[T;3]> for Rgb<T, S> {
508 fn as_mut(&mut self) -> &mut [T;3] {
509 unsafe{ mem::transmute(self) }
510 }
511}
512
513impl<T, S> Borrow<[T;3]> for Rgb<T, S> {
514 fn borrow(&self) -> &[T;3] {
515 unsafe{ mem::transmute(self)}
516 }
517}
518
519impl<T, S> BorrowMut<[T;3]> for Rgb<T, S> {
520 fn borrow_mut(&mut self) -> &mut [T;3] {
521 unsafe{ mem::transmute(self)}
522 }
523}
524
525pub mod consts {
527 use Rgb;
528 use color_space::Srgb;
529
530 pub static ALICEBLUE: Rgb<u8, Srgb> = Rgb::new(0xF0, 0xF8, 0xFF);
531 pub static ANTIQUEWHITE: Rgb<u8, Srgb> = Rgb::new(0xFA, 0xEB, 0xD7);
532 pub static AQUA: Rgb<u8, Srgb> = Rgb::new(0x00, 0xFF, 0xFF);
533 pub static AQUAMARINE: Rgb<u8, Srgb> = Rgb::new(0x7F, 0xFF, 0xD4);
534 pub static AZURE: Rgb<u8, Srgb> = Rgb::new(0xF0, 0xFF, 0xFF);
535 pub static BEIGE: Rgb<u8, Srgb> = Rgb::new(0xF5, 0xF5, 0xDC);
536 pub static BISQUE: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xE4, 0xC4);
537 pub static BLACK: Rgb<u8, Srgb> = Rgb::new(0x00, 0x00, 0x00);
538 pub static BLANCHEDALMOND: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xEB, 0xCD);
539 pub static BLUE: Rgb<u8, Srgb> = Rgb::new(0x00, 0x00, 0xFF);
540 pub static BLUEVIOLET: Rgb<u8, Srgb> = Rgb::new(0x8A, 0x2B, 0xE2);
541 pub static BROWN: Rgb<u8, Srgb> = Rgb::new(0xA5, 0x2A, 0x2A);
542 pub static BURLYWOOD: Rgb<u8, Srgb> = Rgb::new(0xDE, 0xB8, 0x87);
543 pub static CADETBLUE: Rgb<u8, Srgb> = Rgb::new(0x5F, 0x9E, 0xA0);
544 pub static CHARTREUSE: Rgb<u8, Srgb> = Rgb::new(0x7F, 0xFF, 0x00);
545 pub static CHOCOLATE: Rgb<u8, Srgb> = Rgb::new(0xD2, 0x69, 0x1E);
546 pub static CORAL: Rgb<u8, Srgb> = Rgb::new(0xFF, 0x7F, 0x50);
547 pub static CORNFLOWERBLUE: Rgb<u8, Srgb> = Rgb::new(0x64, 0x95, 0xED);
548 pub static CORNSILK: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xF8, 0xDC);
549 pub static CRIMSON: Rgb<u8, Srgb> = Rgb::new(0xDC, 0x14, 0x3C);
550 pub static CYAN: Rgb<u8, Srgb> = Rgb::new(0x00, 0xFF, 0xFF);
551 pub static DARKBLUE: Rgb<u8, Srgb> = Rgb::new(0x00, 0x00, 0x8B);
552 pub static DARKCYAN: Rgb<u8, Srgb> = Rgb::new(0x00, 0x8B, 0x8B);
553 pub static DARKGOLDENROD: Rgb<u8, Srgb> = Rgb::new(0xB8, 0x86, 0x0B);
554 pub static DARKGRAY: Rgb<u8, Srgb> = Rgb::new(0xA9, 0xA9, 0xA9);
555 pub static DARKGREEN: Rgb<u8, Srgb> = Rgb::new(0x00, 0x64, 0x00);
556 pub static DARKKHAKI: Rgb<u8, Srgb> = Rgb::new(0xBD, 0xB7, 0x6B);
557 pub static DARKMAGENTA: Rgb<u8, Srgb> = Rgb::new(0x8B, 0x00, 0x8B);
558 pub static DARKOLIVEGREEN: Rgb<u8, Srgb> = Rgb::new(0x55, 0x6B, 0x2F);
559 pub static DARKORANGE: Rgb<u8, Srgb> = Rgb::new(0xFF, 0x8C, 0x00);
560 pub static DARKORCHID: Rgb<u8, Srgb> = Rgb::new(0x99, 0x32, 0xCC);
561 pub static DARKRED: Rgb<u8, Srgb> = Rgb::new(0x8B, 0x00, 0x00);
562 pub static DARKSALMON: Rgb<u8, Srgb> = Rgb::new(0xE9, 0x96, 0x7A);
563 pub static DARKSEAGREEN: Rgb<u8, Srgb> = Rgb::new(0x8F, 0xBC, 0x8F);
564 pub static DARKSLATEBLUE: Rgb<u8, Srgb> = Rgb::new(0x48, 0x3D, 0x8B);
565 pub static DARKSLATEGRAY: Rgb<u8, Srgb> = Rgb::new(0x2F, 0x4F, 0x4F);
566 pub static DARKTURQUOISE: Rgb<u8, Srgb> = Rgb::new(0x00, 0xCE, 0xD1);
567 pub static DARKVIOLET: Rgb<u8, Srgb> = Rgb::new(0x94, 0x00, 0xD3);
568 pub static DEEPPINK: Rgb<u8, Srgb> = Rgb::new(0xFF, 0x14, 0x93);
569 pub static DEEPSKYBLUE: Rgb<u8, Srgb> = Rgb::new(0x00, 0xBF, 0xFF);
570 pub static DIMGRAY: Rgb<u8, Srgb> = Rgb::new(0x69, 0x69, 0x69);
571 pub static DODGERBLUE: Rgb<u8, Srgb> = Rgb::new(0x1E, 0x90, 0xFF);
572 pub static FIREBRICK: Rgb<u8, Srgb> = Rgb::new(0xB2, 0x22, 0x22);
573 pub static FLORALWHITE: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xFA, 0xF0);
574 pub static FORESTGREEN: Rgb<u8, Srgb> = Rgb::new(0x22, 0x8B, 0x22);
575 pub static FUCHSIA: Rgb<u8, Srgb> = Rgb::new(0xFF, 0x00, 0xFF);
576 pub static GAINSBORO: Rgb<u8, Srgb> = Rgb::new(0xDC, 0xDC, 0xDC);
577 pub static GHOSTWHITE: Rgb<u8, Srgb> = Rgb::new(0xF8, 0xF8, 0xFF);
578 pub static GOLD: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xD7, 0x00);
579 pub static GOLDENROD: Rgb<u8, Srgb> = Rgb::new(0xDA, 0xA5, 0x20);
580 pub static GRAY: Rgb<u8, Srgb> = Rgb::new(0x80, 0x80, 0x80);
581 pub static GREEN: Rgb<u8, Srgb> = Rgb::new(0x00, 0x80, 0x00);
582 pub static GREENYELLOW: Rgb<u8, Srgb> = Rgb::new(0xAD, 0xFF, 0x2F);
583 pub static HONEYDEW: Rgb<u8, Srgb> = Rgb::new(0xF0, 0xFF, 0xF0);
584 pub static HOTPINK: Rgb<u8, Srgb> = Rgb::new(0xFF, 0x69, 0xB4);
585 pub static INDIANRED: Rgb<u8, Srgb> = Rgb::new(0xCD, 0x5C, 0x5C);
586 pub static INDIGO: Rgb<u8, Srgb> = Rgb::new(0x4B, 0x00, 0x82);
587 pub static IVORY: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xFF, 0xF0);
588 pub static KHAKI: Rgb<u8, Srgb> = Rgb::new(0xF0, 0xE6, 0x8C);
589 pub static LAVENDER: Rgb<u8, Srgb> = Rgb::new(0xE6, 0xE6, 0xFA);
590 pub static LAVENDERBLUSH: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xF0, 0xF5);
591 pub static LAWNGREEN: Rgb<u8, Srgb> = Rgb::new(0x7C, 0xFC, 0x00);
592 pub static LEMONCHIFFON: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xFA, 0xCD);
593 pub static LIGHTBLUE: Rgb<u8, Srgb> = Rgb::new(0xAD, 0xD8, 0xE6);
594 pub static LIGHTCORAL: Rgb<u8, Srgb> = Rgb::new(0xF0, 0x80, 0x80);
595 pub static LIGHTCYAN: Rgb<u8, Srgb> = Rgb::new(0xE0, 0xFF, 0xFF);
596 pub static LIGHTGOLDENRODYELLOW: Rgb<u8, Srgb> = Rgb::new(0xFA, 0xFA, 0xD2);
597 pub static LIGHTGREEN: Rgb<u8, Srgb> = Rgb::new(0x90, 0xEE, 0x90);
598 pub static LIGHTGREY: Rgb<u8, Srgb> = Rgb::new(0xD3, 0xD3, 0xD3);
599 pub static LIGHTPINK: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xB6, 0xC1);
600 pub static LIGHTSALMON: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xA0, 0x7A);
601 pub static LIGHTSEAGREEN: Rgb<u8, Srgb> = Rgb::new(0x20, 0xB2, 0xAA);
602 pub static LIGHTSKYBLUE: Rgb<u8, Srgb> = Rgb::new(0x87, 0xCE, 0xFA);
603 pub static LIGHTSLATEGRAY: Rgb<u8, Srgb> = Rgb::new(0x77, 0x88, 0x99);
604 pub static LIGHTSTEELBLUE: Rgb<u8, Srgb> = Rgb::new(0xB0, 0xC4, 0xDE);
605 pub static LIGHTYELLOW: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xFF, 0xE0);
606 pub static LIME: Rgb<u8, Srgb> = Rgb::new(0x00, 0xFF, 0x00);
607 pub static LIMEGREEN: Rgb<u8, Srgb> = Rgb::new(0x32, 0xCD, 0x32);
608 pub static LINEN: Rgb<u8, Srgb> = Rgb::new(0xFA, 0xF0, 0xE6);
609 pub static MAGENTA: Rgb<u8, Srgb> = Rgb::new(0xFF, 0x00, 0xFF);
610 pub static MAROON: Rgb<u8, Srgb> = Rgb::new(0x80, 0x00, 0x00);
611 pub static MEDIUMAQUAMARINE: Rgb<u8, Srgb> = Rgb::new(0x66, 0xCD, 0xAA);
612 pub static MEDIUMBLUE: Rgb<u8, Srgb> = Rgb::new(0x00, 0x00, 0xCD);
613 pub static MEDIUMORCHID: Rgb<u8, Srgb> = Rgb::new(0xBA, 0x55, 0xD3);
614 pub static MEDIUMPURPLE: Rgb<u8, Srgb> = Rgb::new(0x93, 0x70, 0xDB);
615 pub static MEDIUMSEAGREEN: Rgb<u8, Srgb> = Rgb::new(0x3C, 0xB3, 0x71);
616 pub static MEDIUMSLATEBLUE: Rgb<u8, Srgb> = Rgb::new(0x7B, 0x68, 0xEE);
617 pub static MEDIUMSPRINGGREEN: Rgb<u8, Srgb> = Rgb::new(0x00, 0xFA, 0x9A);
618 pub static MEDIUMTURQUOISE: Rgb<u8, Srgb> = Rgb::new(0x48, 0xD1, 0xCC);
619 pub static MEDIUMVIOLETRED: Rgb<u8, Srgb> = Rgb::new(0xC7, 0x15, 0x85);
620 pub static MIDNIGHTBLUE: Rgb<u8, Srgb> = Rgb::new(0x19, 0x19, 0x70);
621 pub static MINTCREAM: Rgb<u8, Srgb> = Rgb::new(0xF5, 0xFF, 0xFA);
622 pub static MISTYROSE: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xE4, 0xE1);
623 pub static MOCCASIN: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xE4, 0xB5);
624 pub static NAVAJOWHITE: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xDE, 0xAD);
625 pub static NAVY: Rgb<u8, Srgb> = Rgb::new(0x00, 0x00, 0x80);
626 pub static OLDLACE: Rgb<u8, Srgb> = Rgb::new(0xFD, 0xF5, 0xE6);
627 pub static OLIVE: Rgb<u8, Srgb> = Rgb::new(0x80, 0x80, 0x00);
628 pub static OLIVEDRAB: Rgb<u8, Srgb> = Rgb::new(0x6B, 0x8E, 0x23);
629 pub static ORANGE: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xA5, 0x00);
630 pub static ORANGERED: Rgb<u8, Srgb> = Rgb::new(0xFF, 0x45, 0x00);
631 pub static ORCHID: Rgb<u8, Srgb> = Rgb::new(0xDA, 0x70, 0xD6);
632 pub static PALEGOLDENROD: Rgb<u8, Srgb> = Rgb::new(0xEE, 0xE8, 0xAA);
633 pub static PALEGREEN: Rgb<u8, Srgb> = Rgb::new(0x98, 0xFB, 0x98);
634 pub static PALEVIOLETRED: Rgb<u8, Srgb> = Rgb::new(0xDB, 0x70, 0x93);
635 pub static PAPAYAWHIP: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xEF, 0xD5);
636 pub static PEACHPUFF: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xDA, 0xB9);
637 pub static PERU: Rgb<u8, Srgb> = Rgb::new(0xCD, 0x85, 0x3F);
638 pub static PINK: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xC0, 0xCB);
639 pub static PLUM: Rgb<u8, Srgb> = Rgb::new(0xDD, 0xA0, 0xDD);
640 pub static POWDERBLUE: Rgb<u8, Srgb> = Rgb::new(0xB0, 0xE0, 0xE6);
641 pub static PURPLE: Rgb<u8, Srgb> = Rgb::new(0x80, 0x00, 0x80);
642 pub static RED: Rgb<u8, Srgb> = Rgb::new(0xFF, 0x00, 0x00);
643 pub static ROSYBROWN: Rgb<u8, Srgb> = Rgb::new(0xBC, 0x8F, 0x8F);
644 pub static ROYALBLUE: Rgb<u8, Srgb> = Rgb::new(0x41, 0x69, 0xE1);
645 pub static SADDLEBROWN: Rgb<u8, Srgb> = Rgb::new(0x8B, 0x45, 0x13);
646 pub static SALMON: Rgb<u8, Srgb> = Rgb::new(0xFA, 0x80, 0x72);
647 pub static SANDYBROWN: Rgb<u8, Srgb> = Rgb::new(0xFA, 0xA4, 0x60);
648 pub static SEAGREEN: Rgb<u8, Srgb> = Rgb::new(0x2E, 0x8B, 0x57);
649 pub static SEASHELL: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xF5, 0xEE);
650 pub static SIENNA: Rgb<u8, Srgb> = Rgb::new(0xA0, 0x52, 0x2D);
651 pub static SILVER: Rgb<u8, Srgb> = Rgb::new(0xC0, 0xC0, 0xC0);
652 pub static SKYBLUE: Rgb<u8, Srgb> = Rgb::new(0x87, 0xCE, 0xEB);
653 pub static SLATEBLUE: Rgb<u8, Srgb> = Rgb::new(0x6A, 0x5A, 0xCD);
654 pub static SLATEGRAY: Rgb<u8, Srgb> = Rgb::new(0x70, 0x80, 0x90);
655 pub static SNOW: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xFA, 0xFA);
656 pub static SPRINGGREEN: Rgb<u8, Srgb> = Rgb::new(0x00, 0xFF, 0x7F);
657 pub static STEELBLUE: Rgb<u8, Srgb> = Rgb::new(0x46, 0x82, 0xB4);
658 pub static TAN: Rgb<u8, Srgb> = Rgb::new(0xD2, 0xB4, 0x8C);
659 pub static TEAL: Rgb<u8, Srgb> = Rgb::new(0x00, 0x80, 0x80);
660 pub static THISTLE: Rgb<u8, Srgb> = Rgb::new(0xD8, 0xBF, 0xD8);
661 pub static TOMATO: Rgb<u8, Srgb> = Rgb::new(0xFF, 0x63, 0x47);
662 pub static TURQUOISE: Rgb<u8, Srgb> = Rgb::new(0x40, 0xE0, 0xD0);
663 pub static VIOLET: Rgb<u8, Srgb> = Rgb::new(0xEE, 0x82, 0xEE);
664 pub static WHEAT: Rgb<u8, Srgb> = Rgb::new(0xF5, 0xDE, 0xB3);
665 pub static WHITE: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xFF, 0xFF);
666 pub static WHITESMOKE: Rgb<u8, Srgb> = Rgb::new(0xF5, 0xF5, 0xF5);
667 pub static YELLOW: Rgb<u8, Srgb> = Rgb::new(0xFF, 0xFF, 0x00);
668 pub static YELLOWGREEN: Rgb<u8, Srgb> = Rgb::new(0x9A, 0xCD, 0x32);
669}
670
671#[cfg(test)]
672mod tests {
673 use {Hsv, ToHsv};
674 use {Rgb, ToRgb};
675 use FloatColor;
676 use angle::*;
677 use num_traits::Saturating;
678
679 #[test]
680 fn test_rgb_to_rgb() {
681 assert_eq!(Rgb::<u8>::new(0xA0, 0xA0, 0xA0).to_rgb::<u8>(), Rgb::<u8>::new(0xA0, 0xA0, 0xA0));
682 assert_eq!(Rgb::<u8>::new(0xA0, 0xA0, 0xA0).to_rgb::<u16>(), Rgb::<u16>::new(0xA0A0, 0xA0A0, 0xA0A0));
683 }
684
685 #[test]
686 fn test_rgb_to_hsv() {
687 assert_eq!(Rgb::<u8>::new(0xFF, 0xFF, 0xFF).to_hsv::<f32>(), Hsv::<f32>::new(Deg(0.0), 0.0, 1.0));
688 assert_eq!(Rgb::<u8>::new(0x99, 0x00, 0x00).to_hsv::<f32>(), Hsv::<f32>::new(Deg(0.0), 1.0, 0.6));
689 assert_eq!(Rgb::<u8>::new(0x00, 0x99, 0x00).to_hsv::<f32>(), Hsv::<f32>::new(Deg(120.0), 1.0, 0.6));
690 assert_eq!(Rgb::<u8>::new(0x00, 0x00, 0x99).to_hsv::<f32>(), Hsv::<f32>::new(Deg(240.0), 1.0, 0.6));
691 }
692
693 #[test]
694 fn test_rgb_ops(){
695 assert_eq!( rgb!(20u8, 20, 20) + rgb!(20, 20, 20), rgb!(40, 40, 40) );
696 assert_eq!( rgb!(254u8, 254, 254).saturating_add( rgb!(20, 20, 20) ), rgb!(255, 255, 255) );
697 assert_eq!( rgb!(20u8, 20, 20).saturating_sub( rgb!(50, 50, 50) ), rgb!(0, 0, 0) );
698 assert_eq!( rgb!(127u8, 127, 127) * rgb!(255, 255, 255), rgb!(127, 127, 127) );
699 assert_eq!( rgb!(127u8, 127, 127) / rgb!(255, 255, 255), rgb!(127, 127, 127) );
700 assert_eq!( rgb!(1.0f32, 1.0, 1.0) * 2.0, rgb!(2.0, 2.0, 2.0));
701 assert_eq!( (rgb!(1.0f32, 1.0, 1.0) * 2.0).saturate(), rgb!(1.0, 1.0, 1.0));
702 }
703}