jdpostct.c (11617B)
1 /* 2 * jdpostct.c 3 * 4 * This file was part of the Independent JPEG Group's software: 5 * Copyright (C) 1994-1996, Thomas G. Lane. 6 * libjpeg-turbo Modifications: 7 * Copyright (C) 2022-2023, D. R. Commander. 8 * For conditions of distribution and use, see the accompanying README.ijg 9 * file. 10 * 11 * This file contains the decompression postprocessing controller. 12 * This controller manages the upsampling, color conversion, and color 13 * quantization/reduction steps; specifically, it controls the buffering 14 * between upsample/color conversion and color quantization/reduction. 15 * 16 * If no color quantization/reduction is required, then this module has no 17 * work to do, and it just hands off to the upsample/color conversion code. 18 * An integrated upsample/convert/quantize process would replace this module 19 * entirely. 20 */ 21 22 #define JPEG_INTERNALS 23 #include "jinclude.h" 24 #include "jpeglib.h" 25 #include "jsamplecomp.h" 26 27 28 #if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) 29 30 /* Private buffer controller object */ 31 32 typedef struct { 33 struct jpeg_d_post_controller pub; /* public fields */ 34 35 /* Color quantization source buffer: this holds output data from 36 * the upsample/color conversion step to be passed to the quantizer. 37 * For two-pass color quantization, we need a full-image buffer; 38 * for one-pass operation, a strip buffer is sufficient. 39 */ 40 jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */ 41 _JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */ 42 JDIMENSION strip_height; /* buffer size in rows */ 43 /* for two-pass mode only: */ 44 JDIMENSION starting_row; /* row # of first row in current strip */ 45 JDIMENSION next_row; /* index of next row to fill/empty in strip */ 46 } my_post_controller; 47 48 typedef my_post_controller *my_post_ptr; 49 50 51 /* Forward declarations */ 52 #if BITS_IN_JSAMPLE != 16 53 METHODDEF(void) post_process_1pass(j_decompress_ptr cinfo, 54 _JSAMPIMAGE input_buf, 55 JDIMENSION *in_row_group_ctr, 56 JDIMENSION in_row_groups_avail, 57 _JSAMPARRAY output_buf, 58 JDIMENSION *out_row_ctr, 59 JDIMENSION out_rows_avail); 60 #endif 61 #if defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 62 METHODDEF(void) post_process_prepass(j_decompress_ptr cinfo, 63 _JSAMPIMAGE input_buf, 64 JDIMENSION *in_row_group_ctr, 65 JDIMENSION in_row_groups_avail, 66 _JSAMPARRAY output_buf, 67 JDIMENSION *out_row_ctr, 68 JDIMENSION out_rows_avail); 69 METHODDEF(void) post_process_2pass(j_decompress_ptr cinfo, 70 _JSAMPIMAGE input_buf, 71 JDIMENSION *in_row_group_ctr, 72 JDIMENSION in_row_groups_avail, 73 _JSAMPARRAY output_buf, 74 JDIMENSION *out_row_ctr, 75 JDIMENSION out_rows_avail); 76 #endif 77 78 79 /* 80 * Initialize for a processing pass. 81 */ 82 83 METHODDEF(void) 84 start_pass_dpost(j_decompress_ptr cinfo, J_BUF_MODE pass_mode) 85 { 86 my_post_ptr post = (my_post_ptr)cinfo->post; 87 88 switch (pass_mode) { 89 case JBUF_PASS_THRU: 90 #if BITS_IN_JSAMPLE != 16 91 if (cinfo->quantize_colors) { 92 /* Single-pass processing with color quantization. */ 93 post->pub._post_process_data = post_process_1pass; 94 /* We could be doing buffered-image output before starting a 2-pass 95 * color quantization; in that case, jinit_d_post_controller did not 96 * allocate a strip buffer. Use the virtual-array buffer as workspace. 97 */ 98 if (post->buffer == NULL) { 99 post->buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray) 100 ((j_common_ptr)cinfo, post->whole_image, 101 (JDIMENSION)0, post->strip_height, TRUE); 102 } 103 } else 104 #endif 105 { 106 /* For single-pass processing without color quantization, 107 * I have no work to do; just call the upsampler directly. 108 */ 109 post->pub._post_process_data = cinfo->upsample->_upsample; 110 } 111 break; 112 #if defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 113 case JBUF_SAVE_AND_PASS: 114 /* First pass of 2-pass quantization */ 115 if (post->whole_image == NULL) 116 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); 117 post->pub._post_process_data = post_process_prepass; 118 break; 119 case JBUF_CRANK_DEST: 120 /* Second pass of 2-pass quantization */ 121 if (post->whole_image == NULL) 122 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); 123 post->pub._post_process_data = post_process_2pass; 124 break; 125 #endif /* defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */ 126 default: 127 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); 128 break; 129 } 130 post->starting_row = post->next_row = 0; 131 } 132 133 134 /* 135 * Process some data in the one-pass (strip buffer) case. 136 * This is used for color precision reduction as well as one-pass quantization. 137 */ 138 139 #if BITS_IN_JSAMPLE != 16 140 141 METHODDEF(void) 142 post_process_1pass(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf, 143 JDIMENSION *in_row_group_ctr, 144 JDIMENSION in_row_groups_avail, _JSAMPARRAY output_buf, 145 JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail) 146 { 147 my_post_ptr post = (my_post_ptr)cinfo->post; 148 JDIMENSION num_rows, max_rows; 149 150 /* Fill the buffer, but not more than what we can dump out in one go. */ 151 /* Note we rely on the upsampler to detect bottom of image. */ 152 max_rows = out_rows_avail - *out_row_ctr; 153 if (max_rows > post->strip_height) 154 max_rows = post->strip_height; 155 num_rows = 0; 156 (*cinfo->upsample->_upsample) (cinfo, input_buf, in_row_group_ctr, 157 in_row_groups_avail, post->buffer, &num_rows, 158 max_rows); 159 /* Quantize and emit data. */ 160 (*cinfo->cquantize->_color_quantize) (cinfo, post->buffer, 161 output_buf + *out_row_ctr, 162 (int)num_rows); 163 *out_row_ctr += num_rows; 164 } 165 166 #endif 167 168 169 #if defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 170 171 /* 172 * Process some data in the first pass of 2-pass quantization. 173 */ 174 175 METHODDEF(void) 176 post_process_prepass(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf, 177 JDIMENSION *in_row_group_ctr, 178 JDIMENSION in_row_groups_avail, _JSAMPARRAY output_buf, 179 JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail) 180 { 181 my_post_ptr post = (my_post_ptr)cinfo->post; 182 JDIMENSION old_next_row, num_rows; 183 184 /* Reposition virtual buffer if at start of strip. */ 185 if (post->next_row == 0) { 186 post->buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray) 187 ((j_common_ptr)cinfo, post->whole_image, 188 post->starting_row, post->strip_height, TRUE); 189 } 190 191 /* Upsample some data (up to a strip height's worth). */ 192 old_next_row = post->next_row; 193 (*cinfo->upsample->_upsample) (cinfo, input_buf, in_row_group_ctr, 194 in_row_groups_avail, post->buffer, 195 &post->next_row, post->strip_height); 196 197 /* Allow quantizer to scan new data. No data is emitted, */ 198 /* but we advance out_row_ctr so outer loop can tell when we're done. */ 199 if (post->next_row > old_next_row) { 200 num_rows = post->next_row - old_next_row; 201 (*cinfo->cquantize->_color_quantize) (cinfo, post->buffer + old_next_row, 202 (_JSAMPARRAY)NULL, (int)num_rows); 203 *out_row_ctr += num_rows; 204 } 205 206 /* Advance if we filled the strip. */ 207 if (post->next_row >= post->strip_height) { 208 post->starting_row += post->strip_height; 209 post->next_row = 0; 210 } 211 } 212 213 214 /* 215 * Process some data in the second pass of 2-pass quantization. 216 */ 217 218 METHODDEF(void) 219 post_process_2pass(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf, 220 JDIMENSION *in_row_group_ctr, 221 JDIMENSION in_row_groups_avail, _JSAMPARRAY output_buf, 222 JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail) 223 { 224 my_post_ptr post = (my_post_ptr)cinfo->post; 225 JDIMENSION num_rows, max_rows; 226 227 /* Reposition virtual buffer if at start of strip. */ 228 if (post->next_row == 0) { 229 post->buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray) 230 ((j_common_ptr)cinfo, post->whole_image, 231 post->starting_row, post->strip_height, FALSE); 232 } 233 234 /* Determine number of rows to emit. */ 235 num_rows = post->strip_height - post->next_row; /* available in strip */ 236 max_rows = out_rows_avail - *out_row_ctr; /* available in output area */ 237 if (num_rows > max_rows) 238 num_rows = max_rows; 239 /* We have to check bottom of image here, can't depend on upsampler. */ 240 max_rows = cinfo->output_height - post->starting_row; 241 if (num_rows > max_rows) 242 num_rows = max_rows; 243 244 /* Quantize and emit data. */ 245 (*cinfo->cquantize->_color_quantize) (cinfo, post->buffer + post->next_row, 246 output_buf + *out_row_ctr, 247 (int)num_rows); 248 *out_row_ctr += num_rows; 249 250 /* Advance if we filled the strip. */ 251 post->next_row += num_rows; 252 if (post->next_row >= post->strip_height) { 253 post->starting_row += post->strip_height; 254 post->next_row = 0; 255 } 256 } 257 258 #endif /* defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */ 259 260 261 /* 262 * Initialize postprocessing controller. 263 */ 264 265 GLOBAL(void) 266 _jinit_d_post_controller(j_decompress_ptr cinfo, boolean need_full_buffer) 267 { 268 my_post_ptr post; 269 270 if (cinfo->data_precision != BITS_IN_JSAMPLE) 271 ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); 272 273 post = (my_post_ptr) 274 (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, 275 sizeof(my_post_controller)); 276 cinfo->post = (struct jpeg_d_post_controller *)post; 277 post->pub.start_pass = start_pass_dpost; 278 post->whole_image = NULL; /* flag for no virtual arrays */ 279 post->buffer = NULL; /* flag for no strip buffer */ 280 281 /* Create the quantization buffer, if needed */ 282 if (cinfo->quantize_colors) { 283 #if BITS_IN_JSAMPLE != 16 284 /* The buffer strip height is max_v_samp_factor, which is typically 285 * an efficient number of rows for upsampling to return. 286 * (In the presence of output rescaling, we might want to be smarter?) 287 */ 288 post->strip_height = (JDIMENSION)cinfo->max_v_samp_factor; 289 if (need_full_buffer) { 290 /* Two-pass color quantization: need full-image storage. */ 291 /* We round up the number of rows to a multiple of the strip height. */ 292 #ifdef QUANT_2PASS_SUPPORTED 293 post->whole_image = (*cinfo->mem->request_virt_sarray) 294 ((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE, 295 cinfo->output_width * cinfo->out_color_components, 296 (JDIMENSION)jround_up((long)cinfo->output_height, 297 (long)post->strip_height), 298 post->strip_height); 299 #else 300 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); 301 #endif /* QUANT_2PASS_SUPPORTED */ 302 } else { 303 /* One-pass color quantization: just make a strip buffer. */ 304 post->buffer = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray) 305 ((j_common_ptr)cinfo, JPOOL_IMAGE, 306 cinfo->output_width * cinfo->out_color_components, 307 post->strip_height); 308 } 309 #else 310 ERREXIT(cinfo, JERR_NOTIMPL); 311 #endif 312 } 313 } 314 315 #endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */