jclossls.c (8895B)
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 lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; \ 61 boolean restart = FALSE; \ 62 int samp, Ra; \ 63 \ 64 samp = *input_buf++; \ 65 *diff_buf++ = samp - INITIAL_PREDICTOR; \ 66 \ 67 while (--width) { \ 68 Ra = samp; \ 69 samp = *input_buf++; \ 70 *diff_buf++ = samp - PREDICTOR1; \ 71 } \ 72 \ 73 /* Account for restart interval (no-op if not using restarts) */ \ 74 if (cinfo->restart_interval) { \ 75 if (--(losslessc->restart_rows_to_go[ci]) == 0) { \ 76 reset_predictor(cinfo, ci); \ 77 restart = TRUE; \ 78 } \ 79 } 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 lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; \ 96 int samp, Ra, Rb, Rc; \ 97 \ 98 Rb = *prev_row++; \ 99 samp = *input_buf++; \ 100 *diff_buf++ = samp - PREDICTOR2; \ 101 \ 102 while (--width) { \ 103 Rc = Rb; \ 104 Rb = *prev_row++; \ 105 Ra = samp; \ 106 samp = *input_buf++; \ 107 *diff_buf++ = samp - PREDICTOR; \ 108 } \ 109 \ 110 /* Account for restart interval (no-op if not using restarts) */ \ 111 if (cinfo->restart_interval) { \ 112 if (--losslessc->restart_rows_to_go[ci] == 0) \ 113 reset_predictor(cinfo, ci); \ 114 } 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 { 129 DIFFERENCE_1D(INITIAL_PREDICTOR2); 130 (void)(restart); 131 } 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 { 138 DIFFERENCE_2D(PREDICTOR2); 139 (void)(Ra); 140 (void)(Rc); 141 } 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 { 148 DIFFERENCE_2D(PREDICTOR3); 149 (void)(Ra); 150 } 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 { 157 DIFFERENCE_2D(PREDICTOR4); 158 } 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 { 165 DIFFERENCE_2D(PREDICTOR5); 166 } 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 { 173 DIFFERENCE_2D(PREDICTOR6); 174 } 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 { 181 DIFFERENCE_2D(PREDICTOR7); 182 (void)(Rc); 183 } 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 { 198 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 if (!restart) { 209 switch (cinfo->Ss) { 210 case 1: 211 losslessc->predict_difference[ci] = jpeg_difference1; 212 break; 213 case 2: 214 losslessc->predict_difference[ci] = jpeg_difference2; 215 break; 216 case 3: 217 losslessc->predict_difference[ci] = jpeg_difference3; 218 break; 219 case 4: 220 losslessc->predict_difference[ci] = jpeg_difference4; 221 break; 222 case 5: 223 losslessc->predict_difference[ci] = jpeg_difference5; 224 break; 225 case 6: 226 losslessc->predict_difference[ci] = jpeg_difference6; 227 break; 228 case 7: 229 losslessc->predict_difference[ci] = jpeg_difference7; 230 break; 231 } 232 } 233 } 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 { 242 lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; 243 244 /* Initialize restart counter */ 245 losslessc->restart_rows_to_go[ci] = 246 cinfo->restart_interval / cinfo->MCUs_per_row; 247 248 /* Set difference function to first row function */ 249 losslessc->predict_difference[ci] = jpeg_difference_first_row; 250 } 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 { 259 do { 260 *output_buf++ = (_JSAMPLE)RIGHT_SHIFT(*input_buf++, cinfo->Al); 261 } while (--width); 262 } 263 264 265 METHODDEF(void) 266 noscale(j_compress_ptr cinfo, 267 _JSAMPROW input_buf, _JSAMPROW output_buf, JDIMENSION width) 268 { 269 memcpy(output_buf, input_buf, width * sizeof(_JSAMPLE)); 270 } 271 272 273 /* 274 * Initialize for a processing pass. 275 */ 276 277 METHODDEF(void) 278 start_pass_lossless(j_compress_ptr cinfo) 279 { 280 lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; 281 int ci; 282 283 /* Set scaler function based on Pt */ 284 if (cinfo->Al) 285 losslessc->scaler_scale = simple_downscale; 286 else 287 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 if (cinfo->restart_interval % cinfo->MCUs_per_row != 0) 293 ERREXIT2(cinfo, JERR_BAD_RESTART, 294 cinfo->restart_interval, cinfo->MCUs_per_row); 295 296 /* Set predictors for start of pass */ 297 for (ci = 0; ci < cinfo->num_components; ci++) 298 reset_predictor(cinfo, ci); 299 } 300 301 302 /* 303 * Initialize the lossless compressor. 304 */ 305 306 GLOBAL(void) 307 _jinit_lossless_compressor(j_compress_ptr cinfo) 308 { 309 lossless_comp_ptr losslessc; 310 311 /* Create subobject in permanent pool */ 312 losslessc = (lossless_comp_ptr) 313 (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT, 314 sizeof(jpeg_lossless_compressor)); 315 cinfo->fdct = (struct jpeg_forward_dct *)losslessc; 316 losslessc->pub.start_pass = start_pass_lossless; 317 } 318 319 #endif /* C_LOSSLESS_SUPPORTED */