use zenpixels::ColorPrimaries;
#[derive(Debug, Clone, Copy)]
pub(crate) struct LumaWeights {
pub kr: f32,
pub kg: f32,
pub kb: f32,
pub qr: i32,
pub qg: i32,
pub qb: i32,
}
const LUMA_SUM_220: i32 = 220;
impl LumaWeights {
#[inline]
pub(crate) fn is_bt601_baseline(&self) -> bool {
self.kr == 0.299 && self.kg == 0.587 && self.kb == 0.114
}
pub fn for_primaries(p: ColorPrimaries) -> Self {
match p {
ColorPrimaries::Bt709 => bt601(),
ColorPrimaries::Bt2020 => bt2020(),
ColorPrimaries::DisplayP3 => display_p3(),
ColorPrimaries::AdobeRgb => adobe_rgb(),
_ => bt601(),
}
}
}
#[inline]
const fn bt601() -> LumaWeights {
LumaWeights {
kr: 0.299,
kg: 0.587,
kb: 0.114,
qr: 66,
qg: 129,
qb: 25,
}
}
#[inline]
const fn bt2020() -> LumaWeights {
LumaWeights {
kr: 0.2627,
kg: 0.6780,
kb: 0.0593,
qr: 58,
qg: 149,
qb: 13,
}
}
#[inline]
const fn display_p3() -> LumaWeights {
LumaWeights {
kr: 0.2289,
kg: 0.6917,
kb: 0.0793,
qr: 50,
qg: 152,
qb: 17,
}
}
#[inline]
const fn adobe_rgb() -> LumaWeights {
LumaWeights {
kr: 0.2974,
kg: 0.6273,
kb: 0.0753,
qr: 65,
qg: 138,
qb: 17,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn weights_sum_to_unity_for_every_primary_set() {
for &p in &[
ColorPrimaries::Bt709,
ColorPrimaries::Bt2020,
ColorPrimaries::DisplayP3,
ColorPrimaries::AdobeRgb,
] {
let w = LumaWeights::for_primaries(p);
let f_sum = w.kr + w.kg + w.kb;
assert!(
(f_sum - 1.0).abs() < 1e-2,
"{p:?}: f32 weights sum {f_sum}, expected ≈ 1.0"
);
let q_sum = w.qr + w.qg + w.qb;
assert!(
(q_sum - LUMA_SUM_220).abs() <= 1,
"{p:?}: fixed-point weights sum {q_sum}, expected ≈ 220 (libwebp baseline)"
);
}
}
#[test]
fn bt709_path_returns_bt601_baseline() {
let w = LumaWeights::for_primaries(ColorPrimaries::Bt709);
assert_eq!(w.kr, 0.299);
assert_eq!(w.kg, 0.587);
assert_eq!(w.kb, 0.114);
assert_eq!((w.qr, w.qg, w.qb), (66, 129, 25));
}
#[test]
fn wide_gamut_paths_diverge_from_bt601() {
for &p in &[
ColorPrimaries::Bt2020,
ColorPrimaries::DisplayP3,
ColorPrimaries::AdobeRgb,
] {
let w = LumaWeights::for_primaries(p);
assert_ne!(
(w.kr, w.kg, w.kb),
(0.299_f32, 0.587_f32, 0.114_f32),
"{p:?} should NOT use BT.601 weights"
);
}
}
}