Hash :
2cbeb8ab
Author :
Date :
1991-10-07T00:00:00
The Independent JPEG Group's JPEG software v1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
/*
* jquant1.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 1-pass color quantization (color mapping) routines.
* These routines are invoked via the methods color_quantize
* and color_quant_init/term.
*/
#include "jinclude.h"
#ifdef QUANT_1PASS_SUPPORTED
/*
* This implementation is a fairly dumb, quick-and-dirty quantizer;
* it's here mostly so that we can start working on colormapped output formats.
*
* We quantize to a color map that is selected in advance of seeing the image;
* the map depends only on the requested number of colors (at least 8).
* The map consists of all combinations of Ncolors[j] color values for each
* component j; we choose Ncolors[] based on the requested # of colors.
* We always use 0 and MAXJSAMPLE in each color (hence the minimum 8 colors).
* Any additional color values are equally spaced between these limits.
*
* The result almost always needs dithering to look decent.
*/
#define MAX_COMPONENTS 4 /* max components I can handle */
static int total_colors; /* Number of distinct output colors */
static int Ncolors[MAX_COMPONENTS]; /* # of values alloced to each component */
/* total_colors is the product of the Ncolors[] values */
static JSAMPARRAY colormap; /* The actual color map */
/* colormap[i][j] = value of i'th color component for output pixel value j */
static JSAMPARRAY colorindex; /* Precomputed mapping for speed */
/* colorindex[i][j] = index of color closest to pixel value j in component i,
* premultiplied so that the correct mapped value for a pixel (r,g,b) is:
* colorindex[0][r] + colorindex[1][g] + colorindex[2][b]
*/
/* Declarations for Floyd-Steinberg dithering.
* Errors are accumulated into the arrays evenrowerrs[] and oddrowerrs[],
* each of which have #colors * (#columns + 2) entries (so that first/last
* pixels need not be special cases). 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.
*
* 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 short 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 */
/*
* Initialize for one-pass color quantization.
*/
METHODDEF void
color_quant_init (decompress_info_ptr cinfo)
{
int max_colors = cinfo->desired_number_of_colors;
int i,j,k, ntc, nci, blksize, blkdist, ptr, val;
if (cinfo->color_out_comps > MAX_COMPONENTS)
ERREXIT1(cinfo->emethods, "Cannot quantize more than %d color components",
MAX_COMPONENTS);
if (max_colors > (MAXJSAMPLE+1))
ERREXIT1(cinfo->emethods, "Cannot request more than %d quantized colors",
MAXJSAMPLE+1);
/* Initialize to 2 color values for each component */
total_colors = 1;
for (i = 0; i < cinfo->color_out_comps; i++) {
Ncolors[i] = 2;
total_colors *= 2;
}
if (total_colors > max_colors)
ERREXIT1(cinfo->emethods, "Cannot quantize to fewer than %d colors",
total_colors);
/* Increase the number of color values until requested limit is reached. */
/* Note that for standard RGB color space, we will have at least as many */
/* red values as green, and at least as many green values as blue. */
i = 0; /* component index to increase next */
/* test calculates ntc = new total_colors if Ncolors[i] is incremented */
while ((ntc = (total_colors / Ncolors[i]) * (Ncolors[i]+1)) <= max_colors) {
Ncolors[i]++; /* OK, apply the increment */
total_colors = ntc;
i++; /* advance to next component */
if (i >= cinfo->color_out_comps) i = 0;
}
/* Report selected color counts */
if (cinfo->color_out_comps == 3)
TRACEMS4(cinfo->emethods, 1, "Quantizing to %d = %d*%d*%d colors",
total_colors, Ncolors[0], Ncolors[1], Ncolors[2]);
else
TRACEMS1(cinfo->emethods, 1, "Quantizing to %d colors", total_colors);
/* Allocate and fill in the colormap and color index. */
/* The colors are ordered in the map in standard row-major order, */
/* i.e. rightmost (highest-indexed) color changes most rapidly. */
colormap = (*cinfo->emethods->alloc_small_sarray)
((long) total_colors, (long) cinfo->color_out_comps);
colorindex = (*cinfo->emethods->alloc_small_sarray)
((long) (MAXJSAMPLE+1), (long) cinfo->color_out_comps);
/* blksize is number of adjacent repeated entries for a component */
/* blkdist is distance between groups of identical entries for a component */
blkdist = total_colors;
for (i = 0; i < cinfo->color_out_comps; i++) {
/* fill in colormap entries for i'th color component */
nci = Ncolors[i]; /* # of distinct values for this color */
blksize = blkdist / nci;
for (j = 0; j < nci; j++) {
val = (j * MAXJSAMPLE + (nci-1)/2) / (nci-1); /* j'th value of color */
for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) {
/* fill in blksize entries beginning at ptr */
for (k = 0; k < blksize; k++)
colormap[i][ptr+k] = val;
}
}
blkdist = blksize; /* blksize of this color is blkdist of next */
/* fill in colorindex entries for i'th color component */
for (j = 0; j <= MAXJSAMPLE; j++) {
/* compute index of color closest to pixel value j */
val = (j * (nci-1) + CENTERJSAMPLE) / MAXJSAMPLE;
/* premultiply so that no multiplication needed in main processing */
val *= blksize;
colorindex[i][j] = val;
}
}
/* Pass the colormap to the output module. Note that the output */
/* module is allowed to save this pointer and use the map during */
/* any put_pixel_rows call! */
(*cinfo->methods->put_color_map) (cinfo, total_colors, colormap);
/* Allocate Floyd-Steinberg workspace if necessary */
if (cinfo->use_dithering) {
size_t arraysize = (cinfo->image_width + 2L) * cinfo->color_out_comps
* 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;
}
}
/*
* Map some rows of pixels to the output colormapped representation.
*/
METHODDEF void
color_quantize (decompress_info_ptr cinfo, int num_rows,
JSAMPIMAGE input_data, JSAMPARRAY output_data)
/* General case, no dithering */
{
register int pixcode, ci;
register long col;
register int row;
register long widthm1 = cinfo->image_width - 1;
register int nc = cinfo->color_out_comps;
for (row = 0; row < num_rows; row++) {
for (col = widthm1; col >= 0; col--) {
pixcode = 0;
for (ci = 0; ci < nc; ci++) {
pixcode += GETJSAMPLE(colorindex[ci]
[GETJSAMPLE(input_data[ci][row][col])]);
}
output_data[row][col] = pixcode;
}
}
}
METHODDEF void
color_quantize3 (decompress_info_ptr cinfo, int num_rows,
JSAMPIMAGE input_data, JSAMPARRAY output_data)
/* Fast path for color_out_comps==3, no dithering */
{
register int pixcode;
register JSAMPROW ptr0, ptr1, ptr2, ptrout;
register long col;
register int row;
register long width = cinfo->image_width;
for (row = 0; row < num_rows; row++) {
ptr0 = input_data[0][row];
ptr1 = input_data[1][row];
ptr2 = input_data[2][row];
ptrout = output_data[row];
for (col = width; col > 0; col--) {
pixcode = GETJSAMPLE(colorindex[0][GETJSAMPLE(*ptr0++)]);
pixcode += GETJSAMPLE(colorindex[1][GETJSAMPLE(*ptr1++)]);
pixcode += GETJSAMPLE(colorindex[2][GETJSAMPLE(*ptr2++)]);
*ptrout++ = pixcode;
}
}
}
METHODDEF void
color_quantize_dither (decompress_info_ptr cinfo, int num_rows,
JSAMPIMAGE input_data, JSAMPARRAY output_data)
/* General case, with Floyd-Steinberg dithering */
{
register int pixcode, ci;
register FSERROR val;
register FSERRPTR thisrowerr, nextrowerr;
register long col;
register int row;
register long width = cinfo->image_width;
register int nc = cinfo->color_out_comps;
for (row = 0; row < num_rows; row++) {
if (on_odd_row) {
/* work right to left in this row */
thisrowerr = oddrowerrs + width*nc;
nextrowerr = evenrowerrs + width*nc;
for (ci = 0; ci < nc; ci++) /* need only initialize this one entry */
nextrowerr[ci] = 0;
for (col = width - 1; col >= 0; col--) {
/* select the output pixel value */
pixcode = 0;
for (ci = 0; ci < nc; ci++) {
/* compute pixel value + accumulated error */
val = (((FSERROR) GETJSAMPLE(input_data[ci][row][col])) << 4)
+ thisrowerr[ci];
if (val < 0) val = 0; /* must watch for range overflow! */
else {
val += 8; /* divide by 16 with proper rounding */
val >>= 4;
if (val > MAXJSAMPLE) val = MAXJSAMPLE;
}
thisrowerr[ci] = val; /* save for error propagation */
pixcode += GETJSAMPLE(colorindex[ci][val]);
}
output_data[row][col] = pixcode;
/* propagate error to adjacent pixels */
for (ci = 0; ci < nc; ci++) {
val = thisrowerr[ci] - GETJSAMPLE(colormap[ci][pixcode]);
thisrowerr[ci-nc] += val * 7;
nextrowerr[ci+nc] += val * 3;
nextrowerr[ci ] += val * 5;
nextrowerr[ci-nc] = val; /* not +=, since not initialized yet */
}
thisrowerr -= nc; /* advance error ptrs to next pixel entry */
nextrowerr -= nc;
}
on_odd_row = FALSE;
} else {
/* work left to right in this row */
thisrowerr = evenrowerrs + nc;
nextrowerr = oddrowerrs + nc;
for (ci = 0; ci < nc; ci++) /* need only initialize this one entry */
nextrowerr[ci] = 0;
for (col = 0; col < width; col++) {
/* select the output pixel value */
pixcode = 0;
for (ci = 0; ci < nc; ci++) {
/* compute pixel value + accumulated error */
val = (((FSERROR) GETJSAMPLE(input_data[ci][row][col])) << 4)
+ thisrowerr[ci];
if (val < 0) val = 0; /* must watch for range overflow! */
else {
val += 8; /* divide by 16 with proper rounding */
val >>= 4;
if (val > MAXJSAMPLE) val = MAXJSAMPLE;
}
thisrowerr[ci] = val; /* save for error propagation */
pixcode += GETJSAMPLE(colorindex[ci][val]);
}
output_data[row][col] = pixcode;
/* propagate error to adjacent pixels */
for (ci = 0; ci < nc; ci++) {
val = thisrowerr[ci] - GETJSAMPLE(colormap[ci][pixcode]);
thisrowerr[ci+nc] += val * 7;
nextrowerr[ci-nc] += val * 3;
nextrowerr[ci ] += val * 5;
nextrowerr[ci+nc] = val; /* not +=, since not initialized yet */
}
thisrowerr += nc; /* advance error ptrs to next pixel entry */
nextrowerr += nc;
}
on_odd_row = TRUE;
}
}
}
/*
* Finish up at the end of the file.
*/
METHODDEF void
color_quant_term (decompress_info_ptr cinfo)
{
/* We can't free the colormap until now, since output module may use it! */
(*cinfo->emethods->free_small_sarray)
(colormap, (long) cinfo->color_out_comps);
(*cinfo->emethods->free_small_sarray)
(colorindex, (long) cinfo->color_out_comps);
if (cinfo->use_dithering) {
(*cinfo->emethods->free_medium) ((void FAR *) evenrowerrs);
(*cinfo->emethods->free_medium) ((void FAR *) oddrowerrs);
}
}
/*
* Prescan some rows of pixels.
* Not used in one-pass case.
*/
METHODDEF void
color_quant_prescan (decompress_info_ptr cinfo, int num_rows,
JSAMPIMAGE image_data)
{
ERREXIT(cinfo->emethods, "Should not get here!");
}
/*
* Do two-pass quantization.
* Not used in one-pass case.
*/
METHODDEF void
color_quant_doit (decompress_info_ptr cinfo, quantize_caller_ptr source_method)
{
ERREXIT(cinfo->emethods, "Should not get here!");
}
/*
* The method selection routine for 1-pass color quantization.
*/
GLOBAL void
jsel1quantize (decompress_info_ptr cinfo)
{
if (! cinfo->two_pass_quantize) {
cinfo->methods->color_quant_init = color_quant_init;
if (cinfo->use_dithering) {
cinfo->methods->color_quantize = color_quantize_dither;
} else {
if (cinfo->color_out_comps == 3)
cinfo->methods->color_quantize = color_quantize3;
else
cinfo->methods->color_quantize = color_quantize;
}
cinfo->methods->color_quant_prescan = color_quant_prescan;
cinfo->methods->color_quant_doit = color_quant_doit;
cinfo->methods->color_quant_term = color_quant_term;
}
}
#endif /* QUANT_1PASS_SUPPORTED */