1use crate::math::Float;
4use crate::transfer::*;
5
6pub trait Encode<T>: TransferFunction {
11 fn encode(v: T) -> T;
13}
14
15impl<F: Float, TF: Encode<F>, const N: usize> Encode<[F; N]> for TF {
16 #[inline(always)]
17 fn encode(v: [F; N]) -> [F; N] {
18 v.map(|x| TF::encode(x))
19 }
20}
21
22impl<F: Float> Encode<F> for Linear {
23 #[inline(always)]
24 fn encode(v: F) -> F {
25 v
26 }
27}
28
29impl<F: Float> Encode<F> for Srgb {
30 #[inline(always)]
31 fn encode(x: F) -> F {
32 let zero = F::ZERO;
33 let one = F::ONE;
34 let neg_one = zero - one;
35 let sign = if x < zero { neg_one } else { one };
36 let abs = x.abs();
37 let threshold = F::from_f64(Self::LINEAR_THRESHOLD as f64);
38 let slope = F::from_f64(Self::LINEAR_SLOPE as f64);
39 let alpha = F::from_f64(Self::ALPHA as f64);
40 let inv_gamma = F::from_f64(1.0 / Self::GAMMA as f64);
41 sign * if abs <= threshold {
42 abs * slope
43 } else {
44 alpha * abs.powf(inv_gamma) - (alpha - one)
45 }
46 }
47}
48
49impl<F: Float> Encode<F> for Rec709 {
50 #[inline(always)]
51 fn encode(x: F) -> F {
52 let zero = F::ZERO;
53 let one = F::ONE;
54 let neg_one = zero - one;
55 let sign = if x < zero { neg_one } else { one };
56 let abs = x.abs();
57 let threshold = F::from_f64(Self::LINEAR_THRESHOLD as f64);
58 let slope = F::from_f64(Self::LINEAR_SLOPE as f64);
59 let alpha = F::from_f64(Self::ALPHA as f64);
60 let power = F::from_f64(Self::POWER as f64);
61 sign * if abs <= threshold {
62 abs * slope
63 } else {
64 alpha * abs.powf(power) - (alpha - one)
65 }
66 }
67}
68
69impl<F: Float> Encode<F> for Pq {
70 #[inline(always)]
71 fn encode(x: F) -> F {
72 let zero = F::ZERO;
73 let m1 = F::from_f64(Self::M1 as f64);
74 let m2 = F::from_f64(Self::M2 as f64);
75 let c1 = F::from_f64(Self::C1 as f64);
76 let c2 = F::from_f64(Self::C2 as f64);
77 let c3 = F::from_f64(Self::C3 as f64);
78 let one = F::ONE;
79 let y_m1 = x.max(zero).powf(m1);
80 ((c1 + c2 * y_m1) / (one + c3 * y_m1)).powf(m2)
81 }
82}
83
84impl<F: Float> Encode<F> for Hlg {
85 #[inline(always)]
86 fn encode(x: F) -> F {
87 let zero = F::ZERO;
88 let one = F::ONE;
89 let neg_one = zero - one;
90 let abs = x.abs();
91 let sign = if x < zero { neg_one } else { one };
92 let threshold = F::from_f64(Self::LINEAR_THRESHOLD as f64);
93 let a = F::from_f64(Self::A as f64);
94 let b = F::from_f64(Self::B as f64);
95 let c = F::from_f64(Self::C as f64);
96 let three = F::from_f64(3.0);
97 let twelve = F::from_f64(12.0);
98 if abs <= threshold {
99 sign * (three * abs).sqrt()
100 } else {
101 sign * (a * (twelve * abs - b).max(F::MIN_POSITIVE).ln() + c)
102 }
103 }
104}
105
106impl<F: Float> Encode<F> for ProPhoto {
107 #[inline(always)]
108 fn encode(x: F) -> F {
109 let zero = F::ZERO;
110 let one = F::ONE;
111 let neg_one = zero - one;
112 let sign = if x < zero { neg_one } else { one };
113 let abs = x.abs();
114 let threshold = F::from_f64(Self::LINEAR_THRESHOLD as f64);
115 let slope = F::from_f64(Self::LINEAR_SLOPE as f64);
116 let inv_gamma = F::from_f64(1.0 / Self::GAMMA as f64);
117 sign * if abs <= threshold {
118 abs * slope
119 } else {
120 abs.powf(inv_gamma)
121 }
122 }
123}
124
125impl<F: Float> Encode<F> for AcesCc {
126 #[inline(always)]
127 fn encode(x: F) -> F {
128 let zero = F::ZERO;
129 let scale = F::from_f64(Self::LOG_SCALE as f64);
130 let offset = F::from_f64(Self::LOG_OFFSET as f64);
131 let log2_recip = F::from_f64(Self::LOG2_RECIP as f64);
132 let neg16: F = F::from_f64(2.0f64.powi(-16));
133 let neg15: F = F::from_f64(2.0f64.powi(-15));
134 let half = F::from_f64(0.5);
135 if x < zero {
136 (neg16.ln() * log2_recip + offset) / scale
137 } else if x < neg15 {
138 (neg16 + x * half).ln() * log2_recip * (F::ONE / scale) + offset / scale
139 } else {
140 x.ln() * log2_recip * (F::ONE / scale) + offset / scale
141 }
142 }
143}
144
145impl<F: Float> Encode<F> for AcesCct {
146 #[inline(always)]
147 fn encode(x: F) -> F {
148 let x_brk = F::from_f64(Self::X_BRK as f64);
149 let a = F::from_f64(Self::A as f64);
150 let b = F::from_f64(Self::B as f64);
151 let scale = F::from_f64(Self::LOG_SCALE as f64);
152 let offset = F::from_f64(Self::LOG_OFFSET as f64);
153 let log2_recip = F::from_f64(Self::LOG2_RECIP as f64);
154 if x <= x_brk {
155 a * x + b
156 } else {
157 (x.ln() * log2_recip + offset) / scale
158 }
159 }
160}
161
162impl<F: Float> Encode<F> for DciP3 {
163 #[inline(always)]
164 fn encode(x: F) -> F {
165 let inv_gamma = F::from_f64(1.0 / Self::GAMMA as f64);
166 x.max(F::ZERO).powf(inv_gamma)
167 }
168}