dicom_toolkit_codec/jpeg_ls/
params.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum InterleaveMode {
6 None = 0,
8 Line = 1,
10 Sample = 2,
12}
13
14impl InterleaveMode {
15 pub fn from_u8(v: u8) -> Option<Self> {
16 match v {
17 0 => Some(Self::None),
18 1 => Some(Self::Line),
19 2 => Some(Self::Sample),
20 _ => None,
21 }
22 }
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum ColorTransform {
28 None = 0,
29 Hp1 = 1,
31 Hp2 = 2,
33 Hp3 = 3,
35}
36
37impl ColorTransform {
38 pub fn from_u8(v: u8) -> Option<Self> {
39 match v {
40 0 => Some(Self::None),
41 1 => Some(Self::Hp1),
42 2 => Some(Self::Hp2),
43 3 => Some(Self::Hp3),
44 _ => None,
45 }
46 }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
51pub struct JlsCustomParameters {
52 pub max_val: i32,
53 pub t1: i32,
54 pub t2: i32,
55 pub t3: i32,
56 pub reset: i32,
57}
58
59#[derive(Debug, Clone)]
61pub struct JlsParameters {
62 pub width: u32,
63 pub height: u32,
64 pub bits_per_sample: u8,
65 pub components: u8,
66 pub near: i32,
68 pub interleave: InterleaveMode,
69 pub color_transform: ColorTransform,
70 pub custom: JlsCustomParameters,
71}
72
73impl Default for JlsParameters {
74 fn default() -> Self {
75 Self {
76 width: 0,
77 height: 0,
78 bits_per_sample: 8,
79 components: 1,
80 near: 0,
81 interleave: InterleaveMode::None,
82 color_transform: ColorTransform::None,
83 custom: JlsCustomParameters::default(),
84 }
85 }
86}
87
88const BASIC_T1: i32 = 3;
90const BASIC_T2: i32 = 7;
91const BASIC_T3: i32 = 21;
92
93pub const BASIC_RESET: i32 = 64;
95
96fn clamp(val: i32, lo: i32, hi: i32) -> i32 {
97 if val > hi || val < lo {
98 lo
99 } else {
100 val
101 }
102}
103
104pub fn compute_default(max_val: i32, near: i32) -> JlsCustomParameters {
108 let factor = (max_val.min(4095) + 128) / 256;
109
110 let t1 = clamp(factor * (BASIC_T1 - 2) + 2 + 3 * near, near + 1, max_val);
111 let t2 = clamp(factor * (BASIC_T2 - 3) + 3 + 5 * near, t1, max_val);
112 let t3 = clamp(factor * (BASIC_T3 - 4) + 4 + 7 * near, t2, max_val);
113
114 JlsCustomParameters {
115 max_val,
116 t1,
117 t2,
118 t3,
119 reset: BASIC_RESET,
120 }
121}
122
123#[derive(Debug, Clone, Copy)]
125pub struct DerivedTraits {
126 pub max_val: i32,
127 pub near: i32,
128 pub range: i32,
129 pub bpp: i32,
130 pub qbpp: i32,
131 pub limit: i32,
132 pub reset: i32,
133}
134
135impl DerivedTraits {
136 pub fn new(max_val: i32, near: i32, reset: i32) -> Self {
137 let range = (max_val + 2 * near) / (2 * near + 1) + 1;
138 let bpp = log2_ceil(max_val);
139 let qbpp = log2_ceil(range);
140 let limit = 2 * (bpp + bpp.max(8));
141 Self {
142 max_val,
143 near,
144 range,
145 bpp,
146 qbpp,
147 limit,
148 reset,
149 }
150 }
151
152 #[inline]
154 pub fn quantize_error(&self, e: i32) -> i32 {
155 if self.near == 0 {
156 return e;
157 }
158 if e > 0 {
159 (e + self.near) / (2 * self.near + 1)
160 } else {
161 -(self.near - e) / (2 * self.near + 1)
162 }
163 }
164
165 #[inline]
167 pub fn mod_range(&self, mut err: i32) -> i32 {
168 if err < 0 {
169 err += self.range;
170 }
171 if err >= (self.range + 1) / 2 {
172 err -= self.range;
173 }
174 err
175 }
176
177 #[inline]
179 pub fn compute_error_val(&self, e: i32) -> i32 {
180 self.mod_range(self.quantize_error(e))
181 }
182
183 #[inline]
185 pub fn dequantize(&self, err: i32) -> i32 {
186 err * (2 * self.near + 1)
187 }
188
189 #[inline]
191 pub fn compute_reconstructed(&self, px: i32, err: i32) -> i32 {
192 let val = px + self.dequantize(err);
193 self.fix_reconstructed(val)
194 }
195
196 fn fix_reconstructed(&self, mut val: i32) -> i32 {
197 if val < -self.near {
198 val += self.range * (2 * self.near + 1);
199 } else if val > self.max_val + self.near {
200 val -= self.range * (2 * self.near + 1);
201 }
202 self.correct_prediction(val)
203 }
204
205 #[inline]
207 pub fn correct_prediction(&self, pxc: i32) -> i32 {
208 if (pxc & self.max_val) == pxc {
209 pxc
210 } else {
211 (!(pxc >> 31)) & self.max_val
212 }
213 }
214}
215
216fn log2_ceil(n: i32) -> i32 {
218 let mut x = 0;
219 while n > (1i32 << x) {
220 x += 1;
221 }
222 x
223}
224
225#[cfg(test)]
228mod tests {
229 use super::*;
230
231 #[test]
232 fn default_thresholds_8bit() {
233 let p = compute_default(255, 0);
234 assert_eq!(p.t1, 3);
235 assert_eq!(p.t2, 7);
236 assert_eq!(p.t3, 21);
237 assert_eq!(p.reset, 64);
238 assert_eq!(p.max_val, 255);
239 }
240
241 #[test]
242 fn default_thresholds_12bit() {
243 let p = compute_default(4095, 0);
244 assert_eq!(p.t1, 18);
245 assert_eq!(p.t2, 67);
246 assert_eq!(p.t3, 276);
247 assert_eq!(p.reset, 64);
248 }
249
250 #[test]
251 fn default_thresholds_16bit() {
252 let p = compute_default(65535, 0);
253 assert_eq!(p.t1, 18);
255 assert_eq!(p.t2, 67);
256 assert_eq!(p.t3, 276);
257 }
258
259 #[test]
260 fn default_thresholds_near_lossless() {
261 let p = compute_default(255, 2);
262 assert_eq!(p.t1, 9);
264 assert_eq!(p.t2, 17);
266 assert_eq!(p.t3, 35);
268 }
269
270 #[test]
271 fn derived_traits_lossless_8bit() {
272 let t = DerivedTraits::new(255, 0, BASIC_RESET);
273 assert_eq!(t.range, 256);
274 assert_eq!(t.bpp, 8);
275 assert_eq!(t.qbpp, 8); assert_eq!(t.limit, 32);
277 }
278
279 #[test]
280 fn derived_traits_near_lossless() {
281 let t = DerivedTraits::new(255, 2, BASIC_RESET);
282 assert_eq!(t.range, 52);
284 assert_eq!(t.bpp, 8);
285 assert_eq!(t.qbpp, 6); }
287
288 #[test]
289 fn log2_ceil_values() {
290 assert_eq!(log2_ceil(1), 0);
291 assert_eq!(log2_ceil(2), 1);
292 assert_eq!(log2_ceil(255), 8);
293 assert_eq!(log2_ceil(256), 8);
294 assert_eq!(log2_ceil(257), 9);
295 assert_eq!(log2_ceil(4095), 12);
296 assert_eq!(log2_ceil(65535), 16);
297 }
298
299 #[test]
300 fn mod_range_lossless_8bit() {
301 let t = DerivedTraits::new(255, 0, BASIC_RESET);
302 assert_eq!(t.mod_range(0), 0);
303 assert_eq!(t.mod_range(1), 1);
304 assert_eq!(t.mod_range(127), 127);
305 assert_eq!(t.mod_range(128), -128);
306 assert_eq!(t.mod_range(-1), -1);
307 assert_eq!(t.mod_range(-128), -128);
308 }
309
310 #[test]
311 fn correct_prediction_clamps() {
312 let t = DerivedTraits::new(255, 0, BASIC_RESET);
313 assert_eq!(t.correct_prediction(100), 100);
314 assert_eq!(t.correct_prediction(0), 0);
315 assert_eq!(t.correct_prediction(255), 255);
316 assert_eq!(t.correct_prediction(300), 255); assert_eq!(t.correct_prediction(-1), 0); }
319}