1 /* convert.c - convert RImage to Pixmap
3 * Raster graphics library
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * 1. Using Grayscale visual with Dithering crashes wmaker
24 * 2. Ghost dock/appicon is wrong in Pseudocolor, Staticgray, Grayscale
30 #include <X11/Xutil.h>
44 extern Pixmap R_CreateXImageMappedPixmap(RContext * context, RXImage * ximage);
49 extern void x86_PseudoColor_32_to_8(unsigned char *image,
50 unsigned char *ximage,
51 char *err, char *nerr,
53 int dr, int dg, int db,
54 unsigned long *pixels,
55 int cpc, int width, int height, int bytesPerPixel, int line_offset);
60 extern int x86_check_mmx();
62 extern void x86_mmx_TrueColor_32_to_16(unsigned char *image,
63 unsigned short *ximage,
64 short *err, short *nerr,
65 const unsigned short *rtable,
66 const unsigned short *gtable,
67 const unsigned short *btable,
68 int dr, int dg, int db,
71 unsigned int boffs, int width, int height, int line_offset);
73 #endif /* ASM_X86_MMX */
75 #define NFREE(n) if (n) free(n)
77 #define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
79 typedef struct RConversionTable {
80 unsigned short table[256];
83 struct RConversionTable *next;
86 typedef struct RStdConversionTable {
87 unsigned int table[256];
92 struct RStdConversionTable *next;
93 } RStdConversionTable;
95 static RConversionTable *conversionTable = NULL;
96 static RStdConversionTable *stdConversionTable = NULL;
98 static unsigned short *computeTable(unsigned short mask)
100 RConversionTable *tmp = conversionTable;
104 if (tmp->index == mask)
112 tmp = (RConversionTable *) malloc(sizeof(RConversionTable));
116 for (i = 0; i < 256; i++)
117 tmp->table[i] = (i * mask + 0x7f) / 0xff;
120 tmp->next = conversionTable;
121 conversionTable = tmp;
125 static unsigned int *computeStdTable(unsigned int mult, unsigned int max)
127 RStdConversionTable *tmp = stdConversionTable;
131 if (tmp->mult == mult && tmp->max == max)
139 tmp = (RStdConversionTable *) malloc(sizeof(RStdConversionTable));
143 for (i = 0; i < 256; i++) {
144 tmp->table[i] = (i * max) / 0xff * mult;
149 tmp->next = stdConversionTable;
150 stdConversionTable = tmp;
155 /***************************************************************************/
158 convertTrueColor_generic(RXImage * ximg, RImage * image,
159 signed char *err, signed char *nerr,
160 const unsigned short *rtable,
161 const unsigned short *gtable,
162 const unsigned short *btable,
163 const int dr, const int dg, const int db,
164 const unsigned short roffs, const unsigned short goffs, const unsigned short boffs)
170 unsigned char *ptr = image->data;
171 int channels = (HAS_ALPHA(image) ? 4 : 3);
173 /* convert and dither the image to XImage */
174 for (y = 0; y < image->height; y++) {
178 for (x = 0; x < image->width; x++, ptr += channels) {
181 pixel = *ptr + err[x];
184 else if (pixel > 0xff)
188 rer = pixel - r * dr;
191 pixel = *(ptr + 1) + err[x + 1];
194 else if (pixel > 0xff)
198 ger = pixel - g * dg;
201 pixel = *(ptr + 2) + err[x + 2];
204 else if (pixel > 0xff)
208 ber = pixel - b * db;
210 pixel = (r << roffs) | (g << goffs) | (b << boffs);
211 XPutPixel(ximg->image, x, y, pixel);
213 /* distribute error */
219 err[x + 1 + 3 * 1] += g;
220 err[x + 2 + 3 * 1] += b;
226 nerr[x + 3 * 1] = rer - 2 * r;
227 nerr[x + 1 + 3 * 1] = ger - 2 * g;
228 nerr[x + 2 + 3 * 1] = ber - 2 * b;
230 /* skip to next line */
236 /* redither the 1st line to distribute error better */
242 for (x = 0; x < image->width; x++, ptr += channels) {
245 pixel = *ptr + err[x];
248 else if (pixel > 0xff)
252 rer = pixel - r * dr;
255 pixel = *(ptr + 1) + err[x + 1];
258 else if (pixel > 0xff)
262 ger = pixel - g * dg;
265 pixel = *(ptr + 2) + err[x + 2];
268 else if (pixel > 0xff)
272 ber = pixel - b * db;
274 pixel = (r << roffs) | (g << goffs) | (b << boffs);
275 XPutPixel(ximg->image, x, y, pixel);
277 /* distribute error */
283 err[x + 1 + 3 * 1] += g;
284 err[x + 2 + 3 * 1] += b;
290 nerr[x + 3 * 1] = rer - 2 * r;
291 nerr[x + 1 + 3 * 1] = ger - 2 * g;
292 nerr[x + 2 + 3 * 1] = ber - 2 * b;
296 static RXImage *image2TrueColor(RContext * ctx, RImage * image)
299 unsigned short rmask, gmask, bmask;
300 unsigned short roffs, goffs, boffs;
301 unsigned short *rtable, *gtable, *btable;
302 int channels = (HAS_ALPHA(image) ? 4 : 3);
304 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
309 roffs = ctx->red_offset;
310 goffs = ctx->green_offset;
311 boffs = ctx->blue_offset;
313 rmask = ctx->visual->red_mask >> roffs;
314 gmask = ctx->visual->green_mask >> goffs;
315 bmask = ctx->visual->blue_mask >> boffs;
317 rtable = computeTable(rmask);
318 gtable = computeTable(gmask);
319 btable = computeTable(bmask);
321 if (rtable == NULL || gtable == NULL || btable == NULL) {
322 RErrorCode = RERR_NOMEMORY;
323 RDestroyXImage(ctx, ximg);
331 if (ctx->attribs->render_mode == RBestMatchRendering) {
335 unsigned char *ptr = image->data;
339 puts("true color match");
341 if (rmask == 0xff && gmask == 0xff && bmask == 0xff) {
342 for (y = 0; y < image->height; y++) {
343 for (x = 0; x < image->width; x++, ptr += channels) {
345 pixel = (*(ptr) << roffs) | (*(ptr + 1) << goffs) | (*(ptr + 2) << boffs);
346 XPutPixel(ximg->image, x, y, pixel);
350 for (y = 0, ofs = 0; y < image->height; y++) {
351 for (x = 0; x < image->width; x++, ofs += channels - 3) {
353 r = rtable[ptr[ofs++]];
354 g = gtable[ptr[ofs++]];
355 b = btable[ptr[ofs++]];
356 pixel = (r << roffs) | (g << goffs) | (b << boffs);
357 XPutPixel(ximg->image, x, y, pixel);
363 const int dr = 0xff / rmask;
364 const int dg = 0xff / gmask;
365 const int db = 0xff / bmask;
368 puts("true color dither");
372 if (ctx->depth == 16 && HAS_ALPHA(image) && x86_check_mmx()) {
376 err = malloc(8 * (image->width + 3));
377 nerr = malloc(8 * (image->width + 3));
381 RErrorCode = RERR_NOMEMORY;
382 RDestroyXImage(ctx, ximg);
385 memset(err, 0, 8 * (image->width + 3));
386 memset(nerr, 0, 8 * (image->width + 3));
388 x86_mmx_TrueColor_32_to_16(image->data,
389 (unsigned short *)ximg->image->data,
391 rtable, gtable, btable,
394 image->width, image->height,
395 ximg->image->bytes_per_line - 2 * image->width);
400 #endif /* ASM_X86_MMX */
404 int ch = (HAS_ALPHA(image) ? 4 : 3);
406 err = malloc(ch * (image->width + 2));
407 nerr = malloc(ch * (image->width + 2));
411 RErrorCode = RERR_NOMEMORY;
412 RDestroyXImage(ctx, ximg);
416 memset(err, 0, ch * (image->width + 2));
417 memset(nerr, 0, ch * (image->width + 2));
419 convertTrueColor_generic(ximg, image, err, nerr,
420 rtable, gtable, btable, dr, dg, db, roffs, goffs, boffs);
434 /***************************************************************************/
437 convertPseudoColor_to_8(RXImage * ximg, RImage * image,
438 signed char *err, signed char *nerr,
439 const unsigned short *rtable,
440 const unsigned short *gtable,
441 const unsigned short *btable,
442 const int dr, const int dg, const int db, unsigned long *pixels, int cpc)
448 unsigned char *ptr = image->data;
449 unsigned char *optr = (unsigned char *)ximg->image->data;
450 int channels = (HAS_ALPHA(image) ? 4 : 3);
451 int cpcpc = cpc * cpc;
453 /* convert and dither the image to XImage */
454 for (y = 0; y < image->height; y++) {
458 for (x = 0; x < image->width * 3; x += 3, ptr += channels) {
461 pixel = *ptr + err[x];
464 else if (pixel > 0xff)
468 rer = pixel - r * dr;
471 pixel = *(ptr + 1) + err[x + 1];
474 else if (pixel > 0xff)
478 ger = pixel - g * dg;
481 pixel = *(ptr + 2) + err[x + 2];
484 else if (pixel > 0xff)
488 ber = pixel - b * db;
490 *optr++ = pixels[r * cpcpc + g * cpc + b];
492 /* distribute error */
499 err[x + 1 + 3 * 1] += g;
500 err[x + 2 + 3 * 1] += b;
506 nerr[x + 3 * 1] = rer - 2 * r;
507 nerr[x + 1 + 3 * 1] = ger - 2 * g;
508 nerr[x + 2 + 3 * 1] = ber - 2 * b;
510 /* skip to next line */
515 optr += ximg->image->bytes_per_line - image->width;
519 static RXImage *image2PseudoColor(RContext * ctx, RImage * image)
522 register int x, y, r, g, b;
525 const int cpc = ctx->attribs->colors_per_channel;
526 const unsigned short rmask = cpc - 1; /* different sizes could be used */
527 const unsigned short gmask = rmask; /* for r,g,b */
528 const unsigned short bmask = rmask;
529 unsigned short *rtable, *gtable, *btable;
530 const int cpccpc = cpc * cpc;
531 int channels = (HAS_ALPHA(image) ? 4 : 3);
533 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
540 /* Tables are same at the moment because rmask==gmask==bmask. */
541 rtable = computeTable(rmask);
542 gtable = computeTable(gmask);
543 btable = computeTable(bmask);
545 if (rtable == NULL || gtable == NULL || btable == NULL) {
546 RErrorCode = RERR_NOMEMORY;
547 RDestroyXImage(ctx, ximg);
551 if (ctx->attribs->render_mode == RBestMatchRendering) {
554 printf("pseudo color match with %d colors per channel\n", cpc);
556 for (y = 0; y < image->height; y++) {
557 for (x = 0; x < image->width; x++, ptr += channels - 3) {
562 pixel = r * cpccpc + g * cpc + b;
563 /*data[ofs] = ctx->colors[pixel].pixel; */
564 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
571 const int dr = 0xff / rmask;
572 const int dg = 0xff / gmask;
573 const int db = 0xff / bmask;
576 printf("pseudo color dithering with %d colors per channel\n", cpc);
578 err = malloc(4 * (image->width + 3));
579 nerr = malloc(4 * (image->width + 3));
583 RErrorCode = RERR_NOMEMORY;
584 RDestroyXImage(ctx, ximg);
587 memset(err, 0, 4 * (image->width + 3));
588 memset(nerr, 0, 4 * (image->width + 3));
592 x86_PseudoColor_32_to_8(image->data, ximg->image->data,
595 dr, dg, db, ctx->pixels, cpc,
596 image->width, image->height,
597 channels, ximg->image->bytes_per_line - image->width);
599 convertPseudoColor_to_8(ximg, image, err + 4, nerr + 4,
600 rtable, gtable, btable, dr, dg, db, ctx->pixels, cpc);
611 * For standard colormap
613 static RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image)
616 register int x, y, r, g, b;
620 unsigned int *rtable, *gtable, *btable;
621 unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
622 int channels = (HAS_ALPHA(image) ? 4 : 3);
624 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
631 data = (unsigned char *)ximg->image->data;
633 rtable = computeStdTable(ctx->std_rgb_map->red_mult, ctx->std_rgb_map->red_max);
635 gtable = computeStdTable(ctx->std_rgb_map->green_mult, ctx->std_rgb_map->green_max);
637 btable = computeStdTable(ctx->std_rgb_map->blue_mult, ctx->std_rgb_map->blue_max);
639 if (rtable == NULL || gtable == NULL || btable == NULL) {
640 RErrorCode = RERR_NOMEMORY;
641 RDestroyXImage(ctx, ximg);
645 if (ctx->attribs->render_mode == RBestMatchRendering) {
646 for (y = 0; y < image->height; y++) {
647 for (x = 0; x < image->width; x++, ptr += channels) {
649 pixel = (rtable[*ptr] + gtable[*(ptr + 1)]
650 + btable[*(ptr + 2)] + base_pixel) & 0xffffffff;
652 XPutPixel(ximg->image, x, y, pixel);
657 signed short *err, *nerr;
663 printf("pseudo color dithering with %d colors per channel\n", ctx->attribs->colors_per_channel);
665 err = (short *)malloc(3 * (image->width + 2) * sizeof(short));
666 nerr = (short *)malloc(3 * (image->width + 2) * sizeof(short));
670 RErrorCode = RERR_NOMEMORY;
671 RDestroyXImage(ctx, ximg);
674 for (x = 0, x1 = 0; x < image->width * 3; x1 += channels - 3) {
675 err[x++] = ptr[x1++];
676 err[x++] = ptr[x1++];
677 err[x++] = ptr[x1++];
679 err[x] = err[x + 1] = err[x + 2] = 0;
680 /* convert and dither the image to XImage */
681 for (y = 0, ofs = 0; y < image->height; y++) {
682 if (y < image->height - 1) {
684 for (x = 0, x1 = (y + 1) * image->width * channels;
685 x < image->width * 3; x1 += channels - 3) {
686 nerr[x++] = ptr[x1++];
687 nerr[x++] = ptr[x1++];
688 nerr[x++] = ptr[x1++];
692 nerr[x++] = ptr[x1++];
693 nerr[x++] = ptr[x1++];
694 nerr[x++] = ptr[x1++];
696 for (x = 0; x < image->width * 3; x += 3, ofs++) {
702 if (err[x + 1] > 0xff)
704 else if (err[x + 1] < 0)
706 if (err[x + 2] > 0xff)
708 else if (err[x + 2] < 0)
712 g = gtable[err[x + 1]];
713 b = btable[err[x + 2]];
717 data[ofs] = base_pixel + pixel;
720 rer = err[x] - (ctx->colors[pixel].red >> 8);
721 ger = err[x + 1] - (ctx->colors[pixel].green >> 8);
722 ber = err[x + 2] - (ctx->colors[pixel].blue >> 8);
724 /* distribute error */
725 err[x + 3 * 1] += (rer * 7) / 16;
726 err[x + 1 + 3 * 1] += (ger * 7) / 16;
727 err[x + 2 + 3 * 1] += (ber * 7) / 16;
729 nerr[x] += (rer * 5) / 16;
730 nerr[x + 1] += (ger * 5) / 16;
731 nerr[x + 2] += (ber * 5) / 16;
734 nerr[x - 3 * 1] += (rer * 3) / 16;
735 nerr[x - 3 * 1 + 1] += (ger * 3) / 16;
736 nerr[x - 3 * 1 + 2] += (ber * 3) / 16;
739 nerr[x + 3 * 1] += rer / 16;
740 nerr[x + 1 + 3 * 1] += ger / 16;
741 nerr[x + 2 + 3 * 1] += ber / 16;
743 /* skip to next line */
748 ofs += ximg->image->bytes_per_line - image->width;
753 ximg->image->data = (char *)data;
758 static RXImage *image2GrayScale(RContext * ctx, RImage * image)
761 register int x, y, g;
763 const int cpc = ctx->attribs->colors_per_channel;
764 unsigned short gmask;
765 unsigned short *table;
767 int channels = (HAS_ALPHA(image) ? 4 : 3);
769 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
776 data = (unsigned char *)ximg->image->data;
778 if (ctx->vclass == StaticGray)
779 gmask = (1 << ctx->depth) - 1; /* use all grays */
781 gmask = cpc * cpc * cpc - 1;
783 table = computeTable(gmask);
786 RErrorCode = RERR_NOMEMORY;
787 RDestroyXImage(ctx, ximg);
791 if (ctx->attribs->render_mode == RBestMatchRendering) {
794 printf("grayscale match with %d colors per channel\n", cpc);
796 for (y = 0; y < image->height; y++) {
797 for (x = 0; x < image->width; x++) {
799 g = table[(*ptr * 30 + *(ptr + 1) * 59 + *(ptr + 2) * 11) / 100];
801 /*data[ofs] = ctx->colors[g].pixel; */
802 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
811 const int dg = 0xff / gmask;
814 printf("grayscale dither with %d colors per channel\n", cpc);
816 gerr = (short *)malloc((image->width + 2) * sizeof(short));
817 ngerr = (short *)malloc((image->width + 2) * sizeof(short));
818 if (!gerr || !ngerr) {
821 RErrorCode = RERR_NOMEMORY;
822 RDestroyXImage(ctx, ximg);
825 for (x = 0, y = 0; x < image->width; x++, y += channels) {
826 gerr[x] = (ptr[y] * 30 + ptr[y + 1] * 59 + ptr[y + 2] * 11) / 100;
829 /* convert and dither the image to XImage */
830 for (y = 0; y < image->height; y++) {
831 if (y < image->height - 1) {
833 for (x = 0, x1 = (y + 1) * image->width * channels; x < image->width;
834 x++, x1 += channels) {
835 ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
839 ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
841 for (x = 0; x < image->width; x++) {
845 else if (gerr[x] < 0)
850 /*data[ofs] = ctx->colors[g].pixel; */
851 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
853 ger = gerr[x] - g * dg;
855 /* distribute error */
862 ngerr[x + 1] += ger - 2 * g;
864 /* skip to next line */
872 ximg->image->data = (char *)data;
877 static RXImage *image2Bitmap(RContext * ctx, RImage * image, int threshold)
880 unsigned char *alpha;
883 ximg = RCreateXImage(ctx, 1, image->width, image->height);
887 alpha = image->data + 3;
889 for (y = 0; y < image->height; y++) {
890 for (x = 0; x < image->width; x++) {
891 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
899 int RConvertImage(RContext * context, RImage * image, Pixmap * pixmap)
901 RXImage *ximg = NULL;
906 assert(context != NULL);
907 assert(image != NULL);
908 assert(pixmap != NULL);
910 switch (context->vclass) {
915 ximg = image2TrueColor(context, image);
926 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
927 ximg = image2StandardPseudoColor(context, image);
929 ximg = image2PseudoColor(context, image);
937 ximg = image2GrayScale(context, image);
945 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, context->depth);
948 if (context->flags.use_shared_pixmap && ximg->is_shared)
949 tmp = R_CreateXImageMappedPixmap(context, ximg);
954 * We have to copy the shm Pixmap into a normal Pixmap because
955 * otherwise, we would have to control when Pixmaps are freed so
956 * that we can detach their shm segments. This is a problem if the
957 * program crash, leaving stale shared memory segments in the
958 * system (lots of them). But with some work, we can optimize
959 * things and remove this XCopyArea. This will require
960 * explicitly freeing all pixmaps when exiting or restarting
963 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0, image->width, image->height, 0, 0);
964 XFreePixmap(context->dpy, tmp);
966 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
969 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
972 RDestroyXImage(context, ximg);
977 /* make the gc permanent (create with context creation).
978 * GC creation is very expensive. altering its properties is not. -Dan
980 int RConvertImageMask(RContext * context, RImage * image, Pixmap * pixmap, Pixmap * mask, int threshold)
984 RXImage *ximg = NULL;
986 assert(context != NULL);
987 assert(image != NULL);
988 assert(pixmap != NULL);
989 assert(mask != NULL);
991 if (!RConvertImage(context, image, pixmap))
994 if (image->format == RRGBFormat) {
999 ximg = image2Bitmap(context, image, threshold);
1004 *mask = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, 1);
1005 gcv.foreground = context->black;
1006 gcv.background = context->white;
1007 gcv.graphics_exposures = False;
1008 gc = XCreateGC(context->dpy, *mask, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
1009 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0, image->width, image->height);
1010 RDestroyXImage(context, ximg);
1011 XFreeGC(context->dpy, gc);
1016 Bool RGetClosestXColor(RContext * context, RColor * color, XColor * retColor)
1018 if (context->vclass == TrueColor) {
1019 unsigned short rmask, gmask, bmask;
1020 unsigned short roffs, goffs, boffs;
1021 unsigned short *rtable, *gtable, *btable;
1023 roffs = context->red_offset;
1024 goffs = context->green_offset;
1025 boffs = context->blue_offset;
1027 rmask = context->visual->red_mask >> roffs;
1028 gmask = context->visual->green_mask >> goffs;
1029 bmask = context->visual->blue_mask >> boffs;
1031 rtable = computeTable(rmask);
1032 gtable = computeTable(gmask);
1033 btable = computeTable(bmask);
1035 retColor->pixel = (rtable[color->red] << roffs) |
1036 (gtable[color->green] << goffs) | (btable[color->blue] << boffs);
1038 retColor->red = color->red << 8;
1039 retColor->green = color->green << 8;
1040 retColor->blue = color->blue << 8;
1041 retColor->flags = DoRed | DoGreen | DoBlue;
1043 } else if (context->vclass == PseudoColor || context->vclass == StaticColor) {
1045 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
1046 unsigned int *rtable, *gtable, *btable;
1048 rtable = computeStdTable(context->std_rgb_map->red_mult, context->std_rgb_map->red_max);
1050 gtable = computeStdTable(context->std_rgb_map->green_mult,
1051 context->std_rgb_map->green_max);
1053 btable = computeStdTable(context->std_rgb_map->blue_mult, context->std_rgb_map->blue_max);
1055 if (rtable == NULL || gtable == NULL || btable == NULL) {
1056 RErrorCode = RERR_NOMEMORY;
1060 retColor->pixel = (rtable[color->red]
1061 + gtable[color->green]
1062 + btable[color->blue]
1063 + context->std_rgb_map->base_pixel) & 0xffffffff;
1064 retColor->red = color->red << 8;
1065 retColor->green = color->green << 8;
1066 retColor->blue = color->blue << 8;
1067 retColor->flags = DoRed | DoGreen | DoBlue;
1070 const int cpc = context->attribs->colors_per_channel;
1071 const unsigned short rmask = cpc - 1; /* different sizes could be used */
1072 const unsigned short gmask = rmask; /* for r,g,b */
1073 const unsigned short bmask = rmask;
1074 unsigned short *rtable, *gtable, *btable;
1075 const int cpccpc = cpc * cpc;
1078 rtable = computeTable(rmask);
1079 gtable = computeTable(gmask);
1080 btable = computeTable(bmask);
1082 if (rtable == NULL || gtable == NULL || btable == NULL) {
1083 RErrorCode = RERR_NOMEMORY;
1086 index = rtable[color->red] * cpccpc + gtable[color->green] * cpc + btable[color->blue];
1087 *retColor = context->colors[index];
1090 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
1092 const int cpc = context->attribs->colors_per_channel;
1093 unsigned short gmask;
1094 unsigned short *table;
1097 if (context->vclass == StaticGray)
1098 gmask = (1 << context->depth) - 1; /* use all grays */
1100 gmask = cpc * cpc * cpc - 1;
1102 table = computeTable(gmask);
1106 index = table[(color->red * 30 + color->green * 59 + color->blue * 11) / 100];
1108 *retColor = context->colors[index];
1110 RErrorCode = RERR_INTERNAL;