#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum Primaries {
Reserved,
Bt709 = 1,
Unspecified = 2,
Bt470M = 4,
Bt470Bg = 5,
Bt601 = 6,
Smpte240 = 7,
GenericFilm = 8,
Bt2020 = 9,
Xyz = 10,
Smpte431 = 11,
Smpte432 = 12,
Ebu3213 = 22,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum TransferFunction {
Reserved,
Bt709 = 1,
Unspecified = 2,
Bt470M = 4,
Bt470Bg = 5,
Bt601 = 6,
Smpte240 = 7,
Linear = 8,
Log100 = 9,
Log100sqrt10 = 10,
Iec61966 = 11,
Bt1361 = 12,
Srgb = 13,
Bt202010bit = 14,
Bt202012bit = 15,
Smpte2084 = 16,
Smpte428 = 17,
Hlg = 18,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum MatrixCoefficients {
Identity = 0, Bt709 = 1, Unspecified = 2, Reserved = 3, Fcc = 4, Bt470Bg = 5, Smpte170m = 6, Smpte240m = 7, YCgCo = 8, Bt2020Ncl = 9, Bt2020Cl = 10, Smpte2085 = 11, ChromaticityDerivedNCL = 12, ChromaticityDerivedCL = 13, ICtCp = 14, IPtC2 = 15, YCgCoRe = 16, YCgCoRo = 17, }
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ColorEncoding {
pub primaries: Primaries,
pub transfer: TransferFunction,
pub matrix: MatrixCoefficients,
pub full_range: bool,
}
impl ColorEncoding {
pub const fn srgb() -> Self {
ColorEncoding {
primaries: Primaries::Bt709,
transfer: TransferFunction::Srgb,
matrix: MatrixCoefficients::Bt709,
full_range: true,
}
}
pub const fn bt709() -> Self {
ColorEncoding {
primaries: Primaries::Bt709,
transfer: TransferFunction::Bt709,
matrix: MatrixCoefficients::Bt709,
full_range: true,
}
}
pub const fn bt2020_pq() -> Self {
ColorEncoding {
primaries: Primaries::Bt2020,
transfer: TransferFunction::Smpte2084,
matrix: MatrixCoefficients::Bt2020Ncl,
full_range: true,
}
}
pub fn nclx_payload(&self) -> Vec<u8> {
let mut p = Vec::with_capacity(11);
p.extend_from_slice(b"nclx");
p.extend_from_slice(&(self.primaries as u16).to_be_bytes());
p.extend_from_slice(&(self.transfer as u16).to_be_bytes());
p.extend_from_slice(&(self.matrix as u16).to_be_bytes());
p.push(if self.full_range { 0x80 } else { 0x00 });
p
}
}
impl Default for ColorEncoding {
fn default() -> Self {
ColorEncoding::srgb()
}
}
#[derive(Clone, Debug)]
pub enum ColorMetadata {
Cicp(ColorEncoding),
Icc(Vec<u8>),
}
impl ColorMetadata {
pub fn color_encoding(&self) -> ColorEncoding {
match self {
ColorMetadata::Cicp(c) => *c,
ColorMetadata::Icc(_) => ColorEncoding::srgb(),
}
}
}
impl Default for ColorMetadata {
fn default() -> Self {
ColorMetadata::Cicp(ColorEncoding::default())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn nclx_payload_layout() {
let p = ColorEncoding::bt709().nclx_payload();
assert_eq!(&p[0..4], b"nclx");
assert_eq!(u16::from_be_bytes([p[4], p[5]]), 1); assert_eq!(u16::from_be_bytes([p[6], p[7]]), 1); assert_eq!(u16::from_be_bytes([p[8], p[9]]), 1); assert_eq!(p[10] >> 7, 1); assert_eq!(p.len(), 11);
}
#[test]
fn pq_encoding_values() {
let e = ColorEncoding::bt2020_pq();
assert_eq!(e.primaries as u8, 9);
assert_eq!(e.transfer as u8, 16);
assert_eq!(e.matrix as u8, 9);
}
}