Simplified code for XK_ISO_Left_Tab
[wmaker-crm.git] / wrlib / convert.c
blob91641f33cd96c8cb418454a7e57c1fda74f11dae
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 #ifdef XSHM
52 Pixmap R_CreateXImageMappedPixmap(RContext *context, RXImage *ximage);
54 #endif
57 typedef struct RConversionTable {
58 unsigned short table[256];
59 unsigned short index;
60 struct RConversionTable *next;
61 } RConversionTable;
64 static RConversionTable *conversionTable = NULL;
67 static unsigned short*
68 computeTable(unsigned short mask)
70 RConversionTable *tmp = conversionTable;
71 int i;
73 while (tmp) {
74 if (tmp->index == mask)
75 break;
76 tmp = tmp->next;
79 if (tmp)
80 return tmp->table;
82 tmp = (RConversionTable *)malloc(sizeof(RConversionTable));
83 if (tmp == NULL)
84 return NULL;
86 for (i=0;i<256;i++)
87 tmp->table[i] = (i*mask + 0x7f)/0xff;
89 tmp->index = mask;
90 tmp->next = conversionTable;
91 conversionTable = tmp;
92 return tmp->table;
97 static RXImage*
98 image2TrueColorD16(RContext *ctx, RImage *image)
100 RXImage *ximg;
101 register int x, y, r, g, b;
102 unsigned char *red, *grn, *blu;
103 unsigned short rmask, gmask, bmask;
104 unsigned short roffs, goffs, boffs;
105 unsigned short *rtable, *gtable, *btable;
106 int ofs;
108 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
109 if (!ximg) {
110 return NULL;
113 red = image->data[0];
114 grn = image->data[1];
115 blu = image->data[2];
117 roffs = ctx->red_offset;
118 goffs = ctx->green_offset;
119 boffs = ctx->blue_offset;
121 rmask = ctx->visual->red_mask >> roffs;
122 gmask = ctx->visual->green_mask >> goffs;
123 bmask = ctx->visual->blue_mask >> boffs;
125 rtable = computeTable(rmask);
126 gtable = computeTable(gmask);
127 btable = computeTable(bmask);
129 if (rtable==NULL || gtable==NULL || btable==NULL) {
130 RErrorCode = RERR_NOMEMORY;
131 RDestroyXImage(ctx, ximg);
132 return NULL;
136 /* dither */
137 short *rerr, *gerr, *berr;
138 short *nrerr, *ngerr, *nberr;
139 short *terr;
140 unsigned short *dataP;
141 int line_offset;
142 int rer, ger, ber;
143 const int dr=0xff/rmask;
144 const int dg=0xff/gmask;
145 const int db=0xff/bmask;
147 rerr = (short*)alloca((image->width+2)*sizeof(short));
148 gerr = (short*)alloca((image->width+2)*sizeof(short));
149 berr = (short*)alloca((image->width+2)*sizeof(short));
150 nrerr = (short*)alloca((image->width+2)*sizeof(short));
151 ngerr = (short*)alloca((image->width+2)*sizeof(short));
152 nberr = (short*)alloca((image->width+2)*sizeof(short));
153 if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) {
154 RErrorCode = RERR_NOMEMORY;
155 RDestroyXImage(ctx, ximg);
156 return NULL;
158 for (x=0; x<image->width; x++) {
159 rerr[x] = red[x];
160 gerr[x] = grn[x];
161 berr[x] = blu[x];
163 rerr[x] = gerr[x] = berr[x] = 0;
165 dataP = (unsigned short*)ximg->image->data;
166 line_offset = ximg->image->bytes_per_line - image->width * 2;
168 /* convert and dither the image to XImage */
169 for (y=0, ofs=0; y<image->height; y++) {
170 if (y<image->height-1) {
171 int x1;
172 for (x=0, x1=ofs+image->width; x<image->width; x++, x1++) {
173 nrerr[x] = red[x1];
174 ngerr[x] = grn[x1];
175 nberr[x] = blu[x1];
177 /* last column */
178 x1--;
179 nrerr[x] = red[x1];
180 ngerr[x] = grn[x1];
181 nberr[x] = blu[x1];
183 for (x=0; x<image->width; x++) {
184 /* reduce pixel */
185 if (rerr[x]>0xff) rerr[x]=0xff; else if (rerr[x]<0) rerr[x]=0;
186 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
187 if (berr[x]>0xff) berr[x]=0xff; else if (berr[x]<0) berr[x]=0;
189 r = rtable[rerr[x]];
190 g = gtable[gerr[x]];
191 b = btable[berr[x]];
193 *(dataP++) = (r<<roffs) | (g<<goffs) | (b<<boffs);
195 /* calc error */
196 rer = rerr[x] - r*dr;
197 ger = gerr[x] - g*dg;
198 ber = berr[x] - b*db;
200 /* distribute error */
201 r = (rer*3)/8;
202 g = (ger*3)/8;
203 b = (ber*3)/8;
204 /* x+1, y */
205 rerr[x+1]+=r;
206 gerr[x+1]+=g;
207 berr[x+1]+=b;
208 /* x, y+1 */
209 nrerr[x]+=r;
210 ngerr[x]+=g;
211 nberr[x]+=b;
212 /* x+1, y+1 */
213 nrerr[x+1]+=rer-2*r;
214 ngerr[x+1]+=ger-2*g;
215 nberr[x+1]+=ber-2*b;
217 ofs += image->width;
218 (char*)dataP += line_offset;
219 /* skip to next line */
220 terr = rerr;
221 rerr = nrerr;
222 nrerr = terr;
224 terr = gerr;
225 gerr = ngerr;
226 ngerr = terr;
228 terr = berr;
229 berr = nberr;
230 nberr = terr;
233 return ximg;
237 static RXImage*
238 image2TrueColor(RContext *ctx, RImage *image)
240 RXImage *ximg;
241 register int x, y, r, g, b;
242 unsigned char *red, *grn, *blu;
243 unsigned long pixel;
244 unsigned short rmask, gmask, bmask;
245 unsigned short roffs, goffs, boffs;
246 unsigned short *rtable, *gtable, *btable;
247 int ofs;
249 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
250 if (!ximg) {
251 return NULL;
254 red = image->data[0];
255 grn = image->data[1];
256 blu = image->data[2];
258 roffs = ctx->red_offset;
259 goffs = ctx->green_offset;
260 boffs = ctx->blue_offset;
262 rmask = ctx->visual->red_mask >> roffs;
263 gmask = ctx->visual->green_mask >> goffs;
264 bmask = ctx->visual->blue_mask >> boffs;
266 #if 0
267 /* this do not seem to increase speed. Only 0.06 second faster in
268 * rendering a 800x600 image to pixmap. 1.12 sec instead of 1.18.
269 * But does not require a 256*256*256 lookup table.
271 if (ctx->depth==24) {
272 #ifdef DEBUG
273 puts("true color match for 24bpp");
274 #endif
275 for (y=0; y < image->height; y++) {
276 for (x=0; x < image->width; x++) {
277 pixel = (*(red++)<<roffs) | (*(grn++)<<goffs) | (*(blu++)<<boffs);
278 XPutPixel(ximg->image, x, y, pixel);
281 return ximg;
283 #endif
285 rtable = computeTable(rmask);
286 gtable = computeTable(gmask);
287 btable = computeTable(bmask);
289 if (rtable==NULL || gtable==NULL || btable==NULL) {
290 RErrorCode = RERR_NOMEMORY;
291 RDestroyXImage(ctx, ximg);
292 return NULL;
295 if (ctx->attribs->render_mode==RBestMatchRendering) {
296 /* fake match */
297 #ifdef DEBUG
298 puts("true color match");
299 #endif
300 for (y=0, ofs=0; y < image->height; y++) {
301 for (x=0; x < image->width; x++, ofs++) {
302 /* reduce pixel */
303 r = rtable[red[ofs]];
304 g = gtable[grn[ofs]];
305 b = btable[blu[ofs]];
306 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
307 XPutPixel(ximg->image, x, y, pixel);
310 } else {
311 /* dither */
312 short *rerr, *gerr, *berr;
313 short *nrerr, *ngerr, *nberr;
314 short *terr;
315 int rer, ger, ber;
316 const int dr=0xff/rmask;
317 const int dg=0xff/gmask;
318 const int db=0xff/bmask;
320 #ifdef DEBUG
321 puts("true color dither");
322 #endif
323 rerr = (short*)alloca((image->width+2)*sizeof(short));
324 gerr = (short*)alloca((image->width+2)*sizeof(short));
325 berr = (short*)alloca((image->width+2)*sizeof(short));
326 nrerr = (short*)alloca((image->width+2)*sizeof(short));
327 ngerr = (short*)alloca((image->width+2)*sizeof(short));
328 nberr = (short*)alloca((image->width+2)*sizeof(short));
329 if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) {
330 RErrorCode = RERR_NOMEMORY;
331 RDestroyXImage(ctx, ximg);
332 return NULL;
334 for (x=0; x<image->width; x++) {
335 rerr[x] = red[x];
336 gerr[x] = grn[x];
337 berr[x] = blu[x];
339 rerr[x] = gerr[x] = berr[x] = 0;
340 /* convert and dither the image to XImage */
341 for (y=0, ofs=0; y<image->height; y++) {
342 if (y<image->height-1) {
343 int x1;
344 for (x=0, x1=ofs+image->width; x<image->width; x++, x1++) {
345 nrerr[x] = red[x1];
346 ngerr[x] = grn[x1];
347 nberr[x] = blu[x1];
349 /* last column */
350 x1--;
351 nrerr[x] = red[x1];
352 ngerr[x] = grn[x1];
353 nberr[x] = blu[x1];
355 for (x=0; x<image->width; x++) {
356 /* reduce pixel */
357 if (rerr[x]>0xff) rerr[x]=0xff; else if (rerr[x]<0) rerr[x]=0;
358 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
359 if (berr[x]>0xff) berr[x]=0xff; else if (berr[x]<0) berr[x]=0;
361 r = rtable[rerr[x]];
362 g = gtable[gerr[x]];
363 b = btable[berr[x]];
365 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
366 XPutPixel(ximg->image, x, y, pixel);
367 /* calc error */
368 rer = rerr[x] - r*dr;
369 ger = gerr[x] - g*dg;
370 ber = berr[x] - b*db;
372 /* distribute error */
373 r = (rer*3)/8;
374 g = (ger*3)/8;
375 b = (ber*3)/8;
376 /* x+1, y */
377 rerr[x+1]+=r;
378 gerr[x+1]+=g;
379 berr[x+1]+=b;
380 /* x, y+1 */
381 nrerr[x]+=r;
382 ngerr[x]+=g;
383 nberr[x]+=b;
384 /* x+1, y+1 */
385 nrerr[x+1]+=rer-2*r;
386 ngerr[x+1]+=ger-2*g;
387 nberr[x+1]+=ber-2*b;
389 ofs+=image->width;
390 /* skip to next line */
391 terr = rerr;
392 rerr = nrerr;
393 nrerr = terr;
395 terr = gerr;
396 gerr = ngerr;
397 ngerr = terr;
399 terr = berr;
400 berr = nberr;
401 nberr = terr;
404 return ximg;
410 static RXImage*
411 image2PseudoColor(RContext *ctx, RImage *image)
413 RXImage *ximg;
414 register int x, y, r, g, b;
415 unsigned char *red, *grn, *blu;
416 unsigned long pixel;
417 const int cpc=ctx->attribs->colors_per_channel;
418 const unsigned short rmask = cpc-1; /* different sizes could be used */
419 const unsigned short gmask = rmask; /* for r,g,b */
420 const unsigned short bmask = rmask;
421 unsigned short *rtable, *gtable, *btable;
422 const int cpccpc = cpc*cpc;
423 unsigned char *data;
424 int ofs;
425 /*register unsigned char maxrgb = 0xff;*/
427 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
428 if (!ximg) {
429 return NULL;
432 red = image->data[0];
433 grn = image->data[1];
434 blu = image->data[2];
436 data = ximg->image->data;
438 /* Tables are same at the moment because rmask==gmask==bmask. */
439 rtable = computeTable(rmask);
440 gtable = computeTable(gmask);
441 btable = computeTable(bmask);
443 if (rtable==NULL || gtable==NULL || btable==NULL) {
444 RErrorCode = RERR_NOMEMORY;
445 RDestroyXImage(ctx, ximg);
446 return NULL;
449 if (ctx->attribs->render_mode == RBestMatchRendering) {
450 /* fake match */
451 #ifdef DEBUG
452 printf("pseudo color match with %d colors per channel\n", cpc);
453 #endif
454 for (y=0, ofs = 0; y<image->height; y++) {
455 for (x=0; x<image->width; x++, ofs++) {
456 /* reduce pixel */
457 r = rtable[red[ofs]];
458 g = gtable[grn[ofs]];
459 b = btable[blu[ofs]];
460 pixel = r*cpccpc + g*cpc + b;
461 /*data[ofs] = ctx->colors[pixel].pixel;*/
462 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
465 } else {
466 /* dither */
467 short *rerr, *gerr, *berr;
468 short *nrerr, *ngerr, *nberr;
469 short *terr;
470 int rer, ger, ber;
471 const int dr=0xff/rmask;
472 const int dg=0xff/gmask;
473 const int db=0xff/bmask;
475 #ifdef DEBUG
476 printf("pseudo color dithering with %d colors per channel\n", cpc);
477 #endif
478 rerr = (short*)alloca((image->width+2)*sizeof(short));
479 gerr = (short*)alloca((image->width+2)*sizeof(short));
480 berr = (short*)alloca((image->width+2)*sizeof(short));
481 nrerr = (short*)alloca((image->width+2)*sizeof(short));
482 ngerr = (short*)alloca((image->width+2)*sizeof(short));
483 nberr = (short*)alloca((image->width+2)*sizeof(short));
484 if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) {
485 RErrorCode = RERR_NOMEMORY;
486 RDestroyXImage(ctx, ximg);
487 return NULL;
489 for (x=0; x<image->width; x++) {
490 rerr[x] = red[x];
491 gerr[x] = grn[x];
492 berr[x] = blu[x];
494 rerr[x] = gerr[x] = berr[x] = 0;
495 /* convert and dither the image to XImage */
496 for (y=0, ofs=0; y<image->height; y++) {
497 if (y<image->height-1) {
498 int x1;
499 for (x=0, x1=ofs+image->width; x<image->width; x++, x1++) {
500 nrerr[x] = red[x1];
501 ngerr[x] = grn[x1];
502 nberr[x] = blu[x1];
504 /* last column */
505 x1--;
506 nrerr[x] = red[x1];
507 ngerr[x] = grn[x1];
508 nberr[x] = blu[x1];
510 for (x=0; x<image->width; x++, ofs++) {
511 /* reduce pixel */
512 if (rerr[x]>0xff) rerr[x]=0xff; else if (rerr[x]<0) rerr[x]=0;
513 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
514 if (berr[x]>0xff) berr[x]=0xff; else if (berr[x]<0) berr[x]=0;
516 r = rtable[rerr[x]];
517 g = gtable[gerr[x]];
518 b = btable[berr[x]];
520 pixel = r*cpccpc + g*cpc + b;
521 /*data[ofs] = ctx->colors[pixel].pixel;*/
522 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
524 /* calc error */
525 rer = rerr[x] - r*dr;
526 ger = gerr[x] - g*dg;
527 ber = berr[x] - b*db;
529 /* distribute error */
530 rerr[x+1]+=(rer*7)/16;
531 gerr[x+1]+=(ger*7)/16;
532 berr[x+1]+=(ber*7)/16;
534 nrerr[x]+=(rer*5)/16;
535 ngerr[x]+=(ger*5)/16;
536 nberr[x]+=(ber*5)/16;
538 if (x>0) {
539 nrerr[x-1]+=(rer*3)/16;
540 ngerr[x-1]+=(ger*3)/16;
541 nberr[x-1]+=(ber*3)/16;
544 nrerr[x+1]+=rer/16;
545 ngerr[x+1]+=ger/16;
546 nberr[x+1]+=ber/16;
547 #if 0
548 /* distribute error */
549 r = (rer*3)/8;
550 g = (ger*3)/8;
551 b = (ber*3)/8;
552 /* x+1, y */
553 rerr[x+1]+=r;
554 gerr[x+1]+=g;
555 berr[x+1]+=b;
556 /* x, y+1 */
557 nrerr[x]+=r;
558 ngerr[x]+=g;
559 nberr[x]+=b;
560 /* x+1, y+1 */
561 nrerr[x+1]+=rer-2*r;
562 ngerr[x+1]+=ger-2*g;
563 nberr[x+1]+=ber-2*b;
564 #endif
566 /* skip to next line */
567 terr = rerr;
568 rerr = nrerr;
569 nrerr = terr;
571 terr = gerr;
572 gerr = ngerr;
573 ngerr = terr;
575 terr = berr;
576 berr = nberr;
577 nberr = terr;
580 ximg->image->data = (char*)data;
582 return ximg;
586 static RXImage*
587 image2GrayScale(RContext *ctx, RImage *image)
589 RXImage *ximg;
590 register int x, y, g;
591 unsigned char *red, *grn, *blu;
592 const int cpc=ctx->attribs->colors_per_channel;
593 unsigned short gmask;
594 unsigned short *table;
595 unsigned char *data;
596 int ofs;
597 /*register unsigned char maxrgb = 0xff;*/
599 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
600 if (!ximg) {
601 return NULL;
604 red = image->data[0];
605 grn = image->data[1];
606 blu = image->data[2];
608 data = ximg->image->data;
610 if (ctx->vclass == StaticGray)
611 gmask = (1<<ctx->depth) - 1; /* use all grays */
612 else
613 gmask = cpc*cpc*cpc-1;
615 table = computeTable(gmask);
617 if (table==NULL) {
618 RErrorCode = RERR_NOMEMORY;
619 RDestroyXImage(ctx, ximg);
620 return NULL;
623 if (ctx->attribs->render_mode == RBestMatchRendering) {
624 /* fake match */
625 #ifdef DEBUG
626 printf("grayscale match with %d colors per channel\n", cpc);
627 #endif
628 for (y=0, ofs = 0; y<image->height; y++) {
629 for (x=0; x<image->width; x++, ofs++) {
630 /* reduce pixel */
631 g = table[(red[ofs]*30+grn[ofs]*59+blu[ofs]*11)/100];
633 /*data[ofs] = ctx->colors[g].pixel;*/
634 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
637 } else {
638 /* dither */
639 short *gerr;
640 short *ngerr;
641 short *terr;
642 int ger;
643 const int dg=0xff/gmask;
645 #ifdef DEBUG
646 printf("grayscale dither with %d colors per channel\n", cpc);
647 #endif
648 gerr = (short*)alloca((image->width+2)*sizeof(short));
649 ngerr = (short*)alloca((image->width+2)*sizeof(short));
650 if (!gerr || !ngerr) {
651 RErrorCode = RERR_NOMEMORY;
652 RDestroyXImage(ctx, ximg);
653 return NULL;
655 for (x=0; x<image->width; x++) {
656 gerr[x] = (red[x]*30 + grn[x]*59 + blu[x]*11)/100;
658 gerr[x] = 0;
659 /* convert and dither the image to XImage */
660 for (y=0, ofs=0; y<image->height; y++) {
661 if (y<image->height-1) {
662 int x1;
663 for (x=0, x1=ofs+image->width; x<image->width; x++, x1++) {
664 ngerr[x] = (red[x1]*30 + grn[x1]*59 + blu[x1]*11)/100;
666 /* last column */
667 x1--;
668 ngerr[x] = (red[x1]*30 + grn[x1]*59 + blu[x1]*11)/100;
670 for (x=0; x<image->width; x++, ofs++) {
671 /* reduce pixel */
672 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
674 g = table[gerr[x]];
676 /*data[ofs] = ctx->colors[g].pixel;*/
677 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
678 /* calc error */
679 ger = gerr[x] - g*dg;
681 /* distribute error */
682 g = (ger*3)/8;
683 /* x+1, y */
684 gerr[x+1]+=g;
685 /* x, y+1 */
686 ngerr[x]+=g;
687 /* x+1, y+1 */
688 ngerr[x+1]+=ger-2*g;
690 /* skip to next line */
691 terr = gerr;
692 gerr = ngerr;
693 ngerr = terr;
696 ximg->image->data = (char*)data;
698 return ximg;
702 static RXImage*
703 image2Bitmap(RContext *ctx, RImage *image, int threshold)
705 RXImage *ximg;
706 unsigned char *alpha;
707 int x, y;
709 ximg = RCreateXImage(ctx, 1, image->width, image->height);
710 if (!ximg) {
711 return NULL;
713 alpha = image->data[3];
715 for (y = 0; y < image->height; y++) {
716 for (x = 0; x < image->width; x++) {
717 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
718 alpha++;
722 return ximg;
727 int
728 RConvertImage(RContext *context, RImage *image, Pixmap *pixmap)
730 RXImage *ximg=NULL;
731 #ifdef XSHM
732 Pixmap tmp;
733 #endif
735 assert(context!=NULL);
736 assert(image!=NULL);
737 assert(pixmap!=NULL);
739 /* clear error message */
740 if (context->vclass == TrueColor) {
742 if (context->attribs->render_mode == RDitheredRendering
743 && (context->depth == 15 || context->depth == 16))
744 ximg = image2TrueColorD16(context, image);
745 else
746 ximg = image2TrueColor(context, image);
748 } else if (context->vclass == PseudoColor || context->vclass == StaticColor)
749 ximg = image2PseudoColor(context, image);
750 else if (context->vclass == GrayScale || context->vclass == StaticGray)
751 ximg = image2GrayScale(context, image);
753 if (!ximg) {
754 #ifdef C_ALLOCA
755 alloca(0);
756 #endif
757 return False;
761 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width,
762 image->height, context->depth);
764 #ifdef XSHM
765 if (context->flags.use_shared_pixmap && ximg->is_shared)
766 tmp = R_CreateXImageMappedPixmap(context, ximg);
767 else
768 tmp = None;
769 if (tmp) {
771 * We have to copy the shm Pixmap into a normal Pixmap because
772 * otherwise, we would have to control when Pixmaps are freed so
773 * that we can detach their shm segments. This is a problem if the
774 * program crash, leaving stale shared memory segments in the
775 * system (lots of them). But with some work, we can optimize
776 * things and remove this XCopyArea. This will require
777 * explicitly freeing all pixmaps when exiting or restarting
778 * wmaker.
780 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0,
781 image->width, image->height, 0, 0);
782 XFreePixmap(context->dpy, tmp);
783 } else {
784 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
785 image->width, image->height);
787 #else /* !XSHM */
788 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
789 image->width, image->height);
790 #endif /* !XSHM */
792 RDestroyXImage(context, ximg);
794 #ifdef C_ALLOCA
795 alloca(0);
796 #endif
797 return True;
801 int
802 RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap,
803 Pixmap *mask, int threshold)
805 GC gc;
806 XGCValues gcv;
807 RXImage *ximg=NULL;
809 assert(context!=NULL);
810 assert(image!=NULL);
811 assert(pixmap!=NULL);
812 assert(mask!=NULL);
814 if (!RConvertImage(context, image, pixmap))
815 return False;
817 if (image->data[3]==NULL) {
818 *mask = None;
819 return True;
822 ximg = image2Bitmap(context, image, threshold);
824 if (!ximg) {
825 #ifdef C_ALLOCA
826 alloca(0);
827 #endif
828 return False;
830 *mask = XCreatePixmap(context->dpy, context->drawable, image->width,
831 image->height, 1);
832 gcv.foreground = context->black;
833 gcv.background = context->white;
834 gcv.graphics_exposures = False;
835 gc = XCreateGC(context->dpy, *mask, GCForeground|GCBackground
836 |GCGraphicsExposures, &gcv);
837 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0,
838 image->width, image->height);
839 RDestroyXImage(context, ximg);
841 #ifdef C_ALLOCA
842 alloca(0);
843 #endif
844 return True;
848 Bool
849 RGetClosestXColor(RContext *context, RColor *color, XColor *retColor)
851 if (context->vclass == TrueColor) {
852 unsigned short rmask, gmask, bmask;
853 unsigned short roffs, goffs, boffs;
854 unsigned short *rtable, *gtable, *btable;
856 roffs = context->red_offset;
857 goffs = context->green_offset;
858 boffs = context->blue_offset;
860 rmask = context->visual->red_mask >> roffs;
861 gmask = context->visual->green_mask >> goffs;
862 bmask = context->visual->blue_mask >> boffs;
864 rtable = computeTable(rmask);
865 gtable = computeTable(gmask);
866 btable = computeTable(bmask);
868 retColor->pixel = (rtable[color->red]<<roffs) |
869 (gtable[color->green]<<goffs) | (btable[color->blue]<<boffs);
871 retColor->red = color->red << 8;
872 retColor->green = color->green << 8;
873 retColor->blue = color->blue << 8;
874 retColor->flags = DoRed|DoGreen|DoBlue;
876 } else if (context->vclass == PseudoColor || context->vclass == StaticColor) {
877 const int cpc=context->attribs->colors_per_channel;
878 const unsigned short rmask = cpc-1; /* different sizes could be used */
879 const unsigned short gmask = rmask; /* for r,g,b */
880 const unsigned short bmask = rmask;
881 unsigned short *rtable, *gtable, *btable;
882 const int cpccpc = cpc*cpc;
883 int index;
885 rtable = computeTable(rmask);
886 gtable = computeTable(gmask);
887 btable = computeTable(bmask);
889 if (rtable==NULL || gtable==NULL || btable==NULL) {
890 RErrorCode = RERR_NOMEMORY;
891 return False;
893 index = rtable[color->red]*cpccpc + gtable[color->green]*cpc
894 + btable[color->blue];
895 *retColor = context->colors[index];
896 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
898 const int cpc = context->attribs->colors_per_channel;
899 unsigned short gmask;
900 unsigned short *table;
901 int index;
903 if (context->vclass == StaticGray)
904 gmask = (1<<context->depth) - 1; /* use all grays */
905 else
906 gmask = cpc*cpc*cpc-1;
908 table = computeTable(gmask);
909 if (!table)
910 return False;
912 index = table[(color->red*30 + color->green*59 + color->blue*11)/100];
914 *retColor = context->colors[index];
915 } else {
916 RErrorCode = RERR_INTERNAL;
917 return False;
920 return True;