⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jquant1.pas

📁 DELPHI版的JPEG文件解码源程序
💻 PAS
📖 第 1 页 / 共 3 页
字号:
Unit JQuant1;

{ This file contains 1-pass color quantization (color mapping) routines.
  These routines provide mapping to a fixed color map using equally spaced
  color values.  Optional Floyd-Steinberg or ordered dithering is available. }

{ Original: jquant1.c; Copyright (C) 1991-1996, Thomas G. Lane. }

interface

uses
  jpeglib;

{$I jconfig.inc}

{GLOBAL}
procedure jinit_1pass_quantizer (cinfo : j_decompress_ptr);

implementation

uses
  jmorecfg,
  jdeferr,
  jerror,
  jutils;

{ The main purpose of 1-pass quantization is to provide a fast, if not very
  high quality, colormapped output capability.  A 2-pass quantizer usually
  gives better visual quality; however, for quantized grayscale output this
  quantizer is perfectly adequate.  Dithering is highly recommended with this
  quantizer, though you can turn it off if you really want to.

  In 1-pass quantization the colormap must be chosen in advance of seeing the
  image.  We use a map consisting of all combinations of Ncolors[i] color
  values for the i'th component.  The Ncolors[] values are chosen so that
  their product, the total number of colors, is no more than that requested.
  (In most cases, the product will be somewhat less.)

  Since the colormap is orthogonal, the representative value for each color
  component can be determined without considering the other components;
  then these indexes can be combined into a colormap index by a standard
  N-dimensional-array-subscript calculation.  Most of the arithmetic involved
  can be precalculated and stored in the lookup table colorindex[].
  colorindex[i][j] maps pixel value j in component i to the nearest
  representative value (grid plane) for that component; this index is
  multiplied by the array stride for component i, so that the
  index of the colormap entry closest to a given pixel value is just
     sum( colorindex[component-number][pixel-component-value] )
  Aside from being fast, this scheme allows for variable spacing between
  representative values with no additional lookup cost.

  If gamma correction has been applied in color conversion, it might be wise
  to adjust the color grid spacing so that the representative colors are
  equidistant in linear space.  At this writing, gamma correction is not
  implemented by jdcolor, so nothing is done here. }


{ Declarations for ordered dithering.

  We use a standard 16x16 ordered dither array.  The basic concept of ordered
  dithering is described in many references, for instance Dale Schumacher's
  chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991).
  In place of Schumacher's comparisons against a "threshold" value, we add a
  "dither" value to the input pixel and then round the result to the nearest
  output value.  The dither value is equivalent to (0.5 - threshold) times
  the distance between output values.  For ordered dithering, we assume that
  the output colors are equally spaced; if not, results will probably be
  worse, since the dither may be too much or too little at a given point.

  The normal calculation would be to form pixel value + dither, range-limit
  this to 0..MAXJSAMPLE, and then index into the colorindex table as usual.
  We can skip the separate range-limiting step by extending the colorindex
  table in both directions. }


