| /* |
| * jdpipe.c |
| * |
| * Copyright (C) 1991, Thomas G. Lane. |
| * This file is part of the Independent JPEG Group's software. |
| * For conditions of distribution and use, see the accompanying README file. |
| * |
| * This file contains decompression pipeline controllers. |
| * These routines are invoked via the d_pipeline_controller method. |
| * |
| * There are four basic pipeline controllers, one for each combination of: |
| * single-scan JPEG file (single component or fully interleaved) |
| * vs. multiple-scan JPEG file (noninterleaved or partially interleaved). |
| * |
| * 2-pass color quantization |
| * vs. no color quantization or 1-pass quantization. |
| * |
| * Note that these conditions determine the needs for "big" images: |
| * multiple scans imply a big image for recombining the color components; |
| * 2-pass color quantization needs a big image for saving the data for pass 2. |
| * |
| * All but the simplest controller (single-scan, no 2-pass quantization) can be |
| * compiled out through configuration options, if you need to make a minimal |
| * implementation. You should leave in multiple-scan support if at all |
| * possible, so that you can handle all legal JPEG files. |
| */ |
| |
| #include "jinclude.h" |
| |
| |
| /* |
| * About the data structures: |
| * |
| * The processing chunk size for unsubsampling is referred to in this file as |
| * a "row group": a row group is defined as Vk (v_samp_factor) sample rows of |
| * any component while subsampled, or Vmax (max_v_samp_factor) unsubsampled |
| * rows. In an interleaved scan each MCU row contains exactly DCTSIZE row |
| * groups of each component in the scan. In a noninterleaved scan an MCU row |
| * is one row of blocks, which might not be an integral number of row groups; |
| * therefore, we read in Vk MCU rows to obtain the same amount of data as we'd |
| * have in an interleaved scan. |
| * To provide context for the unsubsampling step, we have to retain the last |
| * two row groups of the previous MCU row while reading in the next MCU row |
| * (or set of Vk MCU rows). To do this without copying data about, we create |
| * a rather strange data structure. Exactly DCTSIZE+2 row groups of samples |
| * are allocated, but we create two different sets of pointers to this array. |
| * The second set swaps the last two pairs of row groups. By working |
| * alternately with the two sets of pointers, we can access the data in the |
| * desired order. |
| * |
| * Cross-block smoothing also needs context above and below the "current" row. |
| * Since this is an optional feature, I've implemented it in a way that is |
| * much simpler but requires more than the minimum amount of memory. We |
| * simply allocate three extra MCU rows worth of coefficient blocks and use |
| * them to "read ahead" one MCU row in the file. For a typical 1000-pixel-wide |
| * image with 2x2,1x1,1x1 sampling, each MCU row is about 50Kb; an 80x86 |
| * machine may be unable to apply cross-block smoothing to wider images. |
| */ |
| |
| |
| /* |
| * These variables are logically local to the pipeline controller, |
| * but we make them static so that scan_big_image can use them |
| * without having to pass them through the quantization routines. |
| * If you don't support 2-pass quantization, you could make them locals. |
| */ |
| |
| static int rows_in_mem; /* # of sample rows in full-size buffers */ |
| /* Full-size image array holding desubsampled, color-converted data. */ |
| static big_sarray_ptr *fullsize_cnvt_image; |
| static JSAMPIMAGE fullsize_cnvt_ptrs; /* workspace for access_big_sarray() results */ |
| /* Work buffer for color quantization output (full size, only 1 component). */ |
| static JSAMPARRAY quantize_out; |
| |
| |
| /* |
| * Utility routines: common code for pipeline controllers |
| */ |
| |
| LOCAL void |
| interleaved_scan_setup (decompress_info_ptr cinfo) |
| /* Compute all derived info for an interleaved (multi-component) scan */ |
| /* On entry, cinfo->comps_in_scan and cinfo->cur_comp_info[] are set up */ |
| { |
| short ci, mcublks; |
| jpeg_component_info *compptr; |
| |
| if (cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) |
| ERREXIT(cinfo->emethods, "Too many components for interleaved scan"); |
| |
| cinfo->MCUs_per_row = (cinfo->image_width |
| + cinfo->max_h_samp_factor*DCTSIZE - 1) |
| / (cinfo->max_h_samp_factor*DCTSIZE); |
| |
| cinfo->MCU_rows_in_scan = (cinfo->image_height |
| + cinfo->max_v_samp_factor*DCTSIZE - 1) |
| / (cinfo->max_v_samp_factor*DCTSIZE); |
| |
| cinfo->blocks_in_MCU = 0; |
| |
| for (ci = 0; ci < cinfo->comps_in_scan; ci++) { |
| compptr = cinfo->cur_comp_info[ci]; |
| /* for interleaved scan, sampling factors give # of blocks per component */ |
| compptr->MCU_width = compptr->h_samp_factor; |
| compptr->MCU_height = compptr->v_samp_factor; |
| compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; |
| /* compute physical dimensions of component */ |
| compptr->subsampled_width = jround_up(compptr->true_comp_width, |
| (long) (compptr->MCU_width*DCTSIZE)); |
| compptr->subsampled_height = jround_up(compptr->true_comp_height, |
| (long) (compptr->MCU_height*DCTSIZE)); |
| /* Sanity check */ |
| if (compptr->subsampled_width != |
| (cinfo->MCUs_per_row * (compptr->MCU_width*DCTSIZE))) |
| ERREXIT(cinfo->emethods, "I'm confused about the image width"); |
| /* Prepare array describing MCU composition */ |
| mcublks = compptr->MCU_blocks; |
| if (cinfo->blocks_in_MCU + mcublks > MAX_BLOCKS_IN_MCU) |
| ERREXIT(cinfo->emethods, "Sampling factors too large for interleaved scan"); |
| while (mcublks-- > 0) { |
| cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; |
| } |
| } |
| |
| (*cinfo->methods->d_per_scan_method_selection) (cinfo); |
| } |
| |
| |
| LOCAL void |
| noninterleaved_scan_setup (decompress_info_ptr cinfo) |
| /* Compute all derived info for a noninterleaved (single-component) scan */ |
| /* On entry, cinfo->comps_in_scan = 1 and cinfo->cur_comp_info[0] is set up */ |
| { |
| jpeg_component_info *compptr = cinfo->cur_comp_info[0]; |
| |
| /* for noninterleaved scan, always one block per MCU */ |
| compptr->MCU_width = 1; |
| compptr->MCU_height = 1; |
| compptr->MCU_blocks = 1; |
| /* compute physical dimensions of component */ |
| compptr->subsampled_width = jround_up(compptr->true_comp_width, |
| (long) DCTSIZE); |
| compptr->subsampled_height = jround_up(compptr->true_comp_height, |
| (long) DCTSIZE); |
| |
| cinfo->MCUs_per_row = compptr->subsampled_width / DCTSIZE; |
| cinfo->MCU_rows_in_scan = compptr->subsampled_height / DCTSIZE; |
| |
| /* Prepare array describing MCU composition */ |
| cinfo->blocks_in_MCU = 1; |
| cinfo->MCU_membership[0] = 0; |
| |
| (*cinfo->methods->d_per_scan_method_selection) (cinfo); |
| } |
| |
| |
| LOCAL void |
| reverse_DCT (decompress_info_ptr cinfo, |
| JBLOCKIMAGE coeff_data, JSAMPIMAGE output_data, |
| int start_row) |
| /* Perform inverse DCT on each block in an MCU row's worth of data; */ |
| /* output the results into a sample array starting at row start_row. */ |
| /* NB: start_row can only be nonzero when dealing with a single-component */ |
| /* scan; otherwise we'd have to provide for different offsets for different */ |
| /* components, since the heights of interleaved MCU rows can vary. */ |
| { |
| DCTBLOCK block; |
| JBLOCKROW browptr; |
| JSAMPARRAY srowptr; |
| long blocksperrow, bi; |
| short numrows, ri; |
| short ci; |
| |
| for (ci = 0; ci < cinfo->comps_in_scan; ci++) { |
| /* calc size of an MCU row in this component */ |
| blocksperrow = cinfo->cur_comp_info[ci]->subsampled_width / DCTSIZE; |
| numrows = cinfo->cur_comp_info[ci]->MCU_height; |
| /* iterate through all blocks in MCU row */ |
| for (ri = 0; ri < numrows; ri++) { |
| browptr = coeff_data[ci][ri]; |
| srowptr = output_data[ci] + (ri * DCTSIZE + start_row); |
| for (bi = 0; bi < blocksperrow; bi++) { |
| /* copy the data into a local DCTBLOCK. This allows for change of |
| * representation (if DCTELEM != JCOEF). On 80x86 machines it also |
| * brings the data back from FAR storage to NEAR storage. |
| */ |
| { register JCOEFPTR elemptr = browptr[bi]; |
| register DCTELEM *localblkptr = block; |
| register short elem = DCTSIZE2; |
| |
| while (--elem >= 0) |
| *localblkptr++ = (DCTELEM) *elemptr++; |
| } |
| |
| j_rev_dct(block); /* perform inverse DCT */ |
| |
| /* output the data into the sample array. |
| * Note change from signed to unsigned representation: |
| * DCT calculation works with values +-CENTERJSAMPLE, |
| * but sample arrays always hold 0..MAXJSAMPLE. |
| * Have to do explicit range-limiting because of quantization errors |
| * and so forth in the DCT/IDCT phase. |
| */ |
| { register JSAMPROW elemptr; |
| register DCTELEM *localblkptr = block; |
| register short elemr, elemc; |
| register DCTELEM temp; |
| |
| for (elemr = 0; elemr < DCTSIZE; elemr++) { |
| elemptr = srowptr[elemr] + (bi * DCTSIZE); |
| for (elemc = 0; elemc < DCTSIZE; elemc++) { |
| temp = (*localblkptr++) + CENTERJSAMPLE; |
| if (temp < 0) temp = 0; |
| else if (temp > MAXJSAMPLE) temp = MAXJSAMPLE; |
| *elemptr++ = (JSAMPLE) temp; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| |
| |
| LOCAL JSAMPIMAGE |
| alloc_sampimage (decompress_info_ptr cinfo, |
| int num_comps, long num_rows, long num_cols) |
| /* Allocate an in-memory sample image (all components same size) */ |
| { |
| JSAMPIMAGE image; |
| int ci; |
| |
| image = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) |
| (num_comps * SIZEOF(JSAMPARRAY)); |
| for (ci = 0; ci < num_comps; ci++) { |
| image[ci] = (*cinfo->emethods->alloc_small_sarray) (num_cols, num_rows); |
| } |
| return image; |
| } |
| |
| |
| LOCAL void |
| free_sampimage (decompress_info_ptr cinfo, JSAMPIMAGE image, |
| int num_comps, long num_rows) |
| /* Release a sample image created by alloc_sampimage */ |
| { |
| int ci; |
| |
| for (ci = 0; ci < num_comps; ci++) { |
| (*cinfo->emethods->free_small_sarray) (image[ci], num_rows); |
| } |
| (*cinfo->emethods->free_small) ((void *) image); |
| } |
| |
| |
| LOCAL JBLOCKIMAGE |
| alloc_MCU_row (decompress_info_ptr cinfo) |
| /* Allocate one MCU row's worth of coefficient blocks */ |
| { |
| JBLOCKIMAGE image; |
| int ci; |
| |
| image = (JBLOCKIMAGE) (*cinfo->emethods->alloc_small) |
| (cinfo->comps_in_scan * SIZEOF(JBLOCKARRAY)); |
| for (ci = 0; ci < cinfo->comps_in_scan; ci++) { |
| image[ci] = (*cinfo->emethods->alloc_small_barray) |
| (cinfo->cur_comp_info[ci]->subsampled_width / DCTSIZE, |
| (long) cinfo->cur_comp_info[ci]->MCU_height); |
| } |
| return image; |
| } |
| |
| |
| LOCAL void |
| free_MCU_row (decompress_info_ptr cinfo, JBLOCKIMAGE image) |
| /* Release a coefficient block array created by alloc_MCU_row */ |
| { |
| int ci; |
| |
| for (ci = 0; ci < cinfo->comps_in_scan; ci++) { |
| (*cinfo->emethods->free_small_barray) |
| (image[ci], (long) cinfo->cur_comp_info[ci]->MCU_height); |
| } |
| (*cinfo->emethods->free_small) ((void *) image); |
| } |
| |
| |
| LOCAL void |
| alloc_sampling_buffer (decompress_info_ptr cinfo, JSAMPIMAGE subsampled_data[2]) |
| /* Create a subsampled-data buffer having the desired structure */ |
| /* (see comments at head of file) */ |
| { |
| short ci, vs, i; |
| |
| /* Get top-level space for array pointers */ |
| subsampled_data[0] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) |
| (cinfo->comps_in_scan * SIZEOF(JSAMPARRAY)); |
| subsampled_data[1] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) |
| (cinfo->comps_in_scan * SIZEOF(JSAMPARRAY)); |
| |
| for (ci = 0; ci < cinfo->comps_in_scan; ci++) { |
| vs = cinfo->cur_comp_info[ci]->v_samp_factor; /* row group height */ |
| /* Allocate the real storage */ |
| subsampled_data[0][ci] = (*cinfo->emethods->alloc_small_sarray) |
| (cinfo->cur_comp_info[ci]->subsampled_width, |
| (long) (vs * (DCTSIZE+2))); |
| /* Create space for the scrambled-order pointers */ |
| subsampled_data[1][ci] = (JSAMPARRAY) (*cinfo->emethods->alloc_small) |
| (vs * (DCTSIZE+2) * SIZEOF(JSAMPROW)); |
| /* Duplicate the first DCTSIZE-2 row groups */ |
| for (i = 0; i < vs * (DCTSIZE-2); i++) { |
| subsampled_data[1][ci][i] = subsampled_data[0][ci][i]; |
| } |
| /* Copy the last four row groups in swapped order */ |
| for (i = 0; i < vs * 2; i++) { |
| subsampled_data[1][ci][vs*DCTSIZE + i] = subsampled_data[0][ci][vs*(DCTSIZE-2) + i]; |
| subsampled_data[1][ci][vs*(DCTSIZE-2) + i] = subsampled_data[0][ci][vs*DCTSIZE + i]; |
| } |
| } |
| } |
| |
| |
| LOCAL void |
| free_sampling_buffer (decompress_info_ptr cinfo, JSAMPIMAGE subsampled_data[2]) |
| /* Release a sampling buffer created by alloc_sampling_buffer */ |
| { |
| short ci, vs; |
| |
| for (ci = 0; ci < cinfo->comps_in_scan; ci++) { |
| vs = cinfo->cur_comp_info[ci]->v_samp_factor; /* row group height */ |
| /* Free the real storage */ |
| (*cinfo->emethods->free_small_sarray) |
| (subsampled_data[0][ci], (long) (vs * (DCTSIZE+2))); |
| /* Free the scrambled-order pointers */ |
| (*cinfo->emethods->free_small) ((void *) subsampled_data[1][ci]); |
| } |
| |
| /* Free the top-level space */ |
| (*cinfo->emethods->free_small) ((void *) subsampled_data[0]); |
| (*cinfo->emethods->free_small) ((void *) subsampled_data[1]); |
| } |
| |
| |
| LOCAL void |
| duplicate_row (JSAMPARRAY image_data, |
| long num_cols, int source_row, int num_rows) |
| /* Duplicate the source_row at source_row+1 .. source_row+num_rows */ |
| /* This happens only at the bottom of the image, */ |
| /* so it needn't be super-efficient */ |
| { |
| register int row; |
| |
| for (row = 1; row <= num_rows; row++) { |
| jcopy_sample_rows(image_data, source_row, image_data, source_row + row, |
| 1, num_cols); |
| } |
| } |
| |
| |
| LOCAL void |
| expand (decompress_info_ptr cinfo, |
| JSAMPIMAGE subsampled_data, JSAMPIMAGE fullsize_data, |
| long fullsize_width, |
| short above, short current, short below, short out) |
| /* Do unsubsampling expansion of a single row group (of each component). */ |
| /* above, current, below are indexes of row groups in subsampled_data; */ |
| /* out is the index of the target row group in fullsize_data. */ |
| /* Special case: above, below can be -1 to indicate top, bottom of image. */ |
| { |
| jpeg_component_info *compptr; |
| JSAMPARRAY above_ptr, below_ptr; |
| JSAMPROW dummy[MAX_SAMP_FACTOR]; /* for subsample expansion at top/bottom */ |
| short ci, vs, i; |
| |
| for (ci = 0; ci < cinfo->comps_in_scan; ci++) { |
| compptr = cinfo->cur_comp_info[ci]; |
| vs = compptr->v_samp_factor; /* row group height */ |
| |
| if (above >= 0) |
| above_ptr = subsampled_data[ci] + above * vs; |
| else { |
| /* Top of image: make a dummy above-context with copies of 1st row */ |
| /* We assume current=0 in this case */ |
| for (i = 0; i < vs; i++) |
| dummy[i] = subsampled_data[ci][0]; |
| above_ptr = (JSAMPARRAY) dummy; /* possible near->far pointer conv */ |
| } |
| |
| if (below >= 0) |
| below_ptr = subsampled_data[ci] + below * vs; |
| else { |
| /* Bot of image: make a dummy below-context with copies of last row */ |
| for (i = 0; i < vs; i++) |
| dummy[i] = subsampled_data[ci][(current+1)*vs-1]; |
| below_ptr = (JSAMPARRAY) dummy; /* possible near->far pointer conv */ |
| } |
| |
| (*cinfo->methods->unsubsample[ci]) |
| (cinfo, (int) ci, |
| compptr->subsampled_width, (int) vs, |
| fullsize_width, (int) cinfo->max_v_samp_factor, |
| above_ptr, |
| subsampled_data[ci] + current * vs, |
| below_ptr, |
| fullsize_data[ci] + out * cinfo->max_v_samp_factor); |
| } |
| } |
| |
| |
| LOCAL void |
| emit_1pass (decompress_info_ptr cinfo, int num_rows, |
| JSAMPIMAGE fullsize_data, JSAMPIMAGE color_data) |
| /* Do color conversion and output of num_rows full-size rows. */ |
| /* This is not used for 2-pass color quantization. */ |
| { |
| (*cinfo->methods->color_convert) (cinfo, num_rows, |
| fullsize_data, color_data); |
| |
| if (cinfo->quantize_colors) { |
| (*cinfo->methods->color_quantize) (cinfo, num_rows, |
| color_data, quantize_out); |
| |
| (*cinfo->methods->put_pixel_rows) (cinfo, num_rows, |
| &quantize_out); |
| } else { |
| (*cinfo->methods->put_pixel_rows) (cinfo, num_rows, |
| color_data); |
| } |
| } |
| |
| |
| /* |
| * Support routines for 2-pass color quantization. |
| */ |
| |
| #ifdef QUANT_2PASS_SUPPORTED |
| |
| LOCAL void |
| emit_2pass (decompress_info_ptr cinfo, long top_row, int num_rows, |
| JSAMPIMAGE fullsize_data) |
| /* Do color conversion and output data to the quantization buffer image. */ |
| /* This is used only with 2-pass color quantization. */ |
| { |
| short ci; |
| |
| /* Realign the big buffers */ |
| for (ci = 0; ci < cinfo->num_components; ci++) { |
| fullsize_cnvt_ptrs[ci] = (*cinfo->emethods->access_big_sarray) |
| (fullsize_cnvt_image[ci], top_row, TRUE); |
| } |
| |
| /* Do colorspace conversion */ |
| (*cinfo->methods->color_convert) (cinfo, num_rows, |
| fullsize_data, fullsize_cnvt_ptrs); |
| /* Let quantizer get first-pass peek at the data. */ |
| /* (Quantizer could change data if it wants to.) */ |
| (*cinfo->methods->color_quant_prescan) (cinfo, num_rows, fullsize_cnvt_ptrs); |
| } |
| |
| |
| METHODDEF void |
| scan_big_image (decompress_info_ptr cinfo, quantize_method_ptr quantize_method) |
| /* This is the "iterator" routine used by the quantizer. */ |
| { |
| long pixel_rows_output; |
| short ci; |
| |
| for (pixel_rows_output = 0; pixel_rows_output < cinfo->image_height; |
| pixel_rows_output += rows_in_mem) { |
| /* Realign the big buffers */ |
| for (ci = 0; ci < cinfo->num_components; ci++) { |
| fullsize_cnvt_ptrs[ci] = (*cinfo->emethods->access_big_sarray) |
| (fullsize_cnvt_image[ci], pixel_rows_output, FALSE); |
| } |
| /* Let the quantizer have its way with the data. |
| * Note that quantize_out is simply workspace for the quantizer; |
| * when it's ready to output, it must call put_pixel_rows itself. |
| */ |
| (*quantize_method) (cinfo, |
| (int) MIN(rows_in_mem, |
| cinfo->image_height - pixel_rows_output), |
| fullsize_cnvt_ptrs, quantize_out); |
| } |
| } |
| |
| #endif /* QUANT_2PASS_SUPPORTED */ |
| |
| |
| /* |
| * Support routines for cross-block smoothing. |
| */ |
| |
| #ifdef BLOCK_SMOOTHING_SUPPORTED |
| |
| |
| LOCAL void |
| smooth_mcu_row (decompress_info_ptr cinfo, |
| JBLOCKIMAGE above, JBLOCKIMAGE input, JBLOCKIMAGE below, |
| JBLOCKIMAGE output) |
| /* Apply cross-block smoothing to one MCU row's worth of coefficient blocks. */ |
| /* above,below are NULL if at top/bottom of image. */ |
| { |
| jpeg_component_info *compptr; |
| short ci, ri, last; |
| JBLOCKROW prev; |
| |
| for (ci = 0; ci < cinfo->comps_in_scan; ci++) { |
| compptr = cinfo->cur_comp_info[ci]; |
| last = compptr->MCU_height - 1; |
| |
| if (above == NULL) |
| prev = NULL; |
| else |
| prev = above[ci][last]; |
| |
| for (ri = 0; ri < last; ri++) { |
| (*cinfo->methods->smooth_coefficients) (cinfo, compptr, |
| prev, input[ci][ri], input[ci][ri+1], |
| output[ci][ri]); |
| prev = input[ci][ri]; |
| } |
| |
| if (below == NULL) |
| (*cinfo->methods->smooth_coefficients) (cinfo, compptr, |
| prev, input[ci][last], (JBLOCKROW) NULL, |
| output[ci][last]); |
| else |
| (*cinfo->methods->smooth_coefficients) (cinfo, compptr, |
| prev, input[ci][last], below[ci][0], |
| output[ci][last]); |
| } |
| } |
| |
| |
| LOCAL void |
| get_smoothed_row (decompress_info_ptr cinfo, JBLOCKIMAGE coeff_data, |
| JBLOCKIMAGE bsmooth[3], int * whichb, long cur_mcu_row) |
| /* Get an MCU row of coefficients, applying cross-block smoothing. */ |
| /* The output row is placed in coeff_data. bsmooth and whichb hold */ |
| /* working state, and cur_row is needed to check for image top/bottom. */ |
| /* This routine just takes care of the buffering logic. */ |
| { |
| int prev, cur, next; |
| |
| /* Special case for top of image: need to pre-fetch a row & init whichb */ |
| if (cur_mcu_row == 0) { |
| (*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[0]); |
| if (cinfo->MCU_rows_in_scan > 1) { |
| (*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[1]); |
| smooth_mcu_row(cinfo, (JBLOCKIMAGE) NULL, bsmooth[0], bsmooth[1], |
| coeff_data); |
| } else { |
| smooth_mcu_row(cinfo, (JBLOCKIMAGE) NULL, bsmooth[0], (JBLOCKIMAGE) NULL, |
| coeff_data); |
| } |
| *whichb = 1; /* points to next bsmooth[] element to use */ |
| return; |
| } |
| |
| cur = *whichb; /* set up references */ |
| prev = (cur == 0 ? 2 : cur - 1); |
| next = (cur == 2 ? 0 : cur + 1); |
| *whichb = next; /* advance whichb for next time */ |
| |
| /* Special case for bottom of image: don't read another row */ |
| if (cur_mcu_row >= cinfo->MCU_rows_in_scan - 1) { |
| smooth_mcu_row(cinfo, bsmooth[prev], bsmooth[cur], (JBLOCKIMAGE) NULL, |
| coeff_data); |
| return; |
| } |
| |
| /* Normal case: read ahead a new row, smooth the one I got before */ |
| (*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[next]); |
| smooth_mcu_row(cinfo, bsmooth[prev], bsmooth[cur], bsmooth[next], |
| coeff_data); |
| } |
| |
| |
| #endif /* BLOCK_SMOOTHING_SUPPORTED */ |
| |
| |
| |
| /* |
| * Decompression pipeline controller used for single-scan files |
| * without 2-pass color quantization. |
| */ |
| |
| METHODDEF void |
| single_dcontroller (decompress_info_ptr cinfo) |
| { |
| long fullsize_width; /* # of samples per row in full-size buffers */ |
| long cur_mcu_row; /* counts # of MCU rows processed */ |
| long pixel_rows_output; /* # of pixel rows actually emitted */ |
| int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ |
| /* Work buffer for dequantized coefficients (IDCT input) */ |
| JBLOCKIMAGE coeff_data; |
| /* Work buffer for cross-block smoothing input */ |
| #ifdef BLOCK_SMOOTHING_SUPPORTED |
| JBLOCKIMAGE bsmooth[3]; /* this is optional */ |
| int whichb; |
| #endif |
| /* Work buffer for subsampled image data (see comments at head of file) */ |
| JSAMPIMAGE subsampled_data[2]; |
| /* Work buffer for desubsampled data */ |
| JSAMPIMAGE fullsize_data; |
| /* Work buffer for color conversion output (full size) */ |
| JSAMPIMAGE color_data; |
| int whichss, ri; |
| short i; |
| |
| /* Initialize for 1-pass color quantization, if needed */ |
| if (cinfo->quantize_colors) |
| (*cinfo->methods->color_quant_init) (cinfo); |
| |
| /* Prepare for single scan containing all components */ |
| if (cinfo->comps_in_scan == 1) { |
| noninterleaved_scan_setup(cinfo); |
| /* Need to read Vk MCU rows to obtain Vk block rows */ |
| mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; |
| } else { |
| interleaved_scan_setup(cinfo); |
| /* in an interleaved scan, one MCU row provides Vk block rows */ |
| mcu_rows_per_loop = 1; |
| } |
| |
| /* Compute dimensions of full-size pixel buffers */ |
| /* Note these are the same whether interleaved or not. */ |
| rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; |
| fullsize_width = jround_up(cinfo->image_width, |
| (long) (cinfo->max_h_samp_factor * DCTSIZE)); |
| |
| /* Allocate working memory: */ |
| /* coeff_data holds a single MCU row of coefficient blocks */ |
| coeff_data = alloc_MCU_row(cinfo); |
| /* if doing cross-block smoothing, need extra space for its input */ |
| #ifdef BLOCK_SMOOTHING_SUPPORTED |
| if (cinfo->do_block_smoothing) { |
| bsmooth[0] = alloc_MCU_row(cinfo); |
| bsmooth[1] = alloc_MCU_row(cinfo); |
| bsmooth[2] = alloc_MCU_row(cinfo); |
| } |
| #endif |
| /* subsampled_data is sample data before unsubsampling */ |
| alloc_sampling_buffer(cinfo, subsampled_data); |
| /* fullsize_data is sample data after unsubsampling */ |
| fullsize_data = alloc_sampimage(cinfo, (int) cinfo->num_components, |
| (long) rows_in_mem, fullsize_width); |
| /* color_data is the result of the colorspace conversion step */ |
| color_data = alloc_sampimage(cinfo, (int) cinfo->color_out_comps, |
| (long) rows_in_mem, fullsize_width); |
| /* if quantizing colors, also need a one-component output area for that. */ |
| if (cinfo->quantize_colors) |
| quantize_out = (*cinfo->emethods->alloc_small_sarray) |
| (fullsize_width, (long) rows_in_mem); |
| |
| /* Tell the memory manager to instantiate big arrays. |
| * We don't need any big arrays in this controller, |
| * but some other module (like the output file writer) may need one. |
| */ |
| (*cinfo->emethods->alloc_big_arrays) |
| ((long) 0, /* no more small sarrays */ |
| (long) 0, /* no more small barrays */ |
| (long) 0); /* no more "medium" objects */ |
| /* NB: quantizer must get any such objects at color_quant_init time */ |
| |
| /* Initialize to read scan data */ |
| |
| (*cinfo->methods->entropy_decoder_init) (cinfo); |
| (*cinfo->methods->unsubsample_init) (cinfo); |
| (*cinfo->methods->disassemble_init) (cinfo); |
| |
| /* Loop over scan's data: rows_in_mem pixel rows are processed per loop */ |
| |
| pixel_rows_output = 0; |
| whichss = 1; /* arrange to start with subsampled_data[0] */ |
| |
| for (cur_mcu_row = 0; cur_mcu_row < cinfo->MCU_rows_in_scan; |
| cur_mcu_row += mcu_rows_per_loop) { |
| whichss ^= 1; /* switch to other subsample buffer */ |
| |
| /* Obtain v_samp_factor block rows of each component in the scan. */ |
| /* This is a single MCU row if interleaved, multiple MCU rows if not. */ |
| /* In the noninterleaved case there might be fewer than v_samp_factor */ |
| /* block rows remaining; if so, pad with copies of the last pixel row */ |
| /* so that unsubsampling doesn't have to treat it as a special case. */ |
| |
| for (ri = 0; ri < mcu_rows_per_loop; ri++) { |
| if (cur_mcu_row + ri < cinfo->MCU_rows_in_scan) { |
| /* OK to actually read an MCU row. */ |
| #ifdef BLOCK_SMOOTHING_SUPPORTED |
| if (cinfo->do_block_smoothing) |
| get_smoothed_row(cinfo, coeff_data, |
| bsmooth, &whichb, cur_mcu_row + ri); |
| else |
| #endif |
| (*cinfo->methods->disassemble_MCU) (cinfo, coeff_data); |
| |
| reverse_DCT(cinfo, coeff_data, subsampled_data[whichss], |
| ri * DCTSIZE); |
| } else { |
| /* Need to pad out with copies of the last subsampled row. */ |
| /* This can only happen if there is just one component. */ |
| duplicate_row(subsampled_data[whichss][0], |
| cinfo->cur_comp_info[0]->subsampled_width, |
| ri * DCTSIZE - 1, DCTSIZE); |
| } |
| } |
| |
| /* Unsubsample the data */ |
| /* First time through is a special case */ |
| |
| if (cur_mcu_row) { |
| /* Expand last row group of previous set */ |
| expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, |
| (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, |
| (short) (DCTSIZE-1)); |
| /* and dump the previous set's expanded data */ |
| emit_1pass (cinfo, rows_in_mem, fullsize_data, color_data); |
| pixel_rows_output += rows_in_mem; |
| /* Expand first row group of this set */ |
| expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, |
| (short) (DCTSIZE+1), (short) 0, (short) 1, |
| (short) 0); |
| } else { |
| /* Expand first row group with dummy above-context */ |
| expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, |
| (short) (-1), (short) 0, (short) 1, |
| (short) 0); |
| } |
| /* Expand second through next-to-last row groups of this set */ |
| for (i = 1; i <= DCTSIZE-2; i++) { |
| expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, |
| (short) (i-1), (short) i, (short) (i+1), |
| (short) i); |
| } |
| } /* end of outer loop */ |
| |
| /* Expand the last row group with dummy below-context */ |
| /* Note whichss points to last buffer side used */ |
| expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, |
| (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), |
| (short) (DCTSIZE-1)); |
| /* and dump the remaining data (may be less than full height) */ |
| emit_1pass (cinfo, (int) (cinfo->image_height - pixel_rows_output), |
| fullsize_data, color_data); |
| |
| /* Clean up after the scan */ |
| (*cinfo->methods->disassemble_term) (cinfo); |
| (*cinfo->methods->unsubsample_term) (cinfo); |
| (*cinfo->methods->entropy_decoder_term) (cinfo); |
| (*cinfo->methods->read_scan_trailer) (cinfo); |
| |
| /* Verify that we've seen the whole input file */ |
| if ((*cinfo->methods->read_scan_header) (cinfo)) |
| ERREXIT(cinfo->emethods, "Didn't expect more than one scan"); |
| |
| /* Release working memory */ |
| free_MCU_row(cinfo, coeff_data); |
| #ifdef BLOCK_SMOOTHING_SUPPORTED |
| if (cinfo->do_block_smoothing) { |
| free_MCU_row(cinfo, bsmooth[0]); |
| free_MCU_row(cinfo, bsmooth[1]); |
| free_MCU_row(cinfo, bsmooth[2]); |
| } |
| #endif |
| free_sampling_buffer(cinfo, subsampled_data); |
| free_sampimage(cinfo, fullsize_data, (int) cinfo->num_components, |
| (long) rows_in_mem); |
| free_sampimage(cinfo, color_data, (int) cinfo->color_out_comps, |
| (long) rows_in_mem); |
| if (cinfo->quantize_colors) |
| (*cinfo->emethods->free_small_sarray) |
| (quantize_out, (long) rows_in_mem); |
| |
| /* Close up shop */ |
| if (cinfo->quantize_colors) |
| (*cinfo->methods->color_quant_term) (cinfo); |
| } |
| |
| |
| /* |
| * Decompression pipeline controller used for single-scan files |
| * with 2-pass color quantization. |
| */ |
| |
| #ifdef QUANT_2PASS_SUPPORTED |
| |
| METHODDEF void |
| single_2quant_dcontroller (decompress_info_ptr cinfo) |
| { |
| long fullsize_width; /* # of samples per row in full-size buffers */ |
| long cur_mcu_row; /* counts # of MCU rows processed */ |
| long pixel_rows_output; /* # of pixel rows actually emitted */ |
| int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ |
| /* Work buffer for dequantized coefficients (IDCT input) */ |
| JBLOCKIMAGE coeff_data; |
| /* Work buffer for cross-block smoothing input */ |
| #ifdef BLOCK_SMOOTHING_SUPPORTED |
| JBLOCKIMAGE bsmooth[3]; /* this is optional */ |
| int whichb; |
| #endif |
| /* Work buffer for subsampled image data (see comments at head of file) */ |
| JSAMPIMAGE subsampled_data[2]; |
| /* Work buffer for desubsampled data */ |
| JSAMPIMAGE fullsize_data; |
| int whichss, ri; |
| short ci, i; |
| |
| /* Initialize for 2-pass color quantization */ |
| (*cinfo->methods->color_quant_init) (cinfo); |
| |
| /* Prepare for single scan containing all components */ |
| if (cinfo->comps_in_scan == 1) { |
| noninterleaved_scan_setup(cinfo); |
| /* Need to read Vk MCU rows to obtain Vk block rows */ |
| mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; |
| } else { |
| interleaved_scan_setup(cinfo); |
| /* in an interleaved scan, one MCU row provides Vk block rows */ |
| mcu_rows_per_loop = 1; |
| } |
| |
| /* Compute dimensions of full-size pixel buffers */ |
| /* Note these are the same whether interleaved or not. */ |
| rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; |
| fullsize_width = jround_up(cinfo->image_width, |
| (long) (cinfo->max_h_samp_factor * DCTSIZE)); |
| |
| /* Allocate working memory: */ |
| /* coeff_data holds a single MCU row of coefficient blocks */ |
| coeff_data = alloc_MCU_row(cinfo); |
| /* if doing cross-block smoothing, need extra space for its input */ |
| #ifdef BLOCK_SMOOTHING_SUPPORTED |
| if (cinfo->do_block_smoothing) { |
| bsmooth[0] = alloc_MCU_row(cinfo); |
| bsmooth[1] = alloc_MCU_row(cinfo); |
| bsmooth[2] = alloc_MCU_row(cinfo); |
| } |
| #endif |
| /* subsampled_data is sample data before unsubsampling */ |
| alloc_sampling_buffer(cinfo, subsampled_data); |
| /* fullsize_data is sample data after unsubsampling */ |
| fullsize_data = alloc_sampimage(cinfo, (int) cinfo->num_components, |
| (long) rows_in_mem, fullsize_width); |
| /* Also need a one-component output area for color quantizer. */ |
| quantize_out = (*cinfo->emethods->alloc_small_sarray) |
| (fullsize_width, (long) rows_in_mem); |
| |
| /* Get a big image for quantizer input: desubsampled, color-converted data */ |
| fullsize_cnvt_image = (big_sarray_ptr *) (*cinfo->emethods->alloc_small) |
| (cinfo->num_components * SIZEOF(big_sarray_ptr)); |
| for (ci = 0; ci < cinfo->num_components; ci++) { |
| fullsize_cnvt_image[ci] = (*cinfo->emethods->request_big_sarray) |
| (fullsize_width, |
| jround_up(cinfo->image_height, (long) rows_in_mem), |
| (long) rows_in_mem); |
| } |
| /* Also get an area for pointers to currently accessible chunks */ |
| fullsize_cnvt_ptrs = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) |
| (cinfo->num_components * SIZEOF(JSAMPARRAY)); |
| |
| /* Tell the memory manager to instantiate big arrays */ |
| (*cinfo->emethods->alloc_big_arrays) |
| ((long) 0, /* no more small sarrays */ |
| (long) 0, /* no more small barrays */ |
| (long) 0); /* no more "medium" objects */ |
| /* NB: quantizer must get any such objects at color_quant_init time */ |
| |
| /* Initialize to read scan data */ |
| |
| (*cinfo->methods->entropy_decoder_init) (cinfo); |
| (*cinfo->methods->unsubsample_init) (cinfo); |
| (*cinfo->methods->disassemble_init) (cinfo); |
| |
| /* Loop over scan's data: rows_in_mem pixel rows are processed per loop */ |
| |
| pixel_rows_output = 0; |
| whichss = 1; /* arrange to start with subsampled_data[0] */ |
| |
| for (cur_mcu_row = 0; cur_mcu_row < cinfo->MCU_rows_in_scan; |
| cur_mcu_row += mcu_rows_per_loop) { |
| whichss ^= 1; /* switch to other subsample buffer */ |
| |
| /* Obtain v_samp_factor block rows of each component in the scan. */ |
| /* This is a single MCU row if interleaved, multiple MCU rows if not. */ |
| /* In the noninterleaved case there might be fewer than v_samp_factor */ |
| /* block rows remaining; if so, pad with copies of the last pixel row */ |
| /* so that unsubsampling doesn't have to treat it as a special case. */ |
| |
| for (ri = 0; ri < mcu_rows_per_loop; ri++) { |
| if (cur_mcu_row + ri < cinfo->MCU_rows_in_scan) { |
| /* OK to actually read an MCU row. */ |
| #ifdef BLOCK_SMOOTHING_SUPPORTED |
| if (cinfo->do_block_smoothing) |
| get_smoothed_row(cinfo, coeff_data, |
| bsmooth, &whichb, cur_mcu_row + ri); |
| else |
| #endif |
| (*cinfo->methods->disassemble_MCU) (cinfo, coeff_data); |
| |
| reverse_DCT(cinfo, coeff_data, subsampled_data[whichss], |
| ri * DCTSIZE); |
| } else { |
| /* Need to pad out with copies of the last subsampled row. */ |
| /* This can only happen if there is just one component. */ |
| duplicate_row(subsampled_data[whichss][0], |
| cinfo->cur_comp_info[0]->subsampled_width, |
| ri * DCTSIZE - 1, DCTSIZE); |
| } |
| } |
| |
| /* Unsubsample the data */ |
| /* First time through is a special case */ |
| |
| if (cur_mcu_row) { |
| /* Expand last row group of previous set */ |
| expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, |
| (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, |
| (short) (DCTSIZE-1)); |
| /* and dump the previous set's expanded data */ |
| emit_2pass (cinfo, pixel_rows_output, rows_in_mem, fullsize_data); |
| pixel_rows_output += rows_in_mem; |
| /* Expand first row group of this set */ |
| expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, |
| (short) (DCTSIZE+1), (short) 0, (short) 1, |
| (short) 0); |
| } else { |
| /* Expand first row group with dummy above-context */ |
| expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, |
| (short) (-1), (short) 0, (short) 1, |
| (short) 0); |
| } |
| /* Expand second through next-to-last row groups of this set */ |
| for (i = 1; i <= DCTSIZE-2; i++) { |
| expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, |
| (short) (i-1), (short) i, (short) (i+1), |
| (short) i); |
| } |
| } /* end of outer loop */ |
| |
| /* Expand the last row group with dummy below-context */ |
| /* Note whichss points to last buffer side used */ |
| expand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width, |
| (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), |
| (short) (DCTSIZE-1)); |
| /* and dump the remaining data (may be less than full height) */ |
| emit_2pass (cinfo, pixel_rows_output, |
| (int) (cinfo->image_height - pixel_rows_output), |
| fullsize_data); |
| |
| /* Clean up after the scan */ |
| (*cinfo->methods->disassemble_term) (cinfo); |
| (*cinfo->methods->unsubsample_term) (cinfo); |
| (*cinfo->methods->entropy_decoder_term) (cinfo); |
| (*cinfo->methods->read_scan_trailer) (cinfo); |
| |
| /* Verify that we've seen the whole input file */ |
| if ((*cinfo->methods->read_scan_header) (cinfo)) |
| ERREXIT(cinfo->emethods, "Didn't expect more than one scan"); |
| |
| /* Now that we've collected the data, let the color quantizer do its thing */ |
| (*cinfo->methods->color_quant_doit) (cinfo, scan_big_image); |
| |
| /* Release working memory */ |
| free_MCU_row(cinfo, coeff_data); |
| #ifdef BLOCK_SMOOTHING_SUPPORTED |
| if (cinfo->do_block_smoothing) { |
| free_MCU_row(cinfo, bsmooth[0]); |
| free_MCU_row(cinfo, bsmooth[1]); |
| free_MCU_row(cinfo, bsmooth[2]); |
| } |
| #endif |
| free_sampling_buffer(cinfo, subsampled_data); |
| free_sampimage(cinfo, fullsize_data, (int) cinfo->num_components, |
| (long) rows_in_mem); |
| (*cinfo->emethods->free_small_sarray) |
| (quantize_out, (long) rows_in_mem); |
| for (ci = 0; ci < cinfo->num_components; ci++) { |
| (*cinfo->emethods->free_big_sarray) (fullsize_cnvt_image[ci]); |
| } |
| (*cinfo->emethods->free_small) ((void *) fullsize_cnvt_image); |
| (*cinfo->emethods->free_small) ((void *) fullsize_cnvt_ptrs); |
| |
| /* Close up shop */ |
| (*cinfo->methods->color_quant_term) (cinfo); |
| } |
| |
| #endif /* QUANT_2PASS_SUPPORTED */ |
| |
| |
| /* |
| * Decompression pipeline controller used for multiple-scan files |
| * without 2-pass color quantization. |
| * |
| * The current implementation places the "big" buffer at the stage of |
| * desubsampled data. Buffering subsampled data instead would reduce the |
| * size of temp files (by about a factor of 2 in typical cases). However, |
| * the unsubsampling logic is dependent on the assumption that unsubsampling |
| * occurs during a scan, so it's much easier to do the enlargement as the |
| * JPEG file is read. This also simplifies life for the memory manager, |
| * which would otherwise have to deal with overlapping access_big_sarray() |
| * requests. |
| * |
| * At present it appears that most JPEG files will be single-scan, so |
| * it doesn't seem worthwhile to try to make this implementation smarter. |
| */ |
| |
| #ifdef MULTISCAN_FILES_SUPPORTED |
| |
| METHODDEF void |
| multi_dcontroller (decompress_info_ptr cinfo) |
| { |
| long fullsize_width; /* # of samples per row in full-size buffers */ |
| long cur_mcu_row; /* counts # of MCU rows processed */ |
| long pixel_rows_output; /* # of pixel rows actually emitted */ |
| int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */ |
| /* Work buffer for dequantized coefficients (IDCT input) */ |
| JBLOCKIMAGE coeff_data; |
| /* Work buffer for cross-block smoothing input */ |
| #ifdef BLOCK_SMOOTHING_SUPPORTED |
| JBLOCKIMAGE bsmooth[3]; /* this is optional */ |
| int whichb; |
| #endif |
| /* Work buffer for subsampled image data (see comments at head of file) */ |
| JSAMPIMAGE subsampled_data[2]; |
| /* Full-image buffer holding desubsampled, but not color-converted, data */ |
| big_sarray_ptr *fullsize_image; |
| JSAMPIMAGE fullsize_ptrs; /* workspace for access_big_sarray() results */ |
| /* Work buffer for color conversion output (full size) */ |
| JSAMPIMAGE color_data; |
| int whichss, ri; |
| short ci, i; |
| |
| /* Initialize for 1-pass color quantization, if needed */ |
| if (cinfo->quantize_colors) |
| (*cinfo->methods->color_quant_init) (cinfo); |
| |
| /* Compute dimensions of full-size pixel buffers */ |
| /* Note these are the same whether interleaved or not. */ |
| rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE; |
| fullsize_width = jround_up(cinfo->image_width, |
| (long) (cinfo->max_h_samp_factor * DCTSIZE)); |
| |
| /* Allocate all working memory that doesn't depend on scan info */ |
| /* color_data is the result of the colorspace conversion step */ |
| color_data = alloc_sampimage(cinfo, (int) cinfo->color_out_comps, |
| (long) rows_in_mem, fullsize_width); |
| /* if quantizing colors, also need a one-component output area for that. */ |
| if (cinfo->quantize_colors) |
| quantize_out = (*cinfo->emethods->alloc_small_sarray) |
| (fullsize_width, (long) rows_in_mem); |
| |
| /* Get a big image: fullsize_image is sample data after unsubsampling. */ |
| fullsize_image = (big_sarray_ptr *) (*cinfo->emethods->alloc_small) |
| (cinfo->num_components * SIZEOF(big_sarray_ptr)); |
| for (ci = 0; ci < cinfo->num_components; ci++) { |
| fullsize_image[ci] = (*cinfo->emethods->request_big_sarray) |
| (fullsize_width, |
| jround_up(cinfo->image_height, (long) rows_in_mem), |
| (long) rows_in_mem); |
| } |
| /* Also get an area for pointers to currently accessible chunks */ |
| fullsize_ptrs = (JSAMPIMAGE) (*cinfo->emethods->alloc_small) |
| (cinfo->num_components * SIZEOF(JSAMPARRAY)); |
| |
| /* Tell the memory manager to instantiate big arrays */ |
| (*cinfo->emethods->alloc_big_arrays) |
| /* extra sarray space is for subsampled-data buffers: */ |
| ((long) (fullsize_width /* max width in samples */ |
| * cinfo->max_v_samp_factor*(DCTSIZE+2) /* max height */ |
| * cinfo->num_components), /* max components per scan */ |
| /* extra barray space is for MCU-row buffers: */ |
| (long) ((fullsize_width / DCTSIZE) /* max width in blocks */ |
| * cinfo->max_v_samp_factor /* max height */ |
| * cinfo->num_components /* max components per scan */ |
| * (cinfo->do_block_smoothing ? 4 : 1)),/* how many of these we need */ |
| /* no extra "medium"-object space */ |
| /* NB: quantizer must get any such objects at color_quant_init time */ |
| (long) 0); |
| |
| |
| /* Loop over scans in file */ |
| |
| do { |
| |
| /* Prepare for this scan */ |
| if (cinfo->comps_in_scan == 1) { |
| noninterleaved_scan_setup(cinfo); |
| /* Need to read Vk MCU rows to obtain Vk block rows */ |
| mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor; |
| } else { |
| interleaved_scan_setup(cinfo); |
| /* in an interleaved scan, one MCU row provides Vk block rows */ |
| mcu_rows_per_loop = 1; |
| } |
| |
| /* Allocate scan-local working memory */ |
| /* coeff_data holds a single MCU row of coefficient blocks */ |
| coeff_data = alloc_MCU_row(cinfo); |
| /* if doing cross-block smoothing, need extra space for its input */ |
| #ifdef BLOCK_SMOOTHING_SUPPORTED |
| if (cinfo->do_block_smoothing) { |
| bsmooth[0] = alloc_MCU_row(cinfo); |
| bsmooth[1] = alloc_MCU_row(cinfo); |
| bsmooth[2] = alloc_MCU_row(cinfo); |
| } |
| #endif |
| /* subsampled_data is sample data before unsubsampling */ |
| alloc_sampling_buffer(cinfo, subsampled_data); |
| |
| /* line up the big buffers */ |
| for (ci = 0; ci < cinfo->comps_in_scan; ci++) { |
| fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray) |
| (fullsize_image[cinfo->cur_comp_info[ci]->component_index], |
| (long) 0, TRUE); |
| } |
| |
| /* Initialize to read scan data */ |
| |
| (*cinfo->methods->entropy_decoder_init) (cinfo); |
| (*cinfo->methods->unsubsample_init) (cinfo); |
| (*cinfo->methods->disassemble_init) (cinfo); |
| |
| /* Loop over scan's data: rows_in_mem pixel rows are processed per loop */ |
| |
| pixel_rows_output = 0; |
| whichss = 1; /* arrange to start with subsampled_data[0] */ |
| |
| for (cur_mcu_row = 0; cur_mcu_row < cinfo->MCU_rows_in_scan; |
| cur_mcu_row += mcu_rows_per_loop) { |
| whichss ^= 1; /* switch to other subsample buffer */ |
| |
| /* Obtain v_samp_factor block rows of each component in the scan. */ |
| /* This is a single MCU row if interleaved, multiple MCU rows if not. */ |
| /* In the noninterleaved case there might be fewer than v_samp_factor */ |
| /* block rows remaining; if so, pad with copies of the last pixel row */ |
| /* so that unsubsampling doesn't have to treat it as a special case. */ |
| |
| for (ri = 0; ri < mcu_rows_per_loop; ri++) { |
| if (cur_mcu_row + ri < cinfo->MCU_rows_in_scan) { |
| /* OK to actually read an MCU row. */ |
| #ifdef BLOCK_SMOOTHING_SUPPORTED |
| if (cinfo->do_block_smoothing) |
| get_smoothed_row(cinfo, coeff_data, |
| bsmooth, &whichb, cur_mcu_row + ri); |
| else |
| #endif |
| (*cinfo->methods->disassemble_MCU) (cinfo, coeff_data); |
| |
| reverse_DCT(cinfo, coeff_data, subsampled_data[whichss], |
| ri * DCTSIZE); |
| } else { |
| /* Need to pad out with copies of the last subsampled row. */ |
| /* This can only happen if there is just one component. */ |
| duplicate_row(subsampled_data[whichss][0], |
| cinfo->cur_comp_info[0]->subsampled_width, |
| ri * DCTSIZE - 1, DCTSIZE); |
| } |
| } |
| |
| /* Unsubsample the data */ |
| /* First time through is a special case */ |
| |
| if (cur_mcu_row) { |
| /* Expand last row group of previous set */ |
| expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, |
| (short) DCTSIZE, (short) (DCTSIZE+1), (short) 0, |
| (short) (DCTSIZE-1)); |
| /* Realign the big buffers */ |
| pixel_rows_output += rows_in_mem; |
| for (ci = 0; ci < cinfo->comps_in_scan; ci++) { |
| fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray) |
| (fullsize_image[cinfo->cur_comp_info[ci]->component_index], |
| pixel_rows_output, TRUE); |
| } |
| /* Expand first row group of this set */ |
| expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, |
| (short) (DCTSIZE+1), (short) 0, (short) 1, |
| (short) 0); |
| } else { |
| /* Expand first row group with dummy above-context */ |
| expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, |
| (short) (-1), (short) 0, (short) 1, |
| (short) 0); |
| } |
| /* Expand second through next-to-last row groups of this set */ |
| for (i = 1; i <= DCTSIZE-2; i++) { |
| expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, |
| (short) (i-1), (short) i, (short) (i+1), |
| (short) i); |
| } |
| } /* end of outer loop */ |
| |
| /* Expand the last row group with dummy below-context */ |
| /* Note whichss points to last buffer side used */ |
| expand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width, |
| (short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1), |
| (short) (DCTSIZE-1)); |
| |
| /* Clean up after the scan */ |
| (*cinfo->methods->disassemble_term) (cinfo); |
| (*cinfo->methods->unsubsample_term) (cinfo); |
| (*cinfo->methods->entropy_decoder_term) (cinfo); |
| (*cinfo->methods->read_scan_trailer) (cinfo); |
| |
| /* Release scan-local working memory */ |
| free_MCU_row(cinfo, coeff_data); |
| #ifdef BLOCK_SMOOTHING_SUPPORTED |
| if (cinfo->do_block_smoothing) { |
| free_MCU_row(cinfo, bsmooth[0]); |
| free_MCU_row(cinfo, bsmooth[1]); |
| free_MCU_row(cinfo, bsmooth[2]); |
| } |
| #endif |
| free_sampling_buffer(cinfo, subsampled_data); |
| |
| /* Repeat if there is another scan */ |
| } while ((*cinfo->methods->read_scan_header) (cinfo)); |
| |
| /* Now that we've collected all the data, color convert & output it. */ |
| |
| for (pixel_rows_output = 0; pixel_rows_output < cinfo->image_height; |
| pixel_rows_output += rows_in_mem) { |
| |
| /* realign the big buffers */ |
| for (ci = 0; ci < cinfo->num_components; ci++) { |
| fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray) |
| (fullsize_image[ci], pixel_rows_output, FALSE); |
| } |
| |
| emit_1pass (cinfo, |
| (int) MIN(rows_in_mem, cinfo->image_height-pixel_rows_output), |
| fullsize_ptrs, color_data); |
| } |
| |
| /* Release working memory */ |
| free_sampimage(cinfo, color_data, (int) cinfo->color_out_comps, |
| (long) rows_in_mem); |
| if (cinfo->quantize_colors) |
| (*cinfo->emethods->free_small_sarray) |
| (quantize_out, (long) rows_in_mem); |
| for (ci = 0; ci < cinfo->num_components; ci++) { |
| (*cinfo->emethods->free_big_sarray) (fullsize_image[ci]); |
| } |
| (*cinfo->emethods->free_small) ((void *) fullsize_image); |
| (*cinfo->emethods->free_small) ((void *) fullsize_ptrs); |
| |
| /* Close up shop */ |
| if (cinfo->quantize_colors) |
| (*cinfo->methods->color_quant_term) (cinfo); |
| } |
| |
| #endif /* MULTISCAN_FILES_SUPPORTED */ |
| |
| |
| /* |
| * Decompression pipeline controller used for multiple-scan files |
| * with 2-pass color quantization. |
| */ |
| |
| #ifdef MULTISCAN_FILES_SUPPORTED |
| #ifdef QUANT_2PASS_SUPPORTED |
| |
| METHODDEF void |
| multi_2quant_dcontroller (decompress_info_ptr cinfo) |
| { |
| ERREXIT(cinfo->emethods, "Not implemented yet"); |
| } |
| |
| #endif /* QUANT_2PASS_SUPPORTED */ |
| #endif /* MULTISCAN_FILES_SUPPORTED */ |
| |
| |
| /* |
| * The method selection routine for decompression pipeline controllers. |
| * Note that at this point we've already read the JPEG header and first SOS, |
| * so we can tell whether the input is one scan or not. |
| */ |
| |
| GLOBAL void |
| jseldpipeline (decompress_info_ptr cinfo) |
| { |
| /* simplify subsequent tests on color quantization */ |
| if (! cinfo->quantize_colors) |
| cinfo->two_pass_quantize = FALSE; |
| |
| if (cinfo->comps_in_scan == cinfo->num_components) { |
| /* It's a single-scan file */ |
| #ifdef QUANT_2PASS_SUPPORTED |
| if (cinfo->two_pass_quantize) |
| cinfo->methods->d_pipeline_controller = single_2quant_dcontroller; |
| else |
| #endif |
| cinfo->methods->d_pipeline_controller = single_dcontroller; |
| } else { |
| /* It's a multiple-scan file */ |
| #ifdef MULTISCAN_FILES_SUPPORTED |
| #ifdef QUANT_2PASS_SUPPORTED |
| if (cinfo->two_pass_quantize) |
| cinfo->methods->d_pipeline_controller = multi_2quant_dcontroller; |
| else |
| #endif |
| cinfo->methods->d_pipeline_controller = multi_dcontroller; |
| #else |
| ERREXIT(cinfo->emethods, "Multiple-scan support was not compiled"); |
| #endif |
| } |
| } |