dicom_toolkit_codec/jpeg_ls/
context.rs1#[derive(Debug, Clone)]
10pub struct JlsContext {
11 pub a: i32,
13 pub b: i32,
15 pub c: i8,
17 pub n: i16,
19}
20
21static TABLE_C: [i8; 256] = {
24 let mut table = [0i8; 256];
25 let mut i = 0;
27 while i < 127 {
28 table[i] = 1;
29 i += 1;
30 }
31 table[127] = 0;
33 table[128] = 0;
35 let mut i = 129;
37 while i < 256 {
38 table[i] = -1;
39 i += 1;
40 }
41 table
42};
43
44impl JlsContext {
45 pub fn new(a_init: i32) -> Self {
47 Self {
48 a: a_init,
49 b: 0,
50 c: 0,
51 n: 1,
52 }
53 }
54
55 #[inline]
57 pub fn get_golomb(&self) -> i32 {
58 let mut k = 0;
59 let mut ntest = self.n as i32;
60 while ntest < self.a {
61 k += 1;
62 ntest <<= 1;
63 }
64 k
65 }
66
67 #[inline]
69 pub fn get_error_correction(&self, k: i32) -> i32 {
70 if k != 0 {
71 0
72 } else if 2 * self.b <= -(self.n as i32) {
73 1
74 } else {
75 0
76 }
77 }
78
79 #[inline]
82 pub fn update_variables(&mut self, err_val: i32, near: i32, reset_value: i32) {
83 self.a += (if err_val < 0 { -err_val } else { err_val }) - (self.near_correction(near));
84 self.b += err_val * (2 * near + 1);
85 self.adjust_bias(reset_value);
86 }
87
88 #[inline]
90 fn near_correction(&self, _near: i32) -> i32 {
91 0
94 }
95
96 fn adjust_bias(&mut self, reset_value: i32) {
98 let n = self.n as i32;
99
100 if self.b + n <= 0 {
101 self.b += n;
102 if self.b <= -n {
103 self.b = -n + 1;
104 }
105 let idx = ((self.b.wrapping_div(n.max(1)) + 128) as usize).min(255);
107 self.c = self.c.wrapping_add(TABLE_C[idx]);
108 self.c = self.c.max(-128);
109 } else if self.b > 0 {
110 self.b -= n;
111 if self.b > 0 {
112 self.b = 0;
113 }
114 let idx = ((self.b.wrapping_div(n.max(1)) + 128) as usize).min(255);
115 self.c = self.c.wrapping_add(TABLE_C[idx]);
116 }
117
118 self.n += 1;
119 if self.n as i32 == reset_value {
120 self.a >>= 1;
121 self.b >>= 1;
122 self.n >>= 1;
123 if self.n == 0 {
125 self.n = 1;
126 }
127 }
128 }
129}
130
131#[derive(Debug, Clone)]
138pub struct RunModeContext {
139 pub a: i32,
141 pub n: i32,
143 pub nn: i32,
145 pub ri_type: i32,
147 pub reset: i32,
149}
150
151impl RunModeContext {
152 pub fn new(a_init: i32, reset: i32) -> Self {
153 Self {
154 a: a_init,
155 n: 1,
156 nn: 0,
157 ri_type: 0,
158 reset,
159 }
160 }
161
162 #[inline]
164 pub fn get_golomb(&self) -> i32 {
165 let mut k = 0;
166 let mut ntest = self.n;
167 while ntest < self.a {
168 k += 1;
169 ntest <<= 1;
170 }
171 k
172 }
173
174 #[inline]
176 pub fn compute_map(&self, err_val: i32, k: i32) -> i32 {
177 if (k == 0 && err_val > 0 && 2 * self.nn < self.n)
178 || (err_val < 0 && (2 * self.nn >= self.n || k != 0))
179 {
180 1
181 } else {
182 0
183 }
184 }
185
186 pub fn compute_map_negative_e(&self, k: i32) -> bool {
188 k != 0 || 2 * self.nn >= self.n
189 }
190
191 pub fn update_variables(&mut self, err_val: i32, e_mapped: i32) {
193 if err_val < 0 {
194 self.nn += 1;
195 }
196 self.a += (e_mapped + 1 - self.ri_type) >> 1;
197 self.n += 1;
198
199 if self.n == self.reset {
200 self.a >>= 1;
201 self.n >>= 1;
202 self.nn >>= 1;
203 if self.n == 0 {
204 self.n = 1;
205 }
206 }
207 }
208}
209
210#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn initial_golomb_parameter() {
218 let ctx = JlsContext::new(4);
220 assert_eq!(ctx.get_golomb(), 2);
221 }
222
223 #[test]
224 fn golomb_k_zero() {
225 let ctx = JlsContext {
227 a: 1,
228 b: 0,
229 c: 0,
230 n: 2,
231 };
232 assert_eq!(ctx.get_golomb(), 0);
233 }
234
235 #[test]
236 fn error_correction_at_k_zero() {
237 let ctx = JlsContext {
239 a: 1,
240 b: -5,
241 c: 0,
242 n: 2,
243 };
244 assert_eq!(ctx.get_error_correction(0), 1);
245
246 let ctx2 = JlsContext {
248 a: 1,
249 b: 0,
250 c: 0,
251 n: 2,
252 };
253 assert_eq!(ctx2.get_error_correction(0), 0);
254
255 assert_eq!(ctx.get_error_correction(1), 0);
257 }
258
259 #[test]
260 fn update_variables_accumulates() {
261 let mut ctx = JlsContext::new(4);
262 ctx.update_variables(3, 0, 64);
263 assert_eq!(ctx.a, 7); ctx.update_variables(-2, 0, 64);
265 assert_eq!(ctx.a, 9); }
267
268 #[test]
269 fn counter_halving_at_reset() {
270 let mut ctx = JlsContext::new(100);
271 ctx.n = 63; ctx.a = 200;
273 ctx.b = 10;
274 ctx.update_variables(5, 0, 64);
275 assert!(ctx.n <= 32);
277 assert!(ctx.a <= 103); }
279
280 #[test]
281 fn run_mode_context_golomb() {
282 let ctx = RunModeContext::new(4, 64);
283 assert_eq!(ctx.get_golomb(), 2);
284 }
285
286 #[test]
287 fn run_mode_update() {
288 let mut ctx = RunModeContext::new(1, 64);
289 ctx.update_variables(-1, 2);
290 assert_eq!(ctx.nn, 1);
291 assert!(ctx.n > 1);
292 }
293}