color-management: parametrize bt1886
This commit is contained in:
parent
c37567f1cd
commit
ef1727a186
8 changed files with 189 additions and 85 deletions
|
|
@ -1,9 +1,12 @@
|
||||||
|
use crate::utils::ordered_float::F32;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum Eotf {
|
pub enum Eotf {
|
||||||
Linear,
|
Linear,
|
||||||
St2084Pq,
|
St2084Pq,
|
||||||
Bt1886,
|
Bt1886(F32),
|
||||||
Gamma22,
|
Gamma22,
|
||||||
|
Gamma24,
|
||||||
Gamma28,
|
Gamma28,
|
||||||
St240,
|
St240,
|
||||||
Log100,
|
Log100,
|
||||||
|
|
@ -34,3 +37,23 @@ impl EotfPow {
|
||||||
MUL_F32 / self.0 as f32
|
MUL_F32 / self.0 as f32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bt1886_eotf_args(c: F32) -> [f32; 4] {
|
||||||
|
let c = c.0;
|
||||||
|
let gamma = 1.0 / 2.4;
|
||||||
|
let a1 = 1.0 / (1.0 - c);
|
||||||
|
let a2 = 1.0 - c.powf(gamma);
|
||||||
|
let a3 = c.powf(gamma);
|
||||||
|
let a4 = c;
|
||||||
|
[a1, a2, a3, a4]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bt1886_inv_eotf_args(c: F32) -> [f32; 4] {
|
||||||
|
let c = c.0;
|
||||||
|
let gamma = 1.0 / 2.4;
|
||||||
|
let a1 = 1.0 / (1.0 - c.powf(gamma));
|
||||||
|
let a2 = 1.0 - c;
|
||||||
|
let a3 = c;
|
||||||
|
let a4 = c.powf(gamma);
|
||||||
|
[a1, a2, a3, a4]
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use {crate::cmm::cmm_eotf::Eotf, linearize::Linearize};
|
||||||
|
|
||||||
pub const EOTF_LINEAR: u32 = 1;
|
pub const EOTF_LINEAR: u32 = 1;
|
||||||
pub const EOTF_ST2084_PQ: u32 = 2;
|
pub const EOTF_ST2084_PQ: u32 = 2;
|
||||||
pub const EOTF_GAMMA24: u32 = 3;
|
pub const EOTF_BT1886: u32 = 3;
|
||||||
pub const EOTF_GAMMA22: u32 = 4;
|
pub const EOTF_GAMMA22: u32 = 4;
|
||||||
pub const EOTF_GAMMA28: u32 = 5;
|
pub const EOTF_GAMMA28: u32 = 5;
|
||||||
pub const EOTF_ST240: u32 = 6;
|
pub const EOTF_ST240: u32 = 6;
|
||||||
|
|
@ -10,6 +10,7 @@ pub const EOTF_LOG100: u32 = 8;
|
||||||
pub const EOTF_LOG316: u32 = 9;
|
pub const EOTF_LOG316: u32 = 9;
|
||||||
pub const EOTF_ST428: u32 = 10;
|
pub const EOTF_ST428: u32 = 10;
|
||||||
pub const EOTF_POW: u32 = 11;
|
pub const EOTF_POW: u32 = 11;
|
||||||
|
pub const EOTF_GAMMA24: u32 = 12;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Linearize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Linearize)]
|
||||||
pub enum VulkanEotf {
|
pub enum VulkanEotf {
|
||||||
|
|
@ -17,6 +18,7 @@ pub enum VulkanEotf {
|
||||||
St2084Pq,
|
St2084Pq,
|
||||||
Bt1886,
|
Bt1886,
|
||||||
Gamma22,
|
Gamma22,
|
||||||
|
Gamma24,
|
||||||
Gamma28,
|
Gamma28,
|
||||||
St240,
|
St240,
|
||||||
Log100,
|
Log100,
|
||||||
|
|
@ -45,6 +47,7 @@ impl EotfExt for Eotf {
|
||||||
St2084Pq,
|
St2084Pq,
|
||||||
Bt1886,
|
Bt1886,
|
||||||
Gamma22,
|
Gamma22,
|
||||||
|
Gamma24,
|
||||||
Gamma28,
|
Gamma28,
|
||||||
St240,
|
St240,
|
||||||
Log100,
|
Log100,
|
||||||
|
|
@ -60,8 +63,9 @@ impl VulkanEotf {
|
||||||
match self {
|
match self {
|
||||||
Self::Linear => EOTF_LINEAR,
|
Self::Linear => EOTF_LINEAR,
|
||||||
Self::St2084Pq => EOTF_ST2084_PQ,
|
Self::St2084Pq => EOTF_ST2084_PQ,
|
||||||
Self::Bt1886 => EOTF_GAMMA24,
|
Self::Bt1886 => EOTF_BT1886,
|
||||||
Self::Gamma22 => EOTF_GAMMA22,
|
Self::Gamma22 => EOTF_GAMMA22,
|
||||||
|
Self::Gamma24 => EOTF_GAMMA24,
|
||||||
Self::Gamma28 => EOTF_GAMMA28,
|
Self::Gamma28 => EOTF_GAMMA28,
|
||||||
Self::St240 => EOTF_ST240,
|
Self::St240 => EOTF_ST240,
|
||||||
Self::Log100 => EOTF_LOG100,
|
Self::Log100 => EOTF_LOG100,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use {
|
||||||
async_engine::{AsyncEngine, SpawnedFuture},
|
async_engine::{AsyncEngine, SpawnedFuture},
|
||||||
cmm::{
|
cmm::{
|
||||||
cmm_description::{ColorDescription, LinearColorDescription, LinearColorDescriptionId},
|
cmm_description::{ColorDescription, LinearColorDescription, LinearColorDescriptionId},
|
||||||
cmm_eotf::{Eotf, EotfPow},
|
cmm_eotf::{Eotf, EotfPow, bt1886_eotf_args, bt1886_inv_eotf_args},
|
||||||
cmm_transform::ColorMatrix,
|
cmm_transform::ColorMatrix,
|
||||||
},
|
},
|
||||||
cpu_worker::PendingJob,
|
cpu_worker::PendingJob,
|
||||||
|
|
@ -35,7 +35,10 @@ use {
|
||||||
io_uring::IoUring,
|
io_uring::IoUring,
|
||||||
rect::{Rect, Region},
|
rect::{Rect, Region},
|
||||||
theme::Color,
|
theme::Color,
|
||||||
utils::{copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell, stack::Stack},
|
utils::{
|
||||||
|
copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell, ordered_float::F32,
|
||||||
|
stack::Stack,
|
||||||
|
},
|
||||||
video::dmabuf::{DMA_BUF_SYNC_READ, DMA_BUF_SYNC_WRITE, dma_buf_export_sync_file},
|
video::dmabuf::{DMA_BUF_SYNC_READ, DMA_BUF_SYNC_WRITE, dma_buf_export_sync_file},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
|
|
@ -2328,7 +2331,13 @@ impl ColorTransforms {
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct EotfArgsCache {
|
struct EotfArgsCache {
|
||||||
map: AHashMap<(EotfPow, bool), EotfArg>,
|
map: AHashMap<(EotfCacheKey, bool), EotfArg>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
enum EotfCacheKey {
|
||||||
|
Pow(EotfPow),
|
||||||
|
Bt1886(F32),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EotfArg {
|
struct EotfArg {
|
||||||
|
|
@ -2343,27 +2352,43 @@ impl EotfArgsCache {
|
||||||
uniform_buffer_offset_mask: DeviceSize,
|
uniform_buffer_offset_mask: DeviceSize,
|
||||||
writer: &mut GenericBufferWriter,
|
writer: &mut GenericBufferWriter,
|
||||||
) -> Option<DeviceSize> {
|
) -> Option<DeviceSize> {
|
||||||
let Eotf::Pow(pow) = desc.eotf else {
|
let key = match desc.eotf {
|
||||||
return None;
|
Eotf::Bt1886(c) => EotfCacheKey::Bt1886(c),
|
||||||
|
Eotf::Pow(pow) => EotfCacheKey::Pow(pow),
|
||||||
|
_ => return None,
|
||||||
};
|
};
|
||||||
let ct = match self.map.entry((pow, inv)) {
|
let ct = match self.map.entry((key, inv)) {
|
||||||
Entry::Occupied(o) => o.into_mut(),
|
Entry::Occupied(o) => o.into_mut(),
|
||||||
Entry::Vacant(e) => {
|
Entry::Vacant(e) => {
|
||||||
|
#[expect(unused_assignments)]
|
||||||
|
let [mut arg1, mut arg2, mut arg3, mut arg4] = [0.0; 4];
|
||||||
if inv {
|
if inv {
|
||||||
|
match key {
|
||||||
|
EotfCacheKey::Pow(pow) => arg1 = pow.inv_eotf_f32(),
|
||||||
|
EotfCacheKey::Bt1886(c) => {
|
||||||
|
[arg1, arg2, arg3, arg4] = bt1886_inv_eotf_args(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
let data = InvEotfArgs {
|
let data = InvEotfArgs {
|
||||||
arg1: pow.inv_eotf_f32(),
|
arg1,
|
||||||
arg2: 0.0,
|
arg2,
|
||||||
arg3: 0.0,
|
arg3,
|
||||||
arg4: 0.0,
|
arg4,
|
||||||
};
|
};
|
||||||
let offset = writer.write(uniform_buffer_offset_mask, &data);
|
let offset = writer.write(uniform_buffer_offset_mask, &data);
|
||||||
e.insert(EotfArg { offset })
|
e.insert(EotfArg { offset })
|
||||||
} else {
|
} else {
|
||||||
|
match key {
|
||||||
|
EotfCacheKey::Pow(pow) => arg1 = pow.eotf_f32(),
|
||||||
|
EotfCacheKey::Bt1886(c) => {
|
||||||
|
[arg1, arg2, arg3, arg4] = bt1886_eotf_args(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
let data = EotfArgs {
|
let data = EotfArgs {
|
||||||
arg1: pow.eotf_f32(),
|
arg1,
|
||||||
arg2: 0.0,
|
arg2,
|
||||||
arg3: 0.0,
|
arg3,
|
||||||
arg4: 0.0,
|
arg4,
|
||||||
};
|
};
|
||||||
let offset = writer.write(uniform_buffer_offset_mask, &data);
|
let offset = writer.write(uniform_buffer_offset_mask, &data);
|
||||||
e.insert(EotfArg { offset })
|
e.insert(EotfArg { offset })
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#define TF_LINEAR 1
|
#define TF_LINEAR 1
|
||||||
#define TF_ST2084_PQ 2
|
#define TF_ST2084_PQ 2
|
||||||
#define TF_GAMMA24 3
|
#define TF_BT1886 3
|
||||||
#define TF_GAMMA22 4
|
#define TF_GAMMA22 4
|
||||||
#define TF_GAMMA28 5
|
#define TF_GAMMA28 5
|
||||||
#define TF_ST240 6
|
#define TF_ST240 6
|
||||||
|
|
@ -14,6 +14,25 @@
|
||||||
#define TF_LOG316 9
|
#define TF_LOG316 9
|
||||||
#define TF_ST428 10
|
#define TF_ST428 10
|
||||||
#define TF_POW 11
|
#define TF_POW 11
|
||||||
|
#define TF_GAMMA24 12
|
||||||
|
|
||||||
|
vec3 eotf_bt1886(vec3 c) {
|
||||||
|
c = clamp(c, 0.0, 1.0);
|
||||||
|
float a1 = cm_eotf_args.arg1;
|
||||||
|
float a2 = cm_eotf_args.arg2;
|
||||||
|
float a3 = cm_eotf_args.arg3;
|
||||||
|
float a4 = cm_eotf_args.arg4;
|
||||||
|
return a1 * (pow(a2 * c + a3, vec3(2.4)) - a4);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 inv_eotf_bt1886(vec3 c) {
|
||||||
|
c = clamp(c, 0.0, 1.0);
|
||||||
|
float a1 = cm_inv_eotf_args.arg1;
|
||||||
|
float a2 = cm_inv_eotf_args.arg2;
|
||||||
|
float a3 = cm_inv_eotf_args.arg3;
|
||||||
|
float a4 = cm_inv_eotf_args.arg4;
|
||||||
|
return a1 * (pow(a2 * c + a3, vec3(1.0 / 2.4)) - a4);
|
||||||
|
}
|
||||||
|
|
||||||
vec3 eotf_st2084_pq(vec3 c) {
|
vec3 eotf_st2084_pq(vec3 c) {
|
||||||
c = clamp(c, 0.0, 1.0);
|
c = clamp(c, 0.0, 1.0);
|
||||||
|
|
@ -86,8 +105,9 @@ vec3 apply_eotf(vec3 c) {
|
||||||
switch (eotf) {
|
switch (eotf) {
|
||||||
case TF_LINEAR: return c;
|
case TF_LINEAR: return c;
|
||||||
case TF_ST2084_PQ: return eotf_st2084_pq(c);
|
case TF_ST2084_PQ: return eotf_st2084_pq(c);
|
||||||
case TF_GAMMA24: return sign(c) * pow(abs(c), vec3(2.4));
|
case TF_BT1886: return eotf_bt1886(c);
|
||||||
case TF_GAMMA22: return sign(c) * pow(abs(c), vec3(2.2));
|
case TF_GAMMA22: return sign(c) * pow(abs(c), vec3(2.2));
|
||||||
|
case TF_GAMMA24: return sign(c) * pow(abs(c), vec3(2.4));
|
||||||
case TF_GAMMA28: return sign(c) * pow(abs(c), vec3(2.8));
|
case TF_GAMMA28: return sign(c) * pow(abs(c), vec3(2.8));
|
||||||
case TF_ST240: return eotf_st240(c);
|
case TF_ST240: return eotf_st240(c);
|
||||||
case TF_LOG100: return eotf_log100(c);
|
case TF_LOG100: return eotf_log100(c);
|
||||||
|
|
@ -102,8 +122,9 @@ vec3 apply_inv_eotf(vec3 c) {
|
||||||
switch (inv_eotf) {
|
switch (inv_eotf) {
|
||||||
case TF_LINEAR: return c;
|
case TF_LINEAR: return c;
|
||||||
case TF_ST2084_PQ: return inv_eotf_st2084_pq(c);
|
case TF_ST2084_PQ: return inv_eotf_st2084_pq(c);
|
||||||
case TF_GAMMA24: return sign(c) * pow(abs(c), vec3(1.0 / 2.4));
|
case TF_BT1886: return inv_eotf_bt1886(c);
|
||||||
case TF_GAMMA22: return sign(c) * pow(abs(c), vec3(1.0 / 2.2));
|
case TF_GAMMA22: return sign(c) * pow(abs(c), vec3(1.0 / 2.2));
|
||||||
|
case TF_GAMMA24: return sign(c) * pow(abs(c), vec3(1.0 / 2.4));
|
||||||
case TF_GAMMA28: return sign(c) * pow(abs(c), vec3(1.0 / 2.8));
|
case TF_GAMMA28: return sign(c) * pow(abs(c), vec3(1.0 / 2.8));
|
||||||
case TF_ST240: return inv_eotf_st240(c);
|
case TF_ST240: return inv_eotf_st240(c);
|
||||||
case TF_LOG100: return inv_eotf_log100(c);
|
case TF_LOG100: return inv_eotf_log100(c);
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ use {
|
||||||
},
|
},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
utils::ordered_float::F64,
|
utils::ordered_float::{F32, F64},
|
||||||
wire::{
|
wire::{
|
||||||
WpImageDescriptionCreatorParamsV1Id,
|
WpImageDescriptionCreatorParamsV1Id,
|
||||||
wp_image_description_creator_params_v1::{
|
wp_image_description_creator_params_v1::{
|
||||||
|
|
@ -53,14 +53,14 @@ impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreat
|
||||||
type Error = WpImageDescriptionCreatorParamsV1Error;
|
type Error = WpImageDescriptionCreatorParamsV1Error;
|
||||||
|
|
||||||
fn create(&self, req: Create, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn create(&self, req: Create, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
let Some(eotf) = self.tf.get() else {
|
let Some(mut eotf) = self.tf.get() else {
|
||||||
return Err(WpImageDescriptionCreatorParamsV1Error::TfNotSet);
|
return Err(WpImageDescriptionCreatorParamsV1Error::TfNotSet);
|
||||||
};
|
};
|
||||||
let Some((named_primaries, primaries)) = self.primaries.get() else {
|
let Some((named_primaries, primaries)) = self.primaries.get() else {
|
||||||
return Err(WpImageDescriptionCreatorParamsV1Error::PrimariesNotSet);
|
return Err(WpImageDescriptionCreatorParamsV1Error::PrimariesNotSet);
|
||||||
};
|
};
|
||||||
let default_luminance = match eotf {
|
let default_luminance = match eotf {
|
||||||
Eotf::Bt1886 => Luminance::BT1886,
|
Eotf::Bt1886 { .. } => Luminance::BT1886,
|
||||||
Eotf::St2084Pq => Luminance::ST2084_PQ,
|
Eotf::St2084Pq => Luminance::ST2084_PQ,
|
||||||
_ => Luminance::SRGB,
|
_ => Luminance::SRGB,
|
||||||
};
|
};
|
||||||
|
|
@ -71,6 +71,13 @@ impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreat
|
||||||
if luminance.max.0 <= luminance.min.0 || luminance.white.0 <= luminance.min.0 {
|
if luminance.max.0 <= luminance.min.0 || luminance.white.0 <= luminance.min.0 {
|
||||||
return Err(WpImageDescriptionCreatorParamsV1Error::MinLuminanceTooLow);
|
return Err(WpImageDescriptionCreatorParamsV1Error::MinLuminanceTooLow);
|
||||||
}
|
}
|
||||||
|
if let Eotf::Bt1886(c) = &mut eotf {
|
||||||
|
if luminance.min.0 == 0.0 {
|
||||||
|
eotf = Eotf::Gamma24;
|
||||||
|
} else {
|
||||||
|
c.0 = (luminance.min.0 / luminance.max.0) as f32;
|
||||||
|
}
|
||||||
|
}
|
||||||
let target_primaries = self.mastering_primaries.get().unwrap_or(primaries);
|
let target_primaries = self.mastering_primaries.get().unwrap_or(primaries);
|
||||||
let target_luminance = self
|
let target_luminance = self
|
||||||
.mastering_luminance
|
.mastering_luminance
|
||||||
|
|
@ -102,7 +109,7 @@ impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreat
|
||||||
|
|
||||||
fn set_tf_named(&self, req: SetTfNamed, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn set_tf_named(&self, req: SetTfNamed, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
let tf = match req.tf {
|
let tf = match req.tf {
|
||||||
TRANSFER_FUNCTION_BT1886 => Eotf::Bt1886,
|
TRANSFER_FUNCTION_BT1886 => Eotf::Bt1886(F32(0.0)),
|
||||||
TRANSFER_FUNCTION_GAMMA22 => Eotf::Gamma22,
|
TRANSFER_FUNCTION_GAMMA22 => Eotf::Gamma22,
|
||||||
TRANSFER_FUNCTION_GAMMA28 => Eotf::Gamma28,
|
TRANSFER_FUNCTION_GAMMA28 => Eotf::Gamma28,
|
||||||
TRANSFER_FUNCTION_ST240 => Eotf::St240,
|
TRANSFER_FUNCTION_ST240 => Eotf::St240,
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,12 @@ impl WpImageDescriptionInfoV1 {
|
||||||
let tf = match d.eotf {
|
let tf = match d.eotf {
|
||||||
Eotf::Linear => TRANSFER_FUNCTION_EXT_LINEAR,
|
Eotf::Linear => TRANSFER_FUNCTION_EXT_LINEAR,
|
||||||
Eotf::St2084Pq => TRANSFER_FUNCTION_ST2084_PQ,
|
Eotf::St2084Pq => TRANSFER_FUNCTION_ST2084_PQ,
|
||||||
Eotf::Bt1886 => TRANSFER_FUNCTION_BT1886,
|
Eotf::Bt1886 { .. } => TRANSFER_FUNCTION_BT1886,
|
||||||
Eotf::Gamma22 => TRANSFER_FUNCTION_GAMMA22,
|
Eotf::Gamma22 => TRANSFER_FUNCTION_GAMMA22,
|
||||||
|
Eotf::Gamma24 => {
|
||||||
|
self.send_tf_power(EotfPow::GAMMA24);
|
||||||
|
break 'tf;
|
||||||
|
}
|
||||||
Eotf::Gamma28 => TRANSFER_FUNCTION_GAMMA28,
|
Eotf::Gamma28 => TRANSFER_FUNCTION_GAMMA28,
|
||||||
Eotf::St240 => TRANSFER_FUNCTION_ST240,
|
Eotf::St240 => TRANSFER_FUNCTION_ST240,
|
||||||
Eotf::Log100 => TRANSFER_FUNCTION_LOG_100,
|
Eotf::Log100 => TRANSFER_FUNCTION_LOG_100,
|
||||||
|
|
|
||||||
19
src/theme.rs
19
src/theme.rs
|
|
@ -1,7 +1,10 @@
|
||||||
#![expect(clippy::excessive_precision)]
|
#![expect(clippy::excessive_precision)]
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{cmm::cmm_eotf::Eotf, utils::clonecell::CloneCell},
|
crate::{
|
||||||
|
cmm::cmm_eotf::{Eotf, bt1886_eotf_args, bt1886_inv_eotf_args},
|
||||||
|
utils::clonecell::CloneCell,
|
||||||
|
},
|
||||||
num_traits::Float,
|
num_traits::Float,
|
||||||
std::{cell::Cell, cmp::Ordering, ops::Mul, sync::Arc},
|
std::{cell::Cell, cmp::Ordering, ops::Mul, sync::Arc},
|
||||||
};
|
};
|
||||||
|
|
@ -114,8 +117,13 @@ impl Color {
|
||||||
match eotf {
|
match eotf {
|
||||||
Eotf::Linear => convert!(linear),
|
Eotf::Linear => convert!(linear),
|
||||||
Eotf::St2084Pq => convert!(st2084_pq),
|
Eotf::St2084Pq => convert!(st2084_pq),
|
||||||
Eotf::Bt1886 => convert!(gamma24),
|
Eotf::Bt1886(c) => {
|
||||||
|
let [a1, a2, a3, a4] = bt1886_eotf_args(c);
|
||||||
|
let bt1886 = |c: f32| -> f32 { a1 * ((a2 * c + a3).powf(2.4) - a4) };
|
||||||
|
convert!(bt1886)
|
||||||
|
}
|
||||||
Eotf::Gamma22 => convert!(gamma22),
|
Eotf::Gamma22 => convert!(gamma22),
|
||||||
|
Eotf::Gamma24 => convert!(gamma24),
|
||||||
Eotf::Gamma28 => convert!(gamma28),
|
Eotf::Gamma28 => convert!(gamma28),
|
||||||
Eotf::St240 => convert!(st240),
|
Eotf::St240 => convert!(st240),
|
||||||
Eotf::Log100 => convert!(log100),
|
Eotf::Log100 => convert!(log100),
|
||||||
|
|
@ -244,8 +252,13 @@ impl Color {
|
||||||
match eotf {
|
match eotf {
|
||||||
Eotf::Linear => convert!(linear),
|
Eotf::Linear => convert!(linear),
|
||||||
Eotf::St2084Pq => convert!(st2084_pq),
|
Eotf::St2084Pq => convert!(st2084_pq),
|
||||||
Eotf::Bt1886 => convert!(gamma24),
|
Eotf::Bt1886(c) => {
|
||||||
|
let [a1, a2, a3, a4] = bt1886_inv_eotf_args(c);
|
||||||
|
let bt1886 = |c: f32| -> f32 { a1 * ((a2 * c + a3).powf(1.0 / 2.4) - a4) };
|
||||||
|
convert!(bt1886)
|
||||||
|
}
|
||||||
Eotf::Gamma22 => convert!(gamma22),
|
Eotf::Gamma22 => convert!(gamma22),
|
||||||
|
Eotf::Gamma24 => convert!(gamma24),
|
||||||
Eotf::Gamma28 => convert!(gamma28),
|
Eotf::Gamma28 => convert!(gamma28),
|
||||||
Eotf::St240 => convert!(st240),
|
Eotf::St240 => convert!(st240),
|
||||||
Eotf::Log100 => convert!(log100),
|
Eotf::Log100 => convert!(log100),
|
||||||
|
|
|
||||||
|
|
@ -4,64 +4,71 @@ use std::{
|
||||||
ops::{Add, Div, Mul, Sub},
|
ops::{Add, Div, Mul, Sub},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
macro_rules! define {
|
||||||
#[repr(transparent)]
|
($big:ident, $little:ty) => {
|
||||||
pub struct F64(pub f64);
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct $big(pub $little);
|
||||||
|
|
||||||
impl Eq for F64 {}
|
impl Eq for $big {}
|
||||||
|
|
||||||
impl PartialEq for F64 {
|
impl PartialEq for $big {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.0.to_bits() == other.0.to_bits()
|
self.0.to_bits() == other.0.to_bits()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for $big {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.0.to_bits().hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<Self> for $big {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: $big) -> Self::Output {
|
||||||
|
Self(self.0 + rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<Self> for $big {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self(self.0 - rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<Self> for $big {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
Self(self.0 * rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<Self> for $big {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(self, rhs: Self) -> Self::Output {
|
||||||
|
Self(self.0 / rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for $big {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
Display::fmt(&self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for $big {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
Debug::fmt(&self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for F64 {
|
define!(F64, f64);
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
define!(F32, f32);
|
||||||
self.0.to_bits().hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<F64> for F64 {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn add(self, rhs: F64) -> Self::Output {
|
|
||||||
Self(self.0 + rhs.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sub<F64> for F64 {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn sub(self, rhs: F64) -> Self::Output {
|
|
||||||
Self(self.0 - rhs.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul<F64> for F64 {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn mul(self, rhs: F64) -> Self::Output {
|
|
||||||
Self(self.0 * rhs.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Div<F64> for F64 {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn div(self, rhs: F64) -> Self::Output {
|
|
||||||
Self(self.0 / rhs.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for F64 {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
Display::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for F64 {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
Debug::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue