jquant2.c
来自「EVM板JPEG实现,Texas Instruments TMS320C54x 」· C语言 代码 · 共 1,183 行 · 第 1/3 页
C
1,183 行
JSAMPLE bestcolor[BOX_Y_ELEMS * BOX_C_ELEMS * BOX_C_ELEMS];
/* Convert cell coordinates to update box ID */
c0 >>= BOX_Y_LOG;
c1 >>= BOX_C_LOG;
c2 >>= BOX_C_LOG;
/* Compute true coordinates of update box's origin corner.
* Actually we compute the coordinates of the center of the corner
* histogram cell, which are the lower bounds of the volume we care about.
*/
minc0 = (c0 << BOX_Y_SHIFT) + ((1 << Y_SHIFT) >> 1);
minc1 = (c1 << BOX_C_SHIFT) + ((1 << C_SHIFT) >> 1);
minc2 = (c2 << BOX_C_SHIFT) + ((1 << C_SHIFT) >> 1);
/* Determine which colormap entries are close enough to be candidates
* for the nearest entry to some cell in the update box.
*/
numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist);
/* Determine the actually nearest colors. */
find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist,
bestcolor);
/* Save the best color numbers (plus 1) in the main cache array */
c0 <<= BOX_Y_LOG; /* convert ID back to base cell indexes */
c1 <<= BOX_C_LOG;
c2 <<= BOX_C_LOG;
cptr = bestcolor;
for (ic0 = 0; ic0 < BOX_Y_ELEMS; ic0++) {
for (ic1 = 0; ic1 < BOX_C_ELEMS; ic1++) {
cachep = & histogram[c0+ic0][c1+ic1][c2];
for (ic2 = 0; ic2 < BOX_C_ELEMS; ic2++) {
*cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1);
}
}
}
}
/*
* These routines perform second-pass scanning of the image: map each pixel to
* the proper colormap index, and output the indexes to the output file.
*
* output_workspace is a one-component array of pixel dimensions at least
* as large as the input image strip; it can be used to hold the converted
* pixels' colormap indexes.
*/
METHODDEF void
pass2_nodither (decompress_info_ptr cinfo, int num_rows,
JSAMPIMAGE image_data, JSAMPARRAY output_workspace)
/* This version performs no dithering */
{
register JSAMPROW ptr0, ptr1, ptr2, outptr;
register histptr cachep;
register int c0, c1, c2;
int row;
long col;
long width = cinfo->image_width;
/* Convert data to colormap indexes, which we save in output_workspace */
for (row = 0; row < num_rows; row++) {
ptr0 = image_data[0][row];
ptr1 = image_data[1][row];
ptr2 = image_data[2][row];
outptr = output_workspace[row];
for (col = width; col > 0; col--) {
/* get pixel value and index into the cache */
c0 = GETJSAMPLE(*ptr0++) >> Y_SHIFT;
c1 = GETJSAMPLE(*ptr1++) >> C_SHIFT;
c2 = GETJSAMPLE(*ptr2++) >> C_SHIFT;
cachep = & histogram[c0][c1][c2];
/* If we have not seen this color before, find nearest colormap entry */
/* and update the cache */
if (*cachep == 0)
fill_inverse_cmap(cinfo, c0,c1,c2);
/* Now emit the colormap index for this cell */
*outptr++ = (JSAMPLE) (*cachep - 1);
}
}
/* Emit converted rows to the output file */
(*cinfo->methods->put_pixel_rows) (cinfo, num_rows, &output_workspace);
}
/* Declarations for Floyd-Steinberg dithering.
*
* Errors are accumulated into the arrays evenrowerrs[] and oddrowerrs[].
* These have resolutions of 1/16th of a pixel count. The error at a given
* pixel is propagated to its unprocessed neighbors using the standard F-S
* fractions,
* ... (here) 7/16
* 3/16 5/16 1/16
* We work left-to-right on even rows, right-to-left on odd rows.
*
* Each of the arrays has (#columns + 2) entries; the extra entry
* at each end saves us from special-casing the first and last pixels.
* Each entry is three values long.
* In evenrowerrs[], the entries for a component are stored left-to-right, but
* in oddrowerrs[] they are stored right-to-left. This means we always
* process the current row's error entries in increasing order and the next
* row's error entries in decreasing order, regardless of whether we are
* working L-to-R or R-to-L in the pixel data!
*
* Note: on a wide image, we might not have enough room in a PC's near data
* segment to hold the error arrays; so they are allocated with alloc_medium.
*/
#ifdef EIGHT_BIT_SAMPLES
typedef INT16 FSERROR; /* 16 bits should be enough */
#else
typedef INT32 FSERROR; /* may need more than 16 bits? */
#endif
typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */
static FSERRPTR evenrowerrs, oddrowerrs; /* current-row and next-row errors */
static boolean on_odd_row; /* flag to remember which row we are on */
METHODDEF void
pass2_dither (decompress_info_ptr cinfo, int num_rows,
JSAMPIMAGE image_data, JSAMPARRAY output_workspace)
/* This version performs Floyd-Steinberg dithering */
{
#ifdef EIGHT_BIT_SAMPLES
register int c0, c1, c2;
int two_val;
#else
register FSERROR c0, c1, c2;
FSERROR two_val;
#endif
register FSERRPTR thisrowerr, nextrowerr;
JSAMPROW ptr0, ptr1, ptr2, outptr;
histptr cachep;
register int pixcode;
int dir;
int row;
long col;
long width = cinfo->image_width;
JSAMPLE *range_limit = cinfo->sample_range_limit;
JSAMPROW colormap0 = my_colormap[0];
JSAMPROW colormap1 = my_colormap[1];
JSAMPROW colormap2 = my_colormap[2];
SHIFT_TEMPS
/* Convert data to colormap indexes, which we save in output_workspace */
for (row = 0; row < num_rows; row++) {
ptr0 = image_data[0][row];
ptr1 = image_data[1][row];
ptr2 = image_data[2][row];
outptr = output_workspace[row];
if (on_odd_row) {
/* work right to left in this row */
ptr0 += width - 1;
ptr1 += width - 1;
ptr2 += width - 1;
outptr += width - 1;
dir = -1;
thisrowerr = oddrowerrs + 3;
nextrowerr = evenrowerrs + width*3;
on_odd_row = FALSE; /* flip for next time */
} else {
/* work left to right in this row */
dir = 1;
thisrowerr = evenrowerrs + 3;
nextrowerr = oddrowerrs + width*3;
on_odd_row = TRUE; /* flip for next time */
}
/* need only initialize this one entry in nextrowerr */
nextrowerr[0] = nextrowerr[1] = nextrowerr[2] = 0;
for (col = width; col > 0; col--) {
/* For each component, get accumulated error and round to integer;
* form pixel value + error, and range-limit to 0..MAXJSAMPLE.
* RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
* for either sign of the error value. Max error is +- MAXJSAMPLE.
*/
c0 = RIGHT_SHIFT(thisrowerr[0] + 8, 4);
c1 = RIGHT_SHIFT(thisrowerr[1] + 8, 4);
c2 = RIGHT_SHIFT(thisrowerr[2] + 8, 4);
c0 += GETJSAMPLE(*ptr0);
c1 += GETJSAMPLE(*ptr1);
c2 += GETJSAMPLE(*ptr2);
c0 = GETJSAMPLE(range_limit[c0]);
c1 = GETJSAMPLE(range_limit[c1]);
c2 = GETJSAMPLE(range_limit[c2]);
/* Index into the cache with adjusted pixel value */
cachep = & histogram[c0 >> Y_SHIFT][c1 >> C_SHIFT][c2 >> C_SHIFT];
/* If we have not seen this color before, find nearest colormap */
/* entry and update the cache */
if (*cachep == 0)
fill_inverse_cmap(cinfo, c0 >> Y_SHIFT, c1 >> C_SHIFT, c2 >> C_SHIFT);
/* Now emit the colormap index for this cell */
pixcode = *cachep - 1;
*outptr = (JSAMPLE) pixcode;
/* Compute representation error for this pixel */
c0 -= GETJSAMPLE(colormap0[pixcode]);
c1 -= GETJSAMPLE(colormap1[pixcode]);
c2 -= GETJSAMPLE(colormap2[pixcode]);
/* Propagate error to adjacent pixels */
/* Remember that nextrowerr entries are in reverse order! */
two_val = c0 * 2;
nextrowerr[0-3] = c0; /* not +=, since not initialized yet */
c0 += two_val; /* form error * 3 */
nextrowerr[0+3] += c0;
c0 += two_val; /* form error * 5 */
nextrowerr[0 ] += c0;
c0 += two_val; /* form error * 7 */
thisrowerr[0+3] += c0;
two_val = c1 * 2;
nextrowerr[1-3] = c1; /* not +=, since not initialized yet */
c1 += two_val; /* form error * 3 */
nextrowerr[1+3] += c1;
c1 += two_val; /* form error * 5 */
nextrowerr[1 ] += c1;
c1 += two_val; /* form error * 7 */
thisrowerr[1+3] += c1;
two_val = c2 * 2;
nextrowerr[2-3] = c2; /* not +=, since not initialized yet */
c2 += two_val; /* form error * 3 */
nextrowerr[2+3] += c2;
c2 += two_val; /* form error * 5 */
nextrowerr[2 ] += c2;
c2 += two_val; /* form error * 7 */
thisrowerr[2+3] += c2;
/* Advance to next column */
ptr0 += dir;
ptr1 += dir;
ptr2 += dir;
outptr += dir;
thisrowerr += 3; /* cur-row error ptr advances to right */
nextrowerr -= 3; /* next-row error ptr advances to left */
}
}
/* Emit converted rows to the output file */
(*cinfo->methods->put_pixel_rows) (cinfo, num_rows, &output_workspace);
}
/*
* Initialize for two-pass color quantization.
*/
METHODDEF void
color_quant_init (decompress_info_ptr cinfo)
{
int i;
/* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */
if (cinfo->desired_number_of_colors < 8)
{
/* ERREXIT(cinfo->emethods, "Cannot request less than 8 quantized colors"); */
send_command(ERR11);
receive_command();
exit();
}
/* Make sure colormap indexes can be represented by JSAMPLEs */
if (cinfo->desired_number_of_colors > MAXNUMCOLORS)
{
/* ERREXIT1(cinfo->emethods, "Cannot request more than %d quantized colors",
MAXNUMCOLORS); */
send_command(ERR11);
receive_command();
exit();
}
/* Allocate and zero the histogram */
histogram = (hist3d) (*cinfo->emethods->alloc_small)
(HIST_Y_ELEMS * SIZEOF(hist2d));
for (i = 0; i < HIST_Y_ELEMS; i++) {
histogram[i] = (hist2d) (*cinfo->emethods->alloc_medium)
(HIST_C_ELEMS*HIST_C_ELEMS * SIZEOF(histcell));
jzero_far((void FAR *) histogram[i],
HIST_C_ELEMS*HIST_C_ELEMS * SIZEOF(histcell));
}
/* Allocate storage for the internal and external colormaps. */
/* We do this now since it is FAR storage and may affect the memory */
/* manager's space calculations. */
my_colormap = (*cinfo->emethods->alloc_small_sarray)
((long) cinfo->desired_number_of_colors,
(long) 3);
cinfo->colormap = (*cinfo->emethods->alloc_small_sarray)
((long) cinfo->desired_number_of_colors,
(long) cinfo->color_out_comps);
/* Allocate Floyd-Steinberg workspace if necessary */
/* This isn't needed until pass 2, but again it is FAR storage. */
if (cinfo->use_dithering) {
size_t arraysize = (size_t) ((cinfo->image_width + 2L) * 3L * SIZEOF(FSERROR));
evenrowerrs = (FSERRPTR) (*cinfo->emethods->alloc_medium) (arraysize);
oddrowerrs = (FSERRPTR) (*cinfo->emethods->alloc_medium) (arraysize);
/* we only need to zero the forward contribution for current row. */
jzero_far((void FAR *) evenrowerrs, arraysize);
on_odd_row = FALSE;
}
/* Indicate number of passes needed, excluding the prescan pass. */
cinfo->total_passes++; /* I always use one pass */
}
/*
* Perform two-pass quantization: rescan the image data and output the
* converted data via put_color_map and put_pixel_rows.
* The source_method is a routine that can scan the image data; it can
* be called as many times as desired. The processing routine called by
* source_method has the same interface as color_quantize does in the
* one-pass case, except it must call put_pixel_rows itself. (This allows
* me to use multiple passes in which earlier passes don't output anything.)
*/
METHODDEF void
color_quant_doit (decompress_info_ptr cinfo, quantize_caller_ptr source_method)
{
int i;
/* Select the representative colors */
select_colors(cinfo);
/* Pass the external colormap to the output module. */
/* NB: the output module may continue to use the colormap until shutdown. */
(*cinfo->methods->put_color_map) (cinfo, cinfo->actual_number_of_colors,
cinfo->colormap);
/* Re-zero the histogram so pass 2 can use it as nearest-color cache */
for (i = 0; i < HIST_Y_ELEMS; i++) {
jzero_far((void FAR *) histogram[i],
HIST_C_ELEMS*HIST_C_ELEMS * SIZEOF(histcell));
}
/* Perform pass 2 */
if (cinfo->use_dithering)
(*source_method) (cinfo, pass2_dither);
else
(*source_method) (cinfo, pass2_nodither);
}
/*
* Finish up at the end of the file.
*/
METHODDEF void
color_quant_term (decompress_info_ptr cinfo)
{
/* no work (we let free_all release the histogram/cache and colormaps) */
/* Note that we *mustn't* free the external colormap before free_all, */
/* since output module may use it! */
}
/*
* Map some rows of pixels to the output colormapped representation.
* Not used in two-pass case.
*/
METHODDEF void
color_quantize (decompress_info_ptr cinfo, int num_rows,
JSAMPIMAGE input_data, JSAMPARRAY output_data)
{
/* ERREXIT(cinfo->emethods, "Should not get here!"); */
send_command(ERR11);
receive_command();
exit();
}
/*
* The method selection routine for 2-pass color quantization.
*/
GLOBAL void
jsel2quantize (decompress_info_ptr cinfo)
{
if (cinfo->two_pass_quantize) {
/* Make sure jdmaster didn't give me a case I can't handle */
if (cinfo->num_components != 3 || cinfo->jpeg_color_space != CS_YCbCr)
{
/* ERREXIT(cinfo->emethods, "2-pass quantization only handles YCbCr input"); */
send_command(ERR11);
receive_command();
exit();
}
cinfo->methods->color_quant_init = color_quant_init;
cinfo->methods->color_quant_prescan = color_quant_prescan;
cinfo->methods->color_quant_doit = color_quant_doit;
cinfo->methods->color_quant_term = color_quant_term;
cinfo->methods->color_quantize = color_quantize;
}
}
#endif /* QUANT_2PASS_SUPPORTED */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?