Coverage Report

Created: 2025-11-05 08:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/moxcms-0.7.9/src/chad.rs
Line
Count
Source
1
/*
2
 * // Copyright (c) Radzivon Bartoshyk 2/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::matrix::{Matrix3f, Vector3f, Xyz};
30
use crate::{Chromaticity, Matrix3d, Vector3d, XyY};
31
32
pub(crate) const BRADFORD_D: Matrix3d = Matrix3d {
33
    v: [
34
        [0.8951, 0.2664, -0.1614],
35
        [-0.7502, 1.7135, 0.0367],
36
        [0.0389, -0.0685, 1.0296],
37
    ],
38
};
39
40
pub(crate) const BRADFORD_F: Matrix3f = BRADFORD_D.to_f32();
41
42
#[inline]
43
0
pub(crate) const fn compute_chromatic_adaption(
44
0
    source_white_point: Xyz,
45
0
    dest_white_point: Xyz,
46
0
    chad: Matrix3f,
47
0
) -> Matrix3f {
48
0
    let cone_source_xyz = Vector3f {
49
0
        v: [
50
0
            source_white_point.x,
51
0
            source_white_point.y,
52
0
            source_white_point.z,
53
0
        ],
54
0
    };
55
0
    let cone_source_rgb = chad.mul_vector(cone_source_xyz);
56
57
0
    let cone_dest_xyz = Vector3f {
58
0
        v: [dest_white_point.x, dest_white_point.y, dest_white_point.z],
59
0
    };
60
0
    let cone_dest_rgb = chad.mul_vector(cone_dest_xyz);
61
62
0
    let cone = Matrix3f {
63
0
        v: [
64
0
            [cone_dest_rgb.v[0] / cone_source_rgb.v[0], 0., 0.],
65
0
            [0., cone_dest_rgb.v[1] / cone_source_rgb.v[1], 0.],
66
0
            [0., 0., cone_dest_rgb.v[2] / cone_source_rgb.v[2]],
67
0
        ],
68
0
    };
69
70
0
    let chad_inv = chad.inverse();
71
72
0
    let p0 = cone.mat_mul_const(chad);
73
0
    chad_inv.mat_mul_const(p0)
74
0
}
75
76
#[inline]
77
0
pub(crate) const fn compute_chromatic_adaption_d(
78
0
    source_white_point: Xyz,
79
0
    dest_white_point: Xyz,
80
0
    chad: Matrix3d,
81
0
) -> Matrix3d {
82
0
    let cone_source_xyz = Vector3d {
83
0
        v: [
84
0
            source_white_point.x as f64,
85
0
            source_white_point.y as f64,
86
0
            source_white_point.z as f64,
87
0
        ],
88
0
    };
89
0
    let cone_source_rgb = chad.mul_vector(cone_source_xyz);
90
91
0
    let cone_dest_xyz = Vector3d {
92
0
        v: [
93
0
            dest_white_point.x as f64,
94
0
            dest_white_point.y as f64,
95
0
            dest_white_point.z as f64,
96
0
        ],
97
0
    };
98
0
    let cone_dest_rgb = chad.mul_vector(cone_dest_xyz);
99
100
0
    let cone = Matrix3d {
101
0
        v: [
102
0
            [cone_dest_rgb.v[0] / cone_source_rgb.v[0], 0., 0.],
103
0
            [0., cone_dest_rgb.v[1] / cone_source_rgb.v[1], 0.],
104
0
            [0., 0., cone_dest_rgb.v[2] / cone_source_rgb.v[2]],
105
0
        ],
106
0
    };
107
108
0
    let chad_inv = chad.inverse();
109
110
0
    let p0 = cone.mat_mul_const(chad);
111
0
    chad_inv.mat_mul_const(p0)
112
0
}
113
114
0
pub const fn adaption_matrix(source_illumination: Xyz, target_illumination: Xyz) -> Matrix3f {
115
0
    compute_chromatic_adaption(source_illumination, target_illumination, BRADFORD_F)
116
0
}
117
118
0
pub const fn adaption_matrix_d(source_illumination: Xyz, target_illumination: Xyz) -> Matrix3d {
119
0
    compute_chromatic_adaption_d(source_illumination, target_illumination, BRADFORD_D)
120
0
}
121
122
0
pub const fn adapt_to_d50(r: Matrix3f, source_white_pt: XyY) -> Matrix3f {
123
0
    adapt_to_illuminant(r, source_white_pt, Chromaticity::D50.to_xyz())
124
0
}
125
126
0
pub const fn adapt_to_d50_d(r: Matrix3d, source_white_pt: XyY) -> Matrix3d {
127
0
    adapt_to_illuminant_d(r, source_white_pt, Chromaticity::D50.to_xyz())
128
0
}
129
130
0
pub const fn adapt_to_illuminant(
131
0
    r: Matrix3f,
132
0
    source_white_pt: XyY,
133
0
    illuminant_xyz: Xyz,
134
0
) -> Matrix3f {
135
0
    let bradford = adaption_matrix(source_white_pt.to_xyz(), illuminant_xyz);
136
0
    bradford.mat_mul_const(r)
137
0
}
138
139
0
pub const fn adapt_to_illuminant_d(
140
0
    r: Matrix3d,
141
0
    source_white_pt: XyY,
142
0
    illuminant_xyz: Xyz,
143
0
) -> Matrix3d {
144
0
    let bradford = adaption_matrix_d(source_white_pt.to_xyz(), illuminant_xyz);
145
0
    bradford.mat_mul_const(r)
146
0
}
147
148
0
pub const fn adapt_to_illuminant_xyz(
149
0
    r: Matrix3f,
150
0
    source_white_pt: Xyz,
151
0
    illuminant_xyz: Xyz,
152
0
) -> Matrix3f {
153
0
    if source_white_pt.y == 0.0 {
154
0
        return r;
155
0
    }
156
157
0
    let bradford = adaption_matrix(source_white_pt, illuminant_xyz);
158
0
    bradford.mat_mul_const(r)
159
0
}
160
161
0
pub const fn adapt_to_illuminant_xyz_d(
162
0
    r: Matrix3d,
163
0
    source_white_pt: Xyz,
164
0
    illuminant_xyz: Xyz,
165
0
) -> Matrix3d {
166
0
    if source_white_pt.y == 0.0 {
167
0
        return r;
168
0
    }
169
170
0
    let bradford = adaption_matrix_d(source_white_pt, illuminant_xyz);
171
0
    bradford.mat_mul_const(r)
172
0
}