| 1 |
|
|---|
| 2 | /*
|
|---|
| 3 | * bltColor.c --
|
|---|
| 4 | *
|
|---|
| 5 | * This module contains routines for color allocation strategies
|
|---|
| 6 | * used with color images in the BLT toolkit.
|
|---|
| 7 | *
|
|---|
| 8 | * Copyright 1997-1998 Lucent Technologies, Inc.
|
|---|
| 9 | *
|
|---|
| 10 | * Permission to use, copy, modify, and distribute this software and
|
|---|
| 11 | * its documentation for any purpose and without fee is hereby
|
|---|
| 12 | * granted, provided that the above copyright notice appear in all
|
|---|
| 13 | * copies and that both that the copyright notice and warranty
|
|---|
| 14 | * disclaimer appear in supporting documentation, and that the names
|
|---|
| 15 | * of Lucent Technologies any of their entities not be used in
|
|---|
| 16 | * advertising or publicity pertaining to distribution of the software
|
|---|
| 17 | * without specific, written prior permission.
|
|---|
| 18 | *
|
|---|
| 19 | * Lucent Technologies disclaims all warranties with regard to this
|
|---|
| 20 | * software, including all implied warranties of merchantability and
|
|---|
| 21 | * fitness. In no event shall Lucent Technologies be liable for any
|
|---|
| 22 | * special, indirect or consequential damages or any damages
|
|---|
| 23 | * whatsoever resulting from loss of use, data or profits, whether in
|
|---|
| 24 | * an action of contract, negligence or other tortuous action, arising
|
|---|
| 25 | * out of or in connection with the use or performance of this
|
|---|
| 26 | * software.
|
|---|
| 27 | */
|
|---|
| 28 |
|
|---|
| 29 | /*
|
|---|
| 30 | * Color strategies of 8-bit visuals:
|
|---|
| 31 | *
|
|---|
| 32 | * Try to "best" represent an N-color image into 8-bit (256 color)
|
|---|
| 33 | * colormap. The simplest method is use the high bits of each RGB
|
|---|
| 34 | * value (3 bits for red and green, 2 bits for blue). But this
|
|---|
| 35 | * produces lots of contouring since the distribution of colors tends
|
|---|
| 36 | * to be clustered. Other problems: probably can't allocate even 256
|
|---|
| 37 | * colors. Other applications will have already taken some color
|
|---|
| 38 | * slots. Furthermore, we might be displaying several images, and we
|
|---|
| 39 | * can't assume that all images are representative of the colors used.
|
|---|
| 40 | *
|
|---|
| 41 | * If we use a private colormap, we may want to allocate some number
|
|---|
| 42 | * of colors from the default colormap to prevent flashing when
|
|---|
| 43 | * colormaps are switched.
|
|---|
| 44 | *
|
|---|
| 45 | * Switches:
|
|---|
| 46 | *
|
|---|
| 47 | * -exact boolean Try to match the colors of the image rather
|
|---|
| 48 | * then generating a "best" color ramp.
|
|---|
| 49 | *
|
|---|
| 50 | * -threshold value Maximum average error. Indicates how far
|
|---|
| 51 | * to reduce the quantized color palette.
|
|---|
| 52 | *
|
|---|
| 53 | * -tolerance value Allow colors within this distance to match.
|
|---|
| 54 | * This will weight allocation towards harder
|
|---|
| 55 | * to match colors, rather than the most
|
|---|
| 56 | * frequent.
|
|---|
| 57 | *
|
|---|
| 58 | * -mincolors number Minimum number of reduced quantized colors.
|
|---|
| 59 | * or color ramp.
|
|---|
| 60 | *
|
|---|
| 61 | * -dither boolean Turn on/off Floyd-Steinberg dithering.
|
|---|
| 62 | *
|
|---|
| 63 | * -keep number Hint to keep the first N colors in the
|
|---|
| 64 | * in the default colormap. This only applies to
|
|---|
| 65 | * private colormaps.
|
|---|
| 66 | *
|
|---|
| 67 | * -ramp number Number of colors to use in a linear ramp.
|
|---|
| 68 | *
|
|---|
| 69 | */
|
|---|
| 70 |
|
|---|
| 71 | #include "bltInt.h"
|
|---|
| 72 |
|
|---|
| 73 | #ifndef WIN32
|
|---|
| 74 |
|
|---|
| 75 | #include "bltHash.h"
|
|---|
| 76 | #include "bltImage.h"
|
|---|
| 77 |
|
|---|
| 78 | #define NCOLORS 256
|
|---|
| 79 |
|
|---|
| 80 |
|
|---|
| 81 | static void
|
|---|
| 82 | GetPaletteSizes(nColors, nRedsPtr, nGreensPtr, nBluesPtr)
|
|---|
| 83 | int nColors; /* Number of colors requested. */
|
|---|
| 84 | unsigned int *nRedsPtr; /* (out) Number of red components. */
|
|---|
| 85 | unsigned int *nGreensPtr; /* (out) Number of green components. */
|
|---|
| 86 | unsigned int *nBluesPtr; /* (out) Number of blue components. */
|
|---|
| 87 | {
|
|---|
| 88 | unsigned int nBlues, nReds, nGreens;
|
|---|
| 89 |
|
|---|
| 90 | assert(nColors > 1);
|
|---|
| 91 | nBlues = nReds = nGreens = 0;
|
|---|
| 92 | while ((nBlues * nBlues * nBlues) <= nColors) {
|
|---|
| 93 | nBlues++;
|
|---|
| 94 | }
|
|---|
| 95 | nBlues--;
|
|---|
| 96 | while ((nReds * nReds * nBlues) <= nColors) {
|
|---|
| 97 | nReds++;
|
|---|
| 98 | }
|
|---|
| 99 | nReds--;
|
|---|
| 100 | nGreens = nColors / (nBlues * nReds);
|
|---|
| 101 |
|
|---|
| 102 | *nRedsPtr = nReds;
|
|---|
| 103 | *nGreensPtr = nGreens;
|
|---|
| 104 | *nBluesPtr = nBlues;
|
|---|
| 105 | }
|
|---|
| 106 |
|
|---|
| 107 | static void
|
|---|
| 108 | BuildColorRamp(palettePtr, nColors)
|
|---|
| 109 | Pix32 *palettePtr;
|
|---|
| 110 | int nColors;
|
|---|
| 111 | {
|
|---|
| 112 | register unsigned int r, g, b;
|
|---|
| 113 | unsigned int short red, green, blue;
|
|---|
| 114 | unsigned int nReds, nGreens, nBlues;
|
|---|
| 115 |
|
|---|
| 116 | GetPaletteSizes(nColors, &nReds, &nGreens, &nBlues);
|
|---|
| 117 | for (r = 0; r < nReds; r++) {
|
|---|
| 118 | red = (r * USHRT_MAX) / (nReds - 1);
|
|---|
| 119 | for (g = 0; g < nGreens; g++) {
|
|---|
| 120 | green = (g * USHRT_MAX) / (nGreens - 1);
|
|---|
| 121 | for (b = 0; b < nBlues; b++) {
|
|---|
| 122 | blue = (b * USHRT_MAX) / (nBlues - 1);
|
|---|
| 123 | palettePtr->Red = red;
|
|---|
| 124 | palettePtr->Green = green;
|
|---|
| 125 | palettePtr->Blue = blue;
|
|---|
| 126 | palettePtr++;
|
|---|
| 127 | }
|
|---|
| 128 | }
|
|---|
| 129 | }
|
|---|
| 130 |
|
|---|
| 131 | }
|
|---|
| 132 |
|
|---|
| 133 | /*
|
|---|
| 134 | *----------------------------------------------------------------------
|
|---|
| 135 | *
|
|---|
| 136 | * QueryColormap --
|
|---|
| 137 | *
|
|---|
| 138 | * This is for psuedo-color displays only. Fills an array or
|
|---|
| 139 | * XColors with the color values (RGB and pixel) currently
|
|---|
| 140 | * allocated in the colormap.
|
|---|
| 141 | *
|
|---|
| 142 | * Results:
|
|---|
| 143 | * The number of colors allocated is returned. The array "colorArr"
|
|---|
| 144 | * will contain the XColor values of each color in the colormap.
|
|---|
| 145 | *
|
|---|
| 146 | *----------------------------------------------------------------------
|
|---|
| 147 | */
|
|---|
| 148 |
|
|---|
| 149 | static int
|
|---|
| 150 | QueryColormap(display, colorMap, mapColors, numMapColorsPtr)
|
|---|
| 151 | Display *display;
|
|---|
| 152 | Colormap colorMap;
|
|---|
| 153 | XColor mapColors[];
|
|---|
| 154 | int *numMapColorsPtr;
|
|---|
| 155 | {
|
|---|
| 156 | unsigned long int pixelValues[NCOLORS];
|
|---|
| 157 | int numAvail, numMapColors;
|
|---|
| 158 | register int i;
|
|---|
| 159 | register XColor *colorPtr;
|
|---|
| 160 | register unsigned long *indexPtr;
|
|---|
| 161 | int inUse[NCOLORS];
|
|---|
| 162 |
|
|---|
| 163 | /* Initially, we assume all color cells are allocated. */
|
|---|
| 164 | memset((char *)inUse, 0, sizeof(int) * NCOLORS);
|
|---|
| 165 |
|
|---|
| 166 | /*
|
|---|
| 167 | * Start allocating color cells. This will tell us which color cells
|
|---|
| 168 | * haven't already been allocated in the colormap. We'll release the
|
|---|
| 169 | * cells as soon as we find out how many there are.
|
|---|
| 170 | */
|
|---|
| 171 | numAvail = 0;
|
|---|
| 172 | for (indexPtr = pixelValues, i = 0; i < NCOLORS; i++, indexPtr++) {
|
|---|
| 173 | if (!XAllocColorCells(display, colorMap, False, NULL, 0, indexPtr, 1)) {
|
|---|
| 174 | break;
|
|---|
| 175 | }
|
|---|
| 176 | inUse[*indexPtr] = TRUE;/* Indicate the cell is unallocated */
|
|---|
| 177 | numAvail++;
|
|---|
| 178 | }
|
|---|
| 179 | XFreeColors(display, colorMap, pixelValues, numAvail, 0);
|
|---|
| 180 |
|
|---|
| 181 | /*
|
|---|
| 182 | * Put the indices of the cells already allocated into a color array.
|
|---|
| 183 | * We'll use the array to query the RGB values of the allocated colors.
|
|---|
| 184 | */
|
|---|
| 185 | numMapColors = 0;
|
|---|
| 186 | colorPtr = mapColors;
|
|---|
| 187 | for (i = 0; i < NCOLORS; i++) {
|
|---|
| 188 | if (!inUse[i]) {
|
|---|
| 189 | colorPtr->pixel = i;
|
|---|
| 190 | colorPtr->flags = (DoRed | DoGreen | DoBlue);
|
|---|
| 191 | colorPtr++, numMapColors++;
|
|---|
| 192 | }
|
|---|
| 193 | }
|
|---|
| 194 | XQueryColors(display, colorMap, mapColors, numMapColors);
|
|---|
| 195 | *numMapColorsPtr = numMapColors;
|
|---|
| 196 | #ifdef notdef
|
|---|
| 197 | fprintf(stderr, "Number of colors (allocated/free) %d/%d\n", numMapColors,
|
|---|
| 198 | numAvail);
|
|---|
| 199 | #endif
|
|---|
| 200 | return numAvail;
|
|---|
| 201 | }
|
|---|
| 202 |
|
|---|
| 203 | static void
|
|---|
| 204 | FindClosestColor(colorPtr, mapColors, numMapColors)
|
|---|
| 205 | ColorInfo *colorPtr;
|
|---|
| 206 | XColor mapColors[];
|
|---|
| 207 | int numMapColors;
|
|---|
| 208 | {
|
|---|
| 209 | double r, g, b;
|
|---|
| 210 | register int i;
|
|---|
| 211 | double dist, min;
|
|---|
| 212 | XColor *lastMatch;
|
|---|
| 213 | register XColor *mapColorPtr;
|
|---|
| 214 |
|
|---|
| 215 | min = DBL_MAX; /* Any color is closer. */
|
|---|
| 216 | lastMatch = NULL;
|
|---|
| 217 |
|
|---|
| 218 | /* Linear search of color */
|
|---|
| 219 |
|
|---|
| 220 | mapColorPtr = mapColors;
|
|---|
| 221 | for (i = 0; i < numMapColors; i++, mapColorPtr++) {
|
|---|
| 222 | r = (double)mapColorPtr->red - (double)colorPtr->exact.red;
|
|---|
| 223 | g = (double)mapColorPtr->green - (double)colorPtr->exact.green;
|
|---|
| 224 | b = (double)mapColorPtr->blue - (double)colorPtr->exact.blue;
|
|---|
| 225 |
|
|---|
| 226 | dist = (r * r) + (b * b) + (g * g);
|
|---|
| 227 | if (dist < min) {
|
|---|
| 228 | min = dist;
|
|---|
| 229 | lastMatch = mapColorPtr;
|
|---|
| 230 | }
|
|---|
| 231 | }
|
|---|
| 232 | colorPtr->best = *lastMatch;
|
|---|
| 233 | colorPtr->best.flags = (DoRed | DoGreen | DoBlue);
|
|---|
| 234 | colorPtr->error = (float)sqrt(min);
|
|---|
| 235 | }
|
|---|
| 236 |
|
|---|
| 237 | static int
|
|---|
| 238 | CompareColors(a, b)
|
|---|
| 239 | void *a, *b;
|
|---|
| 240 | {
|
|---|
| 241 | ColorInfo *i1Ptr, *i2Ptr;
|
|---|
| 242 |
|
|---|
| 243 | i1Ptr = *(ColorInfo **) a;
|
|---|
| 244 | i2Ptr = *(ColorInfo **) b;
|
|---|
| 245 | if (i2Ptr->error > i1Ptr->error) {
|
|---|
| 246 | return 1;
|
|---|
| 247 | } else if (i2Ptr->error < i1Ptr->error) {
|
|---|
| 248 | return -1;
|
|---|
| 249 | }
|
|---|
| 250 | return 0;
|
|---|
| 251 | }
|
|---|
| 252 |
|
|---|
| 253 | static float
|
|---|
| 254 | MatchColors(colorTabPtr, rgbPtr, numColors, numAvailColors, numMapColors,
|
|---|
| 255 | mapColors)
|
|---|
| 256 | struct ColorTableStruct *colorTabPtr;
|
|---|
| 257 | Pix32 *rgbPtr;
|
|---|
| 258 | int numColors;
|
|---|
| 259 | int numAvailColors;
|
|---|
| 260 | int numMapColors;
|
|---|
| 261 | XColor mapColors[NCOLORS];
|
|---|
| 262 | {
|
|---|
| 263 | int numMatched;
|
|---|
| 264 | float sum;
|
|---|
| 265 | register int i;
|
|---|
| 266 | register ColorInfo *colorPtr;
|
|---|
| 267 |
|
|---|
| 268 | /*
|
|---|
| 269 | * For each quantized color, compute and store the error (i.e
|
|---|
| 270 | * the distance from a color that's already been allocated).
|
|---|
| 271 | * We'll use this information to sort the colors based upon how
|
|---|
| 272 | * badly they match and their frequency to the color image.
|
|---|
| 273 | */
|
|---|
| 274 | colorPtr = colorTabPtr->colorInfo;
|
|---|
| 275 | for (i = 0; i < numColors; i++, colorPtr++, rgbPtr++) {
|
|---|
| 276 | colorPtr->index = i;
|
|---|
| 277 | colorTabPtr->sortedColors[i] = colorPtr;
|
|---|
| 278 | colorPtr->exact.red = rgbPtr->Red;
|
|---|
| 279 | colorPtr->exact.green = rgbPtr->Green;
|
|---|
| 280 | colorPtr->exact.blue = rgbPtr->Blue;
|
|---|
| 281 | colorPtr->exact.flags = (DoRed | DoGreen | DoBlue);
|
|---|
| 282 | FindClosestColor(colorPtr, mapColors, numMapColors);
|
|---|
| 283 | }
|
|---|
| 284 |
|
|---|
| 285 | /* Sort the colors, first by frequency (most to least), then by
|
|---|
| 286 | * matching error (worst to best).
|
|---|
| 287 | */
|
|---|
| 288 | qsort(colorTabPtr->sortedColors, numColors, sizeof(ColorInfo *),
|
|---|
| 289 | (QSortCompareProc *)CompareColors);
|
|---|
| 290 |
|
|---|
| 291 | for (i = 0; i < numColors; i++) {
|
|---|
| 292 | colorPtr = colorTabPtr->sortedColors[i];
|
|---|
| 293 | fprintf(stderr, "%d. %04x%04x%04x / %04x%04x%04x = %f (%d)\n", i,
|
|---|
| 294 | colorPtr->exact.red, colorPtr->exact.green, colorPtr->exact.blue,
|
|---|
| 295 | colorPtr->best.red, colorPtr->best.green, colorPtr->best.blue,
|
|---|
| 296 | colorPtr->error, colorPtr->freq);
|
|---|
| 297 | }
|
|---|
| 298 | sum = 0.0;
|
|---|
| 299 | numMatched = 0;
|
|---|
| 300 | for (i = numAvailColors; i < numColors; i++) {
|
|---|
| 301 | colorPtr = colorTabPtr->sortedColors[i];
|
|---|
| 302 | sum += colorPtr->error;
|
|---|
| 303 | numMatched++;
|
|---|
| 304 | }
|
|---|
| 305 | if (numMatched > 0) {
|
|---|
| 306 | sum /= numMatched;
|
|---|
| 307 | }
|
|---|
| 308 | return sum;
|
|---|
| 309 | }
|
|---|
| 310 |
|
|---|
| 311 |
|
|---|
| 312 | static int
|
|---|
| 313 | AllocateColors(nImageColors, colorTabPtr, matchOnly)
|
|---|
| 314 | int nImageColors;
|
|---|
| 315 | struct ColorTableStruct *colorTabPtr;
|
|---|
| 316 | int matchOnly;
|
|---|
| 317 | {
|
|---|
| 318 | register int i;
|
|---|
| 319 | register ColorInfo *colorPtr;
|
|---|
| 320 | unsigned long int pixelValue;
|
|---|
| 321 |
|
|---|
| 322 | for (i = 0; i < nImageColors; i++) {
|
|---|
| 323 | colorPtr = colorTabPtr->sortedColors[i];
|
|---|
| 324 | if (matchOnly) {
|
|---|
| 325 | XAllocColor(colorTabPtr->display, colorTabPtr->colorMap,
|
|---|
| 326 | &colorPtr->best);
|
|---|
| 327 | pixelValue = colorPtr->best.pixel;
|
|---|
| 328 | } else {
|
|---|
| 329 | colorPtr->allocated = XAllocColor(colorTabPtr->display,
|
|---|
| 330 | colorTabPtr->colorMap, &colorPtr->exact);
|
|---|
| 331 |
|
|---|
| 332 | if (colorPtr->allocated) {
|
|---|
| 333 | pixelValue = colorPtr->exact.pixel;
|
|---|
| 334 | } else {
|
|---|
| 335 | XAllocColor(colorTabPtr->display, colorTabPtr->colorMap,
|
|---|
| 336 | &colorPtr->best);
|
|---|
| 337 | pixelValue = colorPtr->best.pixel;
|
|---|
| 338 | }
|
|---|
| 339 | }
|
|---|
| 340 | colorTabPtr->pixelValues[colorPtr->index] = pixelValue;
|
|---|
| 341 | }
|
|---|
| 342 | colorTabPtr->nPixels = nImageColors;
|
|---|
| 343 | return 1;
|
|---|
| 344 | }
|
|---|
| 345 |
|
|---|
| 346 | ColorTable
|
|---|
| 347 | Blt_CreateColorTable(tkwin)
|
|---|
| 348 | Tk_Window tkwin;
|
|---|
| 349 | {
|
|---|
| 350 | XVisualInfo visualInfo, *visualInfoPtr;
|
|---|
| 351 | int nVisuals;
|
|---|
| 352 | Visual *visualPtr;
|
|---|
| 353 | Display *display;
|
|---|
| 354 | struct ColorTableStruct *colorTabPtr;
|
|---|
| 355 |
|
|---|
| 356 | display = Tk_Display(tkwin);
|
|---|
| 357 | visualPtr = Tk_Visual(tkwin);
|
|---|
| 358 |
|
|---|
| 359 | colorTabPtr = Blt_Calloc(1, sizeof(struct ColorTableStruct));
|
|---|
| 360 | assert(colorTabPtr);
|
|---|
| 361 | colorTabPtr->display = Tk_Display(tkwin);
|
|---|
| 362 | colorTabPtr->colorMap = Tk_Colormap(tkwin);
|
|---|
| 363 |
|
|---|
| 364 | visualInfo.screen = Tk_ScreenNumber(tkwin);
|
|---|
| 365 | visualInfo.visualid = XVisualIDFromVisual(visualPtr);
|
|---|
| 366 | visualInfoPtr = XGetVisualInfo(display, VisualScreenMask | VisualIDMask,
|
|---|
| 367 | &visualInfo, &nVisuals);
|
|---|
| 368 |
|
|---|
| 369 | colorTabPtr->visualInfo = *visualInfoPtr;
|
|---|
| 370 | XFree(visualInfoPtr);
|
|---|
| 371 |
|
|---|
| 372 | return colorTabPtr;
|
|---|
| 373 | }
|
|---|
| 374 |
|
|---|
| 375 | void
|
|---|
| 376 | Blt_FreeColorTable(colorTabPtr)
|
|---|
| 377 | struct ColorTableStruct *colorTabPtr;
|
|---|
| 378 | {
|
|---|
| 379 | if (colorTabPtr == NULL) {
|
|---|
| 380 | return;
|
|---|
| 381 | }
|
|---|
| 382 | if (colorTabPtr->nPixels > 0) {
|
|---|
| 383 | XFreeColors(colorTabPtr->display, colorTabPtr->colorMap,
|
|---|
| 384 | colorTabPtr->pixelValues, colorTabPtr->nPixels, 0);
|
|---|
| 385 | }
|
|---|
| 386 | Blt_Free(colorTabPtr);
|
|---|
| 387 | }
|
|---|
| 388 |
|
|---|
| 389 | extern int redAdjust, greenAdjust, blueAdjust;
|
|---|
| 390 | extern int redMaskShift, greenMaskShift, blueMaskShift;
|
|---|
| 391 |
|
|---|
| 392 | /*
|
|---|
| 393 | *----------------------------------------------------------------------
|
|---|
| 394 | *
|
|---|
| 395 | * Blt_DirectColorTable --
|
|---|
| 396 | *
|
|---|
| 397 | * Creates a color table using the DirectColor visual. We try
|
|---|
| 398 | * to allocate colors across the color spectrum.
|
|---|
| 399 | *
|
|---|
| 400 | * Results:
|
|---|
| 401 | *
|
|---|
| 402 | *
|
|---|
| 403 | *----------------------------------------------------------------------
|
|---|
| 404 | */
|
|---|
| 405 | /*ARGSUSED*/
|
|---|
| 406 | ColorTable
|
|---|
| 407 | Blt_DirectColorTable(interp, tkwin, image)
|
|---|
| 408 | Tcl_Interp *interp;
|
|---|
| 409 | Tk_Window tkwin;
|
|---|
| 410 | Blt_ColorImage image;
|
|---|
| 411 | {
|
|---|
| 412 | struct ColorTableStruct *colorTabPtr;
|
|---|
| 413 | Visual *visualPtr;
|
|---|
| 414 | Display *display;
|
|---|
| 415 | XColor color;
|
|---|
| 416 | int nr, ng, nb;
|
|---|
| 417 | int rBand, gBand, bBand;
|
|---|
| 418 | int rLast, gLast, bLast;
|
|---|
| 419 | unsigned int r, g, b;
|
|---|
| 420 | unsigned int value;
|
|---|
| 421 | register int i;
|
|---|
| 422 |
|
|---|
| 423 | display = Tk_Display(tkwin);
|
|---|
| 424 | visualPtr = Tk_Visual(tkwin);
|
|---|
| 425 |
|
|---|
| 426 | colorTabPtr = Blt_CreateColorTable(tkwin);
|
|---|
| 427 | /*
|
|---|
| 428 | * Compute the number of distinct colors in each band
|
|---|
| 429 | */
|
|---|
| 430 | nr = ((unsigned int)visualPtr->red_mask >> redMaskShift) + 1;
|
|---|
| 431 | ng = ((unsigned int)visualPtr->green_mask >> greenMaskShift) + 1;
|
|---|
| 432 | nb = ((unsigned int)visualPtr->blue_mask >> blueMaskShift) + 1;
|
|---|
| 433 |
|
|---|
| 434 | #ifdef notdef
|
|---|
| 435 | assert((nr <= visualPtr->map_entries) && (ng <= visualPtr->map_entries) &&
|
|---|
| 436 | (nb <= visualPtr->map_entries));
|
|---|
| 437 | #endif
|
|---|
| 438 | rBand = NCOLORS / nr;
|
|---|
| 439 | gBand = NCOLORS / ng;
|
|---|
| 440 | bBand = NCOLORS / nb;
|
|---|
| 441 |
|
|---|
| 442 | retry:
|
|---|
| 443 | color.flags = (DoRed | DoGreen | DoBlue);
|
|---|
| 444 | rLast = gLast = bLast = 0;
|
|---|
| 445 | r = g = b = 0;
|
|---|
| 446 | for (i = 0; i < visualPtr->map_entries; i++) {
|
|---|
| 447 | if (rLast < NCOLORS) {
|
|---|
| 448 | r = rLast + rBand;
|
|---|
| 449 | if (r > NCOLORS) {
|
|---|
| 450 | r = NCOLORS;
|
|---|
| 451 | }
|
|---|
| 452 | }
|
|---|
| 453 | if (gLast < NCOLORS) {
|
|---|
| 454 | g = gLast + gBand;
|
|---|
| 455 | if (g > NCOLORS) {
|
|---|
| 456 | g = NCOLORS;
|
|---|
| 457 | }
|
|---|
| 458 | }
|
|---|
| 459 | if (bLast < NCOLORS) {
|
|---|
| 460 | b = bLast + bBand;
|
|---|
| 461 | if (b > NCOLORS) {
|
|---|
| 462 | b = NCOLORS;
|
|---|
| 463 | }
|
|---|
| 464 | }
|
|---|
| 465 | color.red = (r - 1) * (NCOLORS + 1);
|
|---|
| 466 | color.green = (g - 1) * (NCOLORS + 1);
|
|---|
| 467 | color.blue = (b - 1) * (NCOLORS + 1);
|
|---|
| 468 |
|
|---|
| 469 | if (!XAllocColor(display, colorTabPtr->colorMap, &color)) {
|
|---|
| 470 | XFreeColors(display, colorTabPtr->colorMap,
|
|---|
| 471 | colorTabPtr->pixelValues, i, 0);
|
|---|
| 472 | if ((colorTabPtr->flags & PRIVATE_COLORMAP) == 0) {
|
|---|
| 473 | /*
|
|---|
| 474 | * If we can't allocate a color in the default
|
|---|
| 475 | * colormap, try again, this time with a private
|
|---|
| 476 | * colormap.
|
|---|
| 477 | */
|
|---|
| 478 | fprintf(stderr, "Need to allocate private colormap\n");
|
|---|
| 479 | colorTabPtr->colorMap = Tk_GetColormap(interp, tkwin, ".");
|
|---|
| 480 |
|
|---|
| 481 | XSetWindowColormap(display, Tk_WindowId(tkwin),
|
|---|
| 482 | colorTabPtr->colorMap);
|
|---|
| 483 | colorTabPtr->flags |= PRIVATE_COLORMAP;
|
|---|
| 484 | goto retry;
|
|---|
| 485 | }
|
|---|
| 486 | #ifdef notdef
|
|---|
| 487 | fprintf(stderr, "Failed to allocate after %d colors\n", i);
|
|---|
| 488 | #endif
|
|---|
| 489 | Blt_Free(colorTabPtr);
|
|---|
| 490 | return NULL; /* Ran out of colors in private map? */
|
|---|
| 491 | }
|
|---|
| 492 | colorTabPtr->pixelValues[i] = color.pixel;
|
|---|
| 493 | /*
|
|---|
| 494 | * Fill in pixel values for each band at this intensity
|
|---|
| 495 | */
|
|---|
| 496 | value = color.pixel & visualPtr->red_mask;
|
|---|
| 497 | while (rLast < r) {
|
|---|
| 498 | colorTabPtr->red[rLast++] = value;
|
|---|
| 499 | }
|
|---|
| 500 | value = color.pixel & visualPtr->green_mask;
|
|---|
| 501 | while (gLast < g) {
|
|---|
| 502 | colorTabPtr->green[gLast++] = value;
|
|---|
| 503 | }
|
|---|
| 504 | value = color.pixel & visualPtr->blue_mask;
|
|---|
| 505 | while (bLast < b) {
|
|---|
| 506 | colorTabPtr->blue[bLast++] = value;
|
|---|
| 507 | }
|
|---|
| 508 | }
|
|---|
| 509 | colorTabPtr->nPixels = i;
|
|---|
| 510 | return colorTabPtr;
|
|---|
| 511 | }
|
|---|
| 512 |
|
|---|
| 513 | /*
|
|---|
| 514 | * First attempt:
|
|---|
| 515 | * Allocate colors all the colors in the image (up to NCOLORS). Bail out
|
|---|
| 516 | * on the first failure or if we need more than NCOLORS.
|
|---|
| 517 | */
|
|---|
| 518 | static int
|
|---|
| 519 | GetUniqueColors(image)
|
|---|
| 520 | Blt_ColorImage image;
|
|---|
| 521 | {
|
|---|
| 522 | register int i, nColors;
|
|---|
| 523 | register Pix32 *pixelPtr;
|
|---|
| 524 | Pix32 color;
|
|---|
| 525 | Blt_HashEntry *hPtr;
|
|---|
| 526 | int isNew, nPixels;
|
|---|
| 527 | int refCount;
|
|---|
| 528 | Blt_HashTable colorTable;
|
|---|
| 529 |
|
|---|
| 530 | Blt_InitHashTable(&colorTable, BLT_ONE_WORD_KEYS);
|
|---|
| 531 |
|
|---|
| 532 | nPixels = Blt_ColorImageWidth(image) * Blt_ColorImageHeight(image);
|
|---|
| 533 | nColors = 0;
|
|---|
| 534 | pixelPtr = Blt_ColorImageBits(image);
|
|---|
| 535 | for (i = 0; i < nPixels; i++, pixelPtr++) {
|
|---|
| 536 | color.value = pixelPtr->value;
|
|---|
| 537 | color.Alpha = 0xFF; /* Ignore alpha-channel values */
|
|---|
| 538 | hPtr = Blt_CreateHashEntry(&colorTable, (char *)color.value, &isNew);
|
|---|
| 539 | if (isNew) {
|
|---|
| 540 | refCount = 1;
|
|---|
| 541 | nColors++;
|
|---|
| 542 | } else {
|
|---|
| 543 | refCount = (int)Blt_GetHashValue(hPtr);
|
|---|
| 544 | refCount++;
|
|---|
| 545 | }
|
|---|
| 546 | Blt_SetHashValue(hPtr, (ClientData)refCount);
|
|---|
| 547 | }
|
|---|
| 548 | Blt_DeleteHashTable(&colorTable);
|
|---|
| 549 | return nColors;
|
|---|
| 550 | }
|
|---|
| 551 |
|
|---|
| 552 | #define Blt_DefaultColormap(tkwin) \
|
|---|
| 553 | DefaultColormap(Tk_Display(tkwin), Tk_ScreenNumber(tkwin))
|
|---|
| 554 |
|
|---|
| 555 |
|
|---|
| 556 | static void
|
|---|
| 557 | PrivateColormap(interp, colorTabPtr, image, tkwin)
|
|---|
| 558 | Tcl_Interp *interp;
|
|---|
| 559 | struct ColorTableStruct *colorTabPtr;
|
|---|
| 560 | Blt_ColorImage image;
|
|---|
| 561 | Tk_Window tkwin;
|
|---|
| 562 | {
|
|---|
| 563 | int keepColors = 0;
|
|---|
| 564 | register int i;
|
|---|
| 565 | XColor usedColors[NCOLORS];
|
|---|
| 566 | int nFreeColors, nUsedColors;
|
|---|
| 567 | Colormap colorMap;
|
|---|
| 568 | int inUse[NCOLORS];
|
|---|
| 569 | XColor *colorPtr;
|
|---|
| 570 | XColor *imageColors;
|
|---|
| 571 |
|
|---|
| 572 | /*
|
|---|
| 573 | * Create a private colormap if one doesn't already exist for the
|
|---|
| 574 | * window.
|
|---|
| 575 | */
|
|---|
| 576 |
|
|---|
| 577 | colorTabPtr->colorMap = colorMap = Tk_Colormap(tkwin);
|
|---|
| 578 |
|
|---|
| 579 | nUsedColors = 0; /* Number of colors allocated */
|
|---|
| 580 |
|
|---|
| 581 | if (colorTabPtr->nPixels > 0) {
|
|---|
| 582 | XFreeColors(colorTabPtr->display, colorTabPtr->colorMap,
|
|---|
| 583 | colorTabPtr->pixelValues, colorTabPtr->nPixels, 0);
|
|---|
| 584 | }
|
|---|
| 585 | nFreeColors = QueryColormap(colorTabPtr->display, colorMap, usedColors,
|
|---|
| 586 | &nUsedColors);
|
|---|
| 587 | memset((char *)inUse, 0, sizeof(int) * NCOLORS);
|
|---|
| 588 | if ((nUsedColors == 0) && (keepColors > 0)) {
|
|---|
| 589 |
|
|---|
| 590 | /*
|
|---|
| 591 | * We're starting with a clean colormap so find out what colors
|
|---|
| 592 | * have been used in the default colormap.
|
|---|
| 593 | */
|
|---|
| 594 |
|
|---|
| 595 | nFreeColors = QueryColormap(colorTabPtr->display,
|
|---|
| 596 | Blt_DefaultColormap(tkwin), usedColors, &nUsedColors);
|
|---|
| 597 |
|
|---|
| 598 | /*
|
|---|
| 599 | * Copy a number of colors from the default colormap into the private
|
|---|
| 600 | * colormap. We can assume that this is the working set from most
|
|---|
| 601 | * (non-image related) applications. While this doesn't stop our
|
|---|
| 602 | * image from flashing and looking dumb when colormaps are swapped
|
|---|
| 603 | * in and out, at least everything else should remain unaffected.
|
|---|
| 604 | */
|
|---|
| 605 |
|
|---|
| 606 | if (nUsedColors > keepColors) {
|
|---|
| 607 | nUsedColors = keepColors;
|
|---|
| 608 | }
|
|---|
| 609 | /*
|
|---|
| 610 | * We want to allocate colors in the same ordering as the old colormap,
|
|---|
| 611 | * and we can't assume that the colors in the old map were contiguous.
|
|---|
| 612 | * So mark the colormap locations (i.e. pixels) that we find in use.
|
|---|
| 613 | */
|
|---|
| 614 |
|
|---|
| 615 | }
|
|---|
| 616 | for (colorPtr = usedColors, i = 0; i < nUsedColors; i++, colorPtr++) {
|
|---|
| 617 | inUse[colorPtr->pixel] = TRUE;
|
|---|
| 618 | }
|
|---|
| 619 |
|
|---|
| 620 | /*
|
|---|
| 621 | * In an "exact" colormap, we try to allocate as many of colors from the
|
|---|
| 622 | * image as we can fit. If necessary, we'll cheat and reduce the number
|
|---|
| 623 | * of colors by quantizing.
|
|---|
| 624 | */
|
|---|
| 625 | imageColors = usedColors + nUsedColors;
|
|---|
| 626 |
|
|---|
| 627 | Tk_SetWindowColormap(tkwin, colorMap);
|
|---|
| 628 | }
|
|---|
| 629 |
|
|---|
| 630 | ColorTable
|
|---|
| 631 | Blt_PseudoColorTable(interp, tkwin, image)
|
|---|
| 632 | Tcl_Interp *interp;
|
|---|
| 633 | Tk_Window tkwin;
|
|---|
| 634 | Blt_ColorImage image;
|
|---|
| 635 | {
|
|---|
| 636 | struct ColorTableStruct *colorTabPtr;
|
|---|
| 637 | Colormap defColorMap;
|
|---|
| 638 | int usePrivate;
|
|---|
| 639 |
|
|---|
| 640 | colorTabPtr = Blt_CreateColorTable(tkwin);
|
|---|
| 641 | defColorMap = DefaultColormap(colorTabPtr->display, Tk_ScreenNumber(tkwin));
|
|---|
| 642 | if (colorTabPtr->colorMap == defColorMap) {
|
|---|
| 643 | fprintf(stderr, "Using default colormap\n");
|
|---|
| 644 | }
|
|---|
| 645 | /* All other visuals use an 8-bit colormap */
|
|---|
| 646 | colorTabPtr->lut = Blt_Malloc(sizeof(unsigned int) * 33 * 33 * 33);
|
|---|
| 647 | assert(colorTabPtr->lut);
|
|---|
| 648 |
|
|---|
| 649 | usePrivate = TRUE;
|
|---|
| 650 | if (usePrivate) {
|
|---|
| 651 | PrivateColormap(interp, colorTabPtr, image, tkwin);
|
|---|
| 652 | } else {
|
|---|
| 653 | #ifdef notdef
|
|---|
| 654 | ReadOnlyColormap(colorTabPtr, image, tkwin);
|
|---|
| 655 | #endif
|
|---|
| 656 | }
|
|---|
| 657 | return colorTabPtr;
|
|---|
| 658 | }
|
|---|
| 659 |
|
|---|
| 660 | #ifdef notdef
|
|---|
| 661 |
|
|---|
| 662 | static void
|
|---|
| 663 | ConvoleColorImage(srcImage, destImage, kernelPtr)
|
|---|
| 664 | Blt_ColorImage srcImage, destImage;
|
|---|
| 665 | ConvoleKernel *kernelPtr;
|
|---|
| 666 | {
|
|---|
| 667 | Pix32 *srcPtr, *destPtr;
|
|---|
| 668 | Pix32 *src[MAXROWS];
|
|---|
| 669 | register int x, y, i, j;
|
|---|
| 670 | int red, green, blue;
|
|---|
| 671 |
|
|---|
| 672 | /* i = 0 case, ignore left column of pixels */
|
|---|
| 673 |
|
|---|
| 674 | srcPtr = Blt_ColorImageBits(srcImage);
|
|---|
| 675 | destPtr = Blt_ColorImageBits(destImage);
|
|---|
| 676 |
|
|---|
| 677 | width = Blt_ColorImageWidth(srcImage);
|
|---|
| 678 | height = Blt_ColorImageHeight(srcImage);
|
|---|
| 679 |
|
|---|
| 680 | yOffset = kernelPtr->height / 2;
|
|---|
| 681 | xOffset = kernelPtr->width / 2;
|
|---|
| 682 | for (y = yOffset; y < (height - yOffset); y++) {
|
|---|
| 683 | /* Set up pointers to individual rows */
|
|---|
| 684 | for (i = 0; i < kernelPtr->height; i++) {
|
|---|
| 685 | src[i] = srcPtr + (i * width);
|
|---|
| 686 | }
|
|---|
| 687 | for (x = xOffset; x < (width - xOffset); x++) {
|
|---|
| 688 | red = green = blue = 0;
|
|---|
| 689 | kernPtr = kernelPtr->values;
|
|---|
| 690 | for (i = 0; i < kernelPtr->height; i++) {
|
|---|
| 691 | for (j = 0; j < kernelPtr->width; j++) {
|
|---|
| 692 | red += *valuePtr * src[i][j].Red;
|
|---|
| 693 | green += *valuePtr * src[i][j].Green;
|
|---|
| 694 | blue += *valuePtr * src[i][j].Blue;
|
|---|
| 695 | valuePtr++;
|
|---|
| 696 | }
|
|---|
| 697 | }
|
|---|
| 698 | destPtr->Red = red / kernelPtr->sum;
|
|---|
| 699 | destPtr->Green = green / kernelPtr->sum;
|
|---|
| 700 | destPtr->Blue = blue / kernelPtr->sum;
|
|---|
| 701 | destPtr++;
|
|---|
| 702 | }
|
|---|
| 703 | srcPtr += width;
|
|---|
| 704 | }
|
|---|
| 705 | sum = bot[0].Red +
|
|---|
| 706 | red = bot[0].Red + bot[1].Red + mid[1].Red + top[0].Red + top[1].Red;
|
|---|
| 707 | green = bot[0].Green + bot[1].Green + mid[1].Green + top[0].Green +
|
|---|
| 708 | top[1].Green;
|
|---|
| 709 | blue = bot[0].Blue + bot[1].Blue + mid[1].Blue + top[0].Blue + top[1].Blue;
|
|---|
| 710 | error = (red / 5) - mid[0].Red;
|
|---|
| 711 | redVal = mid[0].Red - (error * blend / blend_divisor);
|
|---|
| 712 | error = (green / 5) - mid[0].Green;
|
|---|
| 713 | greenVal = mid[0].Green - (error * blend / blend_divisor);
|
|---|
| 714 | error = (blue / 5) - mid[0].Blue;
|
|---|
| 715 | blueVal = mid[0].Blue - (error * blend / blend_divisor);
|
|---|
| 716 |
|
|---|
| 717 | out[0].Red = CLAMP(redVal);
|
|---|
| 718 | out[0].Green = CLAMP(greenVal);
|
|---|
| 719 | out[0].Blue = CLAMP(blueVal);
|
|---|
| 720 |
|
|---|
| 721 | for (i = 1; i < (width - 1); i++) {
|
|---|
| 722 | for (chan = 0; chan < 3; chan++) {
|
|---|
| 723 | total = bot[chan][i - 1] + bot[chan][i] + bot[chan][i + 1] +
|
|---|
| 724 | mid[chan][i - 1] + mid[chan][i + 1] +
|
|---|
| 725 | top[chan][i - 1] + top[chan][i] + top[chan][i + 1];
|
|---|
| 726 | avg = total >> 3; /* divide by 8 */
|
|---|
| 727 | diff = avg - mid[chan][i];
|
|---|
| 728 | result = mid[chan][i] - (diff * blend / blend_divisor);
|
|---|
| 729 | out[chan][i] = CLAMP(result);
|
|---|
| 730 | }
|
|---|
| 731 | }
|
|---|
| 732 | /* i = in_hdr.xmax case, ignore right column of pixels */
|
|---|
| 733 | for (chan = 0; chan < 3; chan++) {
|
|---|
| 734 | total = bot[chan][i - 1] + bot[chan][i] +
|
|---|
| 735 | mid[chan][i - 1] +
|
|---|
| 736 | top[chan][i - 1] + top[chan][i];
|
|---|
| 737 | avg = total / 5;
|
|---|
| 738 | diff = avg - mid[chan][i];
|
|---|
| 739 | result = mid[chan][i] - (diff * blend / blend_divisor);
|
|---|
| 740 | out[chan][i] = CLAMP(result);
|
|---|
| 741 | }
|
|---|
| 742 | }
|
|---|
| 743 |
|
|---|
| 744 | static void
|
|---|
| 745 | DitherRow(srcImage, destImage, lastRow, curRow)
|
|---|
| 746 | Blt_ColorImage srcImage, destImage;
|
|---|
| 747 | int width, height;
|
|---|
| 748 | int bottom, top;
|
|---|
| 749 | {
|
|---|
| 750 | int width, height;
|
|---|
| 751 |
|
|---|
| 752 | width = Blt_ColorImageWidth(srcImage);
|
|---|
| 753 | topPtr = Blt_ColorImageBits(destPtr) + (width * row);
|
|---|
| 754 | rowPtr = topPtr + width;
|
|---|
| 755 | botPtr = rowPtr + width;
|
|---|
| 756 |
|
|---|
| 757 | for (x = 0; x < width; x++) {
|
|---|
| 758 |
|
|---|
| 759 | /* Clamp current error entry */
|
|---|
| 760 |
|
|---|
| 761 | midPtr->red = CLAMP(midPtr->red);
|
|---|
| 762 | midPtr->blue = CLAMP(midPtr->blue);
|
|---|
| 763 | midPtr->green = CLAMP(midPtr->green);
|
|---|
| 764 |
|
|---|
| 765 | r = (midPtr->red >> 3) + 1;
|
|---|
| 766 | g = (midPtr->green >> 3) + 1;
|
|---|
| 767 | b = (midPtr->blue >> 3) + 1;
|
|---|
| 768 | index = colorTabPtr->lut[r][g][b];
|
|---|
| 769 |
|
|---|
| 770 | redVal = midPtr->red * (NCOLORS + 1);
|
|---|
| 771 | greenVal = midPtr->green * (NCOLORS + 1);
|
|---|
| 772 | blueVal = midPtr->blue * (NCOLORS + 1);
|
|---|
| 773 |
|
|---|
| 774 | error = colorVal - colorMap[index].red;
|
|---|
| 775 | if (x < 511) {
|
|---|
| 776 | currRow[x + 1].Red = currRow[x + 1].Red + 7 * error / 16;
|
|---|
| 777 | nextRow[x + 1].Red = nextRow[x + 1].Red + error / 16;
|
|---|
| 778 | }
|
|---|
| 779 | nextRow[x].Red = nextRow[x].Red + 5 * error / 16;
|
|---|
| 780 | if (x > 0) {
|
|---|
| 781 | nextRow[x - 1].Red = nextRow[x - 1].Red + 3 * error / 16;
|
|---|
| 782 | }
|
|---|
| 783 | error = row[x][c] - colormap[index][c];
|
|---|
| 784 |
|
|---|
| 785 | value = srcPtr->channel[i] * error[i];
|
|---|
| 786 | value = CLAMP(value);
|
|---|
| 787 | destPtr->channel[i] = value;
|
|---|
| 788 |
|
|---|
| 789 | /* Closest pixel */
|
|---|
| 790 | pixel = PsuedoColorPixel();
|
|---|
| 791 | error[RED] = colorPtr->Red - srcPtr->Red * (NCOLORS + 1);
|
|---|
| 792 |
|
|---|
| 793 | /* translate pixel to colorInfoPtr to get error */
|
|---|
| 794 | colorTabPtr->lut[r][g][b];
|
|---|
| 795 | colorPtr = PixelToColorInfo(pixel);
|
|---|
| 796 | error = colorPtr->error;
|
|---|
| 797 |
|
|---|
| 798 | register rle_pixel *optr;
|
|---|
| 799 | register int j;
|
|---|
| 800 | register short *thisptr, *nextptr = NULL;
|
|---|
| 801 | int chan;
|
|---|
| 802 | static int nchan = 0;
|
|---|
| 803 | int lastline = 0, lastpixel;
|
|---|
| 804 | static int *cval = 0;
|
|---|
| 805 | static rle_pixel *pixel = 0;
|
|---|
| 806 |
|
|---|
| 807 | if (nchan != in_hdr->ncolors)
|
|---|
| 808 | if (cval) {
|
|---|
| 809 | Blt_Free(cval);
|
|---|
| 810 | Blt_Free(pixel);
|
|---|
| 811 | }
|
|---|
| 812 | nchan = in_hdr->ncolors;
|
|---|
| 813 | if (!cval) {
|
|---|
| 814 | if ((cval = Blt_Malloc(nchan * sizeof(int))) == 0)
|
|---|
| 815 | malloc_ERR;
|
|---|
| 816 | if ((pixel = Blt_Malloc(nchan * sizeof(rle_pixel))) == 0)
|
|---|
| 817 | malloc_ERR;
|
|---|
| 818 | }
|
|---|
| 819 | optr = outrow[RLE_RED];
|
|---|
| 820 |
|
|---|
| 821 | thisptr = row_top;
|
|---|
| 822 | if (row_bottom)
|
|---|
| 823 | nextptr = row_bottom;
|
|---|
| 824 | else
|
|---|
| 825 | lastline = 1;
|
|---|
| 826 |
|
|---|
| 827 | for (x = 0; x < width; x++) {
|
|---|
| 828 | int cmap_index = 0;
|
|---|
| 829 |
|
|---|
| 830 | lastpixel = (x == (width - 1));
|
|---|
| 831 | val = srcPtr->Red;
|
|---|
| 832 |
|
|---|
| 833 | for (chan = 0; chan < 3; chan++) {
|
|---|
| 834 | cval[chan] = *thisptr++;
|
|---|
| 835 |
|
|---|
| 836 | /*
|
|---|
| 837 | * Current channel value has been accumulating error,
|
|---|
| 838 | * it could be out of range.
|
|---|
| 839 | */
|
|---|
| 840 | if (cval[chan] < 0)
|
|---|
| 841 | cval[chan] = 0;
|
|---|
| 842 | else if (cval[chan] > 255)
|
|---|
| 843 | cval[chan] = 255;
|
|---|
| 844 |
|
|---|
| 845 | pixel[chan] = cval[chan];
|
|---|
| 846 | }
|
|---|
| 847 |
|
|---|
| 848 | /* find closest color */
|
|---|
| 849 | find_closest(map, nchan, maplen, pixel, &cmap_index);
|
|---|
| 850 | *optr++ = cmap_index;
|
|---|
| 851 |
|
|---|
| 852 | /* thisptr is now looking at pixel to the right of current pixel
|
|---|
| 853 | * nextptr is looking at pixel below current pixel
|
|---|
| 854 | * So, increment thisptr as stuff gets stored. nextptr gets moved
|
|---|
| 855 | * by one, and indexing is done +/- nchan.
|
|---|
| 856 | */
|
|---|
| 857 | for (chan = 0; chan < nchan; chan++) {
|
|---|
| 858 | cval[chan] -= map[chan][cmap_index];
|
|---|
| 859 |
|
|---|
| 860 | if (!lastpixel) {
|
|---|
| 861 | thisptr[chan] += cval[chan] * 7 / 16;
|
|---|
| 862 | }
|
|---|
| 863 | if (!lastline) {
|
|---|
| 864 | if (j != 0) {
|
|---|
| 865 | nextptr[-nchan] += cval[chan] * 3 / 16;
|
|---|
| 866 | }
|
|---|
| 867 | nextptr[0] += cval[chan] * 5 / 16;
|
|---|
| 868 | if (!lastpixel) {
|
|---|
| 869 | nextptr[nchan] += cval[chan] / 16;
|
|---|
| 870 | }
|
|---|
| 871 | nextptr++;
|
|---|
| 872 | }
|
|---|
| 873 | }
|
|---|
| 874 | }
|
|---|
| 875 | }
|
|---|
| 876 | }
|
|---|
| 877 |
|
|---|
| 878 | /********************************************/
|
|---|
| 879 | static Blt_ColorImage
|
|---|
| 880 | DoColorDither(pic24, pic8, w, h, rmap, gmap, bmap, rdisp, gdisp, bdisp, maplen)
|
|---|
| 881 | byte *pic24, *pic8, *rmap, *gmap, *bmap, *rdisp, *gdisp, *bdisp;
|
|---|
| 882 | int w, h, maplen;
|
|---|
| 883 | {
|
|---|
| 884 | /* takes a 24 bit picture, of size w*h, dithers with the colors in
|
|---|
| 885 | rdisp, gdisp, bdisp (which have already been allocated),
|
|---|
| 886 | and generates an 8-bit w*h image, which it returns.
|
|---|
| 887 | ignores input value 'pic8'
|
|---|
| 888 | returns NULL on error
|
|---|
| 889 |
|
|---|
| 890 | note: the rdisp,gdisp,bdisp arrays should be the 'displayed' colors,
|
|---|
| 891 | not the 'desired' colors
|
|---|
| 892 |
|
|---|
| 893 | if pic24 is NULL, uses the passed-in pic8 (an 8-bit image) as
|
|---|
| 894 | the source, and the rmap,gmap,bmap arrays as the desired colors */
|
|---|
| 895 |
|
|---|
| 896 | byte *np, *ep, *newpic;
|
|---|
| 897 | short *cache;
|
|---|
| 898 | int r2, g2, b2;
|
|---|
| 899 | int *thisline, *nextline, *thisptr, *nextptr, *tmpptr;
|
|---|
| 900 | int i, j, rerr, gerr, berr, pwide3;
|
|---|
| 901 | int imax, jmax;
|
|---|
| 902 | int key;
|
|---|
| 903 | long cnt1, cnt2;
|
|---|
| 904 | int error[512]; /* -255 .. 0 .. +255 */
|
|---|
| 905 |
|
|---|
| 906 | /* compute somewhat non-linear floyd-steinberg error mapping table */
|
|---|
| 907 | for (i = j = 0; i <= 0x40; i++, j++) {
|
|---|
| 908 | error[256 + i] = j;
|
|---|
| 909 | error[256 - i] = -j;
|
|---|
| 910 | }
|
|---|
| 911 | for ( /*empty*/ ; i < 0x80; i++, j += !(i & 1) ? 1 : 0) {
|
|---|
| 912 | error[256 + i] = j;
|
|---|
| 913 | error[256 - i] = -j;
|
|---|
| 914 | }
|
|---|
| 915 | for ( /*empty*/ ; i <= 0xff; i++) {
|
|---|
| 916 | error[256 + i] = j;
|
|---|
| 917 | error[256 - i] = -j;
|
|---|
| 918 | }
|
|---|
| 919 |
|
|---|
| 920 | cnt1 = cnt2 = 0;
|
|---|
| 921 | pwide3 = w * 3;
|
|---|
| 922 | imax = h - 1;
|
|---|
| 923 | jmax = w - 1;
|
|---|
| 924 | ep = (pic24) ? pic24 : pic8;
|
|---|
| 925 |
|
|---|
| 926 | /* attempt to malloc things */
|
|---|
| 927 | newpic = Blt_Malloc((size_t) (w * h));
|
|---|
| 928 | cache = Blt_Calloc((size_t) (2 << 14), sizeof(short));
|
|---|
| 929 | thisline = Blt_Malloc(pwide3 * sizeof(int));
|
|---|
| 930 | nextline = Blt_Malloc(pwide3 * sizeof(int));
|
|---|
| 931 | if (!cache || !newpic || !thisline || !nextline) {
|
|---|
| 932 | if (newpic)
|
|---|
| 933 | Blt_Free(newpic);
|
|---|
| 934 | if (cache)
|
|---|
| 935 | Blt_Free(cache);
|
|---|
| 936 | if (thisline)
|
|---|
| 937 | Blt_Free(thisline);
|
|---|
| 938 | if (nextline)
|
|---|
| 939 | Blt_Free(nextline);
|
|---|
| 940 | return (byte *) NULL;
|
|---|
| 941 | }
|
|---|
| 942 | np = newpic;
|
|---|
| 943 |
|
|---|
| 944 | /* Get first line of picture in reverse order. */
|
|---|
| 945 |
|
|---|
| 946 | srcPtr = Blt_ColorImageBits(image), tempPtr = tempArr;
|
|---|
| 947 | for (x = 0; x < width; x++, tempPtr++, srcPtr--) {
|
|---|
| 948 | *tempPtr = *srcPtr;
|
|---|
| 949 | }
|
|---|
| 950 |
|
|---|
| 951 | for (y = 0; y < height; y++) {
|
|---|
| 952 | tempPtr = curRowPtr, curRowPtr = nextRowPtr, nextRowPtr = tempPtr;
|
|---|
| 953 |
|
|---|
| 954 | if (y != (height - 1)) {/* get next line */
|
|---|
| 955 | for (x = 0; x < width; x++, tempPtr++, srcPtr--)
|
|---|
| 956 | *tempPtr = *srcPtr;
|
|---|
| 957 | }
|
|---|
| 958 | }
|
|---|
| 959 |
|
|---|
| 960 |
|
|---|
| 961 | Blt_Free(thisline);
|
|---|
| 962 | Blt_Free(nextline);
|
|---|
| 963 | Blt_Free(cache);
|
|---|
| 964 |
|
|---|
| 965 | return newpic;
|
|---|
| 966 | }
|
|---|
| 967 |
|
|---|
| 968 |
|
|---|
| 969 | static void
|
|---|
| 970 | DitherImage(image)
|
|---|
| 971 | Blt_ColorImage image;
|
|---|
| 972 | {
|
|---|
| 973 | int width, height;
|
|---|
| 974 |
|
|---|
| 975 |
|
|---|
| 976 |
|
|---|
| 977 | }
|
|---|
| 978 |
|
|---|
| 979 | #endif
|
|---|
| 980 |
|
|---|
| 981 | #endif /* WIN32 */
|
|---|