jcdiffct.c (14840B)
1 /* 2 * jcdiffct.c 3 * 4 * This file was part of the Independent JPEG Group's software: 5 * Copyright (C) 1994-1997, 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 the difference buffer controller for compression. 14 * This controller is the top level of the lossless JPEG compressor proper. 15 * The difference buffer lies between the prediction/differencing and entropy 16 * encoding steps. 17 */ 18 19 #define JPEG_INTERNALS 20 #include "jinclude.h" 21 #include "jpeglib.h" 22 #include "jlossls.h" /* Private declarations for lossless codec */ 23 24 25 #ifdef C_LOSSLESS_SUPPORTED 26 27 /* We use a full-image sample buffer when doing Huffman optimization, 28 * and also for writing multiple-scan JPEG files. In all cases, the 29 * full-image buffer is filled during the first pass, and the scaling, 30 * prediction and differencing steps are run during subsequent passes. 31 */ 32 #ifdef ENTROPY_OPT_SUPPORTED 33 #define FULL_SAMP_BUFFER_SUPPORTED 34 #else 35 #ifdef C_MULTISCAN_FILES_SUPPORTED 36 #define FULL_SAMP_BUFFER_SUPPORTED 37 #endif 38 #endif 39 40 41 /* Private buffer controller object */ 42 43 typedef struct { 44 struct jpeg_c_coef_controller pub; /* public fields */ 45 46 JDIMENSION iMCU_row_num; /* iMCU row # within image */ 47 JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ 48 int MCU_vert_offset; /* counts MCU rows within iMCU row */ 49 int MCU_rows_per_iMCU_row; /* number of such rows needed */ 50 51 _JSAMPROW cur_row[MAX_COMPONENTS]; /* row of point-transformed samples */ 52 _JSAMPROW prev_row[MAX_COMPONENTS]; /* previous row of Pt'd samples */ 53 JDIFFARRAY diff_buf[MAX_COMPONENTS]; /* iMCU row of differences */ 54 55 /* In multi-pass modes, we need a virtual sample array for each component. */ 56 jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; 57 } my_diff_controller; 58 59 typedef my_diff_controller *my_diff_ptr; 60 61 62 /* Forward declarations */ 63 METHODDEF(boolean) compress_data(j_compress_ptr cinfo, _JSAMPIMAGE input_buf); 64 #ifdef FULL_SAMP_BUFFER_SUPPORTED 65 METHODDEF(boolean) compress_first_pass(j_compress_ptr cinfo, 66 _JSAMPIMAGE input_buf); 67 METHODDEF(boolean) compress_output(j_compress_ptr cinfo, 68 _JSAMPIMAGE input_buf); 69 #endif 70 71 72 LOCAL(void) 73 start_iMCU_row(j_compress_ptr cinfo) 74 /* Reset within-iMCU-row counters for a new row */ 75 { 76 my_diff_ptr diff = (my_diff_ptr)cinfo->coef; 77 78 /* In an interleaved scan, an MCU row is the same as an iMCU row. 79 * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. 80 * But at the bottom of the image, process only what's left. 81 */ 82 if (cinfo->comps_in_scan > 1) { 83 diff->MCU_rows_per_iMCU_row = 1; 84 } else { 85 if (diff->iMCU_row_num < (cinfo->total_iMCU_rows-1)) 86 diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; 87 else 88 diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; 89 } 90 91 diff->mcu_ctr = 0; 92 diff->MCU_vert_offset = 0; 93 } 94 95 96 /* 97 * Initialize for a processing pass. 98 */ 99 100 METHODDEF(void) 101 start_pass_diff(j_compress_ptr cinfo, J_BUF_MODE pass_mode) 102 { 103 my_diff_ptr diff = (my_diff_ptr)cinfo->coef; 104 105 /* Because it is hitching a ride on the jpeg_forward_dct struct, 106 * start_pass_lossless() will be called at the start of the initial pass. 107 * This ensures that it will be called at the start of the Huffman 108 * optimization and output passes as well. 109 */ 110 if (pass_mode == JBUF_CRANK_DEST) 111 (*cinfo->fdct->start_pass) (cinfo); 112 113 diff->iMCU_row_num = 0; 114 start_iMCU_row(cinfo); 115 116 switch (pass_mode) { 117 case JBUF_PASS_THRU: 118 if (diff->whole_image[0] != NULL) 119 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); 120 diff->pub._compress_data = compress_data; 121 break; 122 #ifdef FULL_SAMP_BUFFER_SUPPORTED 123 case JBUF_SAVE_AND_PASS: 124 if (diff->whole_image[0] == NULL) 125 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); 126 diff->pub._compress_data = compress_first_pass; 127 break; 128 case JBUF_CRANK_DEST: 129 if (diff->whole_image[0] == NULL) 130 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); 131 diff->pub._compress_data = compress_output; 132 break; 133 #endif 134 default: 135 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); 136 break; 137 } 138 } 139 140 141 #define SWAP_ROWS(rowa, rowb) { \ 142 _JSAMPROW temp = rowa; \ 143 rowa = rowb; rowb = temp; \ 144 } 145 146 /* 147 * Process some data in the single-pass case. 148 * We process the equivalent of one fully interleaved MCU row ("iMCU" row) 149 * per call, ie, v_samp_factor rows for each component in the image. 150 * Returns TRUE if the iMCU row is completed, FALSE if suspended. 151 * 152 * NB: input_buf contains a plane for each component in image, 153 * which we index according to the component's SOF position. 154 */ 155 156 METHODDEF(boolean) 157 compress_data(j_compress_ptr cinfo, _JSAMPIMAGE input_buf) 158 { 159 my_diff_ptr diff = (my_diff_ptr)cinfo->coef; 160 lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; 161 JDIMENSION MCU_col_num; /* index of current MCU within row */ 162 JDIMENSION MCU_count; /* number of MCUs encoded */ 163 JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; 164 int ci, compi, yoffset, samp_row, samp_rows, samps_across; 165 jpeg_component_info *compptr; 166 167 /* Loop to write as much as one whole iMCU row */ 168 for (yoffset = diff->MCU_vert_offset; yoffset < diff->MCU_rows_per_iMCU_row; 169 yoffset++) { 170 171 MCU_col_num = diff->mcu_ctr; 172 173 /* Scale and predict each scanline of the MCU row separately. 174 * 175 * Note: We only do this if we are at the start of an MCU row, ie, 176 * we don't want to reprocess a row suspended by the output. 177 */ 178 if (MCU_col_num == 0) { 179 for (ci = 0; ci < cinfo->comps_in_scan; ci++) { 180 compptr = cinfo->cur_comp_info[ci]; 181 compi = compptr->component_index; 182 if (diff->iMCU_row_num < last_iMCU_row) 183 samp_rows = compptr->v_samp_factor; 184 else { 185 /* NB: can't use last_row_height here, since may not be set! */ 186 samp_rows = 187 (int)(compptr->height_in_blocks % compptr->v_samp_factor); 188 if (samp_rows == 0) samp_rows = compptr->v_samp_factor; 189 else { 190 /* Fill dummy difference rows at the bottom edge with zeros, which 191 * will encode to the smallest amount of data. 192 */ 193 for (samp_row = samp_rows; samp_row < compptr->v_samp_factor; 194 samp_row++) 195 memset(diff->diff_buf[compi][samp_row], 0, 196 jround_up((long)compptr->width_in_blocks, 197 (long)compptr->h_samp_factor) * sizeof(JDIFF)); 198 } 199 } 200 samps_across = compptr->width_in_blocks; 201 202 for (samp_row = 0; samp_row < samp_rows; samp_row++) { 203 (*losslessc->scaler_scale) (cinfo, 204 input_buf[compi][samp_row], 205 diff->cur_row[compi], 206 samps_across); 207 (*losslessc->predict_difference[compi]) 208 (cinfo, compi, diff->cur_row[compi], diff->prev_row[compi], 209 diff->diff_buf[compi][samp_row], samps_across); 210 SWAP_ROWS(diff->cur_row[compi], diff->prev_row[compi]); 211 } 212 } 213 } 214 /* Try to write the MCU row (or remaining portion of suspended MCU row). */ 215 MCU_count = 216 (*cinfo->entropy->encode_mcus) (cinfo, 217 diff->diff_buf, yoffset, MCU_col_num, 218 cinfo->MCUs_per_row - MCU_col_num); 219 if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) { 220 /* Suspension forced; update state counters and exit */ 221 diff->MCU_vert_offset = yoffset; 222 diff->mcu_ctr += MCU_col_num; 223 return FALSE; 224 } 225 /* Completed an MCU row, but perhaps not an iMCU row */ 226 diff->mcu_ctr = 0; 227 } 228 /* Completed the iMCU row, advance counters for next one */ 229 diff->iMCU_row_num++; 230 start_iMCU_row(cinfo); 231 return TRUE; 232 } 233 234 235 #ifdef FULL_SAMP_BUFFER_SUPPORTED 236 237 /* 238 * Process some data in the first pass of a multi-pass case. 239 * We process the equivalent of one fully interleaved MCU row ("iMCU" row) 240 * per call, ie, v_samp_factor rows for each component in the image. 241 * This amount of data is read from the source buffer and saved into the 242 * virtual arrays. 243 * 244 * We must also emit the data to the compressor. This is conveniently 245 * done by calling compress_output() after we've loaded the current strip 246 * of the virtual arrays. 247 * 248 * NB: input_buf contains a plane for each component in image. All components 249 * are loaded into the virtual arrays in this pass. However, it may be that 250 * only a subset of the components are emitted to the compressor during 251 * this first pass; be careful about looking at the scan-dependent variables 252 * (MCU dimensions, etc). 253 */ 254 255 METHODDEF(boolean) 256 compress_first_pass(j_compress_ptr cinfo, _JSAMPIMAGE input_buf) 257 { 258 my_diff_ptr diff = (my_diff_ptr)cinfo->coef; 259 JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; 260 JDIMENSION samps_across; 261 int ci, samp_row, samp_rows; 262 _JSAMPARRAY buffer; 263 jpeg_component_info *compptr; 264 265 for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; 266 ci++, compptr++) { 267 /* Align the virtual buffer for this component. */ 268 buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray) 269 ((j_common_ptr)cinfo, diff->whole_image[ci], 270 diff->iMCU_row_num * compptr->v_samp_factor, 271 (JDIMENSION)compptr->v_samp_factor, TRUE); 272 273 /* Count non-dummy sample rows in this iMCU row. */ 274 if (diff->iMCU_row_num < last_iMCU_row) 275 samp_rows = compptr->v_samp_factor; 276 else { 277 /* NB: can't use last_row_height here, since may not be set! */ 278 samp_rows = (int)(compptr->height_in_blocks % compptr->v_samp_factor); 279 if (samp_rows == 0) samp_rows = compptr->v_samp_factor; 280 } 281 samps_across = compptr->width_in_blocks; 282 283 /* Perform point transform scaling and prediction/differencing for all 284 * non-dummy rows in this iMCU row. Each call on these functions 285 * processes a complete row of samples. 286 */ 287 for (samp_row = 0; samp_row < samp_rows; samp_row++) { 288 memcpy(buffer[samp_row], input_buf[ci][samp_row], 289 samps_across * sizeof(_JSAMPLE)); 290 } 291 } 292 /* NB: compress_output will increment iMCU_row_num if successful. 293 * A suspension return will result in redoing all the work above next time. 294 */ 295 296 /* Emit data to the compressor, sharing code with subsequent passes */ 297 return compress_output(cinfo, input_buf); 298 } 299 300 301 /* 302 * Process some data in subsequent passes of a multi-pass case. 303 * We process the equivalent of one fully interleaved MCU row ("iMCU" row) 304 * per call, ie, v_samp_factor rows for each component in the scan. 305 * The data is obtained from the virtual arrays and fed to the compressor. 306 * Returns TRUE if the iMCU row is completed, FALSE if suspended. 307 * 308 * NB: input_buf is ignored; it is likely to be a NULL pointer. 309 */ 310 311 METHODDEF(boolean) 312 compress_output(j_compress_ptr cinfo, _JSAMPIMAGE input_buf) 313 { 314 my_diff_ptr diff = (my_diff_ptr)cinfo->coef; 315 int ci, compi; 316 _JSAMPARRAY buffer[MAX_COMPS_IN_SCAN]; 317 jpeg_component_info *compptr; 318 319 /* Align the virtual buffers for the components used in this scan. 320 * NB: during first pass, this is safe only because the buffers will 321 * already be aligned properly, so jmemmgr.c won't need to do any I/O. 322 */ 323 for (ci = 0; ci < cinfo->comps_in_scan; ci++) { 324 compptr = cinfo->cur_comp_info[ci]; 325 compi = compptr->component_index; 326 buffer[compi] = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray) 327 ((j_common_ptr)cinfo, diff->whole_image[compi], 328 diff->iMCU_row_num * compptr->v_samp_factor, 329 (JDIMENSION)compptr->v_samp_factor, FALSE); 330 } 331 332 return compress_data(cinfo, buffer); 333 } 334 335 #endif /* FULL_SAMP_BUFFER_SUPPORTED */ 336 337 338 /* 339 * Initialize difference buffer controller. 340 */ 341 342 GLOBAL(void) 343 _jinit_c_diff_controller(j_compress_ptr cinfo, boolean need_full_buffer) 344 { 345 my_diff_ptr diff; 346 int ci, row; 347 jpeg_component_info *compptr; 348 349 diff = (my_diff_ptr) 350 (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, 351 sizeof(my_diff_controller)); 352 cinfo->coef = (struct jpeg_c_coef_controller *)diff; 353 diff->pub.start_pass = start_pass_diff; 354 355 /* Create the prediction row buffers. */ 356 for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; 357 ci++, compptr++) { 358 diff->cur_row[ci] = *(_JSAMPARRAY)(*cinfo->mem->alloc_sarray) 359 ((j_common_ptr)cinfo, JPOOL_IMAGE, 360 (JDIMENSION)jround_up((long)compptr->width_in_blocks, 361 (long)compptr->h_samp_factor), 362 (JDIMENSION)1); 363 diff->prev_row[ci] = *(_JSAMPARRAY)(*cinfo->mem->alloc_sarray) 364 ((j_common_ptr)cinfo, JPOOL_IMAGE, 365 (JDIMENSION)jround_up((long)compptr->width_in_blocks, 366 (long)compptr->h_samp_factor), 367 (JDIMENSION)1); 368 } 369 370 /* Create the difference buffer. */ 371 for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; 372 ci++, compptr++) { 373 diff->diff_buf[ci] = 374 ALLOC_DARRAY(JPOOL_IMAGE, 375 (JDIMENSION)jround_up((long)compptr->width_in_blocks, 376 (long)compptr->h_samp_factor), 377 (JDIMENSION)compptr->v_samp_factor); 378 /* Prefill difference rows with zeros. We do this because only actual 379 * data is placed in the buffers during prediction/differencing, leaving 380 * any dummy differences at the right edge as zeros, which will encode 381 * to the smallest amount of data. 382 */ 383 for (row = 0; row < compptr->v_samp_factor; row++) 384 memset(diff->diff_buf[ci][row], 0, 385 jround_up((long)compptr->width_in_blocks, 386 (long)compptr->h_samp_factor) * sizeof(JDIFF)); 387 } 388 389 /* Create the sample buffer. */ 390 if (need_full_buffer) { 391 #ifdef FULL_SAMP_BUFFER_SUPPORTED 392 /* Allocate a full-image virtual array for each component, */ 393 /* padded to a multiple of samp_factor differences in each direction. */ 394 for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; 395 ci++, compptr++) { 396 diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray) 397 ((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE, 398 (JDIMENSION)jround_up((long)compptr->width_in_blocks, 399 (long)compptr->h_samp_factor), 400 (JDIMENSION)jround_up((long)compptr->height_in_blocks, 401 (long)compptr->v_samp_factor), 402 (JDIMENSION)compptr->v_samp_factor); 403 } 404 #else 405 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); 406 #endif 407 } else 408 diff->whole_image[0] = NULL; /* flag for no virtual arrays */ 409 } 410 411 #endif /* C_LOSSLESS_SUPPORTED */