/rust/registry/src/index.crates.io-1949cf8c6b5b557f/moxcms-0.8.1/src/gamma.rs
Line | Count | Source |
1 | | /* |
2 | | * // Copyright (c) Radzivon Bartoshyk 3/2025. All rights reserved. |
3 | | * // |
4 | | * // Redistribution and use in source and binary forms, with or without modification, |
5 | | * // are permitted provided that the following conditions are met: |
6 | | * // |
7 | | * // 1. Redistributions of source code must retain the above copyright notice, this |
8 | | * // list of conditions and the following disclaimer. |
9 | | * // |
10 | | * // 2. Redistributions in binary form must reproduce the above copyright notice, |
11 | | * // this list of conditions and the following disclaimer in the documentation |
12 | | * // and/or other materials provided with the distribution. |
13 | | * // |
14 | | * // 3. Neither the name of the copyright holder nor the names of its |
15 | | * // contributors may be used to endorse or promote products derived from |
16 | | * // this software without specific prior written permission. |
17 | | * // |
18 | | * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
19 | | * // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
20 | | * // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
21 | | * // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
22 | | * // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 | | * // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
24 | | * // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
25 | | * // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
26 | | * // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
27 | | * // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | | */ |
29 | | use crate::mlaf::{fmla, mlaf}; |
30 | | use crate::transform::PointeeSizeExpressible; |
31 | | use crate::*; |
32 | | use num_traits::AsPrimitive; |
33 | | use pxfm::*; |
34 | | |
35 | | #[inline] |
36 | | /// Linear transfer function for sRGB |
37 | 0 | fn srgb_to_linear(gamma: f64) -> f64 { |
38 | 0 | if gamma < 0f64 { |
39 | 0 | 0f64 |
40 | 0 | } else if gamma < 12.92f64 * 0.0030412825601275209f64 { |
41 | 0 | gamma * (1f64 / 12.92f64) |
42 | 0 | } else if gamma < 1.0f64 { |
43 | 0 | f_pow( |
44 | 0 | (gamma + 0.0550107189475866f64) / 1.0550107189475866f64, |
45 | | 2.4f64, |
46 | | ) |
47 | | } else { |
48 | 0 | 1.0f64 |
49 | | } |
50 | 0 | } |
51 | | |
52 | | #[inline] |
53 | | #[cfg(feature = "extended_range")] |
54 | | /// Linear transfer function for sRGB |
55 | | fn srgb_to_linearf_extended(gamma: f32) -> f32 { |
56 | | if gamma < 12.92 * 0.0030412825601275209 { |
57 | | gamma * (1. / 12.92f32) |
58 | | } else { |
59 | | dirty_powf((gamma + 0.0550107189475866) / 1.0550107189475866, 2.4) |
60 | | } |
61 | | } |
62 | | |
63 | | #[inline] |
64 | | /// Gamma transfer function for sRGB |
65 | 0 | fn srgb_from_linear(linear: f64) -> f64 { |
66 | 0 | if linear < 0.0f64 { |
67 | 0 | 0.0f64 |
68 | 0 | } else if linear < 0.0030412825601275209f64 { |
69 | 0 | linear * 12.92f64 |
70 | 0 | } else if linear < 1.0f64 { |
71 | 0 | fmla( |
72 | | 1.0550107189475866f64, |
73 | 0 | f_pow(linear, 1.0f64 / 2.4f64), |
74 | | -0.0550107189475866f64, |
75 | | ) |
76 | | } else { |
77 | 0 | 1.0f64 |
78 | | } |
79 | 0 | } |
80 | | |
81 | | /// Gamma transfer function for sRGB |
82 | | #[cfg(feature = "extended_range")] |
83 | | pub(crate) fn srgb_from_linear_extended(linear: f32) -> f32 { |
84 | | if linear < 0.0030412825601275209f32 { |
85 | | linear * 12.92f32 |
86 | | } else { |
87 | | fmla( |
88 | | 1.0550107189475866f32, |
89 | | dirty_powf(linear, 1.0f32 / 2.4f32), |
90 | | -0.0550107189475866f32, |
91 | | ) |
92 | | } |
93 | | } |
94 | | |
95 | | #[inline] |
96 | | /// Linear transfer function for Rec.709 |
97 | 0 | fn rec709_to_linear(gamma: f64) -> f64 { |
98 | 0 | if gamma < 0.0f64 { |
99 | 0 | 0.0f64 |
100 | 0 | } else if gamma < 4.5f64 * 0.018053968510807f64 { |
101 | 0 | gamma * (1f64 / 4.5f64) |
102 | 0 | } else if gamma < 1.0f64 { |
103 | 0 | f_pow( |
104 | 0 | (gamma + 0.09929682680944f64) / 1.09929682680944f64, |
105 | 0 | 1.0f64 / 0.45f64, |
106 | | ) |
107 | | } else { |
108 | 0 | 1.0f64 |
109 | | } |
110 | 0 | } |
111 | | |
112 | | #[inline] |
113 | | #[cfg(feature = "extended_range")] |
114 | | /// Linear transfer function for Rec.709 |
115 | | fn rec709_to_linearf_extended(gamma: f32) -> f32 { |
116 | | if gamma < 4.5 * 0.018053968510807 { |
117 | | gamma * (1. / 4.5) |
118 | | } else { |
119 | | f_powf((gamma + 0.09929682680944) / 1.09929682680944, 1.0 / 0.45) |
120 | | } |
121 | | } |
122 | | |
123 | | #[inline] |
124 | | /// Gamma transfer function for Rec.709 |
125 | 0 | fn rec709_from_linear(linear: f64) -> f64 { |
126 | 0 | if linear < 0.0f64 { |
127 | 0 | 0.0f64 |
128 | 0 | } else if linear < 0.018053968510807f64 { |
129 | 0 | linear * 4.5f64 |
130 | 0 | } else if linear < 1.0f64 { |
131 | 0 | fmla( |
132 | | 1.09929682680944f64, |
133 | 0 | f_pow(linear, 0.45f64), |
134 | | -0.09929682680944f64, |
135 | | ) |
136 | | } else { |
137 | 0 | 1.0f64 |
138 | | } |
139 | 0 | } |
140 | | |
141 | | /// Gamma transfer function for Rec.709 |
142 | | #[cfg(feature = "extended_range")] |
143 | | fn rec709_from_linearf_extended(linear: f32) -> f32 { |
144 | | if linear < 0.018053968510807 { |
145 | | linear * 4.5 |
146 | | } else { |
147 | | fmla( |
148 | | 1.09929682680944, |
149 | | dirty_powf(linear, 0.45), |
150 | | -0.09929682680944, |
151 | | ) |
152 | | } |
153 | | } |
154 | | |
155 | | /// Linear transfer function for Smpte 428 |
156 | 0 | pub(crate) fn smpte428_to_linear(gamma: f64) -> f64 { |
157 | | const SCALE: f64 = 1. / 0.91655527974030934f64; |
158 | 0 | f_pow(gamma.max(0.).min(1f64), 2.6f64) * SCALE |
159 | 0 | } |
160 | | |
161 | | #[cfg(feature = "extended_range")] |
162 | | /// Linear transfer function for Smpte 428 |
163 | | pub(crate) fn smpte428_to_linearf_extended(gamma: f32) -> f32 { |
164 | | const SCALE: f32 = 1. / 0.91655527974030934; |
165 | | dirty_powf(gamma.max(0.), 2.6) * SCALE |
166 | | } |
167 | | |
168 | | /// Gamma transfer function for Smpte 428 |
169 | 0 | fn smpte428_from_linear(linear: f64) -> f64 { |
170 | | const POWER_VALUE: f64 = 1.0f64 / 2.6f64; |
171 | 0 | f_pow(0.91655527974030934f64 * linear.max(0.), POWER_VALUE) |
172 | 0 | } |
173 | | |
174 | | #[cfg(feature = "extended_range")] |
175 | | /// Gamma transfer function for Smpte 428 |
176 | | fn smpte428_from_linearf(linear: f32) -> f32 { |
177 | | const POWER_VALUE: f32 = 1.0 / 2.6; |
178 | | dirty_powf(0.91655527974030934 * linear.max(0.), POWER_VALUE) |
179 | | } |
180 | | |
181 | | /// Linear transfer function for Smpte 240 |
182 | 0 | pub(crate) fn smpte240_to_linear(gamma: f64) -> f64 { |
183 | 0 | if gamma < 0.0 { |
184 | 0 | 0.0 |
185 | 0 | } else if gamma < 4.0 * 0.022821585529445 { |
186 | 0 | gamma / 4.0 |
187 | 0 | } else if gamma < 1.0 { |
188 | 0 | f_pow((gamma + 0.111572195921731) / 1.111572195921731, 1.0 / 0.45) |
189 | | } else { |
190 | 0 | 1.0 |
191 | | } |
192 | 0 | } |
193 | | |
194 | | #[cfg(feature = "extended_range")] |
195 | | /// Linear transfer function for Smpte 240 |
196 | | pub(crate) fn smpte240_to_linearf_extended(gamma: f32) -> f32 { |
197 | | if gamma < 4.0 * 0.022821585529445 { |
198 | | gamma / 4.0 |
199 | | } else { |
200 | | dirty_powf((gamma + 0.111572195921731) / 1.111572195921731, 1.0 / 0.45) |
201 | | } |
202 | | } |
203 | | |
204 | | /// Gamma transfer function for Smpte 240 |
205 | 0 | fn smpte240_from_linear(linear: f64) -> f64 { |
206 | 0 | if linear < 0.0 { |
207 | 0 | 0.0 |
208 | 0 | } else if linear < 0.022821585529445 { |
209 | 0 | linear * 4.0 |
210 | 0 | } else if linear < 1.0 { |
211 | 0 | fmla(1.111572195921731, f_pow(linear, 0.45), -0.111572195921731) |
212 | | } else { |
213 | 0 | 1.0 |
214 | | } |
215 | 0 | } |
216 | | |
217 | | #[cfg(feature = "extended_range")] |
218 | | /// Gamma transfer function for Smpte 240 |
219 | | fn smpte240_from_linearf_extended(linear: f32) -> f32 { |
220 | | if linear < 0.022821585529445 { |
221 | | linear * 4.0 |
222 | | } else { |
223 | | fmla(1.111572195921731, f_powf(linear, 0.45), -0.111572195921731) |
224 | | } |
225 | | } |
226 | | |
227 | | #[inline] |
228 | | /// Gamma transfer function for Log100 |
229 | 0 | fn log100_from_linear(linear: f64) -> f64 { |
230 | 0 | if linear <= 0.01f64 { |
231 | 0 | 0. |
232 | | } else { |
233 | 0 | 1. + f_log10(linear.min(1.)) / 2.0 |
234 | | } |
235 | 0 | } |
236 | | |
237 | | #[cfg(feature = "extended_range")] |
238 | | /// Gamma transfer function for Log100 |
239 | | fn log100_from_linearf(linear: f32) -> f32 { |
240 | | if linear <= 0.01 { |
241 | | 0. |
242 | | } else { |
243 | | 1. + f_log10f(linear.min(1.)) / 2.0 |
244 | | } |
245 | | } |
246 | | |
247 | | /// Linear transfer function for Log100 |
248 | 0 | pub(crate) fn log100_to_linear(gamma: f64) -> f64 { |
249 | | // The function is non-bijective so choose the middle of [0, 0.00316227766f]. |
250 | | const MID_INTERVAL: f64 = 0.01 / 2.; |
251 | 0 | if gamma <= 0. { |
252 | 0 | MID_INTERVAL |
253 | | } else { |
254 | 0 | f_exp10(2. * (gamma.min(1.) - 1.)) |
255 | | } |
256 | 0 | } |
257 | | |
258 | | #[cfg(feature = "extended_range")] |
259 | | /// Linear transfer function for Log100 |
260 | | pub(crate) fn log100_to_linearf(gamma: f32) -> f32 { |
261 | | // The function is non-bijective so choose the middle of [0, 0.00316227766f]. |
262 | | const MID_INTERVAL: f32 = 0.01 / 2.; |
263 | | if gamma <= 0. { |
264 | | MID_INTERVAL |
265 | | } else { |
266 | | f_exp10f(2. * (gamma.min(1.) - 1.)) |
267 | | } |
268 | | } |
269 | | |
270 | | #[inline] |
271 | | /// Linear transfer function for Log100Sqrt10 |
272 | 0 | pub(crate) fn log100_sqrt10_to_linear(gamma: f64) -> f64 { |
273 | | // The function is non-bijective so choose the middle of [0, 0.00316227766f]. |
274 | | const MID_INTERVAL: f64 = 0.00316227766 / 2.; |
275 | 0 | if gamma <= 0. { |
276 | 0 | MID_INTERVAL |
277 | | } else { |
278 | 0 | f_exp10(2.5 * (gamma.min(1.) - 1.)) |
279 | | } |
280 | 0 | } |
281 | | |
282 | | #[cfg(feature = "extended_range")] |
283 | | /// Linear transfer function for Log100Sqrt10 |
284 | | pub(crate) fn log100_sqrt10_to_linearf(gamma: f32) -> f32 { |
285 | | // The function is non-bijective so choose the middle of [0, 0.00316227766f]. |
286 | | const MID_INTERVAL: f32 = 0.00316227766 / 2.; |
287 | | if gamma <= 0. { |
288 | | MID_INTERVAL |
289 | | } else { |
290 | | f_exp10f(2.5 * (gamma.min(1.) - 1.)) |
291 | | } |
292 | | } |
293 | | |
294 | | /// Gamma transfer function for Log100Sqrt10 |
295 | 0 | fn log100_sqrt10_from_linear(linear: f64) -> f64 { |
296 | 0 | if linear <= 0.00316227766 { |
297 | 0 | 0.0 |
298 | | } else { |
299 | 0 | 1.0 + f_log10(linear.min(1.)) / 2.5 |
300 | | } |
301 | 0 | } |
302 | | |
303 | | #[cfg(feature = "extended_range")] |
304 | | /// Gamma transfer function for Log100Sqrt10 |
305 | | fn log100_sqrt10_from_linearf(linear: f32) -> f32 { |
306 | | if linear <= 0.00316227766 { |
307 | | 0.0 |
308 | | } else { |
309 | | 1.0 + f_log10f(linear.min(1.)) / 2.5 |
310 | | } |
311 | | } |
312 | | |
313 | | /// Gamma transfer function for Bt.1361 |
314 | 0 | fn bt1361_from_linear(linear: f64) -> f64 { |
315 | 0 | if linear < -0.25 { |
316 | 0 | -0.25 |
317 | 0 | } else if linear < 0.0 { |
318 | 0 | fmla( |
319 | | -0.27482420670236, |
320 | 0 | f_pow(-4.0 * linear, 0.45), |
321 | | 0.02482420670236, |
322 | | ) |
323 | 0 | } else if linear < 0.018053968510807 { |
324 | 0 | linear * 4.5 |
325 | 0 | } else if linear < 1.0 { |
326 | 0 | fmla(1.09929682680944, f_pow(linear, 0.45), -0.09929682680944) |
327 | | } else { |
328 | 0 | 1.0 |
329 | | } |
330 | 0 | } |
331 | | |
332 | | #[cfg(feature = "extended_range")] |
333 | | /// Gamma transfer function for Bt.1361 |
334 | | fn bt1361_from_linearf(linear: f32) -> f32 { |
335 | | if linear < -0.25 { |
336 | | -0.25 |
337 | | } else if linear < 0.0 { |
338 | | fmla( |
339 | | -0.27482420670236, |
340 | | dirty_powf(-4.0 * linear, 0.45), |
341 | | 0.02482420670236, |
342 | | ) |
343 | | } else if linear < 0.018053968510807 { |
344 | | linear * 4.5 |
345 | | } else if linear < 1.0 { |
346 | | fmla( |
347 | | 1.09929682680944, |
348 | | dirty_powf(linear, 0.45), |
349 | | -0.09929682680944, |
350 | | ) |
351 | | } else { |
352 | | 1.0 |
353 | | } |
354 | | } |
355 | | |
356 | | /// Linear transfer function for Bt.1361 |
357 | 0 | pub(crate) fn bt1361_to_linear(gamma: f64) -> f64 { |
358 | 0 | if gamma < -0.25f64 { |
359 | 0 | -0.25f64 |
360 | 0 | } else if gamma < 0.0f64 { |
361 | 0 | f_pow( |
362 | 0 | (gamma - 0.02482420670236f64) / -0.27482420670236f64, |
363 | 0 | 1.0f64 / 0.45f64, |
364 | 0 | ) / -4.0f64 |
365 | 0 | } else if gamma < 4.5 * 0.018053968510807 { |
366 | 0 | gamma / 4.5 |
367 | 0 | } else if gamma < 1.0 { |
368 | 0 | f_pow((gamma + 0.09929682680944) / 1.09929682680944, 1.0 / 0.45) |
369 | | } else { |
370 | 0 | 1.0f64 |
371 | | } |
372 | 0 | } |
373 | | |
374 | | #[cfg(feature = "extended_range")] |
375 | | /// Linear transfer function for Bt.1361 |
376 | | fn bt1361_to_linearf(gamma: f32) -> f32 { |
377 | | if gamma < -0.25 { |
378 | | -0.25 |
379 | | } else if gamma < 0.0 { |
380 | | dirty_powf((gamma - 0.02482420670236) / -0.27482420670236, 1.0 / 0.45) / -4.0 |
381 | | } else if gamma < 4.5 * 0.018053968510807 { |
382 | | gamma / 4.5 |
383 | | } else if gamma < 1.0 { |
384 | | dirty_powf((gamma + 0.09929682680944) / 1.09929682680944, 1.0 / 0.45) |
385 | | } else { |
386 | | 1.0 |
387 | | } |
388 | | } |
389 | | |
390 | | #[inline(always)] |
391 | | /// Pure gamma transfer function for gamma 2.2 |
392 | 0 | fn pure_gamma_function(x: f64, gamma: f64) -> f64 { |
393 | 0 | if x <= 0f64 { |
394 | 0 | 0f64 |
395 | 0 | } else if x >= 1f64 { |
396 | 0 | 1f64 |
397 | | } else { |
398 | 0 | f_pow(x, gamma) |
399 | | } |
400 | 0 | } |
401 | | |
402 | | #[cfg(feature = "extended_range")] |
403 | | #[inline(always)] |
404 | | /// Pure gamma transfer function for gamma 2.2 |
405 | | fn pure_gamma_function_f(x: f32, gamma: f32) -> f32 { |
406 | | if x <= 0. { 0. } else { dirty_powf(x, gamma) } |
407 | | } |
408 | | |
409 | 0 | pub(crate) fn iec61966_to_linear(gamma: f64) -> f64 { |
410 | 0 | if gamma < -4.5f64 * 0.018053968510807f64 { |
411 | 0 | f_pow( |
412 | 0 | (-gamma + 0.09929682680944f64) / -1.09929682680944f64, |
413 | 0 | 1.0 / 0.45, |
414 | | ) |
415 | 0 | } else if gamma < 4.5f64 * 0.018053968510807f64 { |
416 | 0 | gamma / 4.5 |
417 | | } else { |
418 | 0 | f_pow( |
419 | 0 | (gamma + 0.09929682680944f64) / 1.09929682680944f64, |
420 | 0 | 1.0 / 0.45, |
421 | | ) |
422 | | } |
423 | 0 | } |
424 | | |
425 | | #[cfg(feature = "extended_range")] |
426 | | fn iec61966_to_linearf(gamma: f32) -> f32 { |
427 | | if gamma < -4.5 * 0.018053968510807 { |
428 | | dirty_powf((-gamma + 0.09929682680944) / -1.09929682680944, 1.0 / 0.45) |
429 | | } else if gamma < 4.5 * 0.018053968510807 { |
430 | | gamma / 4.5 |
431 | | } else { |
432 | | dirty_powf((gamma + 0.09929682680944) / 1.09929682680944, 1.0 / 0.45) |
433 | | } |
434 | | } |
435 | | |
436 | 0 | fn iec61966_from_linear(v: f64) -> f64 { |
437 | 0 | if v < -0.018053968510807f64 { |
438 | 0 | fmla(-1.09929682680944f64, f_pow(-v, 0.45), 0.09929682680944f64) |
439 | 0 | } else if v < 0.018053968510807f64 { |
440 | 0 | v * 4.5f64 |
441 | | } else { |
442 | 0 | fmla(1.09929682680944f64, f_pow(v, 0.45), -0.09929682680944f64) |
443 | | } |
444 | 0 | } |
445 | | |
446 | | #[cfg(feature = "extended_range")] |
447 | | fn iec61966_from_linearf(v: f32) -> f32 { |
448 | | if v < -0.018053968510807 { |
449 | | fmla(-1.09929682680944, dirty_powf(-v, 0.45), 0.09929682680944) |
450 | | } else if v < 0.018053968510807 { |
451 | | v * 4.5 |
452 | | } else { |
453 | | fmla(1.09929682680944, dirty_powf(v, 0.45), -0.09929682680944) |
454 | | } |
455 | | } |
456 | | |
457 | | #[inline] |
458 | | /// Pure gamma transfer function for gamma 2.2 |
459 | 0 | fn gamma2p2_from_linear(linear: f64) -> f64 { |
460 | 0 | pure_gamma_function(linear, 1f64 / 2.2f64) |
461 | 0 | } |
462 | | |
463 | | #[cfg(feature = "extended_range")] |
464 | | #[inline] |
465 | | /// Pure gamma transfer function for gamma 2.2 |
466 | | fn gamma2p2_from_linear_f(linear: f32) -> f32 { |
467 | | pure_gamma_function_f(linear, 1. / 2.2) |
468 | | } |
469 | | |
470 | | #[inline] |
471 | | /// Linear transfer function for gamma 2.2 |
472 | 0 | fn gamma2p2_to_linear(gamma: f64) -> f64 { |
473 | 0 | pure_gamma_function(gamma, 2.2f64) |
474 | 0 | } |
475 | | |
476 | | #[cfg(feature = "extended_range")] |
477 | | #[inline] |
478 | | /// Linear transfer function for gamma 2.2 |
479 | | fn gamma2p2_to_linear_f(gamma: f32) -> f32 { |
480 | | pure_gamma_function_f(gamma, 2.2) |
481 | | } |
482 | | |
483 | | #[inline] |
484 | | /// Pure gamma transfer function for gamma 2.8 |
485 | 0 | fn gamma2p8_from_linear(linear: f64) -> f64 { |
486 | 0 | pure_gamma_function(linear, 1f64 / 2.8f64) |
487 | 0 | } |
488 | | |
489 | | #[cfg(feature = "extended_range")] |
490 | | #[inline] |
491 | | /// Pure gamma transfer function for gamma 2.8 |
492 | | fn gamma2p8_from_linear_f(linear: f32) -> f32 { |
493 | | pure_gamma_function_f(linear, 1. / 2.8) |
494 | | } |
495 | | |
496 | | #[inline] |
497 | | /// Linear transfer function for gamma 2.8 |
498 | 0 | fn gamma2p8_to_linear(gamma: f64) -> f64 { |
499 | 0 | pure_gamma_function(gamma, 2.8f64) |
500 | 0 | } |
501 | | |
502 | | #[cfg(feature = "extended_range")] |
503 | | #[inline] |
504 | | /// Linear transfer function for gamma 2.8 |
505 | | fn gamma2p8_to_linear_f(gamma: f32) -> f32 { |
506 | | pure_gamma_function_f(gamma, 2.8) |
507 | | } |
508 | | |
509 | | #[inline] |
510 | | /// Linear transfer function for PQ |
511 | 0 | pub(crate) fn pq_to_linear(gamma: f64) -> f64 { |
512 | 0 | if gamma > 0.0 { |
513 | 0 | let pow_gamma = f_pow(gamma, 1.0 / 78.84375); |
514 | 0 | let num = (pow_gamma - 0.8359375).max(0.); |
515 | 0 | let den = mlaf(18.8515625, -18.6875, pow_gamma).max(f64::MIN); |
516 | 0 | f_pow(num / den, 1.0 / 0.1593017578125) |
517 | | } else { |
518 | 0 | 0.0 |
519 | | } |
520 | 0 | } |
521 | | |
522 | | /// Linear transfer function for PQ |
523 | 0 | pub(crate) fn pq_to_linearf(gamma: f32) -> f32 { |
524 | 0 | if gamma > 0.0 { |
525 | 0 | let pow_gamma = f_powf(gamma, 1.0 / 78.84375); |
526 | 0 | let num = (pow_gamma - 0.8359375).max(0.); |
527 | 0 | let den = mlaf(18.8515625, -18.6875, pow_gamma).max(f32::MIN); |
528 | 0 | f_powf(num / den, 1.0 / 0.1593017578125) |
529 | | } else { |
530 | 0 | 0.0 |
531 | | } |
532 | 0 | } |
533 | | |
534 | | /// Gamma transfer function for PQ |
535 | 0 | fn pq_from_linear(linear: f64) -> f64 { |
536 | 0 | if linear > 0.0 { |
537 | 0 | let linear = linear.clamp(0., 1.); |
538 | 0 | let pow_linear = f_pow(linear, 0.1593017578125); |
539 | 0 | let num = fmla(0.1640625, pow_linear, -0.1640625); |
540 | 0 | let den = mlaf(1.0, 18.6875, pow_linear); |
541 | 0 | f_pow(1.0 + num / den, 78.84375) |
542 | | } else { |
543 | 0 | 0.0 |
544 | | } |
545 | 0 | } |
546 | | |
547 | | #[inline] |
548 | | /// Gamma transfer function for PQ |
549 | 0 | pub(crate) fn pq_from_linearf(linear: f32) -> f32 { |
550 | 0 | if linear > 0.0 { |
551 | 0 | let linear = linear.max(0.); |
552 | 0 | let pow_linear = f_powf(linear, 0.1593017578125); |
553 | 0 | let num = fmla(0.1640625, pow_linear, -0.1640625); |
554 | 0 | let den = mlaf(1.0, 18.6875, pow_linear); |
555 | 0 | f_powf(1.0 + num / den, 78.84375) |
556 | | } else { |
557 | 0 | 0.0 |
558 | | } |
559 | 0 | } |
560 | | |
561 | | #[inline] |
562 | | /// Linear transfer function for HLG |
563 | 0 | pub(crate) fn hlg_to_linear(gamma: f64) -> f64 { |
564 | 0 | if gamma < 0.0 { |
565 | 0 | return 0.0; |
566 | 0 | } |
567 | 0 | if gamma <= 0.5 { |
568 | 0 | f_pow((gamma * gamma) * (1.0 / 3.0), 1.2) |
569 | | } else { |
570 | 0 | f_pow( |
571 | 0 | (f_exp((gamma - 0.55991073) / 0.17883277) + 0.28466892) / 12.0, |
572 | | 1.2, |
573 | | ) |
574 | | } |
575 | 0 | } |
576 | | |
577 | | #[cfg(feature = "extended_range")] |
578 | | /// Linear transfer function for HLG |
579 | | pub(crate) fn hlg_to_linearf(gamma: f32) -> f32 { |
580 | | if gamma < 0.0 { |
581 | | return 0.0; |
582 | | } |
583 | | if gamma <= 0.5 { |
584 | | f_powf((gamma * gamma) * (1.0 / 3.0), 1.2) |
585 | | } else { |
586 | | f_powf( |
587 | | (f_expf((gamma - 0.55991073) / 0.17883277) + 0.28466892) / 12.0, |
588 | | 1.2, |
589 | | ) |
590 | | } |
591 | | } |
592 | | |
593 | | /// Gamma transfer function for HLG |
594 | 0 | fn hlg_from_linear(linear: f64) -> f64 { |
595 | | // Scale from extended SDR range to [0.0, 1.0]. |
596 | 0 | let mut linear = linear.clamp(0., 1.); |
597 | | // Inverse OOTF followed by OETF see Table 5 and Note 5i in ITU-R BT.2100-2 page 7-8. |
598 | 0 | linear = f_pow(linear, 1.0 / 1.2); |
599 | 0 | if linear < 0.0 { |
600 | 0 | 0.0 |
601 | 0 | } else if linear <= (1.0 / 12.0) { |
602 | 0 | (3.0 * linear).sqrt() |
603 | | } else { |
604 | 0 | fmla( |
605 | | 0.17883277, |
606 | 0 | f_log(fmla(12.0, linear, -0.28466892)), |
607 | | 0.55991073, |
608 | | ) |
609 | | } |
610 | 0 | } |
611 | | |
612 | | #[cfg(feature = "extended_range")] |
613 | | /// Gamma transfer function for HLG |
614 | | fn hlg_from_linearf(linear: f32) -> f32 { |
615 | | // Scale from extended SDR range to [0.0, 1.0]. |
616 | | let mut linear = linear.max(0.); |
617 | | // Inverse OOTF followed by OETF see Table 5 and Note 5i in ITU-R BT.2100-2 page 7-8. |
618 | | linear = f_powf(linear, 1.0 / 1.2); |
619 | | if linear < 0.0 { |
620 | | 0.0 |
621 | | } else if linear <= (1.0 / 12.0) { |
622 | | (3.0 * linear).sqrt() |
623 | | } else { |
624 | | 0.17883277 * f_logf(12.0 * linear - 0.28466892) + 0.55991073 |
625 | | } |
626 | | } |
627 | | |
628 | | #[inline] |
629 | 0 | fn trc_linear(v: f64) -> f64 { |
630 | 0 | v.min(1.).max(0.) |
631 | 0 | } |
632 | | |
633 | | impl TransferCharacteristics { |
634 | 0 | pub fn linearize(self, v: f64) -> f64 { |
635 | 0 | match self { |
636 | 0 | TransferCharacteristics::Reserved => 0f64, |
637 | | TransferCharacteristics::Bt709 |
638 | | | TransferCharacteristics::Bt601 |
639 | | | TransferCharacteristics::Bt202010bit |
640 | 0 | | TransferCharacteristics::Bt202012bit => rec709_to_linear(v), |
641 | 0 | TransferCharacteristics::Unspecified => 0f64, |
642 | 0 | TransferCharacteristics::Bt470M => gamma2p2_to_linear(v), |
643 | 0 | TransferCharacteristics::Bt470Bg => gamma2p8_to_linear(v), |
644 | 0 | TransferCharacteristics::Smpte240 => smpte240_to_linear(v), |
645 | 0 | TransferCharacteristics::Linear => trc_linear(v), |
646 | 0 | TransferCharacteristics::Log100 => log100_to_linear(v), |
647 | 0 | TransferCharacteristics::Log100sqrt10 => log100_sqrt10_to_linear(v), |
648 | 0 | TransferCharacteristics::Iec61966 => iec61966_to_linear(v), |
649 | 0 | TransferCharacteristics::Bt1361 => bt1361_to_linear(v), |
650 | 0 | TransferCharacteristics::Srgb => srgb_to_linear(v), |
651 | 0 | TransferCharacteristics::Smpte2084 => pq_to_linear(v), |
652 | 0 | TransferCharacteristics::Smpte428 => smpte428_to_linear(v), |
653 | 0 | TransferCharacteristics::Hlg => hlg_to_linear(v), |
654 | | } |
655 | 0 | } |
656 | | |
657 | 0 | pub fn gamma(self, v: f64) -> f64 { |
658 | 0 | match self { |
659 | 0 | TransferCharacteristics::Reserved => 0f64, |
660 | | TransferCharacteristics::Bt709 |
661 | | | TransferCharacteristics::Bt601 |
662 | | | TransferCharacteristics::Bt202010bit |
663 | 0 | | TransferCharacteristics::Bt202012bit => rec709_from_linear(v), |
664 | 0 | TransferCharacteristics::Unspecified => 0f64, |
665 | 0 | TransferCharacteristics::Bt470M => gamma2p2_from_linear(v), |
666 | 0 | TransferCharacteristics::Bt470Bg => gamma2p8_from_linear(v), |
667 | 0 | TransferCharacteristics::Smpte240 => smpte240_from_linear(v), |
668 | 0 | TransferCharacteristics::Linear => trc_linear(v), |
669 | 0 | TransferCharacteristics::Log100 => log100_from_linear(v), |
670 | 0 | TransferCharacteristics::Log100sqrt10 => log100_sqrt10_from_linear(v), |
671 | 0 | TransferCharacteristics::Iec61966 => iec61966_from_linear(v), |
672 | 0 | TransferCharacteristics::Bt1361 => bt1361_from_linear(v), |
673 | 0 | TransferCharacteristics::Srgb => srgb_from_linear(v), |
674 | 0 | TransferCharacteristics::Smpte2084 => pq_from_linear(v), |
675 | 0 | TransferCharacteristics::Smpte428 => smpte428_from_linear(v), |
676 | 0 | TransferCharacteristics::Hlg => hlg_from_linear(v), |
677 | | } |
678 | 0 | } |
679 | | |
680 | | #[cfg(feature = "extended_range")] |
681 | | pub(crate) fn extended_gamma_tristimulus(self) -> fn(Rgb<f32>) -> Rgb<f32> { |
682 | | match self { |
683 | | TransferCharacteristics::Reserved => |x| Rgb::new(x.r, x.g, x.b), |
684 | | TransferCharacteristics::Bt709 |
685 | | | TransferCharacteristics::Bt601 |
686 | | | TransferCharacteristics::Bt202010bit |
687 | | | TransferCharacteristics::Bt202012bit => |x| { |
688 | | Rgb::new( |
689 | | rec709_from_linearf_extended(x.r), |
690 | | rec709_from_linearf_extended(x.g), |
691 | | rec709_from_linearf_extended(x.b), |
692 | | ) |
693 | | }, |
694 | | TransferCharacteristics::Unspecified => |x| Rgb::new(x.r, x.g, x.b), |
695 | | TransferCharacteristics::Bt470M => |x| { |
696 | | Rgb::new( |
697 | | gamma2p2_from_linear_f(x.r), |
698 | | gamma2p2_from_linear_f(x.g), |
699 | | gamma2p2_from_linear_f(x.b), |
700 | | ) |
701 | | }, |
702 | | TransferCharacteristics::Bt470Bg => |x| { |
703 | | Rgb::new( |
704 | | gamma2p8_from_linear_f(x.r), |
705 | | gamma2p8_from_linear_f(x.g), |
706 | | gamma2p8_from_linear_f(x.b), |
707 | | ) |
708 | | }, |
709 | | TransferCharacteristics::Smpte240 => |x| { |
710 | | Rgb::new( |
711 | | smpte240_from_linearf_extended(x.r), |
712 | | smpte240_from_linearf_extended(x.g), |
713 | | smpte240_from_linearf_extended(x.b), |
714 | | ) |
715 | | }, |
716 | | TransferCharacteristics::Linear => |x| Rgb::new(x.r, x.g, x.b), |
717 | | TransferCharacteristics::Log100 => |x| { |
718 | | Rgb::new( |
719 | | log100_from_linearf(x.r), |
720 | | log100_from_linearf(x.g), |
721 | | log100_from_linearf(x.b), |
722 | | ) |
723 | | }, |
724 | | TransferCharacteristics::Log100sqrt10 => |x| { |
725 | | Rgb::new( |
726 | | log100_sqrt10_from_linearf(x.r), |
727 | | log100_sqrt10_from_linearf(x.g), |
728 | | log100_sqrt10_from_linearf(x.b), |
729 | | ) |
730 | | }, |
731 | | TransferCharacteristics::Iec61966 => |x| { |
732 | | Rgb::new( |
733 | | iec61966_from_linearf(x.r), |
734 | | iec61966_from_linearf(x.g), |
735 | | iec61966_from_linearf(x.b), |
736 | | ) |
737 | | }, |
738 | | TransferCharacteristics::Bt1361 => |x| { |
739 | | Rgb::new( |
740 | | bt1361_from_linearf(x.r), |
741 | | bt1361_from_linearf(x.g), |
742 | | bt1361_from_linearf(x.b), |
743 | | ) |
744 | | }, |
745 | | TransferCharacteristics::Srgb => |x| { |
746 | | Rgb::new( |
747 | | srgb_from_linear_extended(x.r), |
748 | | srgb_from_linear_extended(x.g), |
749 | | srgb_from_linear_extended(x.b), |
750 | | ) |
751 | | }, |
752 | | TransferCharacteristics::Smpte2084 => |x| { |
753 | | Rgb::new( |
754 | | pq_from_linearf(x.r), |
755 | | pq_from_linearf(x.g), |
756 | | pq_from_linearf(x.b), |
757 | | ) |
758 | | }, |
759 | | TransferCharacteristics::Smpte428 => |x| { |
760 | | Rgb::new( |
761 | | smpte428_from_linearf(x.r), |
762 | | smpte428_from_linearf(x.g), |
763 | | smpte428_from_linearf(x.b), |
764 | | ) |
765 | | }, |
766 | | TransferCharacteristics::Hlg => |x| { |
767 | | Rgb::new( |
768 | | hlg_from_linearf(x.r), |
769 | | hlg_from_linearf(x.g), |
770 | | hlg_from_linearf(x.b), |
771 | | ) |
772 | | }, |
773 | | } |
774 | | } |
775 | | |
776 | | #[cfg(feature = "extended_range")] |
777 | | pub(crate) fn extended_gamma_single(self) -> fn(f32) -> f32 { |
778 | | match self { |
779 | | TransferCharacteristics::Reserved => |x| x, |
780 | | TransferCharacteristics::Bt709 |
781 | | | TransferCharacteristics::Bt601 |
782 | | | TransferCharacteristics::Bt202010bit |
783 | | | TransferCharacteristics::Bt202012bit => |x| rec709_from_linearf_extended(x), |
784 | | TransferCharacteristics::Unspecified => |x| x, |
785 | | TransferCharacteristics::Bt470M => |x| gamma2p2_from_linear_f(x), |
786 | | TransferCharacteristics::Bt470Bg => |x| gamma2p8_from_linear_f(x), |
787 | | TransferCharacteristics::Smpte240 => |x| smpte240_from_linearf_extended(x), |
788 | | TransferCharacteristics::Linear => |x| x, |
789 | | TransferCharacteristics::Log100 => |x| log100_from_linearf(x), |
790 | | TransferCharacteristics::Log100sqrt10 => |x| log100_sqrt10_from_linearf(x), |
791 | | TransferCharacteristics::Iec61966 => |x| iec61966_from_linearf(x), |
792 | | TransferCharacteristics::Bt1361 => |x| bt1361_from_linearf(x), |
793 | | TransferCharacteristics::Srgb => |x| srgb_from_linear_extended(x), |
794 | | TransferCharacteristics::Smpte2084 => |x| pq_from_linearf(x), |
795 | | TransferCharacteristics::Smpte428 => |x| smpte428_from_linearf(x), |
796 | | TransferCharacteristics::Hlg => |x| hlg_from_linearf(x), |
797 | | } |
798 | | } |
799 | | |
800 | | #[cfg(feature = "extended_range")] |
801 | | pub(crate) fn extended_linear_tristimulus(self) -> fn(Rgb<f32>) -> Rgb<f32> { |
802 | | match self { |
803 | | TransferCharacteristics::Reserved => |x| Rgb::new(x.r, x.g, x.b), |
804 | | TransferCharacteristics::Bt709 |
805 | | | TransferCharacteristics::Bt601 |
806 | | | TransferCharacteristics::Bt202010bit |
807 | | | TransferCharacteristics::Bt202012bit => |x| { |
808 | | Rgb::new( |
809 | | rec709_to_linearf_extended(x.r), |
810 | | rec709_to_linearf_extended(x.g), |
811 | | rec709_to_linearf_extended(x.b), |
812 | | ) |
813 | | }, |
814 | | TransferCharacteristics::Unspecified => |x| Rgb::new(x.r, x.g, x.b), |
815 | | TransferCharacteristics::Bt470M => |x| { |
816 | | Rgb::new( |
817 | | gamma2p2_to_linear_f(x.r), |
818 | | gamma2p2_to_linear_f(x.g), |
819 | | gamma2p2_to_linear_f(x.b), |
820 | | ) |
821 | | }, |
822 | | TransferCharacteristics::Bt470Bg => |x| { |
823 | | Rgb::new( |
824 | | gamma2p8_to_linear_f(x.r), |
825 | | gamma2p8_to_linear_f(x.g), |
826 | | gamma2p8_to_linear_f(x.b), |
827 | | ) |
828 | | }, |
829 | | TransferCharacteristics::Smpte240 => |x| { |
830 | | Rgb::new( |
831 | | smpte240_to_linearf_extended(x.r), |
832 | | smpte240_to_linearf_extended(x.g), |
833 | | smpte240_to_linearf_extended(x.b), |
834 | | ) |
835 | | }, |
836 | | TransferCharacteristics::Linear => |x| Rgb::new(x.r, x.g, x.b), |
837 | | TransferCharacteristics::Log100 => |x| { |
838 | | Rgb::new( |
839 | | log100_to_linearf(x.r), |
840 | | log100_to_linearf(x.g), |
841 | | log100_to_linearf(x.b), |
842 | | ) |
843 | | }, |
844 | | TransferCharacteristics::Log100sqrt10 => |x| { |
845 | | Rgb::new( |
846 | | log100_sqrt10_to_linearf(x.r), |
847 | | log100_sqrt10_to_linearf(x.g), |
848 | | log100_sqrt10_to_linearf(x.b), |
849 | | ) |
850 | | }, |
851 | | TransferCharacteristics::Iec61966 => |x| { |
852 | | Rgb::new( |
853 | | iec61966_to_linearf(x.r), |
854 | | iec61966_to_linearf(x.g), |
855 | | iec61966_to_linearf(x.b), |
856 | | ) |
857 | | }, |
858 | | TransferCharacteristics::Bt1361 => |x| { |
859 | | Rgb::new( |
860 | | bt1361_to_linearf(x.r), |
861 | | bt1361_to_linearf(x.g), |
862 | | bt1361_to_linearf(x.b), |
863 | | ) |
864 | | }, |
865 | | TransferCharacteristics::Srgb => |x| { |
866 | | Rgb::new( |
867 | | srgb_to_linearf_extended(x.r), |
868 | | srgb_to_linearf_extended(x.g), |
869 | | srgb_to_linearf_extended(x.b), |
870 | | ) |
871 | | }, |
872 | | TransferCharacteristics::Smpte2084 => { |
873 | | |x| Rgb::new(pq_to_linearf(x.r), pq_to_linearf(x.g), pq_to_linearf(x.b)) |
874 | | } |
875 | | TransferCharacteristics::Smpte428 => |x| { |
876 | | Rgb::new( |
877 | | smpte428_to_linearf_extended(x.r), |
878 | | smpte428_to_linearf_extended(x.g), |
879 | | smpte428_to_linearf_extended(x.b), |
880 | | ) |
881 | | }, |
882 | | TransferCharacteristics::Hlg => |x| { |
883 | | Rgb::new( |
884 | | hlg_to_linearf(x.r), |
885 | | hlg_to_linearf(x.g), |
886 | | hlg_to_linearf(x.b), |
887 | | ) |
888 | | }, |
889 | | } |
890 | | } |
891 | | |
892 | | #[cfg(feature = "extended_range")] |
893 | | pub(crate) fn extended_linear_single(self) -> fn(f32) -> f32 { |
894 | | match self { |
895 | | TransferCharacteristics::Reserved => |x| x, |
896 | | TransferCharacteristics::Bt709 |
897 | | | TransferCharacteristics::Bt601 |
898 | | | TransferCharacteristics::Bt202010bit |
899 | | | TransferCharacteristics::Bt202012bit => |x| rec709_to_linearf_extended(x), |
900 | | TransferCharacteristics::Unspecified => |x| x, |
901 | | TransferCharacteristics::Bt470M => |x| gamma2p2_to_linear_f(x), |
902 | | TransferCharacteristics::Bt470Bg => |x| gamma2p8_to_linear_f(x), |
903 | | TransferCharacteristics::Smpte240 => |x| smpte240_to_linearf_extended(x), |
904 | | TransferCharacteristics::Linear => |x| x, |
905 | | TransferCharacteristics::Log100 => |x| log100_to_linearf(x), |
906 | | TransferCharacteristics::Log100sqrt10 => |x| log100_sqrt10_to_linearf(x), |
907 | | TransferCharacteristics::Iec61966 => |x| iec61966_to_linearf(x), |
908 | | TransferCharacteristics::Bt1361 => |x| bt1361_to_linearf(x), |
909 | | TransferCharacteristics::Srgb => |x| srgb_to_linearf_extended(x), |
910 | | TransferCharacteristics::Smpte2084 => |x| pq_to_linearf(x), |
911 | | TransferCharacteristics::Smpte428 => |x| smpte428_to_linearf_extended(x), |
912 | | TransferCharacteristics::Hlg => |x| hlg_to_linearf(x), |
913 | | } |
914 | | } |
915 | | |
916 | 0 | pub(crate) fn make_linear_table< |
917 | 0 | T: PointeeSizeExpressible, |
918 | 0 | const N: usize, |
919 | 0 | const BIT_DEPTH: usize, |
920 | 0 | >( |
921 | 0 | &self, |
922 | 0 | ) -> Box<[f32; N]> { |
923 | 0 | let mut gamma_table = Box::new([0f32; N]); |
924 | 0 | let max_value = if T::FINITE { |
925 | 0 | (1 << BIT_DEPTH) - 1 |
926 | | } else { |
927 | 0 | T::NOT_FINITE_LINEAR_TABLE_SIZE - 1 |
928 | | }; |
929 | 0 | let cap_values = if T::FINITE { |
930 | 0 | (1u32 << BIT_DEPTH) as usize |
931 | | } else { |
932 | 0 | T::NOT_FINITE_LINEAR_TABLE_SIZE |
933 | | }; |
934 | 0 | assert!(cap_values <= N, "Invalid lut table construction"); |
935 | 0 | let scale_value = 1f64 / max_value as f64; |
936 | 0 | for (i, g) in gamma_table.iter_mut().enumerate().take(cap_values) { |
937 | 0 | *g = self.linearize(i as f64 * scale_value) as f32; |
938 | 0 | } |
939 | 0 | gamma_table |
940 | 0 | } Unexecuted instantiation: <moxcms::cicp::TransferCharacteristics>::make_linear_table::<f64, 65536, 1> Unexecuted instantiation: <moxcms::cicp::TransferCharacteristics>::make_linear_table::<f32, 65536, 1> Unexecuted instantiation: <moxcms::cicp::TransferCharacteristics>::make_linear_table::<u8, 256, 8> Unexecuted instantiation: <moxcms::cicp::TransferCharacteristics>::make_linear_table::<u16, 65536, 16> Unexecuted instantiation: <moxcms::cicp::TransferCharacteristics>::make_linear_table::<u16, 65536, 10> Unexecuted instantiation: <moxcms::cicp::TransferCharacteristics>::make_linear_table::<u16, 65536, 12> |
941 | | |
942 | 0 | pub(crate) fn make_gamma_table< |
943 | 0 | T: Default + Copy + 'static + PointeeSizeExpressible, |
944 | 0 | const BUCKET: usize, |
945 | 0 | const N: usize, |
946 | 0 | >( |
947 | 0 | &self, |
948 | 0 | bit_depth: usize, |
949 | 0 | ) -> Box<[T; BUCKET]> |
950 | 0 | where |
951 | 0 | f32: AsPrimitive<T>, |
952 | | { |
953 | 0 | let mut table = Box::new([T::default(); BUCKET]); |
954 | 0 | let max_range = 1f64 / (N - 1) as f64; |
955 | 0 | let max_value = ((1 << bit_depth) - 1) as f64; |
956 | 0 | if T::FINITE { |
957 | 0 | for (v, output) in table.iter_mut().take(N).enumerate() { |
958 | 0 | *output = ((self.gamma(v as f64 * max_range) * max_value) as f32) |
959 | 0 | .round() |
960 | 0 | .as_(); |
961 | 0 | } |
962 | | } else { |
963 | 0 | for (v, output) in table.iter_mut().take(N).enumerate() { |
964 | 0 | *output = (self.gamma(v as f64 * max_range) as f32).as_(); |
965 | 0 | } |
966 | | } |
967 | 0 | table |
968 | 0 | } Unexecuted instantiation: <moxcms::cicp::TransferCharacteristics>::make_gamma_table::<f64, 65536, 65536> Unexecuted instantiation: <moxcms::cicp::TransferCharacteristics>::make_gamma_table::<f32, 65536, 32768> Unexecuted instantiation: <moxcms::cicp::TransferCharacteristics>::make_gamma_table::<u8, 65536, 4096> Unexecuted instantiation: <moxcms::cicp::TransferCharacteristics>::make_gamma_table::<u16, 65536, 65536> Unexecuted instantiation: <moxcms::cicp::TransferCharacteristics>::make_gamma_table::<u16, 65536, 8192> Unexecuted instantiation: <moxcms::cicp::TransferCharacteristics>::make_gamma_table::<u16, 65536, 16384> Unexecuted instantiation: <moxcms::cicp::TransferCharacteristics>::make_gamma_table::<u16, 65536, 4092> |
969 | | } |
970 | | |
971 | | #[cfg(test)] |
972 | | mod tests { |
973 | | use super::*; |
974 | | |
975 | | #[test] |
976 | | fn srgb_test() { |
977 | | let srgb_0 = srgb_to_linear(0.5); |
978 | | let srgb_1 = srgb_from_linear(srgb_0); |
979 | | assert!((0.5 - srgb_1).abs() < 1e-9f64); |
980 | | } |
981 | | |
982 | | #[test] |
983 | | fn log100_sqrt10_test() { |
984 | | let srgb_0 = log100_sqrt10_to_linear(0.5); |
985 | | let srgb_1 = log100_sqrt10_from_linear(srgb_0); |
986 | | assert_eq!(0.5, srgb_1); |
987 | | } |
988 | | |
989 | | #[test] |
990 | | fn log100_test() { |
991 | | let srgb_0 = log100_to_linear(0.5); |
992 | | let srgb_1 = log100_from_linear(srgb_0); |
993 | | assert_eq!(0.5, srgb_1); |
994 | | } |
995 | | |
996 | | #[test] |
997 | | fn iec61966_test() { |
998 | | let srgb_0 = iec61966_to_linear(0.5); |
999 | | let srgb_1 = iec61966_from_linear(srgb_0); |
1000 | | assert!((0.5 - srgb_1).abs() < 1e-9f64); |
1001 | | } |
1002 | | |
1003 | | #[test] |
1004 | | fn smpte240_test() { |
1005 | | let srgb_0 = smpte240_to_linear(0.5); |
1006 | | let srgb_1 = smpte240_from_linear(srgb_0); |
1007 | | assert!((0.5 - srgb_1).abs() < 1e-9f64); |
1008 | | } |
1009 | | |
1010 | | #[test] |
1011 | | fn smpte428_test() { |
1012 | | let srgb_0 = smpte428_to_linear(0.5); |
1013 | | let srgb_1 = smpte428_from_linear(srgb_0); |
1014 | | assert!((0.5 - srgb_1).abs() < 1e-9f64); |
1015 | | } |
1016 | | |
1017 | | #[test] |
1018 | | fn rec709_test() { |
1019 | | let srgb_0 = rec709_to_linear(0.5); |
1020 | | let srgb_1 = rec709_from_linear(srgb_0); |
1021 | | assert!((0.5 - srgb_1).abs() < 1e-9f64); |
1022 | | } |
1023 | | |
1024 | | #[cfg(feature = "extended_range")] |
1025 | | #[test] |
1026 | | fn rec709f_test() { |
1027 | | let srgb_0 = rec709_to_linearf_extended(0.5); |
1028 | | let srgb_1 = rec709_from_linearf_extended(srgb_0); |
1029 | | assert!((0.5 - srgb_1).abs() < 1e-5f32); |
1030 | | } |
1031 | | |
1032 | | #[cfg(feature = "extended_range")] |
1033 | | #[test] |
1034 | | fn srgbf_test() { |
1035 | | let srgb_0 = srgb_to_linearf_extended(0.5); |
1036 | | let srgb_1 = srgb_from_linear_extended(srgb_0); |
1037 | | assert!((0.5 - srgb_1).abs() < 1e-5f32); |
1038 | | } |
1039 | | |
1040 | | #[test] |
1041 | | fn hlg_test() { |
1042 | | let z0 = hlg_to_linear(0.5); |
1043 | | let z1 = hlg_from_linear(z0); |
1044 | | assert!((0.5 - z1).abs() < 1e-5f64); |
1045 | | } |
1046 | | |
1047 | | #[test] |
1048 | | fn pq_test() { |
1049 | | let z0 = pq_to_linear(0.5); |
1050 | | let z1 = pq_from_linear(z0); |
1051 | | assert!((0.5 - z1).abs() < 1e-5f64); |
1052 | | } |
1053 | | |
1054 | | #[test] |
1055 | | fn pqf_test() { |
1056 | | let z0 = pq_to_linearf(0.5); |
1057 | | let z1 = pq_from_linearf(z0); |
1058 | | assert!((0.5 - z1).abs() < 1e-5f32); |
1059 | | } |
1060 | | |
1061 | | #[test] |
1062 | | fn iec_test() { |
1063 | | let z0 = iec61966_to_linear(0.5); |
1064 | | let z1 = iec61966_from_linear(z0); |
1065 | | assert!((0.5 - z1).abs() < 1e-5f64); |
1066 | | } |
1067 | | |
1068 | | #[test] |
1069 | | fn bt1361_test() { |
1070 | | let z0 = bt1361_to_linear(0.5); |
1071 | | let z1 = bt1361_from_linear(z0); |
1072 | | assert!((0.5 - z1).abs() < 1e-5f64); |
1073 | | } |
1074 | | } |