use crate::math::Float;
use crate::transfer::*;
pub trait Encode<T>: TransferFunction {
fn encode(v: T) -> T;
}
impl<F: Float, TF: Encode<F>, const N: usize> Encode<[F; N]> for TF {
#[inline(always)]
fn encode(v: [F; N]) -> [F; N] {
v.map(|x| TF::encode(x))
}
}
impl<F: Float> Encode<F> for Linear {
#[inline(always)]
fn encode(v: F) -> F {
v
}
}
impl<F: Float> Encode<F> for Srgb {
#[inline(always)]
fn encode(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::LINEAR_THRESHOLD as f64);
let slope = F::from_f64(Self::LINEAR_SLOPE as f64);
let alpha = F::from_f64(Self::ALPHA as f64);
let inv_gamma = F::from_f64(1.0 / Self::GAMMA as f64);
sign * if abs <= threshold {
abs * slope
} else {
alpha * abs.powf(inv_gamma) - (alpha - one)
}
}
}
impl<F: Float> Encode<F> for Rec709 {
#[inline(always)]
fn encode(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::LINEAR_THRESHOLD as f64);
let slope = F::from_f64(Self::LINEAR_SLOPE as f64);
let alpha = F::from_f64(Self::ALPHA as f64);
let power = F::from_f64(Self::POWER as f64);
sign * if abs <= threshold {
abs * slope
} else {
alpha * abs.powf(power) - (alpha - one)
}
}
}
impl<F: Float> Encode<F> for Pq {
#[inline(always)]
fn encode(x: F) -> F {
let zero = F::ZERO;
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 one = F::ONE;
let y_m1 = x.max(zero).powf(m1);
((c1 + c2 * y_m1) / (one + c3 * y_m1)).powf(m2)
}
}
impl<F: Float> Encode<F> for Hlg {
#[inline(always)]
fn encode(x: F) -> F {
let zero = F::ZERO;
let one = F::ONE;
let neg_one = zero - one;
let abs = x.abs();
let sign = if x < zero { neg_one } else { one };
let threshold = F::from_f64(Self::LINEAR_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 abs <= threshold {
sign * (three * abs).sqrt()
} else {
sign * (a * (twelve * abs - b).max(F::MIN_POSITIVE).ln() + c)
}
}
}
impl<F: Float> Encode<F> for ProPhoto {
#[inline(always)]
fn encode(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::LINEAR_THRESHOLD as f64);
let slope = F::from_f64(Self::LINEAR_SLOPE as f64);
let inv_gamma = F::from_f64(1.0 / Self::GAMMA as f64);
sign * if abs <= threshold {
abs * slope
} else {
abs.powf(inv_gamma)
}
}
}
impl<F: Float> Encode<F> for AcesCc {
#[inline(always)]
fn encode(x: F) -> F {
let zero = F::ZERO;
let scale = F::from_f64(Self::LOG_SCALE as f64);
let offset = F::from_f64(Self::LOG_OFFSET as f64);
let log2_recip = F::from_f64(Self::LOG2_RECIP as f64);
let neg16: F = F::from_f64(2.0f64.powi(-16));
let neg15: F = F::from_f64(2.0f64.powi(-15));
let half = F::from_f64(0.5);
if x < zero {
(neg16.ln() * log2_recip + offset) / scale
} else if x < neg15 {
(neg16 + x * half).ln() * log2_recip * (F::ONE / scale) + offset / scale
} else {
x.ln() * log2_recip * (F::ONE / scale) + offset / scale
}
}
}
impl<F: Float> Encode<F> for AcesCct {
#[inline(always)]
fn encode(x: F) -> F {
let x_brk = F::from_f64(Self::X_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 log2_recip = F::from_f64(Self::LOG2_RECIP as f64);
if x <= x_brk {
a * x + b
} else {
(x.ln() * log2_recip + offset) / scale
}
}
}
impl<F: Float> Encode<F> for DciP3 {
#[inline(always)]
fn encode(x: F) -> F {
let inv_gamma = F::from_f64(1.0 / Self::GAMMA as f64);
x.max(F::ZERO).powf(inv_gamma)
}
}