use crate::math::Float;
use crate::transfer::*;
pub trait Decode<T>: TransferFunction {
fn decode(v: T) -> T;
}
impl<F: Float, TF: Decode<F>, const N: usize> Decode<[F; N]> for TF {
#[inline(always)]
fn decode(v: [F; N]) -> [F; N] {
v.map(|x| TF::decode(x))
}
}
impl<F: Float> Decode<F> for Linear {
#[inline(always)]
fn decode(v: F) -> F {
v
}
}
impl<F: Float> Decode<F> for Srgb {
#[inline(always)]
fn decode(x: F) -> F {
let threshold = F::from_f64(Self::ENCODED_THRESHOLD as f64);
let slope = F::from_f64(Self::LINEAR_SLOPE as f64);
let alpha = F::from_f64(Self::ALPHA as f64);
let gamma = F::from_f64(Self::GAMMA as f64);
let one = F::ONE;
if x <= threshold {
x / slope
} else {
((x + (alpha - one)) / alpha).powf(gamma)
}
}
}
impl<F: Float> Decode<F> for Rec709 {
#[inline(always)]
fn decode(x: F) -> F {
let threshold = F::from_f64(Self::ENCODED_THRESHOLD as f64);
let slope = F::from_f64(Self::LINEAR_SLOPE as f64);
let alpha = F::from_f64(Self::ALPHA as f64);
let inv_power = F::from_f64(1.0 / Self::POWER as f64);
let one = F::ONE;
if x <= threshold {
x / slope
} else {
((x + (alpha - one)) / alpha).powf(inv_power)
}
}
}
impl<F: Float> Decode<F> for Pq {
#[inline(always)]
fn decode(x: F) -> F {
let zero = F::ZERO;
let one = F::ONE;
let m1 = F::from_f64(Self::M1 as f64);
let m2 = F::from_f64(Self::M2 as f64);
let c1 = F::from_f64(Self::C1 as f64);
let c2 = F::from_f64(Self::C2 as f64);
let c3 = F::from_f64(Self::C3 as f64);
let v_m2 = x.max(zero).powf(one / m2);
let num = (v_m2 - c1).max(zero);
let den = c2 - c3 * v_m2;
(num / den).powf(one / m1)
}
}
impl<F: Float> Decode<F> for Hlg {
#[inline(always)]
fn decode(x: F) -> F {
let zero = F::ZERO;
let one = F::ONE;
let neg_one = zero - one;
let threshold = F::from_f64(Self::ENCODED_THRESHOLD as f64);
let a = F::from_f64(Self::A as f64);
let b = F::from_f64(Self::B as f64);
let c = F::from_f64(Self::C as f64);
let three = F::from_f64(3.0);
let twelve = F::from_f64(12.0);
if x.abs() <= threshold {
x * x.abs() / three
} else {
let sign = if x < zero { neg_one } else { one };
sign * ((x.abs() - c) / a).exp() + b / twelve
}
}
}
impl<F: Float> Decode<F> for ProPhoto {
#[inline(always)]
fn decode(x: F) -> F {
let zero = F::ZERO;
let one = F::ONE;
let neg_one = zero - one;
let sign = if x < zero { neg_one } else { one };
let abs = x.abs();
let threshold = F::from_f64(Self::ENCODED_THRESHOLD as f64);
let slope = F::from_f64(Self::LINEAR_SLOPE as f64);
let gamma = F::from_f64(Self::GAMMA as f64);
sign * if abs <= threshold {
abs / slope
} else {
abs.powf(gamma)
}
}
}
impl<F: Float> Decode<F> for AcesCc {
#[inline(always)]
fn decode(x: F) -> F {
let cut1 = F::from_f64(Self::CUT1 as f64);
let scale = F::from_f64(Self::LOG_SCALE as f64);
let offset = F::from_f64(Self::LOG_OFFSET as f64);
let ln2 = F::from_f64(core::f64::consts::LN_2);
let neg16: F = F::from_f64(2.0f64.powi(-16));
let two = F::from_f64(2.0);
let linear = x * scale - offset;
if x < cut1 {
((linear * ln2).exp() - neg16) * two
} else {
(linear * ln2).exp()
}
}
}
impl<F: Float> Decode<F> for AcesCct {
#[inline(always)]
fn decode(x: F) -> F {
let y_brk = F::from_f64(Self::Y_BRK as f64);
let a = F::from_f64(Self::A as f64);
let b = F::from_f64(Self::B as f64);
let scale = F::from_f64(Self::LOG_SCALE as f64);
let offset = F::from_f64(Self::LOG_OFFSET as f64);
let ln2 = F::from_f64(core::f64::consts::LN_2);
if x <= y_brk {
(x - b) / a
} else {
((x * scale - offset) * ln2).exp()
}
}
}
impl<F: Float> Decode<F> for DciP3 {
#[inline(always)]
fn decode(x: F) -> F {
let gamma = F::from_f64(Self::GAMMA as f64);
x.max(F::ZERO).powf(gamma)
}
}