const
  ODITHER_SIZE  = 16;   { dimension of dither matrix }
{ NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break }
  ODITHER_CELLS = (ODITHER_SIZE*ODITHER_SIZE);  { # cells in matrix }
  ODITHER_MASK = (ODITHER_SIZE-1); { mask for wrapping around counters }

type
  ODITHER_vector = Array[0..ODITHER_SIZE-1] of int;
  ODITHER_MATRIX = Array[0..ODITHER_SIZE-1] of ODITHER_vector;
  {ODITHER_MATRIX_PTR = ^array[0..ODITHER_SIZE-1] of int;}
  ODITHER_MATRIX_PTR = ^ODITHER_MATRIX;

const
  base_dither_matrix : Array[0..ODITHER_SIZE-1,0..ODITHER_SIZE-1] of UINT8
  = (
  { Bayer's order-4 dither array.  Generated by the code given in
    Stephen Hawley's article "Ordered Dithering" in Graphics Gems I.
    The values in this array must range from 0 to ODITHER_CELLS-1. }

  (   0,192, 48,240, 12,204, 60,252,  3,195, 51,243, 15,207, 63,255 ),
  ( 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 ),
  (  32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 ),
  ( 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 ),
  (   8,200, 56,248,  4,196, 52,244, 11,203, 59,251,  7,199, 55,247 ),
  ( 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 ),
  (  40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 ),
  ( 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 ),
  (   2,194, 50,242, 14,206, 62,254,  1,193, 49,241, 13,205, 61,253 ),
  ( 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 ),
  (  34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 ),
  ( 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 ),
  (  10,202, 58,250,  6,198, 54,246,  9,201, 57,249,  5,197, 53,245 ),
  ( 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 ),
  (  42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 ),
  ( 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 )
  );


{ Declarations for Floyd-Steinberg dithering.

  Errors are accumulated into the array fserrors[], at a resolution of
  1/16th of a pixel count.  The error at a given pixel is propagated
  to its not-yet-processed 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.

  We can get away with a single array (holding one row's worth of errors)
  by using it to store the current row's errors at pixel columns not yet
  processed, but the next row's errors at columns already processed.  We
  need only a few extra variables to hold the errors immediately around the
  current column.  (If we are lucky, those variables are in registers, but
  even if not, they're probably cheaper to access than array elements are.)

  The fserrors[] array is indexed [component#][position].
  We provide (#columns + 2) entries per component; the extra entry at each
  end saves us from special-casing the first and last pixels.

  Note: on a wide image, we might not have enough room in a PC's near data
  segment to hold the error array; so it is allocated with alloc_large. }

{$ifdef BITS_IN_JSAMPLE_IS_8}
type
  FSERROR = INT16;              { 16 bits should be enough }
  LOCFSERROR = int;             { use 'int' for calculation temps }
{$else}
type
  FSERROR = INT32;              { may need more than 16 bits }
  LOCFSERROR = INT32;           { be sure calculation temps are big enough }
{$endif}

type
  jFSError = 0..(MaxInt div SIZEOF(FSERROR))-1;
  FS_ERROR_FIELD = array[jFSError] of FSERROR;
  FS_ERROR_FIELD_PTR = ^FS_ERROR_FIELD;{far}
                                { pointer to error array (in FAR storage!) }
  FSERRORPTR = ^FSERROR;


{ Private subobject }

const
  MAX_Q_COMPS = 4;              { max components I can handle }

type
  my_cquantize_ptr = ^my_cquantizer;
  my_cquantizer = record
    pub : jpeg_color_quantizer; { public fields }

    { Initially allocated colormap is saved here }
    sv_colormap : JSAMPARRAY;   { The color map as a 2-D pixel array }
    sv_actual : int;            { number of entries in use }

    colorindex : JSAMPARRAY;    { Precomputed mapping for speed }
    { colorindex[i][j] = index of color closest to pixel value j in component i,
      premultiplied as described above.  Since colormap indexes must fit into
      JSAMPLEs, the entries of this array will too. }

    is_padded : boolean;        { is the colorindex padded for odither? }

    Ncolors : array[0..MAX_Q_COMPS-1] of int;
                                { # of values alloced to each component }

    { Variables for ordered dithering }
    row_index : int;            { cur row's vertical index in dither matrix }
    odither : array[0..MAX_Q_COMPS-1] of ODITHER_MATRIX_PTR;
                                { one dither array per component }
    { Variables for Floyd-Steinberg dithering }
    fserrors : array[0..MAX_Q_COMPS-1] of FS_ERROR_FIELD_PTR;
                                { accumulated errors }
    on_odd_row : boolean;       { flag to remember which row we are on }
  end;


{ Policy-making subroutines for create_colormap and create_colorindex.
  These routines determine the colormap to be used.  The rest of the module
  only assumes that the colormap is orthogonal.

   * select_ncolors decides how to divvy up the available colors
     among the components.
   * output_value defines the set of representative values for a component.
   * largest_input_value defines the mapping from input values to
     representative values for a component.
  Note that the latter two routines may impose different policies for
  different components, though this is not currently done. }



{LOCAL}
function select_ncolors (cinfo : j_decompress_ptr;
                         var Ncolors : array of int) : int;
{ Determine allocation of desired colors to components, }
{ and fill in Ncolors[] array to indicate choice. }
{ Return value is total number of colors (product of Ncolors[] values). }
var
  nc : int;
  max_colors : int;
  total_colors, iroot, i, j : int;
  changed : boolean;
  temp : long;
const
  RGB_order:array[0..2] of int = (RGB_GREEN, RGB_RED, RGB_BLUE);
begin
  nc := cinfo^.out_color_components; { number of color components }
  max_colors := cinfo^.desired_number_of_colors;

  { We can allocate at least the nc'th root of max_colors per component. }
  { Compute floor(nc'th root of max_colors). }
  iroot := 1;
  repeat
    Inc(iroot);
    temp := iroot;		{ set temp = iroot ** nc }
    for i := 1 to pred(nc) do
      temp := temp * iroot;
  until (temp > long(max_colors)); { repeat till iroot exceeds root }
  Dec(iroot);                   { now iroot = floor(root) }

  { Must have at least 2 color values per component }
  if (iroot < 2) then
    ERREXIT1(j_common_ptr(cinfo), JERR_QUANT_FEW_COLORS, int(temp));

  { Initialize to iroot color values for each component }
  total_colors := 1;
  for i := 0 to pred(nc) do
  begin
    Ncolors[i] := iroot;
    total_colors := total_colors * iroot;
  end;

  { We may be able to increment the count for one or more components without
    exceeding max_colors, though we know not all can be incremented.
    Sometimes, the first component can be incremented more than once!
    (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.)
    In RGB colorspace, try to increment G first, then R, then B. }

  repeat
    changed := FALSE;
    for i := 0 to pred(nc) do
    begin
      if cinfo^.out_color_space = JCS_RGB then
        j := RGB_order[i]
      else
        j := i;
      { calculate new total_colors if Ncolors[j] is incremented }
      temp := total_colors div Ncolors[j];
      temp := temp * (Ncolors[j]+1);   { done in long arith to avoid oflo }
      if (temp > long(max_colors)) then
	break;                  { won't fit, done with this pass }
      Inc(Ncolors[j]);		{ OK, apply the increment }
      total_colors := int(temp);
      changed := TRUE;
    end;
  until not changed;

  select_ncolors := total_colors;
end;


{LOCAL}
function output_value (cinfo : j_decompress_ptr;
                       ci : int; j : int; maxj : int) : int;
{ Return j'th output value, where j will range from 0 to maxj }
{ The output values must fall in 0..MAXJSAMPLE in increasing order }
begin
  { We always provide values 0 and MAXJSAMPLE for each component;
    any additional values are equally spaced between these limits.
    (Forcing the upper and lower values to the limits ensures that
    dithering can't produce a color outside the selected gamut.) }

  output_value := int (( INT32(j) * MAXJSAMPLE + maxj div 2) div maxj);
end;


{LOCAL}
function largest_input_value (cinfo : j_decompress_ptr;
                              ci : int; j : int; maxj : int) : int;
{ Return largest input value that should map to j'th output value }
{ Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE }
begin
  { Breakpoints are halfway between values returned by output_value }
  largest_input_value := int (( INT32(2*j + 1) * MAXJSAMPLE +
                                 maxj) div (2*maxj));
end;


{ Create the colormap. }

{LOCAL}
procedure create_colormap (cinfo : j_decompress_ptr);
var
  cquantize : my_cquantize_ptr;
  colormap : JSAMPARRAY;        { Created colormap }

  total_colors : int;           { Number of distinct output colors }
  i,j,k, nci, blksize, blkdist, ptr, val : int;
begin
  cquantize := my_cquantize_ptr (cinfo^.cquantize);

  { Select number of colors for each component }
  total_colors := select_ncolors(cinfo, cquantize^.Ncolors);

  { Report selected color counts }
  {$IFDEF DEBUG}
  if (cinfo^.out_color_components = 3) then
    TRACEMS4(j_common_ptr(cinfo), 1, JTRC_QUANT_3_NCOLORS,
	     total_colors, cquantize^.Ncolors[0],
	     cquantize^.Ncolors[1], cquantize^.Ncolors[2])
  else
    TRACEMS1(j_common_ptr(cinfo), 1, JTRC_QUANT_NCOLORS, total_colors);
  {$ENDIF}

  { Allocate and fill in the colormap. }
  { The colors are ordered in the map in standard row-major order, }
  { i.e. rightmost (highest-indexed) color changes most rapidly. }

  colormap := cinfo^.mem^.alloc_sarray(
     j_common_ptr(cinfo), JPOOL_IMAGE,
     JDIMENSION(total_colors), JDIMENSION(cinfo^.out_color_components));

  { blksize is number of adjacent repeated entries for a component }
  { blkdist is distance between groups of identical entries for a component }
  blkdist := total_colors;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -