1311 lines
46 KiB
C
1311 lines
46 KiB
C
/*
|
|
* 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((long) 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
|
|
}
|
|
}
|