Coverage Report

Created: 2026-03-10 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/moxcms-0.8.1/src/helpers.rs
Line
Count
Source
1
/*
2
 * // Copyright (c) Radzivon Bartoshyk 6/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::matan::*;
30
use crate::reader::{
31
    s15_fixed16_number_to_double, uint8_number_to_float_fast, uint16_number_to_float_fast,
32
};
33
use crate::{CmsError, LutStore, Matrix3d, ToneReprCurve, Vector3d};
34
35
impl LutStore {
36
0
    pub fn to_clut_f32(&self) -> Vec<f32> {
37
0
        match self {
38
0
            LutStore::Store8(store) => store
39
0
                .iter()
40
0
                .map(|x| uint8_number_to_float_fast(*x))
41
0
                .collect(),
42
0
            LutStore::Store16(store) => store
43
0
                .iter()
44
0
                .map(|x| uint16_number_to_float_fast(*x as u32))
45
0
                .collect(),
46
        }
47
0
    }
48
49
    #[cfg(feature = "any_to_any")]
50
    pub(crate) fn is_degenerated(&self, entries: usize, channel: usize) -> bool {
51
        let start = entries * channel;
52
        let end = start + entries;
53
54
        match &self {
55
            LutStore::Store8(v) => is_curve_degenerated(&v[start..end]),
56
            LutStore::Store16(v) => is_curve_degenerated(&v[start..end]),
57
        }
58
    }
59
60
    #[cfg(feature = "any_to_any")]
61
    pub(crate) fn is_monotonic(&self, entries: usize, channel: usize) -> bool {
62
        let start = entries * channel;
63
        let end = start + entries;
64
65
        match &self {
66
            LutStore::Store8(v) => is_curve_monotonic(&v[start..end]),
67
            LutStore::Store16(v) => is_curve_monotonic(&v[start..end]),
68
        }
69
    }
70
71
    #[cfg(feature = "any_to_any")]
72
    pub(crate) fn have_discontinuities(&self, entries: usize, channel: usize) -> bool {
73
        let start = entries * channel;
74
        let end = start + entries;
75
76
        match &self {
77
            LutStore::Store8(v) => does_curve_have_discontinuity(&v[start..end]),
78
            LutStore::Store16(v) => does_curve_have_discontinuity(&v[start..end]),
79
        }
80
    }
81
82
    #[cfg(feature = "any_to_any")]
83
    #[allow(dead_code)]
84
    pub(crate) fn is_linear(&self, entries: usize, channel: usize) -> bool {
85
        let start = entries * channel;
86
        let end = start + entries;
87
88
        match &self {
89
            LutStore::Store8(v) => is_curve_linear8(&v[start..end]),
90
            LutStore::Store16(v) => is_curve_linear16(&v[start..end]),
91
        }
92
    }
93
94
    #[cfg(feature = "any_to_any")]
95
    #[allow(dead_code)]
96
    pub(crate) fn is_descending(&self, entries: usize, channel: usize) -> bool {
97
        let start = entries * channel;
98
        let end = start + entries;
99
100
        match &self {
101
            LutStore::Store8(v) => is_curve_descending(&v[start..end]),
102
            LutStore::Store16(v) => is_curve_descending(&v[start..end]),
103
        }
104
    }
105
106
    #[allow(dead_code)]
107
0
    pub(crate) fn is_ascending(&self, entries: usize, channel: usize) -> bool {
108
0
        let start = entries * channel;
109
0
        let end = start + entries;
110
111
0
        match &self {
112
0
            LutStore::Store8(v) => is_curve_ascending(&v[start..end]),
113
0
            LutStore::Store16(v) => is_curve_ascending(&v[start..end]),
114
        }
115
0
    }
116
}
117
118
impl ToneReprCurve {
119
    #[cfg(feature = "lut")]
120
0
    pub(crate) fn is_linear(&self) -> bool {
121
0
        match &self {
122
0
            ToneReprCurve::Lut(lut) => {
123
0
                if lut.is_empty() {
124
0
                    return true;
125
0
                }
126
0
                if lut.len() == 1 {
127
0
                    let gamma = 1. / crate::trc::u8_fixed_8number_to_float(lut[0]);
128
0
                    if (gamma - 1.).abs() < 1e-4 {
129
0
                        return true;
130
0
                    }
131
0
                }
132
0
                is_curve_linear16(lut)
133
            }
134
0
            ToneReprCurve::Parametric(parametric) => {
135
0
                if parametric.is_empty() {
136
0
                    return true;
137
0
                }
138
0
                if parametric.len() == 1 && parametric[0] == 1. {
139
0
                    return true;
140
0
                }
141
0
                false
142
            }
143
        }
144
0
    }
145
146
    #[cfg(feature = "any_to_any")]
147
    pub(crate) fn is_monotonic(&self) -> bool {
148
        match &self {
149
            ToneReprCurve::Lut(lut) => is_curve_monotonic(lut),
150
            ToneReprCurve::Parametric(_) => true,
151
        }
152
    }
153
154
    #[cfg(feature = "any_to_any")]
155
    pub(crate) fn is_degenerated(&self) -> bool {
156
        match &self {
157
            ToneReprCurve::Lut(lut) => is_curve_degenerated(lut),
158
            ToneReprCurve::Parametric(_) => false,
159
        }
160
    }
161
162
    #[cfg(feature = "any_to_any")]
163
    pub(crate) fn have_discontinuities(&self) -> bool {
164
        match &self {
165
            ToneReprCurve::Lut(lut) => does_curve_have_discontinuity(lut),
166
            ToneReprCurve::Parametric(_) => false,
167
        }
168
    }
169
}
170
171
0
pub(crate) fn read_matrix_3d(arr: &[u8]) -> Result<Matrix3d, CmsError> {
172
0
    if arr.len() < 36 {
173
0
        return Err(CmsError::InvalidProfile);
174
0
    }
175
176
0
    let m_tag = &arr[..36];
177
178
0
    let e00 = i32::from_be_bytes([m_tag[0], m_tag[1], m_tag[2], m_tag[3]]);
179
0
    let e01 = i32::from_be_bytes([m_tag[4], m_tag[5], m_tag[6], m_tag[7]]);
180
0
    let e02 = i32::from_be_bytes([m_tag[8], m_tag[9], m_tag[10], m_tag[11]]);
181
182
0
    let e10 = i32::from_be_bytes([m_tag[12], m_tag[13], m_tag[14], m_tag[15]]);
183
0
    let e11 = i32::from_be_bytes([m_tag[16], m_tag[17], m_tag[18], m_tag[19]]);
184
0
    let e12 = i32::from_be_bytes([m_tag[20], m_tag[21], m_tag[22], m_tag[23]]);
185
186
0
    let e20 = i32::from_be_bytes([m_tag[24], m_tag[25], m_tag[26], m_tag[27]]);
187
0
    let e21 = i32::from_be_bytes([m_tag[28], m_tag[29], m_tag[30], m_tag[31]]);
188
0
    let e22 = i32::from_be_bytes([m_tag[32], m_tag[33], m_tag[34], m_tag[35]]);
189
190
0
    Ok(Matrix3d {
191
0
        v: [
192
0
            [
193
0
                s15_fixed16_number_to_double(e00),
194
0
                s15_fixed16_number_to_double(e01),
195
0
                s15_fixed16_number_to_double(e02),
196
0
            ],
197
0
            [
198
0
                s15_fixed16_number_to_double(e10),
199
0
                s15_fixed16_number_to_double(e11),
200
0
                s15_fixed16_number_to_double(e12),
201
0
            ],
202
0
            [
203
0
                s15_fixed16_number_to_double(e20),
204
0
                s15_fixed16_number_to_double(e21),
205
0
                s15_fixed16_number_to_double(e22),
206
0
            ],
207
0
        ],
208
0
    })
209
0
}
210
211
0
pub(crate) fn read_vector_3d(arr: &[u8]) -> Result<Vector3d, CmsError> {
212
0
    if arr.len() < 12 {
213
0
        return Err(CmsError::InvalidProfile);
214
0
    }
215
216
0
    let m_tag = &arr[..12];
217
218
0
    let b0 = i32::from_be_bytes([m_tag[0], m_tag[1], m_tag[2], m_tag[3]]);
219
0
    let b1 = i32::from_be_bytes([m_tag[4], m_tag[5], m_tag[6], m_tag[7]]);
220
0
    let b2 = i32::from_be_bytes([m_tag[8], m_tag[9], m_tag[10], m_tag[11]]);
221
222
0
    Ok(Vector3d {
223
0
        v: [
224
0
            s15_fixed16_number_to_double(b0),
225
0
            s15_fixed16_number_to_double(b1),
226
0
            s15_fixed16_number_to_double(b2),
227
0
        ],
228
0
    })
229
0
}