1
0
Fork 0
forked from wry/wry
wry/src/cmm/cmm_luminance.rs
2025-11-28 15:31:33 +01:00

87 lines
2.1 KiB
Rust

use crate::{
cmm::cmm_transform::{ColorMatrix, Xyz},
utils::ordered_float::F64,
};
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct Luminance {
pub min: F64,
pub max: F64,
pub white: F64,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct TargetLuminance {
pub min: F64,
pub max: F64,
}
impl Luminance {
pub const SRGB: Self = Self {
min: F64(0.2),
max: F64(80.0),
white: F64(80.0),
};
pub const BT1886: Self = Self {
min: F64(0.01),
max: F64(100.0),
white: F64(100.0),
};
pub const ST2084_PQ: Self = Self {
min: F64(0.0),
max: F64(10000.0),
white: F64(203.0),
};
#[expect(dead_code)]
pub const HLG: Self = Self {
min: F64(0.005),
max: F64(1000.0),
white: F64(203.0),
};
pub const WINDOWS_SCRGB: Self = Self {
min: Self::ST2084_PQ.min,
max: Self::ST2084_PQ.max,
// This causes the white balance formula (with target ST2084_PQ) to simplify to
// `Y * 80 / 10000`, meaning that sRGB pure white maps to a luminance of
// 80 cd/m^2.
white: F64(Self::ST2084_PQ.white.0 / 80.0 * Self::ST2084_PQ.max.0),
};
}
impl Luminance {
pub fn to_target(&self) -> TargetLuminance {
TargetLuminance {
min: self.min,
max: self.max,
}
}
}
impl Default for Luminance {
fn default() -> Self {
Self::SRGB
}
}
#[expect(non_snake_case)]
pub fn white_balance(from: &Luminance, to: &Luminance, w_to: (F64, F64)) -> ColorMatrix<Xyz, Xyz> {
let a = ((from.max - from.min) / (to.max - to.min) * (to.white - to.min)
/ (from.white - from.min))
.0;
// let d = ((from.min - to.min) / (to.max - to.min)).0.max(0.0);
let d = 0.0;
let s = a - d;
let (F64(x_to), F64(y_to)) = w_to;
let X_to = x_to / y_to;
let Y_to = 1.0;
let Z_to = (1.0 - x_to - y_to) / y_to;
ColorMatrix::new([
[s, 0.0, 0.0, d * X_to],
[0.0, s, 0.0, d * Y_to],
[0.0, 0.0, s, d * Z_to],
])
}