1use crate::matan::*;
30use crate::reader::{
31 s15_fixed16_number_to_double, uint8_number_to_float_fast, uint16_number_to_float_fast,
32};
33use crate::{CmsError, LutStore, Matrix3d, ToneReprCurve, Vector3d};
34
35impl LutStore {
36 pub fn to_clut_f32(&self) -> Vec<f32> {
37 match self {
38 LutStore::Store8(store) => store
39 .iter()
40 .map(|x| uint8_number_to_float_fast(*x))
41 .collect(),
42 LutStore::Store16(store) => store
43 .iter()
44 .map(|x| uint16_number_to_float_fast(*x as u32))
45 .collect(),
46 }
47 }
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 pub(crate) fn is_ascending(&self, entries: usize, channel: usize) -> bool {
108 let start = entries * channel;
109 let end = start + entries;
110
111 match &self {
112 LutStore::Store8(v) => is_curve_ascending(&v[start..end]),
113 LutStore::Store16(v) => is_curve_ascending(&v[start..end]),
114 }
115 }
116}
117
118impl ToneReprCurve {
119 #[cfg(feature = "lut")]
120 pub(crate) fn is_linear(&self) -> bool {
121 match &self {
122 ToneReprCurve::Lut(lut) => {
123 if lut.is_empty() {
124 return true;
125 }
126 if lut.len() == 1 {
127 let gamma = 1. / crate::trc::u8_fixed_8number_to_float(lut[0]);
128 if (gamma - 1.).abs() < 1e-4 {
129 return true;
130 }
131 }
132 is_curve_linear16(lut)
133 }
134 ToneReprCurve::Parametric(parametric) => {
135 if parametric.is_empty() {
136 return true;
137 }
138 if parametric.len() == 1 && parametric[0] == 1. {
139 return true;
140 }
141 false
142 }
143 }
144 }
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
171pub(crate) fn read_matrix_3d(arr: &[u8]) -> Result<Matrix3d, CmsError> {
172 if arr.len() < 36 {
173 return Err(CmsError::InvalidProfile);
174 }
175
176 let m_tag = &arr[..36];
177
178 let e00 = i32::from_be_bytes([m_tag[0], m_tag[1], m_tag[2], m_tag[3]]);
179 let e01 = i32::from_be_bytes([m_tag[4], m_tag[5], m_tag[6], m_tag[7]]);
180 let e02 = i32::from_be_bytes([m_tag[8], m_tag[9], m_tag[10], m_tag[11]]);
181
182 let e10 = i32::from_be_bytes([m_tag[12], m_tag[13], m_tag[14], m_tag[15]]);
183 let e11 = i32::from_be_bytes([m_tag[16], m_tag[17], m_tag[18], m_tag[19]]);
184 let e12 = i32::from_be_bytes([m_tag[20], m_tag[21], m_tag[22], m_tag[23]]);
185
186 let e20 = i32::from_be_bytes([m_tag[24], m_tag[25], m_tag[26], m_tag[27]]);
187 let e21 = i32::from_be_bytes([m_tag[28], m_tag[29], m_tag[30], m_tag[31]]);
188 let e22 = i32::from_be_bytes([m_tag[32], m_tag[33], m_tag[34], m_tag[35]]);
189
190 Ok(Matrix3d {
191 v: [
192 [
193 s15_fixed16_number_to_double(e00),
194 s15_fixed16_number_to_double(e01),
195 s15_fixed16_number_to_double(e02),
196 ],
197 [
198 s15_fixed16_number_to_double(e10),
199 s15_fixed16_number_to_double(e11),
200 s15_fixed16_number_to_double(e12),
201 ],
202 [
203 s15_fixed16_number_to_double(e20),
204 s15_fixed16_number_to_double(e21),
205 s15_fixed16_number_to_double(e22),
206 ],
207 ],
208 })
209}
210
211pub(crate) fn read_vector_3d(arr: &[u8]) -> Result<Vector3d, CmsError> {
212 if arr.len() < 12 {
213 return Err(CmsError::InvalidProfile);
214 }
215
216 let m_tag = &arr[..12];
217
218 let b0 = i32::from_be_bytes([m_tag[0], m_tag[1], m_tag[2], m_tag[3]]);
219 let b1 = i32::from_be_bytes([m_tag[4], m_tag[5], m_tag[6], m_tag[7]]);
220 let b2 = i32::from_be_bytes([m_tag[8], m_tag[9], m_tag[10], m_tag[11]]);
221
222 Ok(Vector3d {
223 v: [
224 s15_fixed16_number_to_double(b0),
225 s15_fixed16_number_to_double(b1),
226 s15_fixed16_number_to_double(b2),
227 ],
228 })
229}