C# Class BitMiracle.LibJpeg.Classic.Internal.my_2pass_cquantizer

This module implements the well-known Heckbert paradigm for color quantization. Most of the ideas used here can be traced back to Heckbert's seminal paper Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. In the first pass over the image, we accumulate a histogram showing the usage count of each possible color. To keep the histogram to a reasonable size, we reduce the precision of the input; typical practice is to retain 5 or 6 bits per color, so that 8 or 4 different input values are counted in the same histogram cell. Next, the color-selection step begins with a box representing the whole color space, and repeatedly splits the "largest" remaining box until we have as many boxes as desired colors. Then the mean color in each remaining box becomes one of the possible output colors. The second pass over the image maps each input pixel to the closest output color (optionally after applying a Floyd-Steinberg dithering correction). This mapping is logically trivial, but making it go fast enough requires considerable care. Heckbert-style quantizers vary a good deal in their policies for choosing the "largest" box and deciding where to cut it. The particular policies used here have proved out well in experimental comparisons, but better ones may yet be found. In earlier versions of the IJG code, this module quantized in YCbCr color space, processing the raw upsampled data without a color conversion step. This allowed the color conversion math to be done only once per colormap entry, not once per pixel. However, that optimization precluded other useful optimizations (such as merging color conversion with upsampling) and it also interfered with desired capabilities such as quantizing to an externally-supplied colormap. We have therefore abandoned that approach. The present code works in the post-conversion color space, typically RGB. To improve the visual quality of the results, we actually work in scaled RGB space, giving G distances more weight than R, and R in turn more than B. To do everything in integer math, we must use integer scale factors. The 2/3/1 scale factors used here correspond loosely to the relative weights of the colors in the NTSC grayscale equation. If you want to use this code to quantize a non-RGB color space, you'll probably need to change these scale factors. First we have the histogram data structure and routines for creating it. The number of bits of precision can be adjusted by changing these symbols. We recommend keeping 6 bits for G and 5 each for R and B. If you have plenty of memory and cycles, 6 bits all around gives marginally better results; if you are short of memory, 5 bits all around will save some space but degrade the results. To maintain a fully accurate histogram, we'd need to allocate a "long" (preferably unsigned long) for each cell. In practice this is overkill; we can get by with 16 bits per cell. Few of the cell counts will overflow, and clamping those that do overflow to the maximum value will give close- enough results. This reduces the recommended histogram size from 256Kb to 128Kb, which is a useful savings on PC-class machines. (In the second pass the histogram space is re-used for pixel mapping data; in that capacity, each cell must be able to store zero to the number of desired colors. 16 bits/cell is plenty for that too.) Since the JPEG code is intended to run in small memory model on 80x86 machines, we can't just allocate the histogram in one chunk. Instead of a true 3-D array, we use a row of pointers to 2-D arrays. Each pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that on 80x86 machines, the pointer row is in near memory but the actual arrays are in far memory (same arrangement as we use for image arrays). 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 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, one value for each color component.
Inheritance: jpeg_color_quantizer
Show file Open project: prepare/HTML-Renderer

Public Methods

Method Description
color_quantize ( byte input_buf, int in_row, byte output_buf, int out_row, int num_rows ) : void
finish_pass ( ) : void
my_2pass_cquantizer ( jpeg_decompress_struct cinfo ) : System

Module initialization routine for 2-pass color quantization.

new_color_map ( ) : void

Switch to a new external colormap between output passes.

start_pass ( bool is_pre_scan ) : void

Initialize for each processing pass.

Private Methods

Method Description
compute_color ( box boxlist, int boxIndex, int icolor ) : void

Compute representative color for a box, put it in colormap[icolor]

fill_inverse_cmap ( int c0, int c1, int c2 ) : void

Fill the inverse-colormap entries in the update box that contains histogram cell c0/c1/c2. (Only that one cell MUST be filled, but we can fill as many others as we wish.)

find_best_colors ( int minc0, int minc1, int minc2, int numcolors, byte colorlist, byte bestcolor ) : void

Find the closest colormap entry for each cell in the update box, given the list of candidate colors prepared by find_nearby_colors. Return the indexes of the closest entries in the bestcolor[] array. This routine uses Thomas' incremental distance calculation method to find the distance from a colormap entry to successive cells in the box.

find_biggest_color_pop ( box boxlist, int numboxes ) : int

Find the splittable box with the largest color population Returns null if no splittable boxes remain

find_biggest_volume ( box boxlist, int numboxes ) : int

Find the splittable box with the largest (scaled) volume Returns null if no splittable boxes remain

find_nearby_colors ( int minc0, int minc1, int minc2, byte colorlist ) : int

Locate the colormap entries close enough to an update box to be candidates for the nearest entry to some cell(s) in the update box. The update box is specified by the center coordinates of its first cell. The number of candidate colormap entries is returned, and their colormap indexes are placed in colorlist[]. This routine uses Heckbert's "locally sorted search" criterion to select the colors that need further consideration.

finish_pass1 ( ) : void

Finish up at the end of each pass.

init_error_limit ( ) : void

Initialize the error-limiting transfer function (lookup table). The raw F-S error computation can potentially compute error values of up to +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be much less, otherwise obviously wrong pixels will be created. (Typical effects include weird fringes at color-area boundaries, isolated bright pixels in a dark area, etc.) The standard advice for avoiding this problem is to ensure that the "corners" of the color cube are allocated as output colors; then repeated errors in the same direction cannot cause cascading error buildup. However, that only prevents the error from getting completely out of hand; Aaron Giles reports that error limiting improves the results even with corner colors allocated. A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty well, but the smoother transfer function used below is even better. Thanks to Aaron Giles for this idea.

median_cut ( box boxlist, int numboxes, int desired_colors ) : int

Repeatedly select and split the largest box until we have enough boxes

pass2_fs_dither ( byte input_buf, int in_row, byte output_buf, int out_row, int num_rows ) : void

Map some rows of pixels to the output colormapped representation. This version performs Floyd-Steinberg dithering

pass2_no_dither ( byte input_buf, int in_row, byte output_buf, int out_row, int num_rows ) : void

Map some rows of pixels to the output colormapped representation. This version performs no dithering

prescan_quantize ( byte input_buf, int in_row, int num_rows ) : void

Prescan some rows of pixels. In this module the prescan simply updates the histogram, which has been initialized to zeroes by start_pass. An output_buf parameter is required by the method signature, but no data is actually output (in fact the buffer controller is probably passing a null pointer).

select_colors ( int desired_colors ) : void

Master routine for color selection

update_box ( box boxlist, int boxIndex ) : void

Shrink the min/max bounds of a box to enclose only nonzero elements, and recompute its volume and population

Method Details

color_quantize() public method

public color_quantize ( byte input_buf, int in_row, byte output_buf, int out_row, int num_rows ) : void
input_buf byte
in_row int
output_buf byte
out_row int
num_rows int
return void

finish_pass() public method

public finish_pass ( ) : void
return void

my_2pass_cquantizer() public method

Module initialization routine for 2-pass color quantization.
public my_2pass_cquantizer ( jpeg_decompress_struct cinfo ) : System
cinfo jpeg_decompress_struct
return System

new_color_map() public method

Switch to a new external colormap between output passes.
public new_color_map ( ) : void
return void

start_pass() public method

Initialize for each processing pass.
public start_pass ( bool is_pre_scan ) : void
is_pre_scan bool
return void