/src/libjpeg-turbo.main/jclossls.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * jclossls.c |
3 | | * |
4 | | * This file was part of the Independent JPEG Group's software: |
5 | | * Copyright (C) 1998, Thomas G. Lane. |
6 | | * Lossless JPEG Modifications: |
7 | | * Copyright (C) 1999, Ken Murchison. |
8 | | * libjpeg-turbo Modifications: |
9 | | * Copyright (C) 2022, D. R. Commander. |
10 | | * For conditions of distribution and use, see the accompanying README.ijg |
11 | | * file. |
12 | | * |
13 | | * This file contains prediction, sample differencing, and point transform |
14 | | * routines for the lossless JPEG compressor. |
15 | | */ |
16 | | |
17 | | #define JPEG_INTERNALS |
18 | | #include "jinclude.h" |
19 | | #include "jpeglib.h" |
20 | | #include "jlossls.h" |
21 | | |
22 | | #ifdef C_LOSSLESS_SUPPORTED |
23 | | |
24 | | |
25 | | /************************** Sample differencing **************************/ |
26 | | |
27 | | /* |
28 | | * In order to avoid a performance penalty for checking which predictor is |
29 | | * being used and which row is being processed for each call of the |
30 | | * undifferencer, and to promote optimization, we have separate differencing |
31 | | * functions for each predictor selection value. |
32 | | * |
33 | | * We are able to avoid duplicating source code by implementing the predictors |
34 | | * and differencers as macros. Each of the differencing functions is simply a |
35 | | * wrapper around a DIFFERENCE macro with the appropriate PREDICTOR macro |
36 | | * passed as an argument. |
37 | | */ |
38 | | |
39 | | /* Forward declarations */ |
40 | | LOCAL(void) reset_predictor(j_compress_ptr cinfo, int ci); |
41 | | |
42 | | |
43 | | /* Predictor for the first column of the first row: 2^(P-Pt-1) */ |
44 | | #define INITIAL_PREDICTORx (1 << (cinfo->data_precision - cinfo->Al - 1)) |
45 | | |
46 | | /* Predictor for the first column of the remaining rows: Rb */ |
47 | | #define INITIAL_PREDICTOR2 prev_row[0] |
48 | | |
49 | | |
50 | | /* |
51 | | * 1-Dimensional differencer routine. |
52 | | * |
53 | | * This macro implements the 1-D horizontal predictor (1). INITIAL_PREDICTOR |
54 | | * is used as the special case predictor for the first column, which must be |
55 | | * either INITIAL_PREDICTOR2 or INITIAL_PREDICTORx. The remaining samples |
56 | | * use PREDICTOR1. |
57 | | */ |
58 | | |
59 | | #define DIFFERENCE_1D(INITIAL_PREDICTOR) \ |
60 | 0 | lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; \ |
61 | 0 | boolean restart = FALSE; \ |
62 | 0 | int samp, Ra; \ |
63 | 0 | \ |
64 | 0 | samp = *input_buf++; \ |
65 | 0 | *diff_buf++ = samp - INITIAL_PREDICTOR; \ |
66 | 0 | \ |
67 | 0 | while (--width) { \ |
68 | 0 | Ra = samp; \ |
69 | 0 | samp = *input_buf++; \ |
70 | 0 | *diff_buf++ = samp - PREDICTOR1; \ |
71 | 0 | } \ |
72 | 0 | \ |
73 | 0 | /* Account for restart interval (no-op if not using restarts) */ \ |
74 | 0 | if (cinfo->restart_interval) { \ |
75 | 0 | if (--(losslessc->restart_rows_to_go[ci]) == 0) { \ |
76 | 0 | reset_predictor(cinfo, ci); \ |
77 | 0 | restart = TRUE; \ |
78 | 0 | } \ |
79 | 0 | } |
80 | | |
81 | | |
82 | | /* |
83 | | * 2-Dimensional differencer routine. |
84 | | * |
85 | | * This macro implements the 2-D horizontal predictors (#2-7). PREDICTOR2 is |
86 | | * used as the special case predictor for the first column. The remaining |
87 | | * samples use PREDICTOR, which is a function of Ra, Rb, and Rc. |
88 | | * |
89 | | * Because prev_row and output_buf may point to the same storage area (in an |
90 | | * interleaved image with Vi=1, for example), we must take care to buffer Rb/Rc |
91 | | * before writing the current reconstructed sample value into output_buf. |
92 | | */ |
93 | | |
94 | | #define DIFFERENCE_2D(PREDICTOR) \ |
95 | 0 | lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; \ |
96 | 0 | int samp, Ra, Rb, Rc; \ |
97 | 0 | \ |
98 | 0 | Rb = *prev_row++; \ |
99 | 0 | samp = *input_buf++; \ |
100 | 0 | *diff_buf++ = samp - PREDICTOR2; \ |
101 | 0 | \ |
102 | 0 | while (--width) { \ |
103 | 0 | Rc = Rb; \ |
104 | 0 | Rb = *prev_row++; \ |
105 | 0 | Ra = samp; \ |
106 | 0 | samp = *input_buf++; \ |
107 | 0 | *diff_buf++ = samp - PREDICTOR; \ |
108 | 0 | } \ |
109 | 0 | \ |
110 | 0 | /* Account for restart interval (no-op if not using restarts) */ \ |
111 | 0 | if (cinfo->restart_interval) { \ |
112 | 0 | if (--losslessc->restart_rows_to_go[ci] == 0) \ |
113 | 0 | reset_predictor(cinfo, ci); \ |
114 | 0 | } |
115 | | |
116 | | |
117 | | /* |
118 | | * Differencers for the second and subsequent rows in a scan or restart |
119 | | * interval. The first sample in the row is differenced using the vertical |
120 | | * predictor (2). The rest of the samples are differenced using the predictor |
121 | | * specified in the scan header. |
122 | | */ |
123 | | |
124 | | METHODDEF(void) |
125 | | jpeg_difference1(j_compress_ptr cinfo, int ci, |
126 | | _JSAMPROW input_buf, _JSAMPROW prev_row, |
127 | | JDIFFROW diff_buf, JDIMENSION width) |
128 | 0 | { |
129 | 0 | DIFFERENCE_1D(INITIAL_PREDICTOR2); |
130 | 0 | (void)(restart); |
131 | 0 | } |
132 | | |
133 | | METHODDEF(void) |
134 | | jpeg_difference2(j_compress_ptr cinfo, int ci, |
135 | | _JSAMPROW input_buf, _JSAMPROW prev_row, |
136 | | JDIFFROW diff_buf, JDIMENSION width) |
137 | 0 | { |
138 | 0 | DIFFERENCE_2D(PREDICTOR2); |
139 | 0 | (void)(Ra); |
140 | 0 | (void)(Rc); |
141 | 0 | } |
142 | | |
143 | | METHODDEF(void) |
144 | | jpeg_difference3(j_compress_ptr cinfo, int ci, |
145 | | _JSAMPROW input_buf, _JSAMPROW prev_row, |
146 | | JDIFFROW diff_buf, JDIMENSION width) |
147 | 0 | { |
148 | 0 | DIFFERENCE_2D(PREDICTOR3); |
149 | 0 | (void)(Ra); |
150 | 0 | } |
151 | | |
152 | | METHODDEF(void) |
153 | | jpeg_difference4(j_compress_ptr cinfo, int ci, |
154 | | _JSAMPROW input_buf, _JSAMPROW prev_row, |
155 | | JDIFFROW diff_buf, JDIMENSION width) |
156 | 0 | { |
157 | 0 | DIFFERENCE_2D(PREDICTOR4); |
158 | 0 | } |
159 | | |
160 | | METHODDEF(void) |
161 | | jpeg_difference5(j_compress_ptr cinfo, int ci, |
162 | | _JSAMPROW input_buf, _JSAMPROW prev_row, |
163 | | JDIFFROW diff_buf, JDIMENSION width) |
164 | 0 | { |
165 | 0 | DIFFERENCE_2D(PREDICTOR5); |
166 | 0 | } |
167 | | |
168 | | METHODDEF(void) |
169 | | jpeg_difference6(j_compress_ptr cinfo, int ci, |
170 | | _JSAMPROW input_buf, _JSAMPROW prev_row, |
171 | | JDIFFROW diff_buf, JDIMENSION width) |
172 | 0 | { |
173 | 0 | DIFFERENCE_2D(PREDICTOR6); |
174 | 0 | } |
175 | | |
176 | | METHODDEF(void) |
177 | | jpeg_difference7(j_compress_ptr cinfo, int ci, |
178 | | _JSAMPROW input_buf, _JSAMPROW prev_row, |
179 | | JDIFFROW diff_buf, JDIMENSION width) |
180 | 0 | { |
181 | 0 | DIFFERENCE_2D(PREDICTOR7); |
182 | 0 | (void)(Rc); |
183 | 0 | } |
184 | | |
185 | | |
186 | | /* |
187 | | * Differencer for the first row in a scan or restart interval. The first |
188 | | * sample in the row is differenced using the special predictor constant |
189 | | * x = 2 ^ (P-Pt-1). The rest of the samples are differenced using the |
190 | | * 1-D horizontal predictor (1). |
191 | | */ |
192 | | |
193 | | METHODDEF(void) |
194 | | jpeg_difference_first_row(j_compress_ptr cinfo, int ci, |
195 | | _JSAMPROW input_buf, _JSAMPROW prev_row, |
196 | | JDIFFROW diff_buf, JDIMENSION width) |
197 | 0 | { |
198 | 0 | DIFFERENCE_1D(INITIAL_PREDICTORx); |
199 | | |
200 | | /* |
201 | | * Now that we have differenced the first row, we want to use the |
202 | | * differencer that corresponds to the predictor specified in the |
203 | | * scan header. |
204 | | * |
205 | | * Note that we don't do this if we have just reset the predictor |
206 | | * for a new restart interval. |
207 | | */ |
208 | 0 | if (!restart) { |
209 | 0 | switch (cinfo->Ss) { |
210 | 0 | case 1: |
211 | 0 | losslessc->predict_difference[ci] = jpeg_difference1; |
212 | 0 | break; |
213 | 0 | case 2: |
214 | 0 | losslessc->predict_difference[ci] = jpeg_difference2; |
215 | 0 | break; |
216 | 0 | case 3: |
217 | 0 | losslessc->predict_difference[ci] = jpeg_difference3; |
218 | 0 | break; |
219 | 0 | case 4: |
220 | 0 | losslessc->predict_difference[ci] = jpeg_difference4; |
221 | 0 | break; |
222 | 0 | case 5: |
223 | 0 | losslessc->predict_difference[ci] = jpeg_difference5; |
224 | 0 | break; |
225 | 0 | case 6: |
226 | 0 | losslessc->predict_difference[ci] = jpeg_difference6; |
227 | 0 | break; |
228 | 0 | case 7: |
229 | 0 | losslessc->predict_difference[ci] = jpeg_difference7; |
230 | 0 | break; |
231 | 0 | } |
232 | 0 | } |
233 | 0 | } |
234 | | |
235 | | /* |
236 | | * Reset predictor at the start of a pass or restart interval. |
237 | | */ |
238 | | |
239 | | LOCAL(void) |
240 | | reset_predictor(j_compress_ptr cinfo, int ci) |
241 | 0 | { |
242 | 0 | lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; |
243 | | |
244 | | /* Initialize restart counter */ |
245 | 0 | losslessc->restart_rows_to_go[ci] = |
246 | 0 | cinfo->restart_interval / cinfo->MCUs_per_row; |
247 | | |
248 | | /* Set difference function to first row function */ |
249 | 0 | losslessc->predict_difference[ci] = jpeg_difference_first_row; |
250 | 0 | } |
251 | | |
252 | | |
253 | | /********************** Sample downscaling by 2^Pt ***********************/ |
254 | | |
255 | | METHODDEF(void) |
256 | | simple_downscale(j_compress_ptr cinfo, |
257 | | _JSAMPROW input_buf, _JSAMPROW output_buf, JDIMENSION width) |
258 | 0 | { |
259 | 0 | do { |
260 | 0 | *output_buf++ = (_JSAMPLE)RIGHT_SHIFT(*input_buf++, cinfo->Al); |
261 | 0 | } while (--width); |
262 | 0 | } |
263 | | |
264 | | |
265 | | METHODDEF(void) |
266 | | noscale(j_compress_ptr cinfo, |
267 | | _JSAMPROW input_buf, _JSAMPROW output_buf, JDIMENSION width) |
268 | 0 | { |
269 | 0 | memcpy(output_buf, input_buf, width * sizeof(_JSAMPLE)); |
270 | 0 | } |
271 | | |
272 | | |
273 | | /* |
274 | | * Initialize for a processing pass. |
275 | | */ |
276 | | |
277 | | METHODDEF(void) |
278 | | start_pass_lossless(j_compress_ptr cinfo) |
279 | 0 | { |
280 | 0 | lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; |
281 | 0 | int ci; |
282 | | |
283 | | /* Set scaler function based on Pt */ |
284 | 0 | if (cinfo->Al) |
285 | 0 | losslessc->scaler_scale = simple_downscale; |
286 | 0 | else |
287 | 0 | losslessc->scaler_scale = noscale; |
288 | | |
289 | | /* Check that the restart interval is an integer multiple of the number |
290 | | * of MCUs in an MCU row. |
291 | | */ |
292 | 0 | if (cinfo->restart_interval % cinfo->MCUs_per_row != 0) |
293 | 0 | ERREXIT2(cinfo, JERR_BAD_RESTART, |
294 | 0 | cinfo->restart_interval, cinfo->MCUs_per_row); |
295 | | |
296 | | /* Set predictors for start of pass */ |
297 | 0 | for (ci = 0; ci < cinfo->num_components; ci++) |
298 | 0 | reset_predictor(cinfo, ci); |
299 | 0 | } |
300 | | |
301 | | |
302 | | /* |
303 | | * Initialize the lossless compressor. |
304 | | */ |
305 | | |
306 | | GLOBAL(void) |
307 | | _jinit_lossless_compressor(j_compress_ptr cinfo) |
308 | 0 | { |
309 | 0 | lossless_comp_ptr losslessc; |
310 | | |
311 | | /* Create subobject in permanent pool */ |
312 | 0 | losslessc = (lossless_comp_ptr) |
313 | 0 | (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT, |
314 | 0 | sizeof(jpeg_lossless_compressor)); |
315 | 0 | cinfo->fdct = (struct jpeg_forward_dct *)losslessc; |
316 | 0 | losslessc->pub.start_pass = start_pass_lossless; |
317 | 0 | } Unexecuted instantiation: j12init_lossless_compressor Unexecuted instantiation: j16init_lossless_compressor Unexecuted instantiation: jinit_lossless_compressor |
318 | | |
319 | | #endif /* C_LOSSLESS_SUPPORTED */ |