ff_format/color.rs
1//! Color space and related type definitions.
2//!
3//! This module provides enums for color-related metadata commonly found
4//! in video streams, including color space, color range, and color primaries.
5//!
6//! # Examples
7//!
8//! ```
9//! use ff_format::color::{ColorSpace, ColorRange, ColorPrimaries};
10//!
11//! // HD video typically uses BT.709
12//! let space = ColorSpace::Bt709;
13//! let range = ColorRange::Limited;
14//! let primaries = ColorPrimaries::Bt709;
15//!
16//! assert!(space.is_hd());
17//! assert!(!range.is_full());
18//! ```
19
20use std::fmt;
21
22/// Color space (matrix coefficients) for YUV to RGB conversion.
23///
24/// The color space defines how YUV values are converted to RGB and vice versa.
25/// Different standards use different matrix coefficients for this conversion.
26///
27/// # Common Usage
28///
29/// - **BT.709**: HD content (720p, 1080p)
30/// - **BT.470BG / SMPTE-170M**: SD content (576i PAL / 480i NTSC)
31/// - **BT.2020 NCL / CL**: UHD/HDR content (4K, 8K)
32/// - **RGB**: Identity matrix for RGB/GBR content
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
34#[non_exhaustive]
35pub enum ColorSpace {
36 /// ITU-R BT.709 — HD television matrix (most common for HD video)
37 #[default]
38 Bt709,
39 /// ITU-R BT.470BG — BT.601 625-line (PAL/SECAM SD) matrix
40 Bt470bg,
41 /// SMPTE 170M — BT.601 525-line (NTSC SD) matrix
42 Smpte170m,
43 /// ITU-R BT.2020 non-constant luminance — UHD/HDR matrix
44 Bt2020Ncl,
45 /// ITU-R BT.2020 constant luminance — UHD/HDR matrix
46 Bt2020Cl,
47 /// Identity / RGB (GBR planar) — no YUV matrix
48 Rgb,
49 /// FCC — legacy NTSC 1953 matrix
50 Fcc,
51 /// SMPTE 240M — legacy HD matrix
52 Smpte240m,
53 /// `YCgCo` — reversible `YCgCo` matrix
54 Ycgco,
55 /// Color space matrix is not specified or unknown
56 Unknown,
57}
58
59impl ColorSpace {
60 /// Returns the name of the color space as a human-readable string.
61 ///
62 /// # Examples
63 ///
64 /// ```
65 /// use ff_format::color::ColorSpace;
66 ///
67 /// assert_eq!(ColorSpace::Bt709.name(), "bt709");
68 /// assert_eq!(ColorSpace::Bt2020Ncl.name(), "bt2020ncl");
69 /// ```
70 #[must_use]
71 pub const fn name(&self) -> &'static str {
72 match self {
73 Self::Bt709 => "bt709",
74 Self::Bt470bg => "bt470bg",
75 Self::Smpte170m => "smpte170m",
76 Self::Bt2020Ncl => "bt2020ncl",
77 Self::Bt2020Cl => "bt2020cl",
78 Self::Rgb => "rgb",
79 Self::Fcc => "fcc",
80 Self::Smpte240m => "smpte240m",
81 Self::Ycgco => "ycgco",
82 Self::Unknown => "unknown",
83 }
84 }
85
86 /// Returns `true` if this is the HD matrix (BT.709).
87 ///
88 /// # Examples
89 ///
90 /// ```
91 /// use ff_format::color::ColorSpace;
92 ///
93 /// assert!(ColorSpace::Bt709.is_hd());
94 /// assert!(!ColorSpace::Smpte170m.is_hd());
95 /// ```
96 #[must_use]
97 pub const fn is_hd(&self) -> bool {
98 matches!(self, Self::Bt709)
99 }
100
101 /// Returns `true` if this is an SD matrix (BT.601: BT.470BG or SMPTE-170M).
102 ///
103 /// # Examples
104 ///
105 /// ```
106 /// use ff_format::color::ColorSpace;
107 ///
108 /// assert!(ColorSpace::Smpte170m.is_sd());
109 /// assert!(!ColorSpace::Bt709.is_sd());
110 /// ```
111 #[must_use]
112 pub const fn is_sd(&self) -> bool {
113 matches!(self, Self::Bt470bg | Self::Smpte170m)
114 }
115
116 /// Returns `true` if this is a UHD/HDR matrix (BT.2020 NCL or CL).
117 ///
118 /// # Examples
119 ///
120 /// ```
121 /// use ff_format::color::ColorSpace;
122 ///
123 /// assert!(ColorSpace::Bt2020Ncl.is_uhd());
124 /// assert!(!ColorSpace::Bt709.is_uhd());
125 /// ```
126 #[must_use]
127 pub const fn is_uhd(&self) -> bool {
128 matches!(self, Self::Bt2020Ncl | Self::Bt2020Cl)
129 }
130
131 /// Returns `true` if the color space is unknown.
132 ///
133 /// # Examples
134 ///
135 /// ```
136 /// use ff_format::color::ColorSpace;
137 ///
138 /// assert!(ColorSpace::Unknown.is_unknown());
139 /// assert!(!ColorSpace::Bt709.is_unknown());
140 /// ```
141 #[must_use]
142 pub const fn is_unknown(&self) -> bool {
143 matches!(self, Self::Unknown)
144 }
145}
146
147impl fmt::Display for ColorSpace {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 write!(f, "{}", self.name())
150 }
151}
152
153/// Color range defining the valid range of color values.
154///
155/// Video typically uses "limited" range where black is at level 16 and white
156/// at level 235 (for 8-bit). Computer graphics typically use "full" range
157/// where black is 0 and white is 255.
158///
159/// # Common Usage
160///
161/// - **Limited**: Broadcast video, Blu-ray, streaming services
162/// - **Full**: Computer graphics, screenshots, game capture
163#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
164#[non_exhaustive]
165pub enum ColorRange {
166 /// Limited/TV range (16-235 for Y, 16-240 for UV in 8-bit)
167 #[default]
168 Limited,
169 /// Full/PC range (0-255 for all components in 8-bit)
170 Full,
171 /// Color range is not specified or unknown
172 Unknown,
173}
174
175impl ColorRange {
176 /// Returns the name of the color range as a human-readable string.
177 ///
178 /// # Examples
179 ///
180 /// ```
181 /// use ff_format::color::ColorRange;
182 ///
183 /// assert_eq!(ColorRange::Limited.name(), "limited");
184 /// assert_eq!(ColorRange::Full.name(), "full");
185 /// ```
186 #[must_use]
187 pub const fn name(&self) -> &'static str {
188 match self {
189 Self::Limited => "limited",
190 Self::Full => "full",
191 Self::Unknown => "unknown",
192 }
193 }
194
195 /// Returns `true` if this is full (PC) range.
196 ///
197 /// # Examples
198 ///
199 /// ```
200 /// use ff_format::color::ColorRange;
201 ///
202 /// assert!(ColorRange::Full.is_full());
203 /// assert!(!ColorRange::Limited.is_full());
204 /// ```
205 #[must_use]
206 pub const fn is_full(&self) -> bool {
207 matches!(self, Self::Full)
208 }
209
210 /// Returns `true` if this is limited (TV) range.
211 ///
212 /// # Examples
213 ///
214 /// ```
215 /// use ff_format::color::ColorRange;
216 ///
217 /// assert!(ColorRange::Limited.is_limited());
218 /// assert!(!ColorRange::Full.is_limited());
219 /// ```
220 #[must_use]
221 pub const fn is_limited(&self) -> bool {
222 matches!(self, Self::Limited)
223 }
224
225 /// Returns `true` if the color range is unknown.
226 ///
227 /// # Examples
228 ///
229 /// ```
230 /// use ff_format::color::ColorRange;
231 ///
232 /// assert!(ColorRange::Unknown.is_unknown());
233 /// assert!(!ColorRange::Limited.is_unknown());
234 /// ```
235 #[must_use]
236 pub const fn is_unknown(&self) -> bool {
237 matches!(self, Self::Unknown)
238 }
239
240 /// Returns the minimum value for luma (Y) in 8-bit.
241 ///
242 /// # Examples
243 ///
244 /// ```
245 /// use ff_format::color::ColorRange;
246 ///
247 /// assert_eq!(ColorRange::Limited.luma_min_8bit(), 16);
248 /// assert_eq!(ColorRange::Full.luma_min_8bit(), 0);
249 /// ```
250 #[must_use]
251 pub const fn luma_min_8bit(&self) -> u8 {
252 match self {
253 Self::Limited => 16,
254 Self::Full | Self::Unknown => 0,
255 }
256 }
257
258 /// Returns the maximum value for luma (Y) in 8-bit.
259 ///
260 /// # Examples
261 ///
262 /// ```
263 /// use ff_format::color::ColorRange;
264 ///
265 /// assert_eq!(ColorRange::Limited.luma_max_8bit(), 235);
266 /// assert_eq!(ColorRange::Full.luma_max_8bit(), 255);
267 /// ```
268 #[must_use]
269 pub const fn luma_max_8bit(&self) -> u8 {
270 match self {
271 Self::Limited => 235,
272 Self::Full | Self::Unknown => 255,
273 }
274 }
275}
276
277impl fmt::Display for ColorRange {
278 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
279 write!(f, "{}", self.name())
280 }
281}
282
283/// Color primaries defining the color gamut (the range of colors that can be represented).
284///
285/// Different standards define different primary colors (red, green, blue points)
286/// which determine the overall range of colors that can be displayed.
287///
288/// # Common Usage
289///
290/// - **BT.709**: HD content, same as sRGB primaries
291/// - **BT.470BG / SMPTE-170M**: SD content (PAL/SECAM / NTSC)
292/// - **DCI-P3 / Display P3**: digital cinema and wide-gamut displays
293/// - **BT.2020**: Wide color gamut for UHD/HDR
294#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
295#[non_exhaustive]
296pub enum ColorPrimaries {
297 /// ITU-R BT.709 primaries (same as sRGB, most common)
298 #[default]
299 Bt709,
300 /// ITU-R BT.470BG primaries (PAL/SECAM SD video)
301 Bt470bg,
302 /// SMPTE 170M primaries (NTSC SD video)
303 Smpte170m,
304 /// SMPTE 240M primaries (legacy HD)
305 Smpte240m,
306 /// Generic film primaries (Illuminant C)
307 Film,
308 /// DCI-P3 primaries (SMPTE RP 431-2, digital cinema)
309 DciP3,
310 /// Display P3 primaries (SMPTE EG 432-1, wide-gamut displays)
311 DisplayP3,
312 /// ITU-R BT.2020 primaries (wide color gamut for UHD/HDR)
313 Bt2020,
314 /// Color primaries are not specified or unknown
315 Unknown,
316}
317
318impl ColorPrimaries {
319 /// Returns the name of the color primaries as a human-readable string.
320 ///
321 /// # Examples
322 ///
323 /// ```
324 /// use ff_format::color::ColorPrimaries;
325 ///
326 /// assert_eq!(ColorPrimaries::Bt709.name(), "bt709");
327 /// assert_eq!(ColorPrimaries::Bt2020.name(), "bt2020");
328 /// ```
329 #[must_use]
330 pub const fn name(&self) -> &'static str {
331 match self {
332 Self::Bt709 => "bt709",
333 Self::Bt470bg => "bt470bg",
334 Self::Smpte170m => "smpte170m",
335 Self::Smpte240m => "smpte240m",
336 Self::Film => "film",
337 Self::DciP3 => "dci-p3",
338 Self::DisplayP3 => "display-p3",
339 Self::Bt2020 => "bt2020",
340 Self::Unknown => "unknown",
341 }
342 }
343
344 /// Returns `true` if this uses a wide color gamut (BT.2020, DCI-P3, or Display P3).
345 ///
346 /// # Examples
347 ///
348 /// ```
349 /// use ff_format::color::ColorPrimaries;
350 ///
351 /// assert!(ColorPrimaries::Bt2020.is_wide_gamut());
352 /// assert!(ColorPrimaries::DciP3.is_wide_gamut());
353 /// assert!(!ColorPrimaries::Bt709.is_wide_gamut());
354 /// ```
355 #[must_use]
356 pub const fn is_wide_gamut(&self) -> bool {
357 matches!(self, Self::Bt2020 | Self::DciP3 | Self::DisplayP3)
358 }
359
360 /// Returns `true` if the color primaries are unknown.
361 ///
362 /// # Examples
363 ///
364 /// ```
365 /// use ff_format::color::ColorPrimaries;
366 ///
367 /// assert!(ColorPrimaries::Unknown.is_unknown());
368 /// assert!(!ColorPrimaries::Bt709.is_unknown());
369 /// ```
370 #[must_use]
371 pub const fn is_unknown(&self) -> bool {
372 matches!(self, Self::Unknown)
373 }
374}
375
376impl fmt::Display for ColorPrimaries {
377 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378 write!(f, "{}", self.name())
379 }
380}
381
382/// Color transfer characteristic (opto-electronic transfer function).
383///
384/// The transfer characteristic defines how scene luminance maps to the signal
385/// level stored in the video bitstream. Different HDR and SDR standards use
386/// different curves.
387///
388/// # Common Usage
389///
390/// - **`Bt709`**: Standard SDR video (HD television)
391/// - **`Gamma22`** / **`Gamma28`**: Pure power-law gamma 2.2 / 2.8 (legacy SDR)
392/// - **`Smpte170m`** / **`Smpte240m`**: SD / legacy-HD transfer characteristics
393/// - **`Srgb`**: sRGB / IEC 61966-2-1 (computer graphics, web)
394/// - **`Pq`**: HDR10 and Dolby Vision (SMPTE ST 2084 / Perceptual Quantizer)
395/// - **`Hlg`**: Hybrid Log-Gamma — broadcast-compatible HDR (ARIB STD-B67)
396/// - **`Bt2020_10`** / **`Bt2020_12`**: BT.2020 SDR at 10/12-bit depth
397/// - **`Linear`**: Linear light, no gamma applied
398#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
399#[non_exhaustive]
400pub enum ColorTransfer {
401 /// ITU-R BT.709 transfer characteristic (standard SDR)
402 #[default]
403 Bt709,
404 /// Pure power-law gamma 2.2 (assumed display gamma)
405 Gamma22,
406 /// Pure power-law gamma 2.8 (BT.470 System B/G)
407 Gamma28,
408 /// SMPTE 170M transfer characteristic (SD)
409 Smpte170m,
410 /// SMPTE 240M transfer characteristic (legacy HD)
411 Smpte240m,
412 /// Linear light transfer (no gamma)
413 Linear,
414 /// sRGB / IEC 61966-2-1 transfer characteristic
415 Srgb,
416 /// ITU-R BT.2020 for 10-bit content
417 Bt2020_10,
418 /// ITU-R BT.2020 for 12-bit content
419 Bt2020_12,
420 /// Perceptual Quantizer / SMPTE ST 2084 — HDR10
421 Pq,
422 /// Hybrid Log-Gamma (ARIB STD-B67) — broadcast HDR
423 Hlg,
424 /// Transfer characteristic is not specified or unknown
425 Unknown,
426}
427
428impl ColorTransfer {
429 /// Returns the name of the color transfer characteristic as a string.
430 ///
431 /// # Examples
432 ///
433 /// ```
434 /// use ff_format::color::ColorTransfer;
435 ///
436 /// assert_eq!(ColorTransfer::Bt709.name(), "bt709");
437 /// assert_eq!(ColorTransfer::Hlg.name(), "hlg");
438 /// assert_eq!(ColorTransfer::Pq.name(), "pq");
439 /// ```
440 #[must_use]
441 pub const fn name(&self) -> &'static str {
442 match self {
443 Self::Bt709 => "bt709",
444 Self::Gamma22 => "gamma22",
445 Self::Gamma28 => "gamma28",
446 Self::Smpte170m => "smpte170m",
447 Self::Smpte240m => "smpte240m",
448 Self::Linear => "linear",
449 Self::Srgb => "srgb",
450 Self::Bt2020_10 => "bt2020-10",
451 Self::Bt2020_12 => "bt2020-12",
452 Self::Pq => "pq",
453 Self::Hlg => "hlg",
454 Self::Unknown => "unknown",
455 }
456 }
457
458 /// Returns `true` if this is an HDR transfer characteristic (`Pq` or `Hlg`).
459 ///
460 /// # Examples
461 ///
462 /// ```
463 /// use ff_format::color::ColorTransfer;
464 ///
465 /// assert!(ColorTransfer::Pq.is_hdr());
466 /// assert!(ColorTransfer::Hlg.is_hdr());
467 /// assert!(!ColorTransfer::Bt709.is_hdr());
468 /// ```
469 #[must_use]
470 pub const fn is_hdr(&self) -> bool {
471 matches!(self, Self::Pq | Self::Hlg)
472 }
473
474 /// Returns `true` if this is Hybrid Log-Gamma (HLG).
475 ///
476 /// # Examples
477 ///
478 /// ```
479 /// use ff_format::color::ColorTransfer;
480 ///
481 /// assert!(ColorTransfer::Hlg.is_hlg());
482 /// assert!(!ColorTransfer::Pq.is_hlg());
483 /// ```
484 #[must_use]
485 pub const fn is_hlg(&self) -> bool {
486 matches!(self, Self::Hlg)
487 }
488
489 /// Returns `true` if this is Perceptual Quantizer / SMPTE ST 2084 (PQ).
490 ///
491 /// # Examples
492 ///
493 /// ```
494 /// use ff_format::color::ColorTransfer;
495 ///
496 /// assert!(ColorTransfer::Pq.is_pq());
497 /// assert!(!ColorTransfer::Hlg.is_pq());
498 /// ```
499 #[must_use]
500 pub const fn is_pq(&self) -> bool {
501 matches!(self, Self::Pq)
502 }
503
504 /// Returns `true` if the transfer characteristic is unknown.
505 ///
506 /// # Examples
507 ///
508 /// ```
509 /// use ff_format::color::ColorTransfer;
510 ///
511 /// assert!(ColorTransfer::Unknown.is_unknown());
512 /// assert!(!ColorTransfer::Bt709.is_unknown());
513 /// ```
514 #[must_use]
515 pub const fn is_unknown(&self) -> bool {
516 matches!(self, Self::Unknown)
517 }
518}
519
520impl fmt::Display for ColorTransfer {
521 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
522 write!(f, "{}", self.name())
523 }
524}
525
526/// Alpha modes.
527///
528/// The alpha mode defines how the alpha channel should be handled when
529/// converting video frames.
530#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
531#[non_exhaustive]
532pub enum AlphaMode {
533 /// Unassociated alpha.
534 #[default]
535 Straight,
536 /// Associated alpha.
537 Premultiplied,
538 /// Alpha mode is not specified or unknown
539 Unknown,
540}
541
542impl AlphaMode {
543 /// Returns the name of the alpha mode as a string.
544 ///
545 /// # Examples
546 ///
547 /// ```
548 /// use ff_format::color::AlphaMode;
549 ///
550 /// assert_eq!(AlphaMode::Straight.name(), "straight");
551 /// assert_eq!(AlphaMode::Premultiplied.name(), "premultiplied");
552 /// ```
553 #[must_use]
554 pub const fn name(&self) -> &'static str {
555 match self {
556 Self::Straight => "straight",
557 Self::Premultiplied => "premultiplied",
558 Self::Unknown => "unknown",
559 }
560 }
561
562 /// Returns `true` if this is a straight alpha mode.
563 ///
564 /// # Examples
565 ///
566 /// ```
567 /// use ff_format::color::AlphaMode;
568 ///
569 /// assert!(AlphaMode::Straight.is_straight());
570 /// assert!(!AlphaMode::Premultiplied.is_straight());
571 /// ```
572 #[must_use]
573 pub const fn is_straight(&self) -> bool {
574 matches!(self, Self::Straight)
575 }
576
577 /// Returns `true` if this is a premultiplied alpha mode.
578 ///
579 /// # Examples
580 ///
581 /// ```
582 /// use ff_format::color::AlphaMode;
583 ///
584 /// assert!(AlphaMode::Premultiplied.is_premultiplied());
585 /// assert!(!AlphaMode::Straight.is_premultiplied());
586 /// ```
587 #[must_use]
588 pub const fn is_premultiplied(&self) -> bool {
589 matches!(self, Self::Premultiplied)
590 }
591
592 /// Returns `true` if the alpha mode is unknown.
593 ///
594 /// # Examples
595 ///
596 /// ```
597 /// use ff_format::color::AlphaMode;
598 ///
599 /// assert!(AlphaMode::Unknown.is_unknown());
600 /// assert!(!AlphaMode::Straight.is_unknown());
601 /// ```
602 #[must_use]
603 pub const fn is_unknown(&self) -> bool {
604 matches!(self, Self::Unknown)
605 }
606}
607
608impl fmt::Display for AlphaMode {
609 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
610 write!(f, "{}", self.name())
611 }
612}
613
614#[cfg(test)]
615mod tests {
616 use super::*;
617
618 mod color_space_tests {
619 use super::*;
620
621 #[test]
622 fn test_names() {
623 assert_eq!(ColorSpace::Bt709.name(), "bt709");
624 assert_eq!(ColorSpace::Bt470bg.name(), "bt470bg");
625 assert_eq!(ColorSpace::Smpte170m.name(), "smpte170m");
626 assert_eq!(ColorSpace::Bt2020Ncl.name(), "bt2020ncl");
627 assert_eq!(ColorSpace::Bt2020Cl.name(), "bt2020cl");
628 assert_eq!(ColorSpace::Rgb.name(), "rgb");
629 assert_eq!(ColorSpace::Fcc.name(), "fcc");
630 assert_eq!(ColorSpace::Smpte240m.name(), "smpte240m");
631 assert_eq!(ColorSpace::Ycgco.name(), "ycgco");
632 assert_eq!(ColorSpace::Unknown.name(), "unknown");
633 }
634
635 #[test]
636 fn test_display() {
637 assert_eq!(format!("{}", ColorSpace::Bt709), "bt709");
638 assert_eq!(format!("{}", ColorSpace::Bt2020Ncl), "bt2020ncl");
639 }
640
641 #[test]
642 fn test_default() {
643 assert_eq!(ColorSpace::default(), ColorSpace::Bt709);
644 }
645
646 #[test]
647 fn test_is_hd_sd_uhd() {
648 assert!(ColorSpace::Bt709.is_hd());
649 assert!(!ColorSpace::Bt709.is_sd());
650 assert!(!ColorSpace::Bt709.is_uhd());
651
652 assert!(!ColorSpace::Smpte170m.is_hd());
653 assert!(ColorSpace::Smpte170m.is_sd());
654 assert!(ColorSpace::Bt470bg.is_sd());
655 assert!(!ColorSpace::Smpte170m.is_uhd());
656
657 assert!(!ColorSpace::Bt2020Ncl.is_hd());
658 assert!(!ColorSpace::Bt2020Ncl.is_sd());
659 assert!(ColorSpace::Bt2020Ncl.is_uhd());
660 assert!(ColorSpace::Bt2020Cl.is_uhd());
661 }
662
663 #[test]
664 fn test_is_unknown() {
665 assert!(ColorSpace::Unknown.is_unknown());
666 assert!(!ColorSpace::Bt709.is_unknown());
667 }
668
669 #[test]
670 fn test_debug() {
671 assert_eq!(format!("{:?}", ColorSpace::Bt709), "Bt709");
672 assert_eq!(format!("{:?}", ColorSpace::Rgb), "Rgb");
673 }
674
675 #[test]
676 fn test_equality_and_hash() {
677 use std::collections::HashSet;
678
679 assert_eq!(ColorSpace::Bt709, ColorSpace::Bt709);
680 assert_ne!(ColorSpace::Bt709, ColorSpace::Smpte170m);
681
682 let mut set = HashSet::new();
683 set.insert(ColorSpace::Bt709);
684 set.insert(ColorSpace::Smpte170m);
685 assert!(set.contains(&ColorSpace::Bt709));
686 assert!(!set.contains(&ColorSpace::Bt2020Ncl));
687 }
688
689 #[test]
690 fn test_copy() {
691 let space = ColorSpace::Bt709;
692 let copied = space;
693 assert_eq!(space, copied);
694 }
695 }
696
697 mod color_range_tests {
698 use super::*;
699
700 #[test]
701 fn test_names() {
702 assert_eq!(ColorRange::Limited.name(), "limited");
703 assert_eq!(ColorRange::Full.name(), "full");
704 assert_eq!(ColorRange::Unknown.name(), "unknown");
705 }
706
707 #[test]
708 fn test_display() {
709 assert_eq!(format!("{}", ColorRange::Limited), "limited");
710 assert_eq!(format!("{}", ColorRange::Full), "full");
711 }
712
713 #[test]
714 fn test_default() {
715 assert_eq!(ColorRange::default(), ColorRange::Limited);
716 }
717
718 #[test]
719 fn test_is_full_limited() {
720 assert!(ColorRange::Full.is_full());
721 assert!(!ColorRange::Full.is_limited());
722
723 assert!(!ColorRange::Limited.is_full());
724 assert!(ColorRange::Limited.is_limited());
725 }
726
727 #[test]
728 fn test_is_unknown() {
729 assert!(ColorRange::Unknown.is_unknown());
730 assert!(!ColorRange::Limited.is_unknown());
731 }
732
733 #[test]
734 fn test_luma_values() {
735 assert_eq!(ColorRange::Limited.luma_min_8bit(), 16);
736 assert_eq!(ColorRange::Limited.luma_max_8bit(), 235);
737
738 assert_eq!(ColorRange::Full.luma_min_8bit(), 0);
739 assert_eq!(ColorRange::Full.luma_max_8bit(), 255);
740
741 assert_eq!(ColorRange::Unknown.luma_min_8bit(), 0);
742 assert_eq!(ColorRange::Unknown.luma_max_8bit(), 255);
743 }
744
745 #[test]
746 fn test_equality_and_hash() {
747 use std::collections::HashSet;
748
749 assert_eq!(ColorRange::Limited, ColorRange::Limited);
750 assert_ne!(ColorRange::Limited, ColorRange::Full);
751
752 let mut set = HashSet::new();
753 set.insert(ColorRange::Limited);
754 set.insert(ColorRange::Full);
755 assert!(set.contains(&ColorRange::Limited));
756 assert!(!set.contains(&ColorRange::Unknown));
757 }
758 }
759
760 mod color_primaries_tests {
761 use super::*;
762
763 #[test]
764 fn test_names() {
765 assert_eq!(ColorPrimaries::Bt709.name(), "bt709");
766 assert_eq!(ColorPrimaries::Bt470bg.name(), "bt470bg");
767 assert_eq!(ColorPrimaries::Smpte170m.name(), "smpte170m");
768 assert_eq!(ColorPrimaries::Smpte240m.name(), "smpte240m");
769 assert_eq!(ColorPrimaries::Film.name(), "film");
770 assert_eq!(ColorPrimaries::DciP3.name(), "dci-p3");
771 assert_eq!(ColorPrimaries::DisplayP3.name(), "display-p3");
772 assert_eq!(ColorPrimaries::Bt2020.name(), "bt2020");
773 assert_eq!(ColorPrimaries::Unknown.name(), "unknown");
774 }
775
776 #[test]
777 fn test_display() {
778 assert_eq!(format!("{}", ColorPrimaries::Bt709), "bt709");
779 assert_eq!(format!("{}", ColorPrimaries::Bt2020), "bt2020");
780 }
781
782 #[test]
783 fn test_default() {
784 assert_eq!(ColorPrimaries::default(), ColorPrimaries::Bt709);
785 }
786
787 #[test]
788 fn test_is_wide_gamut() {
789 assert!(ColorPrimaries::Bt2020.is_wide_gamut());
790 assert!(ColorPrimaries::DciP3.is_wide_gamut());
791 assert!(ColorPrimaries::DisplayP3.is_wide_gamut());
792 assert!(!ColorPrimaries::Bt709.is_wide_gamut());
793 assert!(!ColorPrimaries::Smpte170m.is_wide_gamut());
794 }
795
796 #[test]
797 fn test_is_unknown() {
798 assert!(ColorPrimaries::Unknown.is_unknown());
799 assert!(!ColorPrimaries::Bt709.is_unknown());
800 }
801
802 #[test]
803 fn test_equality_and_hash() {
804 use std::collections::HashSet;
805
806 assert_eq!(ColorPrimaries::Bt709, ColorPrimaries::Bt709);
807 assert_ne!(ColorPrimaries::Bt709, ColorPrimaries::Bt2020);
808
809 let mut set = HashSet::new();
810 set.insert(ColorPrimaries::Bt709);
811 set.insert(ColorPrimaries::Bt2020);
812 assert!(set.contains(&ColorPrimaries::Bt709));
813 assert!(!set.contains(&ColorPrimaries::Smpte170m));
814 }
815 }
816
817 mod color_transfer_tests {
818 use super::*;
819
820 #[test]
821 fn test_names() {
822 assert_eq!(ColorTransfer::Bt709.name(), "bt709");
823 assert_eq!(ColorTransfer::Gamma22.name(), "gamma22");
824 assert_eq!(ColorTransfer::Gamma28.name(), "gamma28");
825 assert_eq!(ColorTransfer::Smpte170m.name(), "smpte170m");
826 assert_eq!(ColorTransfer::Smpte240m.name(), "smpte240m");
827 assert_eq!(ColorTransfer::Linear.name(), "linear");
828 assert_eq!(ColorTransfer::Srgb.name(), "srgb");
829 assert_eq!(ColorTransfer::Bt2020_10.name(), "bt2020-10");
830 assert_eq!(ColorTransfer::Bt2020_12.name(), "bt2020-12");
831 assert_eq!(ColorTransfer::Pq.name(), "pq");
832 assert_eq!(ColorTransfer::Hlg.name(), "hlg");
833 assert_eq!(ColorTransfer::Unknown.name(), "unknown");
834 }
835
836 #[test]
837 fn test_display() {
838 assert_eq!(format!("{}", ColorTransfer::Hlg), "hlg");
839 assert_eq!(format!("{}", ColorTransfer::Pq), "pq");
840 assert_eq!(format!("{}", ColorTransfer::Bt709), "bt709");
841 }
842
843 #[test]
844 fn test_default() {
845 assert_eq!(ColorTransfer::default(), ColorTransfer::Bt709);
846 }
847
848 #[test]
849 fn hlg_is_hdr_should_return_true() {
850 assert!(ColorTransfer::Hlg.is_hdr());
851 assert!(ColorTransfer::Hlg.is_hlg());
852 assert!(!ColorTransfer::Hlg.is_pq());
853 }
854
855 #[test]
856 fn pq_is_hdr_should_return_true() {
857 assert!(ColorTransfer::Pq.is_hdr());
858 assert!(ColorTransfer::Pq.is_pq());
859 assert!(!ColorTransfer::Pq.is_hlg());
860 }
861
862 #[test]
863 fn sdr_transfers_are_not_hdr() {
864 assert!(!ColorTransfer::Bt709.is_hdr());
865 assert!(!ColorTransfer::Gamma22.is_hdr());
866 assert!(!ColorTransfer::Gamma28.is_hdr());
867 assert!(!ColorTransfer::Smpte170m.is_hdr());
868 assert!(!ColorTransfer::Smpte240m.is_hdr());
869 assert!(!ColorTransfer::Srgb.is_hdr());
870 assert!(!ColorTransfer::Bt2020_10.is_hdr());
871 assert!(!ColorTransfer::Bt2020_12.is_hdr());
872 assert!(!ColorTransfer::Linear.is_hdr());
873 }
874
875 #[test]
876 fn is_unknown_should_only_match_unknown() {
877 assert!(ColorTransfer::Unknown.is_unknown());
878 assert!(!ColorTransfer::Bt709.is_unknown());
879 assert!(!ColorTransfer::Hlg.is_unknown());
880 }
881
882 #[test]
883 fn test_equality_and_hash() {
884 use std::collections::HashSet;
885
886 assert_eq!(ColorTransfer::Hlg, ColorTransfer::Hlg);
887 assert_ne!(ColorTransfer::Hlg, ColorTransfer::Pq);
888
889 let mut set = HashSet::new();
890 set.insert(ColorTransfer::Hlg);
891 set.insert(ColorTransfer::Pq);
892 assert!(set.contains(&ColorTransfer::Hlg));
893 assert!(!set.contains(&ColorTransfer::Bt709));
894 }
895 }
896
897 mod alpha_mode_tests {
898 use super::*;
899
900 #[test]
901 fn test_names() {
902 assert_eq!(AlphaMode::Straight.name(), "straight");
903 assert_eq!(AlphaMode::Premultiplied.name(), "premultiplied");
904 assert_eq!(AlphaMode::Unknown.name(), "unknown");
905 }
906
907 #[test]
908 fn test_display() {
909 assert_eq!(format!("{}", AlphaMode::Straight), "straight");
910 assert_eq!(format!("{}", AlphaMode::Premultiplied), "premultiplied");
911 assert_eq!(format!("{}", AlphaMode::Unknown), "unknown");
912 }
913
914 #[test]
915 fn test_default() {
916 assert_eq!(AlphaMode::default(), AlphaMode::Straight);
917 }
918
919 #[test]
920 fn is_straight_should_only_match_straight() {
921 assert!(AlphaMode::Straight.is_straight());
922 assert!(!AlphaMode::Premultiplied.is_straight());
923 assert!(!AlphaMode::Unknown.is_straight());
924 }
925
926 #[test]
927 fn is_premultiplied_should_only_match_premultiplied() {
928 assert!(AlphaMode::Premultiplied.is_premultiplied());
929 assert!(!AlphaMode::Straight.is_premultiplied());
930 assert!(!AlphaMode::Unknown.is_premultiplied());
931 }
932
933 #[test]
934 fn is_unknown_should_only_match_unknown() {
935 assert!(AlphaMode::Unknown.is_unknown());
936 assert!(!AlphaMode::Straight.is_unknown());
937 assert!(!AlphaMode::Premultiplied.is_unknown());
938 }
939
940 #[test]
941 fn test_equality_and_hash() {
942 use std::collections::HashSet;
943
944 assert_eq!(AlphaMode::Straight, AlphaMode::Straight);
945 assert_ne!(AlphaMode::Premultiplied, AlphaMode::Straight);
946
947 let mut set = HashSet::new();
948 set.insert(AlphaMode::Straight);
949 assert!(set.contains(&AlphaMode::Straight));
950 assert!(!set.contains(&AlphaMode::Premultiplied));
951 }
952 }
953}