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 */
|
---|