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}