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