Initial revision
[wmaker-crm.git] / wrlib / convert.c
blob3736f41695932e351cb1164fcd0ad8c8f5614084
1 /* convert.c - convert RImage to Pixmap
2 *
3 * Raster graphics library
5 * Copyright (c) 1997 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.
21 #include <config.h>
23 /* AIX requires this to be the first thing in the file. */
24 #ifdef __GNUC__
25 # define alloca __builtin_alloca
26 #else
27 # if HAVE_ALLOCA_H
28 # include <alloca.h>
29 # else
30 # ifdef _AIX
31 # pragma alloca
32 # else
33 # ifndef alloca /* predefined by HP cc +Olibcalls */
34 char *alloca ();
35 # endif
36 # endif
37 # endif
38 #endif
41 #include <X11/Xlib.h>
42 #include <X11/Xutil.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
47 #include <assert.h>
49 #include "wraster.h"
51 #define MIN(a,b) ((a)<(b) ? (a) : (b))
54 typedef struct RConversionTable {
55 unsigned short table[256];
56 unsigned short index;
57 struct RConversionTable *next;
58 } RConversionTable;
62 * Lookup table for index*3/8
64 static char errorTable1[]={
65 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5,
66 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11,
67 12, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17,
68 18, 18, 18, 19, 19, 19, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23,
69 24, 24, 24, 25, 25, 25, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29,
70 30, 30, 30, 31, 31, 31, 32, 32, 33, 33, 33, 34, 34, 34, 35, 35,
71 36, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41,
72 42, 42, 42, 43, 43, 43, 44, 44, 45, 45, 45, 46, 46, 46, 47, 47,
73 48, 48, 48, 49, 49, 49, 50, 50, 51, 51, 51, 52, 52, 52, 53, 53,
74 54, 54, 54, 55, 55, 55, 56, 56, 57, 57, 57, 58, 58, 58, 59, 59,
75 60, 60, 60, 61, 61, 61, 62, 62, 63, 63, 63, 64, 64, 64, 65, 65,
76 66, 66, 66, 67, 67, 67, 68, 68, 69, 69, 69, 70, 70, 70, 71, 71,
77 72, 72, 72, 73, 73, 73, 74, 74, 75, 75, 75, 76, 76, 76, 77, 77,
78 78, 78, 78, 79, 79, 79, 80, 80, 81, 81, 81, 82, 82, 82, 83, 83,
79 84, 84, 84, 85, 85, 85, 86, 86, 87, 87, 87, 88, 88, 88, 89, 89,
80 90, 90, 90, 91, 91, 91, 92, 92, 93, 93, 93, 94, 94, 94, 95
83 * Lookup table for index*2/8
85 static char errorTable2[]={
86 0, 1, 2, 1, 2, 3, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5,
87 4, 5, 6, 5, 6, 7, 6, 7, 6, 7, 8, 7, 8, 9, 8, 9,
88 8, 9, 10, 9, 10, 11, 10, 11, 10, 11, 12, 11, 12, 13, 12, 13,
89 12, 13, 14, 13, 14, 15, 14, 15, 14, 15, 16, 15, 16, 17, 16, 17,
90 16, 17, 18, 17, 18, 19, 18, 19, 18, 19, 20, 19, 20, 21, 20, 21,
91 20, 21, 22, 21, 22, 23, 22, 23, 22, 23, 24, 23, 24, 25, 24, 25,
92 24, 25, 26, 25, 26, 27, 26, 27, 26, 27, 28, 27, 28, 29, 28, 29,
93 28, 29, 30, 29, 30, 31, 30, 31, 30, 31, 32, 31, 32, 33, 32, 33,
94 32, 33, 34, 33, 34, 35, 34, 35, 34, 35, 36, 35, 36, 37, 36, 37,
95 36, 37, 38, 37, 38, 39, 38, 39, 38, 39, 40, 39, 40, 41, 40, 41,
96 40, 41, 42, 41, 42, 43, 42, 43, 42, 43, 44, 43, 44, 45, 44, 45,
97 44, 45, 46, 45, 46, 47, 46, 47, 46, 47, 48, 47, 48, 49, 48, 49,
98 48, 49, 50, 49, 50, 51, 50, 51, 50, 51, 52, 51, 52, 53, 52, 53,
99 52, 53, 54, 53, 54, 55, 54, 55, 54, 55, 56, 55, 56, 57, 56, 57,
100 56, 57, 58, 57, 58, 59, 58, 59, 58, 59, 60, 59, 60, 61, 60, 61,
101 60, 61, 62, 61, 62, 63, 62, 63, 62, 63, 64, 63, 64, 65, 64
106 static RConversionTable *conversionTable = NULL;
109 static unsigned short*
110 computeTable(unsigned short mask)
112 RConversionTable *tmp = conversionTable;
113 int i;
115 while (tmp) {
116 if (tmp->index == mask)
117 break;
118 tmp = tmp->next;
121 if (tmp)
122 return tmp->table;
124 tmp = (RConversionTable *)malloc(sizeof(RConversionTable));
125 if (tmp == NULL)
126 return NULL;
128 for (i=0;i<256;i++)
129 tmp->table[i] = (i*mask + 0x7f)/0xff;
131 tmp->index = mask;
132 tmp->next = conversionTable;
133 conversionTable = tmp;
134 return tmp->table;
138 static RXImage*
139 image2TrueColor(RContext *ctx, RImage *image)
141 RXImage *ximg;
142 register int x, y, r, g, b;
143 unsigned char *red, *grn, *blu;
144 unsigned long pixel;
145 unsigned short rmask, gmask, bmask;
146 unsigned short roffs, goffs, boffs;
147 unsigned short *rtable, *gtable, *btable;
149 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
150 if (!ximg) {
151 return NULL;
154 red = image->data[0];
155 grn = image->data[1];
156 blu = image->data[2];
158 roffs = ctx->red_offset;
159 goffs = ctx->green_offset;
160 boffs = ctx->blue_offset;
162 rmask = ctx->visual->red_mask >> roffs;
163 gmask = ctx->visual->green_mask >> goffs;
164 bmask = ctx->visual->blue_mask >> boffs;
166 #if 0
167 /* this do not seem to increase speed. Only 0.06 second faster in
168 * rendering a 800x600 image to pixmap. 1.12 sec instead of 1.18.
169 * But does not require a 256*256*256 lookup table.
171 if (ctx->depth==24) {
172 #ifdef DEBUG
173 puts("true color match for 24bpp");
174 #endif
175 for (y=0; y < image->height; y++) {
176 for (x=0; x < image->width; x++) {
177 pixel = (*(red++)<<roffs) | (*(grn++)<<goffs) | (*(blu++)<<boffs);
178 XPutPixel(ximg->image, x, y, pixel);
181 return ximg;
183 #endif
185 rtable = computeTable(rmask);
186 gtable = computeTable(gmask);
187 btable = computeTable(bmask);
189 if (rtable==NULL || gtable==NULL || btable==NULL) {
190 sprintf(RErrorString, "out of memory");
191 RDestroyXImage(ctx, ximg);
192 return NULL;
195 if (ctx->attribs->render_mode==RM_MATCH) {
196 /* fake match */
197 #ifdef DEBUG
198 puts("true color match");
199 #endif
200 for (y=0; y < image->height; y++) {
201 for (x=0; x < image->width; x++) {
202 /* reduce pixel */
203 r = rtable[*red++];
204 g = gtable[*grn++];
205 b = btable[*blu++];
206 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
207 XPutPixel(ximg->image, x, y, pixel);
210 } else {
211 /* dither */
212 unsigned char *rerr, *gerr, *berr;
213 unsigned char *nrerr, *ngerr, *nberr;
214 unsigned char *rerr_, *gerr_, *berr_;
215 unsigned char *nrerr_, *ngerr_, *nberr_;
216 unsigned char *terr;
217 register int ac, err;
218 int width = image->width;
219 int dr=0xff-rmask;
220 int dg=0xff-gmask;
221 int db=0xff-bmask;
223 while ((dr & 1)==0) dr = dr >> 1;
224 while ((dg & 1)==0) dg = dg >> 1;
225 while ((db & 1)==0) db = db >> 1;
227 #ifdef DEBUG
228 puts("true color dither");
229 #endif
230 rerr_ = rerr = (unsigned char*)alloca((width+2)*sizeof(char));
231 gerr_ = gerr = (unsigned char*)alloca((width+2)*sizeof(char));
232 berr_ = berr = (unsigned char*)alloca((width+2)*sizeof(char));
233 nrerr_ = nrerr = (unsigned char*)alloca((width+2)*sizeof(char));
234 ngerr_ = ngerr = (unsigned char*)alloca((width+2)*sizeof(char));
235 nberr_ = nberr = (unsigned char*)alloca((width+2)*sizeof(char));
236 if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) {
237 sprintf(RErrorString, "out of memory");
238 RDestroyXImage(ctx, ximg);
239 return NULL;
241 for (x=0; x<width; x++) {
242 rerr[x] = *red++;
243 gerr[x] = *grn++;
244 berr[x] = *blu++;
246 rerr[x] = gerr[x] = berr[x] = 0;
247 /* convert and dither the image to XImage */
248 for (y=0; y<image->height; y++) {
249 if (y<image->height-1) {
250 memcpy(nrerr, red, width);
251 memcpy(ngerr, grn, width);
252 memcpy(nberr, blu, width);
253 red+=width;
254 grn+=width;
255 blu+=width;
256 /* last column */
257 nrerr[x] = *(red-1);
258 ngerr[x] = *(grn-1);
259 nberr[x] = *(blu-1);
261 for (x=0; x<width; x++) {
262 /* reduce pixel */
263 pixel = (rtable[*rerr]<<roffs) | (gtable[*gerr]<<goffs)
264 | (btable[*berr]<<boffs);
265 XPutPixel(ximg->image, x, y, pixel);
266 /* calc error */
267 err = *rerr&dr;
268 rerr++;
269 /* distribute error */
270 ac = errorTable1[err] + *rerr;
271 *rerr=MIN(ac, 0xff);
272 ac = errorTable1[err] + *nrerr;
273 *nrerr=MIN(ac, 0xff);
274 nrerr++;
275 ac = *nrerr + errorTable2[err];
276 *nrerr=MIN(ac,0xff);
278 /* calc error */
279 err = *gerr&dg;
280 gerr++;
281 /* distribute error */
282 ac = errorTable1[err] + *gerr;
283 *gerr=MIN(ac, 0xff);
284 ac = errorTable1[err] + *ngerr;
285 *ngerr=MIN(ac, 0xff);
286 ngerr++;
287 ac = *ngerr + errorTable2[err];
288 *ngerr=MIN(ac,0xff);
290 /* calc error */
291 err = *berr&db;
292 berr++;
293 /* distribute error */
294 ac = errorTable1[err] + *berr;
295 *berr=MIN(ac, 0xff);
296 ac = errorTable1[err] + *nberr;
297 *nberr=MIN(ac, 0xff);
298 nberr++;
299 ac = *nberr + errorTable2[err];
300 *nberr=MIN(ac,0xff);
302 /* skip to next line */
303 rerr = nrerr_;
304 nrerr = rerr_;
305 terr = nrerr_;
306 nrerr_ = rerr_;
307 rerr_ = terr;
309 gerr = ngerr_;
310 ngerr = gerr_;
311 terr = ngerr_;
312 ngerr_ = gerr_;
313 gerr_ = terr;
315 berr = nberr_;
316 nberr = berr_;
317 terr = nberr_;
318 nberr_ = berr_;
319 berr_ = terr;
322 return ximg;
327 static RXImage*
328 image2PseudoColor(RContext *ctx, RImage *image)
330 RXImage *ximg;
331 register int x, y, r, g, b;
332 unsigned char *red, *grn, *blu;
333 unsigned long pixel;
334 const int cpc=ctx->attribs->colors_per_channel;
335 const unsigned short rmask = cpc-1; /* different sizes could be used */
336 const unsigned short gmask = rmask; /* for r,g,b */
337 const unsigned short bmask = rmask;
338 unsigned short *rtable, *gtable, *btable;
339 const int cpccpc = cpc*cpc;
340 unsigned char *data;
341 int ofs;
342 /*register unsigned char maxrgb = 0xff;*/
344 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
345 if (!ximg) {
346 return NULL;
349 red = image->data[0];
350 grn = image->data[1];
351 blu = image->data[2];
353 data = ximg->image->data;
355 /* Tables are same at the moment because rmask==gmask==bmask. */
356 rtable = computeTable(rmask);
357 gtable = computeTable(gmask);
358 btable = computeTable(bmask);
360 if (rtable==NULL || gtable==NULL || btable==NULL) {
361 sprintf(RErrorString, "out of memory");
362 RDestroyXImage(ctx, ximg);
363 return NULL;
366 if (ctx->attribs->render_mode == RM_MATCH) {
367 /* fake match */
368 #ifdef DEBUG
369 printf("pseudo color match with %d colors per channel\n", cpc);
370 #endif
371 for (y=0, ofs = 0; y<image->height; y++) {
372 for (x=0; x<image->width; x++, ofs++) {
373 /* reduce pixel */
374 r = rtable[red[ofs]];
375 g = gtable[grn[ofs]];
376 b = btable[blu[ofs]];
377 pixel = r*cpccpc + g*cpc + b;
378 /*data[ofs] = ctx->colors[pixel].pixel;*/
379 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
382 } else {
383 /* dither */
384 short *rerr, *gerr, *berr;
385 short *nrerr, *ngerr, *nberr;
386 short *terr;
387 int rer, ger, ber;
388 const int dr=0xff/rmask;
389 const int dg=0xff/gmask;
390 const int db=0xff/bmask;
392 #ifdef DEBUG
393 printf("pseudo color dithering with %d colors per channel\n", cpc);
394 #endif
395 rerr = (short*)alloca((image->width+2)*sizeof(short));
396 gerr = (short*)alloca((image->width+2)*sizeof(short));
397 berr = (short*)alloca((image->width+2)*sizeof(short));
398 nrerr = (short*)alloca((image->width+2)*sizeof(short));
399 ngerr = (short*)alloca((image->width+2)*sizeof(short));
400 nberr = (short*)alloca((image->width+2)*sizeof(short));
401 if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) {
402 sprintf(RErrorString, "out of memory");
403 RDestroyXImage(ctx, ximg);
404 return NULL;
406 for (x=0; x<image->width; x++) {
407 rerr[x] = red[x];
408 gerr[x] = grn[x];
409 berr[x] = blu[x];
411 rerr[x] = gerr[x] = berr[x] = 0;
412 /* convert and dither the image to XImage */
413 for (y=0, ofs=0; y<image->height; y++) {
414 if (y<image->height-1) {
415 int x1;
416 for (x=0, x1=ofs+image->width; x<image->width; x++, x1++) {
417 nrerr[x] = red[x1];
418 ngerr[x] = grn[x1];
419 nberr[x] = blu[x1];
421 /* last column */
422 x1--;
423 nrerr[x] = red[x1];
424 ngerr[x] = grn[x1];
425 nberr[x] = blu[x1];
427 for (x=0; x<image->width; x++, ofs++) {
428 /* reduce pixel */
429 if (rerr[x]>0xff) rerr[x]=0xff; else if (rerr[x]<0) rerr[x]=0;
430 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
431 if (berr[x]>0xff) berr[x]=0xff; else if (berr[x]<0) berr[x]=0;
433 r = rtable[rerr[x]];
434 g = gtable[gerr[x]];
435 b = btable[berr[x]];
437 pixel = r*cpccpc + g*cpc + b;
438 /*data[ofs] = ctx->colors[pixel].pixel;*/
439 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
440 /* calc error */
441 rer = rerr[x] - r*dr;
442 ger = gerr[x] - g*dg;
443 ber = berr[x] - b*db;
445 /* distribute error */
446 r = (rer*3)/8;
447 g = (ger*3)/8;
448 b = (ber*3)/8;
449 /* x+1, y */
450 rerr[x+1]+=r;
451 gerr[x+1]+=g;
452 berr[x+1]+=b;
453 /* x, y+1 */
454 nrerr[x]+=r;
455 ngerr[x]+=g;
456 nberr[x]+=b;
457 /* x+1, y+1 */
458 nrerr[x+1]+=rer-2*r;
459 ngerr[x+1]+=ger-2*g;
460 nberr[x+1]+=ber-2*b;
462 /* skip to next line */
463 terr = rerr;
464 rerr = nrerr;
465 nrerr = terr;
467 terr = gerr;
468 gerr = ngerr;
469 ngerr = terr;
471 terr = berr;
472 berr = nberr;
473 nberr = terr;
477 return ximg;
481 static RXImage*
482 image2GrayScale(RContext *ctx, RImage *image)
484 RXImage *ximg;
485 register int x, y, g;
486 unsigned char *red, *grn, *blu;
487 const int cpc=ctx->attribs->colors_per_channel;
488 unsigned short gmask;
489 unsigned short *table;
490 unsigned char *data;
491 int ofs;
492 /*register unsigned char maxrgb = 0xff;*/
494 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
495 if (!ximg) {
496 return NULL;
499 red = image->data[0];
500 grn = image->data[1];
501 blu = image->data[2];
503 data = ximg->image->data;
505 if (ctx->vclass == StaticGray)
506 gmask = (1<<ctx->depth) - 1; /* use all grays */
507 else
508 gmask = cpc*cpc*cpc-1;
510 table = computeTable(gmask);
512 if (table==NULL) {
513 sprintf(RErrorString, "out of memory");
514 RDestroyXImage(ctx, ximg);
515 return NULL;
518 if (ctx->attribs->render_mode == RM_MATCH) {
519 /* fake match */
520 #ifdef DEBUG
521 printf("grayscale match with %d colors per channel\n", cpc);
522 #endif
523 for (y=0, ofs = 0; y<image->height; y++) {
524 for (x=0; x<image->width; x++, ofs++) {
525 /* reduce pixel */
526 g = table[(red[ofs]*30+grn[ofs]*59+blu[ofs]*11)/100];
528 /*data[ofs] = ctx->colors[g].pixel;*/
529 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
532 } else {
533 /* dither */
534 short *gerr;
535 short *ngerr;
536 short *terr;
537 int ger;
538 const int dg=0xff/gmask;
540 #ifdef DEBUG
541 printf("grayscale dither with %d colors per channel\n", cpc);
542 #endif
543 gerr = (short*)alloca((image->width+2)*sizeof(short));
544 ngerr = (short*)alloca((image->width+2)*sizeof(short));
545 if (!gerr || !ngerr) {
546 sprintf(RErrorString, "out of memory");
547 RDestroyXImage(ctx, ximg);
548 return NULL;
550 for (x=0; x<image->width; x++) {
551 gerr[x] = (red[x]*30 + grn[x]*59 + blu[x]*11)/100;
553 gerr[x] = 0;
554 /* convert and dither the image to XImage */
555 for (y=0, ofs=0; y<image->height; y++) {
556 if (y<image->height-1) {
557 int x1;
558 for (x=0, x1=ofs+image->width; x<image->width; x++, x1++) {
559 ngerr[x] = (red[x1]*30 + grn[x1]*59 + blu[x1]*11)/100;
561 /* last column */
562 x1--;
563 ngerr[x] = (red[x1]*30 + grn[x1]*59 + blu[x1]*11)/100;
565 for (x=0; x<image->width; x++, ofs++) {
566 /* reduce pixel */
567 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
569 g = table[gerr[x]];
571 /*data[ofs] = ctx->colors[g].pixel;*/
572 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
573 /* calc error */
574 ger = gerr[x] - g*dg;
576 /* distribute error */
577 g = (ger*3)/8;
578 /* x+1, y */
579 gerr[x+1]+=g;
580 /* x, y+1 */
581 ngerr[x]+=g;
582 /* x+1, y+1 */
583 ngerr[x+1]+=ger-2*g;
585 /* skip to next line */
586 terr = gerr;
587 gerr = ngerr;
588 ngerr = terr;
591 ximg->image->data = (char*)data;
593 return ximg;
597 static RXImage*
598 image2Bitmap(RContext *ctx, RImage *image, int threshold)
600 RXImage *ximg;
601 unsigned char *alpha;
602 int x, y;
604 ximg = RCreateXImage(ctx, 1, image->width, image->height);
605 if (!ximg) {
606 return NULL;
608 alpha = image->data[3];
610 for (y = 0; y < image->height; y++) {
611 for (x = 0; x < image->width; x++) {
612 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
613 alpha++;
617 return ximg;
622 int
623 RConvertImage(RContext *context, RImage *image, Pixmap *pixmap)
625 RXImage *ximg=NULL;
627 assert(context!=NULL);
628 assert(image!=NULL);
629 assert(pixmap!=NULL);
631 /* clear error message */
632 RErrorString[0] = 0;
634 if (context->vclass == TrueColor)
635 ximg = image2TrueColor(context, image);
636 else if (context->vclass == PseudoColor || context->vclass == StaticColor)
637 ximg = image2PseudoColor(context, image);
638 else if (context->vclass == GrayScale || context->vclass == StaticGray)
639 ximg = image2GrayScale(context, image);
641 if (!ximg) {
642 strcat(RErrorString, ":could not convert RImage to XImage");
643 #ifdef C_ALLOCA
644 alloca(0);
645 #endif
646 return False;
648 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width,
649 image->height, context->depth);
650 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
651 image->width, image->height);
653 RDestroyXImage(context, ximg);
655 #ifdef C_ALLOCA
656 alloca(0);
657 #endif
658 return True;
662 int
663 RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap,
664 Pixmap *mask, int threshold)
666 GC gc;
667 XGCValues gcv;
668 RXImage *ximg=NULL;
670 assert(context!=NULL);
671 assert(image!=NULL);
672 assert(pixmap!=NULL);
673 assert(mask!=NULL);
675 if (!RConvertImage(context, image, pixmap))
676 return False;
678 if (image->data[3]==NULL) {
679 *mask = None;
680 return True;
683 ximg = image2Bitmap(context, image, threshold);
685 if (!ximg) {
686 strcat(RErrorString, ":could not convert RImage mask to XImage");
687 #ifdef C_ALLOCA
688 alloca(0);
689 #endif
690 return False;
692 *mask = XCreatePixmap(context->dpy, context->drawable, image->width,
693 image->height, 1);
694 gcv.foreground = context->black;
695 gcv.background = context->white;
696 gcv.graphics_exposures = False;
697 gc = XCreateGC(context->dpy, *mask, GCForeground|GCBackground
698 |GCGraphicsExposures, &gcv);
699 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0,
700 image->width, image->height);
701 RDestroyXImage(context, ximg);
703 #ifdef C_ALLOCA
704 alloca(0);
705 #endif
706 return True;
710 Bool
711 RGetClosestXColor(RContext *context, RColor *color, XColor *retColor)
713 RErrorString[0] = 0;
715 if (context->vclass == TrueColor) {
716 unsigned short rmask, gmask, bmask;
717 unsigned short roffs, goffs, boffs;
718 unsigned short *rtable, *gtable, *btable;
720 roffs = context->red_offset;
721 goffs = context->green_offset;
722 boffs = context->blue_offset;
724 rmask = context->visual->red_mask >> roffs;
725 gmask = context->visual->green_mask >> goffs;
726 bmask = context->visual->blue_mask >> boffs;
728 rtable = computeTable(rmask);
729 gtable = computeTable(gmask);
730 btable = computeTable(bmask);
732 retColor->pixel = (rtable[color->red]<<roffs) |
733 (rtable[color->green]<<goffs) | (rtable[color->blue]<<boffs);
735 retColor->red = rtable[color->red] << 8;
736 retColor->green = rtable[color->green] << 8;
737 retColor->blue = rtable[color->blue] << 8;
738 retColor->flags = DoRed|DoGreen|DoBlue;
740 } else if (context->vclass == PseudoColor || context->vclass == StaticColor) {
741 const int cpc=context->attribs->colors_per_channel;
742 const unsigned short rmask = cpc-1; /* different sizes could be used */
743 const unsigned short gmask = rmask; /* for r,g,b */
744 const unsigned short bmask = rmask;
745 unsigned short *rtable, *gtable, *btable;
746 const int cpccpc = cpc*cpc;
747 int index;
749 rtable = computeTable(rmask);
750 gtable = computeTable(gmask);
751 btable = computeTable(bmask);
753 if (rtable==NULL || gtable==NULL || btable==NULL) {
754 sprintf(RErrorString, "out of memory");
755 return False;
757 index = rtable[color->red]*cpccpc + gtable[color->green]*cpc
758 + btable[color->blue];
759 *retColor = context->colors[index];
760 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
762 const int cpc = context->attribs->colors_per_channel;
763 unsigned short gmask;
764 unsigned short *table;
765 int index;
767 if (context->vclass == StaticGray)
768 gmask = (1<<context->depth) - 1; /* use all grays */
769 else
770 gmask = cpc*cpc*cpc-1;
772 table = computeTable(gmask);
773 if (!table)
774 return False;
776 index = table[(color->red*30 + color->green*59 + color->blue*11)/100];
778 *retColor = context->colors[index];
779 } else {
780 sprintf(RErrorString, "internal bug:unsupported visual:%i",
781 context->vclass);
782 return False;
785 return True;