[go: up one dir, main page]

cint/
lib.rs

1//! # `cint` - `c`olor `int`erop
2//!
3//! This library provides a lean, minimal, and stable set of types
4//! for color interoperation between crates in Rust. Its goal is to serve the same
5//! function that [`mint`](https://docs.rs/mint/) provides for (linear algebra) math types.
6//! It does not actually provide any conversion, math, etc. for these types, but rather
7//! serves as a stable interface that multiple libraries can rely on and then convert
8//! to their own internal representations to actually use. It is also `#![no_std]`.
9//! [`bytemuck`](https://docs.rs/bytemuck/) impls are provided with the `bytemuck` feature.
10//!
11//! # How to Use
12//!
13//! If you have no idea about color management or encoding principles but you want to
14//! use this crate in your own, here's a *very basic* rundown.
15//!
16//! If you have a color that you loaded from an 8-bit format like a PNG, JPG, etc.,
17//! **or** if you have a color that you picked from some sort of online color picker
18//! or in Photoshop or Aseprite, then what you have is almost certainly an [`EncodedSrgb<u8>`]
19//! color. If you have a color that you loaded
20//! from a similar format but has floating point values instead of `u8` ints, then you
21//! almost certainly instead have a [`EncodedSrgb<f32>`] color.
22//!
23//! If you "linearized" or performed "inverse gamma correction" on such a color, then you instead
24//! might have a [`LinearSrgb<f32>`].
25//!
26//! If you are more familiar with color encoding, then you'll find a collection of other color spaces
27//! represented, as well as the generic color types (like [`GenericColor3<ComponentTy>`]) which
28//! can be used if the color space you wish to use is not represented.
29//!
30//! All spaces are also collected into the [`Spaces`] enum, and you can get the variant represented
31//! by any of the concrete color types by taking advantage of the [`ColorType`]'s `SPACE` associated
32//! type, i.e. `EncodedSrgb::SPACE` will give `Spaces::EncodedSrgb`.
33//!
34//! The [`ColorInterop`] trait exists to provide a "canonical" transformation to and from `cint` types.
35//! Since it is often possible to convert a color to and from multiple `cint` types, and because of
36//! how the Rust type inference system works, it can often be inconvenient to chain together `from`
37//! or `into` calls from the [From]/[Into] trait. [`ColorInterop`] solves this by providing a strongly
38//! typed "reference" conversion to/from `cint` types. This way, you can do things like:
39//!
40//! ```rust
41//! let color_crate1 = color_crate2.into_cint().into();
42//! // or
43//! let color_crate2 = ColorCrate2::from_cint(color_crate1.into());
44//! ```
45//!
46//! which would otherwise be quite inconvenient. **Provider crates** (those that provide their own color
47//! types) should implement the relevant [`From`]/[`Into`] implementations to and from `cint` types, and
48//! also the [ColorInterop] trait once for each color type. The [`into_cint`][ColorInterop::into_cint] and
49//! [`from_cint`][ColorInterop::from_cint] methods will then be provided automatically.
50//!
51//! ## Colors with alpha channels
52//!
53//! `cint` provides the [`Alpha<ColorTy>`] and [`PremultipliedAlpha<ColorTy>`]
54//! structs, which are generic over the inner `ColorTy`.
55//! To represent an [`EncodedSrgb<u8>`] color with a premultiplied alpha component,
56//! you'd use [`PremultipliedAlpha<EncodedSrgb<u8>>`]. If, on the other hand, you want to represent
57//! an [`Oklab<f32>`] color with an independent alpha component, you'd use [`Alpha<Oklab<f32>>`]
58#![no_std]
59#![allow(unsafe_code)]
60
61#[cfg(feature = "bytemuck")]
62use bytemuck::{Pod, Zeroable};
63
64/// A trait used to simpify the interface of the [`Alpha`] and [`PremultipliedAlpha`] types and
65/// allow use with [`Spaces`] enum.
66pub trait ColorType {
67    type ComponentTy: Copy;
68    const SPACE: Spaces;
69    const NUM_COMPONENTS: usize;
70}
71
72/// A trait that should be implemented by provider crates on their local color types so that you can call
73/// `color.to_cint()` and `Color::from_cint(cint_color)`.
74///
75/// Provider crates should also do relevant `From`/`Into` impls, but [`ColorInterop`] provides a "canonical"
76/// transformation to the closest `cint` color type.
77pub trait ColorInterop
78where
79    Self: Into<<Self as ColorInterop>::CintTy>,
80{
81    type CintTy: Into<Self>;
82
83    /// Convert `self` into its canonical `cint` type.
84    fn from_cint(col: Self::CintTy) -> Self {
85        col.into()
86    }
87
88    /// Create a `Self` from its canonical `cint` type.
89    fn into_cint(self) -> Self::CintTy {
90        self.into()
91    }
92}
93
94/// A color with an alpha component.
95///
96/// The color components and alpha component are completely separate.
97#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
98#[repr(C)]
99pub struct Alpha<ColorTy: ColorType> {
100    /// The contained color, which is completely separate from the `alpha` value.
101    pub color: ColorTy,
102    /// The alpha component.
103    pub alpha: ColorTy::ComponentTy,
104}
105
106impl<BaseColorTy: ColorType> ColorType for Alpha<BaseColorTy> {
107    type ComponentTy = BaseColorTy::ComponentTy;
108    const SPACE: Spaces = BaseColorTy::SPACE;
109    const NUM_COMPONENTS: usize = BaseColorTy::NUM_COMPONENTS + 1;
110}
111
112#[cfg(feature = "bytemuck")]
113unsafe impl<ColorTy: ColorType + Zeroable> Zeroable for Alpha<ColorTy> {}
114#[cfg(feature = "bytemuck")]
115unsafe impl<ColorTy: ColorType + Pod> Pod for Alpha<ColorTy> {}
116
117/// A premultiplied color with an alpha component.
118///
119/// The color components have been premultiplied by the alpha component.
120#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
121pub struct PremultipliedAlpha<ColorTy: ColorType> {
122    /// The contained color, which has been premultiplied with `alpha`
123    pub color: ColorTy,
124    /// The alpha component.
125    pub alpha: ColorTy::ComponentTy,
126}
127
128impl<BaseColorTy: ColorType> ColorType for PremultipliedAlpha<BaseColorTy> {
129    type ComponentTy = BaseColorTy::ComponentTy;
130    const SPACE: Spaces = BaseColorTy::SPACE;
131    const NUM_COMPONENTS: usize = BaseColorTy::NUM_COMPONENTS + 1;
132}
133
134#[cfg(feature = "bytemuck")]
135unsafe impl<ColorTy: ColorType + Zeroable> Zeroable for PremultipliedAlpha<ColorTy> {}
136#[cfg(feature = "bytemuck")]
137unsafe impl<ColorTy: ColorType + Pod> Pod for PremultipliedAlpha<ColorTy> {}
138
139macro_rules! color_struct {
140    {
141        $(#[$doc:meta])*
142        $name:ident<$default_component_ty:ty, $num_components:literal> {
143            $($(#[$compdoc:meta])+
144            $compname:ident,)+
145        }
146    } => {
147        $(#[$doc])*
148        #[repr(C)]
149        #[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Eq, Ord)]
150        pub struct $name<ComponentTy=$default_component_ty> {
151            $($(#[$compdoc])+
152            pub $compname: ComponentTy,)+
153        }
154
155        impl<CTy: Clone + Copy> ColorType for $name<CTy> {
156            type ComponentTy = CTy;
157            const SPACE: Spaces = Spaces::$name;
158            const NUM_COMPONENTS: usize = $num_components;
159        }
160
161        #[cfg(feature = "bytemuck")]
162        unsafe impl<ComponentTy: Zeroable> Zeroable for $name<ComponentTy> {}
163        #[cfg(feature = "bytemuck")]
164        unsafe impl<ComponentTy: Pod> Pod for $name<ComponentTy> {}
165
166        impl<ComponentTy> From<[ComponentTy; $num_components]> for $name<ComponentTy> {
167            fn from([$($compname),+]: [ComponentTy; $num_components]) -> $name<ComponentTy> {
168                $name {
169                    $($compname,)+
170                }
171            }
172        }
173
174        #[allow(clippy::from_over_into)]
175        impl<ComponentTy> Into<[ComponentTy; $num_components]> for $name<ComponentTy> {
176            fn into(self) -> [ComponentTy; $num_components] {
177                let $name {
178                    $($compname,)+
179                } = self;
180                [$($compname),+]
181            }
182        }
183
184        impl<ComponentTy> AsRef<[ComponentTy; $num_components]> for $name<ComponentTy> {
185            fn as_ref(&self) -> &[ComponentTy; $num_components] {
186                // SAFETY: same layout is guaranteed by repr C
187                unsafe { &*(self as *const $name<ComponentTy> as *const [ComponentTy; $num_components]) }
188            }
189        }
190
191        impl<ComponentTy> AsMut<[ComponentTy; $num_components]> for $name<ComponentTy> {
192            fn as_mut(&mut self) -> &mut [ComponentTy; $num_components] {
193                // SAFETY: same layout is guaranteed by repr C
194                unsafe { &mut *(self as *mut $name<ComponentTy> as *mut [ComponentTy; $num_components]) }
195            }
196        }
197
198        macro_rules! impl_alpha_traits {
199            ($alphaty:ident) => {
200                impl<ComponentTy: Copy> From<$alphaty<$name<ComponentTy>>> for $name<ComponentTy> {
201                    fn from(col_alpha: $alphaty<$name<ComponentTy>>) -> $name<ComponentTy> {
202                        col_alpha.color
203                    }
204                }
205
206                impl<ComponentTy: Copy> From<[ComponentTy; $num_components + 1]> for $alphaty<$name<ComponentTy>> {
207                    fn from([$($compname,)+ alpha]: [ComponentTy; $num_components + 1]) -> $alphaty<$name<ComponentTy>> {
208                        $alphaty {
209                            color: $name::from([$($compname,)+]),
210                            alpha,
211                        }
212                    }
213                }
214
215                #[allow(clippy::from_over_into)]
216                impl<ComponentTy: Copy> Into<[ComponentTy; $num_components + 1]> for $alphaty<$name<ComponentTy>> {
217                    fn into(self) -> [ComponentTy; $num_components + 1] {
218                        let $alphaty {
219                            color,
220                            alpha
221                        } = self;
222
223                        let $name {
224                            $($compname,)+
225                        } = color;
226
227                        [$($compname,)+ alpha]
228                    }
229                }
230
231                impl<ComponentTy: Copy> AsRef<[ComponentTy; $num_components + 1]> for $alphaty<$name<ComponentTy>> {
232                    fn as_ref(&self) -> &[ComponentTy; $num_components + 1] {
233                        // SAFETY: same layout is guaranteed by repr C
234                        unsafe { &*(self as *const $alphaty<$name<ComponentTy>> as *const [ComponentTy; $num_components + 1]) }
235                    }
236                }
237
238                impl<ComponentTy: Copy> AsMut<[ComponentTy; $num_components + 1]> for $alphaty<$name<ComponentTy>> {
239                    fn as_mut(&mut self) -> &mut [ComponentTy; $num_components + 1] {
240                        // SAFETY: same layout is guaranteed by repr C
241                        unsafe { &mut *(self as *mut $alphaty<$name<ComponentTy>> as *mut [ComponentTy; $num_components + 1]) }
242                    }
243                }
244            }
245        }
246
247        impl_alpha_traits!(Alpha);
248        impl_alpha_traits!(PremultipliedAlpha);
249    };
250}
251
252macro_rules! color_spaces {
253    {
254        $($(#[$space_doc:meta])*
255        $space_name:ident<$default_component_ty:ty, $num_components:literal> {
256            $($(#[$comp_doc:meta])+
257            $comp_name:ident,)+
258        })*
259    } => {
260        /// An enum with a variant for each of the color spaces
261        /// supported by the library. Useful for tracking as metadata
262        /// in something like an image type, and for runtime-determined color types.
263        #[repr(u32)]
264        #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
265        pub enum Spaces {
266            $(
267                $(#[$space_doc])*
268                $space_name,
269            )*
270        }
271
272        impl Spaces {
273            pub fn num_components(&self) -> usize {
274                match *self {
275                    $(
276                        Self::$space_name => $num_components,
277                    )*
278                }
279            }
280        }
281
282        $(
283            color_struct! {
284                $(#[$space_doc])*
285                $space_name<$default_component_ty, $num_components> {
286                    $( $(#[$comp_doc])+
287                    $comp_name,)+
288                }
289            }
290        )*
291    }
292}
293
294color_spaces! {
295    /// A color in the encoded sRGB color space.
296    ///
297    /// This color space uses the sRGB/Rec.709 primaries, D65 white point,
298    /// and sRGB transfer functions. The encoded version is nonlinear, with the
299    /// sRGB OETF, aka "gamma compensation", applied.
300    EncodedSrgb<u8, 3> {
301        /// The red component.
302        r,
303        /// The green component.
304        g,
305        /// The blue component.
306        b,
307    }
308
309    /// A color in the linear (decoded) sRGB color space.
310    ///
311    /// This color space uses the sRGB/Rec.709 primaries, D65 white point,
312    /// and sRGB transfer functions. This version is linear, with the
313    /// sRGB EOTF, aka "inverse gamma compensation", applied in order to
314    /// decode it from [`EncodedSrgb`]
315    LinearSrgb<f32, 3> {
316        /// The red component.
317        r,
318        /// The green component.
319        g,
320        /// The blue component.
321        b,
322    }
323
324    /// A color in the encoded Rec.709/BT.709 color space.
325    ///
326    /// This color space uses the BT.709 primaries, D65 white point,
327    /// and BT.601 (reused in BT.709) transfer function. The encoded version is nonlinear, with the
328    /// BT.601 OETF applied.
329    EncodedRec709<u8, 3> {
330        /// The red component.
331        r,
332        /// The green component.
333        g,
334        /// The blue component.
335        b,
336    }
337
338    /// A color in the Rec.709/BT.709 color space.
339    ///
340    /// This color space uses the BT.709 primaries, D65 white point,
341    /// and BT.601 (reused in BT.709) transfer function. This version is linear, without the
342    /// BT.601 OETF applied.
343    Rec709<f32, 3> {
344        /// The red component.
345        r,
346        /// The green component.
347        g,
348        /// The blue component.
349        b,
350    }
351
352    /// A color in a generic color space that can be represented by 3 components. The user
353    /// is responsible for ensuring that the correct color space is respected.
354    GenericColor3<f32, 3> {
355        /// The first component.
356        x,
357        /// The second component.
358        y,
359        /// The third component.
360        z,
361    }
362
363    /// A color in a generic color space that can be represented by 1 component. The user
364    /// is responsible for ensuring that the correct color space is respected.
365    GenericColor1<f32, 1> {
366        /// The first component.
367        x,
368    }
369
370    /// A single-channel CIE luminance.
371    Luminance<f32, 1> {
372        /// CIE luminance.
373        l,
374    }
375
376    /// A single-channel CIE luma (non-linear transform from luminance).
377    Luma<f32, 1> {
378        /// CIE luminance.
379        l,
380    }
381
382    /// A color in the ACEScg color space.
383    ///
384    /// This color space uses the ACES AP1 primaries and D60 white point.
385    AcesCg<f32, 3> {
386        /// The red component.
387        r,
388        /// The green component.
389        g,
390        /// The blue component.
391        b,
392    }
393
394    /// A color in the ACES 2065-1 color space.
395    ///
396    /// This color space uses the ACES AP0 primaries and D60 white point.
397    Aces2065<f32, 3> {
398        /// The red component.
399        r,
400        /// The green component.
401        g,
402        /// The blue component.
403        b,
404    }
405
406    /// A color in the ACEScc color space.
407    ///
408    /// This color space uses the ACES AP1 primaries and D60 white point
409    /// and a pure logarithmic transfer function.
410    AcesCc<f32, 3> {
411        /// The red component.
412        r,
413        /// The green component.
414        g,
415        /// The blue component.
416        b,
417    }
418
419    /// A color in the ACEScct color space.
420    ///
421    /// This color space uses the ACES AP1 primaries and D60 white point
422    /// and a logarithmic transfer function with a toe such that values
423    /// are able to go negative.
424    AcesCct<f32, 3> {
425        /// The red component.
426        r,
427        /// The green component.
428        g,
429        /// The blue component.
430        b,
431    }
432
433    /// A color in the Display P3 (aka P3 D65) color space.
434    ///
435    /// This color space uses the P3 primaries and D65 white point
436    /// and sRGB transfer functions. This version is linear,
437    /// without the sRGB OETF applied.
438    DisplayP3<f32, 3> {
439        /// The red component.
440        r,
441        /// The green component.
442        g,
443        /// The blue component.
444        b,
445    }
446
447    /// A color in the Display P3 (aka P3 D65) color space.
448    ///
449    /// This color space uses the P3 primaries and D65 white point
450    /// and sRGB transfer functions. This encoded version is nonlinear,
451    /// with the sRGB OETF applied.
452    EncodedDisplayP3<u8, 3> {
453        /// The red component.
454        r,
455        /// The green component.
456        g,
457        /// The blue component.
458        b,
459    }
460
461    /// A color in the DCI-P3 (aka P3 DCI and P3 D60) color space.
462    ///
463    /// If you are looking for the P3 which is used on new Apple displays, see
464    /// [`DisplayP3`] instead.
465    ///
466    /// This color space uses the P3 primaries and D60 white point.
467    DciP3<f32, 3> {
468        /// The red component.
469        r,
470        /// The green component.
471        g,
472        /// The blue component.
473        b,
474    }
475
476    /// A color in the X'Y'Z' color space, a DCI specification used for digital cinema mastering.
477    ///
478    /// This color space uses the CIE XYZ primaries, with special DCI white point and pure 2.6 gamma encoding.
479    DciXYZPrime<f32, 3> {
480        /// The X' component.
481        x,
482        /// The Y' component.
483        y,
484        /// The Z' component.
485        z,
486    }
487
488    /// A color in the BT.2020 color space.
489    ///
490    /// This color space uses the BT.2020 primaries and D65 white point.
491    Bt2020<f32, 3> {
492        /// The red component.
493        r,
494        /// The green component.
495        g,
496        /// The blue component.
497        b,
498    }
499
500    /// A color in the encoded BT.2020 color space.
501    ///
502    /// This color space uses the BT.2020 primaries and D65 white point and
503    /// the BT.2020 transfer functions (equivalent to BT.601 transfer functions
504    /// but with higher precision). This encoded version is nonlinear, with the
505    /// BT.2020/BT.601 OETF applied.
506    EncodedBt2020<f32, 3> {
507        /// The red component.
508        r,
509        /// The green component.
510        g,
511        /// The blue component.
512        b,
513    }
514
515    /// A color in the BT.2100 color space.
516    ///
517    /// This color space uses the BT.2020 primaries and D65 white point.
518    Bt2100<f32, 3> {
519        /// The red component.
520        r,
521        /// The green component.
522        g,
523        /// The blue component.
524        b,
525    }
526
527    /// A color in the encoded BT.2100 color space with PQ (Perceptual Quantizer)
528    /// transfer function.
529    ///
530    /// This color space uses the BT.2020 primaries and D65 white point and
531    /// the ST 2084/"PQ" transfer function. It is nonlinear.
532    EncodedBt2100PQ<f32, 3> {
533        /// The red component.
534        r,
535        /// The green component.
536        g,
537        /// The blue component.
538        b,
539    }
540
541    /// A color in the encoded BT.2100 color space with HLG (Hybrid Log-Gamma)
542    /// transfer function.
543    ///
544    /// This color space uses the BT.2020 primaries and D65 white point and
545    /// the HLG transfer function. It is nonlinear.
546    EncodedBt2100HLG<f32, 3> {
547        /// The red component.
548        r,
549        /// The green component.
550        g,
551        /// The blue component.
552        b,
553    }
554
555    /// A color in the ICtCp color space with PQ (Perceptual Quantizer)
556    /// nonlinearity.
557    ///
558    /// This color space is based on the BT.2020 primaries and D65 white point,
559    /// but is not an RGB color space. Instead it is a roughly perceptual color
560    /// space meant to more efficiently encode HDR content.
561    ICtCpPQ<f32, 3> {
562        /// The I (intensity) component.
563        i,
564        /// The Ct (chroma-tritan) component.
565        ct,
566        /// The Cp (chroma-protan) component.
567        cp,
568    }
569
570    /// A color in the ICtCp color space with HLG (Hybrid Log-Gamma)
571    /// nonlinearity.
572    ///
573    /// This color space is based on the BT.2020 primaries and D65 white point,
574    /// but is not an RGB color space. Instead it is a roughly perceptual color
575    /// space meant to more efficiently encode HDR content.
576    ICtCpHLG<f32, 3> {
577        /// The I (intensity) component.
578        i,
579        /// The Ct (chroma-tritan) component.
580        ct,
581        /// The Cp (chroma-protan) component.
582        cp,
583    }
584
585    /// A color in the CIE XYZ color space.
586    ///
587    /// This color space uses the CIE XYZ primaries and D65 white point.
588    CieXYZ<f32, 3> {
589        /// The X component.
590        x,
591        /// The Y component.
592        y,
593        /// The Z component.
594        z,
595    }
596
597    /// A color in the CIE L\*a\*b\* color space.
598    CieLab<f32, 3> {
599        /// The L (lightness) component. Varies from 0 to 100.
600        l,
601        /// The a component, representing green-red chroma difference.
602        a,
603        /// The b component, representing blue-yellow chroma difference.
604        b,
605    }
606
607    /// A color in the CIE L\*C\*h° color space.
608    CieLCh<f32, 3> {
609        /// The L (lightness) component. Varies from 0 to 100.
610        l,
611        /// The C (chroma) component. Varies from 0 to a hue dependent maximum.
612        c,
613        /// The h (hue) component. Varies from -PI to PI.
614        h,
615    }
616
617    /// A color in the Oklab color space.
618    Oklab<f32, 3> {
619        /// The L (lightness) component. Varies from 0 to 1
620        l,
621        /// The a component, representing green-red chroma difference.
622        a,
623        /// The b component, representing blue-yellow chroma difference.
624        b,
625    }
626
627    /// A color in the Oklch color space (a transformation from Oklab to LCh° coordinates).
628    Oklch<f32, 3> {
629        /// The L (lightness) component. Varies from 0 to 1.
630        l,
631        /// The C (chroma) component. Varies from 0 to a hue dependent maximum.
632        c,
633        /// The h (hue) component. Varies from -PI to PI.
634        h,
635    }
636
637    /// A color in the HSL color space.
638    ///
639    /// Since HSL is a relative color space, it is required to know the RGB space which
640    /// it was transformed from. We define this as the linear sRGB space, as that is
641    /// the most common case.
642    Hsl<f32, 3> {
643        /// The H (hue) component. Varies from 0 to 1.
644        h,
645        /// The S (saturation) component. Varies from 0 to 1.
646        s,
647        /// The L (lightness) component. Varies from 0 to 1.
648        l,
649    }
650
651    /// A color in the HSV color space.
652    ///
653    /// Since HSV is a relative color space, it is required to know the RGB space which
654    /// it was transformed from. We define this as the linear sRGB space, as that is
655    /// the most common case.
656    Hsv<f32, 3> {
657        /// The H (hue) component. Varies from 0 to 1.
658        h,
659        /// The S (saturation) component. Varies from 0 to 1.
660        s,
661        /// The V (value) component. Varies from 0 to 1.
662        v,
663    }
664
665    /// A color in the YCbCr color space. See discussion of the difference between YCbCr, YUV, and
666    /// YPbPr in [YCbCr Wikipedia article](https://en.wikipedia.org/wiki/YCbCr)
667    ///
668    /// Since YCbCr is a relative color space, it is required to know the RGB space which
669    /// it was transformed from. We define this as being converted from the LinearSrgb color space.
670    YCbCr<u8, 3> {
671        /// The Y (luminance) component.
672        y,
673        /// The Cb (chroma-blue/yellow) component.
674        cb,
675        /// The Cr (chroma-red/green) component.
676        cr,
677    }
678
679    /// A color in the Y'CbCr color space. See discussion of the difference between YCbCr, Y'CbCr,
680    /// YUV, YPbPr, and Y'PbPr in the [YCbCr Wikipedia article](https://en.wikipedia.org/wiki/YCbCr)
681    ///
682    /// Since Y'CbCr is a relative color space, it is required to know the RGB space which
683    /// it was transformed from. We define this as being converted from the EncodedSrgb color space.
684    YPrimeCbCr<u8, 3> {
685        /// The Y' (luma) component.
686        y,
687        /// The Cb (chroma-blue/yellow) component.
688        cb,
689        /// The Cr (chroma-red/green) component.
690        cr,
691    }
692
693    /// A color in the YPbPr color space. See discussion of the difference between YCbCr,
694    /// YUV, YPbPr, and Y'PbPr in the [YCbCr Wikipedia article](https://en.wikipedia.org/wiki/YCbCr)
695    ///
696    /// Since YPbPr is a relative color space, it is required to know the RGB space which
697    /// it was transformed from. We define this as being converted from the LinearSrgb color space.
698    YPbPr<f32, 3> {
699        /// The Y (luminance) component.
700        y,
701        /// The Pb (chroma-blue/yellow) component.
702        pb,
703        /// The Pr (chroma-red/green) component.
704        pr,
705    }
706
707    /// A color in the Y'PbPr color space. See discussion of the difference between YCbCr,
708    /// YUV, YPbPr, and Y'PbPr in the [YCbCr Wikipedia article](https://en.wikipedia.org/wiki/YCbCr)
709    ///
710    /// Since Y'PbPr is a relative color space, it is required to know the RGB space which
711    /// it was transformed from. We define this as being converted from the EncodedSrgb color space.
712    YPrimePbPr<f32, 3> {
713        /// The Y' (luma) component.
714        y,
715        /// The Pb (chroma-blue/yellow) component.
716        pb,
717        /// The Pr (chroma-red/green) component.
718        pr,
719    }
720
721    /// A color in the YUV color space. See discussion of the difference between YCbCr, YUV, and
722    /// YPbPr in [YCbCr Wikipedia article](https://en.wikipedia.org/wiki/YCbCr)
723    Yuv<f32, 3> {
724        /// The Y (luminance) component.
725        y,
726        /// The U (chroma-blue/yellow) component.
727        u,
728        /// The V (chroma-red/green) component.
729        v,
730    }
731
732    /// A color in the YCxCz (also called YyCxCz) color space, originally defined in "Optimized
733    /// universal color palette design for error diffusion" by B. W. Kolpatzik and C. A. Bouman.
734    /// Can be thought of as a "linear CIE Lab".
735    YCxCz<f32, 3> {
736        /// The Yy (luminance) component.
737        y,
738        /// The Cx (chroma difference blue/yellow) component
739        cx,
740        /// The Cz (chroma difference red/green) component
741        cz,
742    }
743}