source: trunk/kitgen/8.x/blt/generic/bltColor.c

Last change on this file was 175, checked in by demin, 12 years ago

initial commit

File size: 26.6 KB
Line 
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
81static void
82GetPaletteSizes(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
107static void
108BuildColorRamp(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
149static int
150QueryColormap(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
203static void
204FindClosestColor(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
237static int
238CompareColors(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
253static float
254MatchColors(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
312static int
313AllocateColors(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
346ColorTable
347Blt_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
375void
376Blt_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
389extern int redAdjust, greenAdjust, blueAdjust;
390extern 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*/
406ColorTable
407Blt_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 */
518static int
519GetUniqueColors(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
556static void
557PrivateColormap(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
630ColorTable
631Blt_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
662static void
663ConvoleColorImage(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
744static void
745DitherRow(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/********************************************/
879static Blt_ColorImage
880DoColorDither(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
969static void
970DitherImage(image)
971 Blt_ColorImage image;
972{
973 int width, height;
974
975
976
977}
978
979#endif
980
981#endif /* WIN32 */
Note: See TracBrowser for help on using the repository browser.