Coverage Report

Created: 2025-12-20 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/moxcms-0.7.11/src/defaults.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::chad::BRADFORD_D;
30
use crate::cicp::create_rec709_parametric;
31
use crate::trc::{ToneReprCurve, curve_from_gamma};
32
use crate::{
33
    CicpColorPrimaries, CicpProfile, ColorPrimaries, ColorProfile, DataColorSpace,
34
    LocalizableString, LutMultidimensionalType, LutWarehouse, Matrix3d, MatrixCoefficients,
35
    ProfileClass, ProfileText, RenderingIntent, TransferCharacteristics, Vector3, XyY,
36
};
37
use pxfm::{copysignk, exp, floor, pow};
38
39
/// From lcms: `cmsWhitePointFromTemp`
40
/// tempK must be >= 4000. and <= 25000.
41
/// Invalid values of tempK will return
42
/// (x,y,Y) = (-1.0, -1.0, -1.0)
43
/// similar to argyll: `icx_DTEMP2XYZ()`
44
0
const fn white_point_from_temperature(temp_k: i32) -> XyY {
45
0
    let mut white_point = XyY {
46
0
        x: 0.,
47
0
        y: 0.,
48
0
        yb: 0.,
49
0
    };
50
    // No optimization provided.
51
0
    let temp_k = temp_k as f64; // Square
52
0
    let temp_k2 = temp_k * temp_k; // Cube
53
0
    let temp_k3 = temp_k2 * temp_k;
54
    // For correlated color temperature (T) between 4000K and 7000K:
55
0
    let x = if temp_k > 4000.0 && temp_k <= 7000.0 {
56
0
        -4.6070 * (1E9 / temp_k3) + 2.9678 * (1E6 / temp_k2) + 0.09911 * (1E3 / temp_k) + 0.244063
57
0
    } else if temp_k > 7000.0 && temp_k <= 25000.0 {
58
0
        -2.0064 * (1E9 / temp_k3) + 1.9018 * (1E6 / temp_k2) + 0.24748 * (1E3 / temp_k) + 0.237040
59
    } else {
60
        // or for correlated color temperature (T) between 7000K and 25000K:
61
        // Invalid tempK
62
0
        white_point.x = -1.0;
63
0
        white_point.y = -1.0;
64
0
        white_point.yb = -1.0;
65
0
        debug_assert!(false, "invalid temp");
66
0
        return white_point;
67
    };
68
    // Obtain y(x)
69
0
    let y = -3.000 * (x * x) + 2.870 * x - 0.275;
70
    // wave factors (not used, but here for futures extensions)
71
    // let M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y);
72
    // let M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y);
73
    // Fill white_point struct
74
0
    white_point.x = x;
75
0
    white_point.y = y;
76
0
    white_point.yb = 1.0;
77
0
    white_point
78
0
}
79
80
pub const WHITE_POINT_D50: XyY = white_point_from_temperature(5003);
81
pub const WHITE_POINT_D60: XyY = white_point_from_temperature(6000);
82
pub const WHITE_POINT_D65: XyY = white_point_from_temperature(6504);
83
pub const WHITE_POINT_DCI_P3: XyY = white_point_from_temperature(6300);
84
85
// https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2100-2-201807-I!!PDF-F.pdf
86
// Perceptual Quantization / SMPTE standard ST.2084
87
#[inline]
88
0
const fn pq_curve(x: f64) -> f64 {
89
    const M1: f64 = 2610.0 / 16384.0;
90
    const M2: f64 = (2523.0 / 4096.0) * 128.0;
91
    const C1: f64 = 3424.0 / 4096.0;
92
    const C2: f64 = (2413.0 / 4096.0) * 32.0;
93
    const C3: f64 = (2392.0 / 4096.0) * 32.0;
94
95
0
    if x == 0.0 {
96
0
        return 0.0;
97
0
    }
98
0
    let sign = x;
99
0
    let x = x.abs();
100
101
0
    let xpo = pow(x, 1.0 / M2);
102
0
    let num = (xpo - C1).max(0.0);
103
0
    let den = C2 - C3 * xpo;
104
0
    let res = pow(num / den, 1.0 / M1);
105
106
0
    copysignk(res, sign)
107
0
}
108
109
0
pub(crate) const fn build_trc_table_pq() -> [u16; 4096] {
110
0
    let mut table = [0u16; 4096];
111
112
    const NUM_ENTRIES: usize = 4096;
113
0
    let mut i = 0usize;
114
0
    while i < NUM_ENTRIES {
115
0
        let x: f64 = i as f64 / (NUM_ENTRIES - 1) as f64;
116
0
        let y: f64 = pq_curve(x);
117
        let mut output: f64;
118
0
        output = y * 65535.0 + 0.5;
119
0
        if output > 65535.0 {
120
0
            output = 65535.0
121
0
        }
122
0
        if output < 0.0 {
123
0
            output = 0.0
124
0
        }
125
0
        table[i] = floor(output) as u16;
126
0
        i += 1;
127
    }
128
0
    table
129
0
}
130
131
0
pub(crate) const fn build_trc_table_hlg() -> [u16; 4096] {
132
0
    let mut table = [0u16; 4096];
133
134
    const NUM_ENTRIES: usize = 4096;
135
0
    let mut i = 0usize;
136
0
    while i < NUM_ENTRIES {
137
0
        let x: f64 = i as f64 / (NUM_ENTRIES - 1) as f64;
138
0
        let y: f64 = hlg_curve(x);
139
        let mut output: f64;
140
0
        output = y * 65535.0 + 0.5;
141
0
        if output > 65535.0 {
142
0
            output = 65535.0
143
0
        }
144
0
        if output < 0.0 {
145
0
            output = 0.0
146
0
        }
147
0
        table[i] = floor(output) as u16;
148
0
        i += 1;
149
    }
150
0
    table
151
0
}
152
153
// https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2100-2-201807-I!!PDF-F.pdf
154
// Hybrid Log-Gamma
155
0
const fn hlg_curve(x: f64) -> f64 {
156
    const BETA: f64 = 0.04;
157
    const RA: f64 = 5.591816309728916; // 1.0 / A where A = 0.17883277
158
    const B: f64 = 0.28466892; // 1.0 - 4.0 * A
159
    const C: f64 = 0.5599107295; // 0,5 –aln(4a)
160
161
0
    let e = (x * (1.0 - BETA) + BETA).max(0.0);
162
163
0
    if e == 0.0 {
164
0
        return 0.0;
165
0
    }
166
167
0
    let sign = e.abs();
168
169
0
    let res = if e <= 0.5 {
170
0
        e * e / 3.0
171
    } else {
172
0
        (exp((e - C) * RA) + B) / 12.0
173
    };
174
175
0
    copysignk(res, sign)
176
0
}
177
178
/// Perceptual Quantizer Lookup table
179
pub const PQ_LUT_TABLE: [u16; 4096] = build_trc_table_pq();
180
/// Hybrid Log Gamma Lookup table
181
pub const HLG_LUT_TABLE: [u16; 4096] = build_trc_table_hlg();
182
183
impl ColorProfile {
184
    const SRGB_COLORANTS: Matrix3d =
185
        ColorProfile::colorants_matrix(WHITE_POINT_D65, ColorPrimaries::BT_709);
186
187
    const DISPLAY_P3_COLORANTS: Matrix3d =
188
        ColorProfile::colorants_matrix(WHITE_POINT_D65, ColorPrimaries::SMPTE_432);
189
190
    const ADOBE_RGB_COLORANTS: Matrix3d =
191
        ColorProfile::colorants_matrix(WHITE_POINT_D65, ColorPrimaries::ADOBE_RGB);
192
193
    const DCI_P3_COLORANTS: Matrix3d =
194
        ColorProfile::colorants_matrix(WHITE_POINT_DCI_P3, ColorPrimaries::DCI_P3);
195
196
    const PRO_PHOTO_RGB_COLORANTS: Matrix3d =
197
        ColorProfile::colorants_matrix(WHITE_POINT_D50, ColorPrimaries::PRO_PHOTO_RGB);
198
199
    const BT2020_COLORANTS: Matrix3d =
200
        ColorProfile::colorants_matrix(WHITE_POINT_D65, ColorPrimaries::BT_2020);
201
202
    const ACES_2065_1_COLORANTS: Matrix3d =
203
        ColorProfile::colorants_matrix(WHITE_POINT_D60, ColorPrimaries::ACES_2065_1);
204
205
    const ACES_CG_COLORANTS: Matrix3d =
206
        ColorProfile::colorants_matrix(WHITE_POINT_D60, ColorPrimaries::ACES_CG);
207
208
    #[inline]
209
0
    fn basic_rgb_profile() -> ColorProfile {
210
0
        ColorProfile {
211
0
            profile_class: ProfileClass::DisplayDevice,
212
0
            rendering_intent: RenderingIntent::Perceptual,
213
0
            color_space: DataColorSpace::Rgb,
214
0
            pcs: DataColorSpace::Xyz,
215
0
            chromatic_adaptation: Some(BRADFORD_D),
216
0
            white_point: WHITE_POINT_D50.to_xyzd(),
217
0
            ..Default::default()
218
0
        }
219
0
    }
220
221
    /// Creates new profile from CICP
222
0
    pub fn new_from_cicp(cicp_color_primaries: CicpProfile) -> ColorProfile {
223
0
        let mut basic = ColorProfile::basic_rgb_profile();
224
0
        basic.update_rgb_colorimetry_from_cicp(cicp_color_primaries);
225
0
        basic
226
0
    }
227
228
    /// Creates new sRGB profile
229
0
    pub fn new_srgb() -> ColorProfile {
230
0
        let mut profile = ColorProfile::basic_rgb_profile();
231
0
        profile.update_colorants(ColorProfile::SRGB_COLORANTS);
232
233
0
        let curve =
234
0
            ToneReprCurve::Parametric(vec![2.4, 1. / 1.055, 0.055 / 1.055, 1. / 12.92, 0.04045]);
235
0
        profile.red_trc = Some(curve.clone());
236
0
        profile.blue_trc = Some(curve.clone());
237
0
        profile.green_trc = Some(curve);
238
0
        profile.media_white_point = Some(WHITE_POINT_D65.to_xyzd());
239
0
        profile.cicp = Some(CicpProfile {
240
0
            color_primaries: CicpColorPrimaries::Bt709,
241
0
            transfer_characteristics: TransferCharacteristics::Srgb,
242
0
            matrix_coefficients: MatrixCoefficients::Bt709,
243
0
            full_range: false,
244
0
        });
245
0
        profile.description = Some(ProfileText::Localizable(vec![LocalizableString::new(
246
0
            "en".to_string(),
247
0
            "US".to_string(),
248
0
            "sRGB IEC61966-2.1".to_string(),
249
0
        )]));
250
0
        profile.copyright = Some(ProfileText::Localizable(vec![LocalizableString::new(
251
0
            "en".to_string(),
252
0
            "US".to_string(),
253
0
            "Public Domain".to_string(),
254
0
        )]));
255
0
        profile
256
0
    }
257
258
    /// Creates new Adobe RGB profile
259
0
    pub fn new_adobe_rgb() -> ColorProfile {
260
0
        let mut profile = ColorProfile::basic_rgb_profile();
261
0
        profile.update_colorants(ColorProfile::ADOBE_RGB_COLORANTS);
262
263
0
        let curve = curve_from_gamma(2.19921875f32);
264
0
        profile.red_trc = Some(curve.clone());
265
0
        profile.blue_trc = Some(curve.clone());
266
0
        profile.green_trc = Some(curve);
267
0
        profile.media_white_point = Some(WHITE_POINT_D65.to_xyzd());
268
0
        profile.white_point = WHITE_POINT_D50.to_xyzd();
269
0
        profile.description = Some(ProfileText::Localizable(vec![LocalizableString::new(
270
0
            "en".to_string(),
271
0
            "US".to_string(),
272
0
            "Adobe RGB 1998".to_string(),
273
0
        )]));
274
0
        profile.copyright = Some(ProfileText::Localizable(vec![LocalizableString::new(
275
0
            "en".to_string(),
276
0
            "US".to_string(),
277
0
            "Public Domain".to_string(),
278
0
        )]));
279
0
        profile
280
0
    }
281
282
    /// Creates new Display P3 profile
283
0
    pub fn new_display_p3() -> ColorProfile {
284
0
        let mut profile = ColorProfile::basic_rgb_profile();
285
0
        profile.update_colorants(ColorProfile::DISPLAY_P3_COLORANTS);
286
287
0
        let curve =
288
0
            ToneReprCurve::Parametric(vec![2.4, 1. / 1.055, 0.055 / 1.055, 1. / 12.92, 0.04045]);
289
0
        profile.red_trc = Some(curve.clone());
290
0
        profile.blue_trc = Some(curve.clone());
291
0
        profile.green_trc = Some(curve);
292
0
        profile.media_white_point = Some(WHITE_POINT_D65.to_xyzd());
293
0
        profile.cicp = Some(CicpProfile {
294
0
            color_primaries: CicpColorPrimaries::Smpte431,
295
0
            transfer_characteristics: TransferCharacteristics::Srgb,
296
0
            matrix_coefficients: MatrixCoefficients::Bt709,
297
0
            full_range: false,
298
0
        });
299
0
        profile.description = Some(ProfileText::Localizable(vec![LocalizableString::new(
300
0
            "en".to_string(),
301
0
            "US".to_string(),
302
0
            "Display P3".to_string(),
303
0
        )]));
304
0
        profile.copyright = Some(ProfileText::Localizable(vec![LocalizableString::new(
305
0
            "en".to_string(),
306
0
            "US".to_string(),
307
0
            "Public Domain".to_string(),
308
0
        )]));
309
0
        profile
310
0
    }
311
312
    /// Creates new Display P3 PQ profile
313
0
    pub fn new_display_p3_pq() -> ColorProfile {
314
0
        let mut profile = ColorProfile::basic_rgb_profile();
315
0
        profile.update_colorants(ColorProfile::DISPLAY_P3_COLORANTS);
316
317
0
        let curve = ToneReprCurve::Lut(PQ_LUT_TABLE.to_vec());
318
319
0
        profile.red_trc = Some(curve.clone());
320
0
        profile.blue_trc = Some(curve.clone());
321
0
        profile.green_trc = Some(curve);
322
0
        profile.media_white_point = Some(WHITE_POINT_D65.to_xyzd());
323
0
        profile.cicp = Some(CicpProfile {
324
0
            color_primaries: CicpColorPrimaries::Smpte431,
325
0
            transfer_characteristics: TransferCharacteristics::Smpte2084,
326
0
            matrix_coefficients: MatrixCoefficients::Bt709,
327
0
            full_range: false,
328
0
        });
329
0
        profile.description = Some(ProfileText::Localizable(vec![LocalizableString::new(
330
0
            "en".to_string(),
331
0
            "US".to_string(),
332
0
            "Display P3 PQ".to_string(),
333
0
        )]));
334
0
        profile.copyright = Some(ProfileText::Localizable(vec![LocalizableString::new(
335
0
            "en".to_string(),
336
0
            "US".to_string(),
337
0
            "Public Domain".to_string(),
338
0
        )]));
339
0
        profile
340
0
    }
341
342
    /// Creates new DCI P3 profile
343
0
    pub fn new_dci_p3() -> ColorProfile {
344
0
        let mut profile = ColorProfile::basic_rgb_profile();
345
0
        profile.update_colorants(ColorProfile::DCI_P3_COLORANTS);
346
347
0
        let curve = curve_from_gamma(2.6f32);
348
0
        profile.red_trc = Some(curve.clone());
349
0
        profile.blue_trc = Some(curve.clone());
350
0
        profile.green_trc = Some(curve);
351
0
        profile.media_white_point = Some(WHITE_POINT_DCI_P3.to_xyzd());
352
0
        profile.cicp = Some(CicpProfile {
353
0
            color_primaries: CicpColorPrimaries::Smpte432,
354
0
            transfer_characteristics: TransferCharacteristics::Srgb,
355
0
            matrix_coefficients: MatrixCoefficients::Bt709,
356
0
            full_range: false,
357
0
        });
358
0
        profile.description = Some(ProfileText::Localizable(vec![LocalizableString::new(
359
0
            "en".to_string(),
360
0
            "US".to_string(),
361
0
            "DCI P3".to_string(),
362
0
        )]));
363
0
        profile.copyright = Some(ProfileText::Localizable(vec![LocalizableString::new(
364
0
            "en".to_string(),
365
0
            "US".to_string(),
366
0
            "Public Domain".to_string(),
367
0
        )]));
368
0
        profile
369
0
    }
370
371
    /// Creates new ProPhoto RGB profile
372
0
    pub fn new_pro_photo_rgb() -> ColorProfile {
373
0
        let mut profile = ColorProfile::basic_rgb_profile();
374
0
        profile.update_colorants(ColorProfile::PRO_PHOTO_RGB_COLORANTS);
375
376
0
        let curve = curve_from_gamma(1.8f32);
377
0
        profile.red_trc = Some(curve.clone());
378
0
        profile.blue_trc = Some(curve.clone());
379
0
        profile.green_trc = Some(curve);
380
0
        profile.media_white_point = Some(WHITE_POINT_D50.to_xyzd());
381
0
        profile.description = Some(ProfileText::Localizable(vec![LocalizableString::new(
382
0
            "en".to_string(),
383
0
            "US".to_string(),
384
0
            "ProPhoto RGB".to_string(),
385
0
        )]));
386
0
        profile.copyright = Some(ProfileText::Localizable(vec![LocalizableString::new(
387
0
            "en".to_string(),
388
0
            "US".to_string(),
389
0
            "Public Domain".to_string(),
390
0
        )]));
391
0
        profile
392
0
    }
393
394
    /// Creates new Bt.2020 profile
395
0
    pub fn new_bt2020() -> ColorProfile {
396
0
        let mut profile = ColorProfile::basic_rgb_profile();
397
0
        profile.update_colorants(ColorProfile::BT2020_COLORANTS);
398
399
0
        let curve = ToneReprCurve::Parametric(create_rec709_parametric().to_vec());
400
0
        profile.red_trc = Some(curve.clone());
401
0
        profile.blue_trc = Some(curve.clone());
402
0
        profile.green_trc = Some(curve);
403
0
        profile.media_white_point = Some(WHITE_POINT_D65.to_xyzd());
404
0
        profile.description = Some(ProfileText::Localizable(vec![LocalizableString::new(
405
0
            "en".to_string(),
406
0
            "US".to_string(),
407
0
            "Rec.2020".to_string(),
408
0
        )]));
409
0
        profile.copyright = Some(ProfileText::Localizable(vec![LocalizableString::new(
410
0
            "en".to_string(),
411
0
            "US".to_string(),
412
0
            "Public Domain".to_string(),
413
0
        )]));
414
0
        profile
415
0
    }
416
417
    /// Creates new Bt.2020 PQ profile
418
0
    pub fn new_bt2020_pq() -> ColorProfile {
419
0
        let mut profile = ColorProfile::basic_rgb_profile();
420
0
        profile.update_colorants(ColorProfile::BT2020_COLORANTS);
421
422
0
        let curve = ToneReprCurve::Lut(PQ_LUT_TABLE.to_vec());
423
424
0
        profile.red_trc = Some(curve.clone());
425
0
        profile.blue_trc = Some(curve.clone());
426
0
        profile.green_trc = Some(curve);
427
0
        profile.media_white_point = Some(WHITE_POINT_D65.to_xyzd());
428
0
        profile.cicp = Some(CicpProfile {
429
0
            color_primaries: CicpColorPrimaries::Bt2020,
430
0
            transfer_characteristics: TransferCharacteristics::Smpte2084,
431
0
            matrix_coefficients: MatrixCoefficients::Bt709,
432
0
            full_range: false,
433
0
        });
434
0
        profile.description = Some(ProfileText::Localizable(vec![LocalizableString::new(
435
0
            "en".to_string(),
436
0
            "US".to_string(),
437
0
            "Rec.2020 PQ".to_string(),
438
0
        )]));
439
0
        profile.copyright = Some(ProfileText::Localizable(vec![LocalizableString::new(
440
0
            "en".to_string(),
441
0
            "US".to_string(),
442
0
            "Public Domain".to_string(),
443
0
        )]));
444
0
        profile
445
0
    }
446
447
    /// Creates new Bt.2020 HLG profile
448
0
    pub fn new_bt2020_hlg() -> ColorProfile {
449
0
        let mut profile = ColorProfile::basic_rgb_profile();
450
0
        profile.update_colorants(ColorProfile::BT2020_COLORANTS);
451
452
0
        let curve = ToneReprCurve::Lut(HLG_LUT_TABLE.to_vec());
453
454
0
        profile.red_trc = Some(curve.clone());
455
0
        profile.blue_trc = Some(curve.clone());
456
0
        profile.green_trc = Some(curve);
457
0
        profile.media_white_point = Some(WHITE_POINT_D65.to_xyzd());
458
0
        profile.cicp = Some(CicpProfile {
459
0
            color_primaries: CicpColorPrimaries::Bt2020,
460
0
            transfer_characteristics: TransferCharacteristics::Hlg,
461
0
            matrix_coefficients: MatrixCoefficients::Bt709,
462
0
            full_range: false,
463
0
        });
464
0
        profile.description = Some(ProfileText::Localizable(vec![LocalizableString::new(
465
0
            "en".to_string(),
466
0
            "US".to_string(),
467
0
            "Rec.2020 HLG".to_string(),
468
0
        )]));
469
0
        profile.copyright = Some(ProfileText::Localizable(vec![LocalizableString::new(
470
0
            "en".to_string(),
471
0
            "US".to_string(),
472
0
            "Public Domain".to_string(),
473
0
        )]));
474
0
        profile
475
0
    }
476
477
    /// Creates new Monochrome profile
478
0
    pub fn new_gray_with_gamma(gamma: f32) -> ColorProfile {
479
0
        ColorProfile {
480
0
            gray_trc: Some(curve_from_gamma(gamma)),
481
0
            profile_class: ProfileClass::DisplayDevice,
482
0
            rendering_intent: RenderingIntent::Perceptual,
483
0
            color_space: DataColorSpace::Gray,
484
0
            media_white_point: Some(WHITE_POINT_D65.to_xyzd()),
485
0
            white_point: WHITE_POINT_D50.to_xyzd(),
486
0
            chromatic_adaptation: Some(BRADFORD_D),
487
0
            copyright: Some(ProfileText::Localizable(vec![LocalizableString::new(
488
0
                "en".to_string(),
489
0
                "US".to_string(),
490
0
                "Public Domain".to_string(),
491
0
            )])),
492
0
            ..Default::default()
493
0
        }
494
0
    }
495
496
    /// Creates new ACES 2065-1/AP0 profile
497
0
    pub fn new_aces_aces_2065_1_linear() -> ColorProfile {
498
0
        let mut profile = ColorProfile::basic_rgb_profile();
499
0
        profile.update_colorants(ColorProfile::ACES_2065_1_COLORANTS);
500
501
0
        let curve = ToneReprCurve::Lut(vec![]);
502
0
        profile.red_trc = Some(curve.clone());
503
0
        profile.blue_trc = Some(curve.clone());
504
0
        profile.green_trc = Some(curve);
505
0
        profile.media_white_point = Some(WHITE_POINT_D60.to_xyzd());
506
0
        profile.description = Some(ProfileText::Localizable(vec![LocalizableString::new(
507
0
            "en".to_string(),
508
0
            "US".to_string(),
509
0
            "ACES 2065-1".to_string(),
510
0
        )]));
511
0
        profile.copyright = Some(ProfileText::Localizable(vec![LocalizableString::new(
512
0
            "en".to_string(),
513
0
            "US".to_string(),
514
0
            "Public Domain".to_string(),
515
0
        )]));
516
0
        profile
517
0
    }
518
519
    /// Creates new ACEScg profile
520
0
    pub fn new_aces_cg_linear() -> ColorProfile {
521
0
        let mut profile = ColorProfile::basic_rgb_profile();
522
0
        profile.update_colorants(ColorProfile::ACES_CG_COLORANTS);
523
524
0
        let curve = ToneReprCurve::Lut(vec![]);
525
0
        profile.red_trc = Some(curve.clone());
526
0
        profile.blue_trc = Some(curve.clone());
527
0
        profile.green_trc = Some(curve);
528
0
        profile.media_white_point = Some(WHITE_POINT_D60.to_xyzd());
529
0
        profile.description = Some(ProfileText::Localizable(vec![LocalizableString::new(
530
0
            "en".to_string(),
531
0
            "US".to_string(),
532
0
            "ACEScg/AP1".to_string(),
533
0
        )]));
534
0
        profile.copyright = Some(ProfileText::Localizable(vec![LocalizableString::new(
535
0
            "en".to_string(),
536
0
            "US".to_string(),
537
0
            "Public Domain".to_string(),
538
0
        )]));
539
0
        profile
540
0
    }
541
542
    /// Creates new Generic CIE LAB profile
543
0
    pub fn new_lab() -> ColorProfile {
544
0
        let mut profile = ColorProfile {
545
0
            profile_class: ProfileClass::DisplayDevice,
546
0
            rendering_intent: RenderingIntent::Perceptual,
547
0
            color_space: DataColorSpace::Lab,
548
0
            pcs: DataColorSpace::Xyz,
549
0
            chromatic_adaptation: Some(BRADFORD_D),
550
0
            white_point: WHITE_POINT_D50.to_xyzd(),
551
0
            media_white_point: Some(WHITE_POINT_D65.to_xyzd()),
552
0
            ..Default::default()
553
0
        };
554
555
0
        let b_to_a_lut = LutWarehouse::Multidimensional(LutMultidimensionalType {
556
0
            num_input_channels: 3,
557
0
            num_output_channels: 3,
558
0
            grid_points: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
559
0
            clut: None,
560
0
            b_curves: vec![
561
0
                ToneReprCurve::Lut(vec![]),
562
0
                ToneReprCurve::Lut(vec![]),
563
0
                ToneReprCurve::Lut(vec![]),
564
0
            ],
565
0
            matrix: Matrix3d::IDENTITY,
566
0
            a_curves: vec![],
567
0
            m_curves: vec![],
568
0
            bias: Vector3::default(),
569
0
        });
570
0
        profile.lut_b_to_a_perceptual = Some(b_to_a_lut.clone());
571
0
        profile.lut_b_to_a_colorimetric = Some(b_to_a_lut);
572
573
0
        let a_to_b = LutWarehouse::Multidimensional(LutMultidimensionalType {
574
0
            num_input_channels: 3,
575
0
            num_output_channels: 3,
576
0
            grid_points: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
577
0
            clut: None,
578
0
            b_curves: vec![
579
0
                ToneReprCurve::Lut(vec![]),
580
0
                ToneReprCurve::Lut(vec![]),
581
0
                ToneReprCurve::Lut(vec![]),
582
0
            ],
583
0
            matrix: Matrix3d::IDENTITY,
584
0
            a_curves: vec![],
585
0
            m_curves: vec![],
586
0
            bias: Vector3::default(),
587
0
        });
588
0
        profile.lut_a_to_b_colorimetric = Some(a_to_b.clone());
589
0
        profile.lut_a_to_b_perceptual = Some(a_to_b);
590
591
0
        profile.description = Some(ProfileText::Localizable(vec![LocalizableString::new(
592
0
            "en".to_string(),
593
0
            "US".to_string(),
594
0
            "Generic L*a*b* Profile".to_string(),
595
0
        )]));
596
0
        profile.copyright = Some(ProfileText::Localizable(vec![LocalizableString::new(
597
0
            "en".to_string(),
598
0
            "US".to_string(),
599
0
            "Public Domain".to_string(),
600
0
        )]));
601
602
0
        profile
603
0
    }
604
}