Coverage Report

Created: 2025-11-11 07:15

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