use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum ColorSpace {
#[default]
Bt709,
Bt601,
Bt2020,
DciP3,
Srgb,
Unknown,
}
impl ColorSpace {
#[must_use]
pub const fn name(&self) -> &'static str {
match self {
Self::Bt709 => "bt709",
Self::Bt601 => "bt601",
Self::Bt2020 => "bt2020",
Self::DciP3 => "dcip3",
Self::Srgb => "srgb",
Self::Unknown => "unknown",
}
}
#[must_use]
pub const fn is_hd(&self) -> bool {
matches!(self, Self::Bt709)
}
#[must_use]
pub const fn is_sd(&self) -> bool {
matches!(self, Self::Bt601)
}
#[must_use]
pub const fn is_uhd(&self) -> bool {
matches!(self, Self::Bt2020)
}
#[must_use]
pub const fn is_cinema(&self) -> bool {
matches!(self, Self::DciP3)
}
#[must_use]
pub const fn is_unknown(&self) -> bool {
matches!(self, Self::Unknown)
}
}
impl fmt::Display for ColorSpace {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum ColorRange {
#[default]
Limited,
Full,
Unknown,
}
impl ColorRange {
#[must_use]
pub const fn name(&self) -> &'static str {
match self {
Self::Limited => "limited",
Self::Full => "full",
Self::Unknown => "unknown",
}
}
#[must_use]
pub const fn is_full(&self) -> bool {
matches!(self, Self::Full)
}
#[must_use]
pub const fn is_limited(&self) -> bool {
matches!(self, Self::Limited)
}
#[must_use]
pub const fn is_unknown(&self) -> bool {
matches!(self, Self::Unknown)
}
#[must_use]
pub const fn luma_min_8bit(&self) -> u8 {
match self {
Self::Limited => 16,
Self::Full | Self::Unknown => 0,
}
}
#[must_use]
pub const fn luma_max_8bit(&self) -> u8 {
match self {
Self::Limited => 235,
Self::Full | Self::Unknown => 255,
}
}
}
impl fmt::Display for ColorRange {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum ColorPrimaries {
#[default]
Bt709,
Bt601,
Bt2020,
Unknown,
}
impl ColorPrimaries {
#[must_use]
pub const fn name(&self) -> &'static str {
match self {
Self::Bt709 => "bt709",
Self::Bt601 => "bt601",
Self::Bt2020 => "bt2020",
Self::Unknown => "unknown",
}
}
#[must_use]
pub const fn is_wide_gamut(&self) -> bool {
matches!(self, Self::Bt2020)
}
#[must_use]
pub const fn is_unknown(&self) -> bool {
matches!(self, Self::Unknown)
}
}
impl fmt::Display for ColorPrimaries {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum ColorTransfer {
#[default]
Bt709,
Bt2020_10,
Bt2020_12,
Hlg,
Pq,
Linear,
Unknown,
}
impl ColorTransfer {
#[must_use]
pub const fn name(&self) -> &'static str {
match self {
Self::Bt709 => "bt709",
Self::Bt2020_10 => "bt2020-10",
Self::Bt2020_12 => "bt2020-12",
Self::Hlg => "hlg",
Self::Pq => "pq",
Self::Linear => "linear",
Self::Unknown => "unknown",
}
}
#[must_use]
pub const fn is_hdr(&self) -> bool {
matches!(self, Self::Pq | Self::Hlg)
}
#[must_use]
pub const fn is_hlg(&self) -> bool {
matches!(self, Self::Hlg)
}
#[must_use]
pub const fn is_pq(&self) -> bool {
matches!(self, Self::Pq)
}
#[must_use]
pub const fn is_unknown(&self) -> bool {
matches!(self, Self::Unknown)
}
}
impl fmt::Display for ColorTransfer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name())
}
}
#[cfg(test)]
mod tests {
use super::*;
mod color_space_tests {
use super::*;
#[test]
fn test_names() {
assert_eq!(ColorSpace::Bt709.name(), "bt709");
assert_eq!(ColorSpace::Bt601.name(), "bt601");
assert_eq!(ColorSpace::Bt2020.name(), "bt2020");
assert_eq!(ColorSpace::DciP3.name(), "dcip3");
assert_eq!(ColorSpace::Srgb.name(), "srgb");
assert_eq!(ColorSpace::Unknown.name(), "unknown");
}
#[test]
fn test_display() {
assert_eq!(format!("{}", ColorSpace::Bt709), "bt709");
assert_eq!(format!("{}", ColorSpace::Bt2020), "bt2020");
}
#[test]
fn test_default() {
assert_eq!(ColorSpace::default(), ColorSpace::Bt709);
}
#[test]
fn test_is_hd_sd_uhd() {
assert!(ColorSpace::Bt709.is_hd());
assert!(!ColorSpace::Bt709.is_sd());
assert!(!ColorSpace::Bt709.is_uhd());
assert!(!ColorSpace::Bt601.is_hd());
assert!(ColorSpace::Bt601.is_sd());
assert!(!ColorSpace::Bt601.is_uhd());
assert!(!ColorSpace::Bt2020.is_hd());
assert!(!ColorSpace::Bt2020.is_sd());
assert!(ColorSpace::Bt2020.is_uhd());
}
#[test]
fn dcip3_is_cinema_should_return_true() {
assert!(ColorSpace::DciP3.is_cinema());
assert!(!ColorSpace::Bt709.is_cinema());
assert!(!ColorSpace::Bt2020.is_cinema());
}
#[test]
fn test_is_unknown() {
assert!(ColorSpace::Unknown.is_unknown());
assert!(!ColorSpace::Bt709.is_unknown());
}
#[test]
fn test_debug() {
assert_eq!(format!("{:?}", ColorSpace::Bt709), "Bt709");
assert_eq!(format!("{:?}", ColorSpace::Srgb), "Srgb");
}
#[test]
fn test_equality_and_hash() {
use std::collections::HashSet;
assert_eq!(ColorSpace::Bt709, ColorSpace::Bt709);
assert_ne!(ColorSpace::Bt709, ColorSpace::Bt601);
let mut set = HashSet::new();
set.insert(ColorSpace::Bt709);
set.insert(ColorSpace::Bt601);
assert!(set.contains(&ColorSpace::Bt709));
assert!(!set.contains(&ColorSpace::Bt2020));
}
#[test]
fn test_copy() {
let space = ColorSpace::Bt709;
let copied = space;
assert_eq!(space, copied);
}
}
mod color_range_tests {
use super::*;
#[test]
fn test_names() {
assert_eq!(ColorRange::Limited.name(), "limited");
assert_eq!(ColorRange::Full.name(), "full");
assert_eq!(ColorRange::Unknown.name(), "unknown");
}
#[test]
fn test_display() {
assert_eq!(format!("{}", ColorRange::Limited), "limited");
assert_eq!(format!("{}", ColorRange::Full), "full");
}
#[test]
fn test_default() {
assert_eq!(ColorRange::default(), ColorRange::Limited);
}
#[test]
fn test_is_full_limited() {
assert!(ColorRange::Full.is_full());
assert!(!ColorRange::Full.is_limited());
assert!(!ColorRange::Limited.is_full());
assert!(ColorRange::Limited.is_limited());
}
#[test]
fn test_is_unknown() {
assert!(ColorRange::Unknown.is_unknown());
assert!(!ColorRange::Limited.is_unknown());
}
#[test]
fn test_luma_values() {
assert_eq!(ColorRange::Limited.luma_min_8bit(), 16);
assert_eq!(ColorRange::Limited.luma_max_8bit(), 235);
assert_eq!(ColorRange::Full.luma_min_8bit(), 0);
assert_eq!(ColorRange::Full.luma_max_8bit(), 255);
assert_eq!(ColorRange::Unknown.luma_min_8bit(), 0);
assert_eq!(ColorRange::Unknown.luma_max_8bit(), 255);
}
#[test]
fn test_equality_and_hash() {
use std::collections::HashSet;
assert_eq!(ColorRange::Limited, ColorRange::Limited);
assert_ne!(ColorRange::Limited, ColorRange::Full);
let mut set = HashSet::new();
set.insert(ColorRange::Limited);
set.insert(ColorRange::Full);
assert!(set.contains(&ColorRange::Limited));
assert!(!set.contains(&ColorRange::Unknown));
}
}
mod color_primaries_tests {
use super::*;
#[test]
fn test_names() {
assert_eq!(ColorPrimaries::Bt709.name(), "bt709");
assert_eq!(ColorPrimaries::Bt601.name(), "bt601");
assert_eq!(ColorPrimaries::Bt2020.name(), "bt2020");
assert_eq!(ColorPrimaries::Unknown.name(), "unknown");
}
#[test]
fn test_display() {
assert_eq!(format!("{}", ColorPrimaries::Bt709), "bt709");
assert_eq!(format!("{}", ColorPrimaries::Bt2020), "bt2020");
}
#[test]
fn test_default() {
assert_eq!(ColorPrimaries::default(), ColorPrimaries::Bt709);
}
#[test]
fn test_is_wide_gamut() {
assert!(ColorPrimaries::Bt2020.is_wide_gamut());
assert!(!ColorPrimaries::Bt709.is_wide_gamut());
assert!(!ColorPrimaries::Bt601.is_wide_gamut());
}
#[test]
fn test_is_unknown() {
assert!(ColorPrimaries::Unknown.is_unknown());
assert!(!ColorPrimaries::Bt709.is_unknown());
}
#[test]
fn test_equality_and_hash() {
use std::collections::HashSet;
assert_eq!(ColorPrimaries::Bt709, ColorPrimaries::Bt709);
assert_ne!(ColorPrimaries::Bt709, ColorPrimaries::Bt2020);
let mut set = HashSet::new();
set.insert(ColorPrimaries::Bt709);
set.insert(ColorPrimaries::Bt2020);
assert!(set.contains(&ColorPrimaries::Bt709));
assert!(!set.contains(&ColorPrimaries::Bt601));
}
}
mod color_transfer_tests {
use super::*;
#[test]
fn test_names() {
assert_eq!(ColorTransfer::Bt709.name(), "bt709");
assert_eq!(ColorTransfer::Bt2020_10.name(), "bt2020-10");
assert_eq!(ColorTransfer::Bt2020_12.name(), "bt2020-12");
assert_eq!(ColorTransfer::Hlg.name(), "hlg");
assert_eq!(ColorTransfer::Pq.name(), "pq");
assert_eq!(ColorTransfer::Linear.name(), "linear");
assert_eq!(ColorTransfer::Unknown.name(), "unknown");
}
#[test]
fn test_display() {
assert_eq!(format!("{}", ColorTransfer::Hlg), "hlg");
assert_eq!(format!("{}", ColorTransfer::Pq), "pq");
assert_eq!(format!("{}", ColorTransfer::Bt709), "bt709");
}
#[test]
fn test_default() {
assert_eq!(ColorTransfer::default(), ColorTransfer::Bt709);
}
#[test]
fn hlg_is_hdr_should_return_true() {
assert!(ColorTransfer::Hlg.is_hdr());
assert!(ColorTransfer::Hlg.is_hlg());
assert!(!ColorTransfer::Hlg.is_pq());
}
#[test]
fn pq_is_hdr_should_return_true() {
assert!(ColorTransfer::Pq.is_hdr());
assert!(ColorTransfer::Pq.is_pq());
assert!(!ColorTransfer::Pq.is_hlg());
}
#[test]
fn sdr_transfers_are_not_hdr() {
assert!(!ColorTransfer::Bt709.is_hdr());
assert!(!ColorTransfer::Bt2020_10.is_hdr());
assert!(!ColorTransfer::Bt2020_12.is_hdr());
assert!(!ColorTransfer::Linear.is_hdr());
}
#[test]
fn is_unknown_should_only_match_unknown() {
assert!(ColorTransfer::Unknown.is_unknown());
assert!(!ColorTransfer::Bt709.is_unknown());
assert!(!ColorTransfer::Hlg.is_unknown());
}
#[test]
fn test_equality_and_hash() {
use std::collections::HashSet;
assert_eq!(ColorTransfer::Hlg, ColorTransfer::Hlg);
assert_ne!(ColorTransfer::Hlg, ColorTransfer::Pq);
let mut set = HashSet::new();
set.insert(ColorTransfer::Hlg);
set.insert(ColorTransfer::Pq);
assert!(set.contains(&ColorTransfer::Hlg));
assert!(!set.contains(&ColorTransfer::Bt709));
}
}
}