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