#![allow(dead_code)]
use std::f32::consts::E;
pub const DCI_P3_WHITE_XY: [f32; 2] = [0.314, 0.351];
pub const DCI_P3_GAMMA: f32 = 2.6;
#[derive(Debug, Clone, Copy)]
pub struct DciP3Primaries {
pub red: [f32; 2],
pub green: [f32; 2],
pub blue: [f32; 2],
}
impl Default for DciP3Primaries {
fn default() -> Self {
Self {
red: [0.680, 0.320],
green: [0.265, 0.690],
blue: [0.150, 0.060],
}
}
}
#[derive(Debug, Clone)]
pub struct DciP3Config {
pub primaries: DciP3Primaries,
pub white_point: [f32; 2],
pub gamma: f32,
pub peak_luminance_nits: f32,
}
impl Default for DciP3Config {
fn default() -> Self {
Self {
primaries: DciP3Primaries::default(),
white_point: DCI_P3_WHITE_XY,
gamma: DCI_P3_GAMMA,
peak_luminance_nits: 48.0,
}
}
}
pub fn dci_p3_eotf(encoded: f32) -> f32 {
encoded.clamp(0.0, 1.0).powf(DCI_P3_GAMMA)
}
pub fn dci_p3_oetf(linear: f32) -> f32 {
linear.clamp(0.0, 1.0).powf(1.0 / DCI_P3_GAMMA)
}
pub fn export_dci_p3_config(cfg: &DciP3Config) -> String {
format!(
"DCI-P3\nGamma: {:.1}\nPeak: {:.0} nits\nWhite: ({:.3}, {:.3})\n",
cfg.gamma, cfg.peak_luminance_nits, cfg.white_point[0], cfg.white_point[1],
)
}
pub fn validate_dci_p3_config(cfg: &DciP3Config) -> bool {
cfg.peak_luminance_nits > 0.0 && cfg.gamma > 0.0
}
pub fn dci_p3_to_linear(rgb: [f32; 3]) -> [f32; 3] {
[
dci_p3_eotf(rgb[0]),
dci_p3_eotf(rgb[1]),
dci_p3_eotf(rgb[2]),
]
}
pub fn log_luminance(linear: f32) -> f32 {
linear.max(f32::EPSILON).ln() / E.ln()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_eotf_zero() {
assert_eq!(dci_p3_eotf(0.0), 0.0);
}
#[test]
fn test_eotf_one() {
assert!((dci_p3_eotf(1.0) - 1.0).abs() < f32::EPSILON);
}
#[test]
fn test_oetf_zero() {
assert_eq!(dci_p3_oetf(0.0), 0.0);
}
#[test]
fn test_oetf_one() {
assert!((dci_p3_oetf(1.0) - 1.0).abs() < f32::EPSILON);
}
#[test]
fn test_roundtrip() {
let v = 0.5f32;
let enc = dci_p3_oetf(v);
let dec = dci_p3_eotf(enc);
assert!((dec - v).abs() < 0.001);
}
#[test]
fn test_export_contains_dci() {
let cfg = DciP3Config::default();
assert!(export_dci_p3_config(&cfg).contains("DCI-P3"));
}
#[test]
fn test_validate_default() {
assert!(validate_dci_p3_config(&DciP3Config::default()));
}
#[test]
fn test_validate_zero_peak_fails() {
let cfg = DciP3Config {
peak_luminance_nits: 0.0,
..Default::default()
};
assert!(!validate_dci_p3_config(&cfg));
}
#[test]
fn test_dci_p3_to_linear_length() {
assert_eq!(dci_p3_to_linear([0.5, 0.5, 0.5]).len(), 3);
}
#[test]
fn test_log_luminance_one() {
assert!(log_luminance(1.0).abs() < 0.001);
}
}