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 + -
显示快捷键?