1
0
Fork 0
forked from wry/wry

color-management-v1: implement target color volume

This commit is contained in:
Julian Orth 2025-03-11 11:41:42 +01:00
parent 5ad5c5cbcf
commit 04f280aabe
10 changed files with 249 additions and 64 deletions

View file

@ -1,13 +1,13 @@
use {
crate::{
cmm::{
cmm_luminance::{Luminance, white_balance},
cmm_luminance::{Luminance, TargetLuminance, white_balance},
cmm_manager::Shared,
cmm_primaries::{NamedPrimaries, Primaries},
cmm_transfer_function::TransferFunction,
cmm_transform::{ColorMatrix, Local, Xyz, bradford_adjustment},
},
utils::free_list::FreeList,
utils::{free_list::FreeList, ordered_float::F64},
},
std::rc::Rc,
};
@ -38,6 +38,10 @@ pub struct LinearColorDescription {
pub xyz_from_local: ColorMatrix<Xyz, Local>,
pub local_from_xyz: ColorMatrix<Local, Xyz>,
pub luminance: Luminance,
pub target_primaries: Primaries,
pub target_luminance: TargetLuminance,
pub max_cll: Option<F64>,
pub max_fall: Option<F64>,
pub(super) shared: Rc<Shared>,
}
@ -45,7 +49,6 @@ pub struct LinearColorDescription {
pub struct ColorDescription {
pub id: ColorDescriptionId,
pub linear: Rc<LinearColorDescription>,
#[expect(dead_code)]
pub named_primaries: Option<NamedPrimaries>,
pub transfer_function: TransferFunction,
pub(super) shared: Rc<Shared>,
@ -62,6 +65,26 @@ impl LinearColorDescription {
}
mat * self.xyz_from_local
}
pub fn embeds_into(&self, target: &Self) -> bool {
if self.id == target.id {
return true;
}
if self.primaries != target.primaries {
return false;
}
if self.luminance != target.luminance {
return false;
}
true
}
}
impl ColorDescription {
pub fn embeds_into(&self, target: &Self) -> bool {
self.transfer_function == target.transfer_function
&& self.linear.embeds_into(&target.linear)
}
}
impl Drop for LinearColorDescription {

View file

@ -10,6 +10,12 @@ pub struct Luminance {
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),
@ -46,6 +52,15 @@ impl Luminance {
};
}
impl Luminance {
pub fn to_target(&self) -> TargetLuminance {
TargetLuminance {
min: self.min,
max: self.max,
}
}
}
impl Default for Luminance {
fn default() -> Self {
Self::SRGB

View file

@ -5,11 +5,11 @@ use {
ColorDescription, ColorDescriptionIds, LinearColorDescription,
LinearColorDescriptionId, LinearColorDescriptionIds,
},
cmm_luminance::Luminance,
cmm_luminance::{Luminance, TargetLuminance},
cmm_primaries::{NamedPrimaries, Primaries},
cmm_transfer_function::TransferFunction,
},
utils::{copyhashmap::CopyHashMap, numcell::NumCell},
utils::{copyhashmap::CopyHashMap, numcell::NumCell, ordered_float::F64},
},
std::rc::{Rc, Weak},
};
@ -35,6 +35,10 @@ pub(super) struct Shared {
struct LinearDescriptionKey {
primaries: Primaries,
luminance: Luminance,
target_primaries: Primaries,
target_luminance: TargetLuminance,
max_cll: Option<F64>,
max_fall: Option<F64>,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
@ -60,6 +64,10 @@ impl ColorManager {
Primaries::SRGB,
Luminance::SRGB,
TransferFunction::Srgb,
Primaries::SRGB,
Luminance::SRGB.to_target(),
None,
None,
);
let srgb_linear = get_description(
&shared,
@ -70,6 +78,10 @@ impl ColorManager {
Primaries::SRGB,
Luminance::SRGB,
TransferFunction::Linear,
Primaries::SRGB,
Luminance::SRGB.to_target(),
None,
None,
);
let windows_scrgb = get_description(
&shared,
@ -80,6 +92,10 @@ impl ColorManager {
Primaries::SRGB,
Luminance::WINDOWS_SCRGB,
TransferFunction::Linear,
Primaries::BT2020,
Luminance::ST2084_PQ.to_target(),
None,
None,
);
Rc::new(Self {
linear_ids,
@ -110,6 +126,10 @@ impl ColorManager {
primaries: Primaries,
luminance: Luminance,
transfer_function: TransferFunction,
target_primaries: Primaries,
target_luminance: TargetLuminance,
max_cll: Option<F64>,
max_fall: Option<F64>,
) -> Rc<ColorDescription> {
get_description(
&self.shared,
@ -120,6 +140,10 @@ impl ColorManager {
primaries,
luminance,
transfer_function,
target_primaries,
target_luminance,
max_cll,
max_fall,
)
}
}
@ -133,6 +157,10 @@ fn get_description(
primaries: Primaries,
luminance: Luminance,
transfer_function: TransferFunction,
target_primaries: Primaries,
target_luminance: TargetLuminance,
max_cll: Option<F64>,
max_fall: Option<F64>,
) -> Rc<ColorDescription> {
macro_rules! gc {
($d:ident, $i:expr) => {
@ -147,6 +175,10 @@ fn get_description(
let key = LinearDescriptionKey {
primaries,
luminance,
target_primaries,
target_luminance,
max_cll,
max_fall,
};
if let Some(d) = linear_descriptions.get(&key) {
if let Some(d) = d.upgrade() {
@ -180,6 +212,10 @@ fn get_description(
xyz_from_local,
local_from_xyz,
luminance,
target_primaries,
target_luminance,
max_cll,
max_fall,
shared: shared.clone(),
});
linear_descriptions.set(key, Rc::downgrade(&d));

View file

@ -141,7 +141,18 @@ mod transforms {
fn check(p1: Primaries, p2: Primaries, expected: [[f64; 4]; 3]) {
let manager = ColorManager::new();
let d = |p| manager.get_description(None, p, Luminance::SRGB, TransferFunction::Linear);
let d = |p| {
manager.get_description(
None,
p,
Luminance::SRGB,
TransferFunction::Linear,
p,
Luminance::SRGB.to_target(),
None,
None,
)
};
let d1 = d(p1);
let d2 = d(p2);
let m = d1.linear.color_transform(&d2.linear);