Various bug fixes.
[wmaker-crm.git] / wrlib / convert.c
blob710fdfe22dad83e1c819af04926c813706897d6c
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 dataP = (unsigned short *)((char *)dataP + line_offset);
220 /* skip to next line */
221 terr = rerr;
222 rerr = nrerr;
223 nrerr = terr;
225 terr = gerr;
226 gerr = ngerr;
227 ngerr = terr;
229 terr = berr;
230 berr = nberr;
231 nberr = terr;
234 return ximg;
238 static RXImage*
239 image2TrueColor(RContext *ctx, RImage *image)
241 RXImage *ximg;
242 register int x, y, r, g, b;
243 unsigned char *red, *grn, *blu;
244 unsigned long pixel;
245 unsigned short rmask, gmask, bmask;
246 unsigned short roffs, goffs, boffs;
247 unsigned short *rtable, *gtable, *btable;
248 int ofs;
250 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
251 if (!ximg) {
252 return NULL;
255 red = image->data[0];
256 grn = image->data[1];
257 blu = image->data[2];
259 roffs = ctx->red_offset;
260 goffs = ctx->green_offset;
261 boffs = ctx->blue_offset;
263 rmask = ctx->visual->red_mask >> roffs;
264 gmask = ctx->visual->green_mask >> goffs;
265 bmask = ctx->visual->blue_mask >> boffs;
267 #if 0
268 /* this do not seem to increase speed. Only 0.06 second faster in
269 * rendering a 800x600 image to pixmap. 1.12 sec instead of 1.18.
270 * But does not require a 256*256*256 lookup table.
272 if (ctx->depth==24) {
273 #ifdef DEBUG
274 puts("true color match for 24bpp");
275 #endif
276 for (y=0; y < image->height; y++) {
277 for (x=0; x < image->width; x++) {
278 pixel = (*(red++)<<roffs) | (*(grn++)<<goffs) | (*(blu++)<<boffs);
279 XPutPixel(ximg->image, x, y, pixel);
282 return ximg;
284 #endif
286 rtable = computeTable(rmask);
287 gtable = computeTable(gmask);
288 btable = computeTable(bmask);
290 if (rtable==NULL || gtable==NULL || btable==NULL) {
291 RErrorCode = RERR_NOMEMORY;
292 RDestroyXImage(ctx, ximg);
293 return NULL;
296 if (ctx->attribs->render_mode==RBestMatchRendering) {
297 /* fake match */
298 #ifdef DEBUG
299 puts("true color match");
300 #endif
301 for (y=0, ofs=0; y < image->height; y++) {
302 for (x=0; x < image->width; x++, ofs++) {
303 /* reduce pixel */
304 r = rtable[red[ofs]];
305 g = gtable[grn[ofs]];
306 b = btable[blu[ofs]];
307 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
308 XPutPixel(ximg->image, x, y, pixel);
311 } else {
312 /* dither */
313 short *rerr, *gerr, *berr;
314 short *nrerr, *ngerr, *nberr;
315 short *terr;
316 int rer, ger, ber;
317 const int dr=0xff/rmask;
318 const int dg=0xff/gmask;
319 const int db=0xff/bmask;
321 #ifdef DEBUG
322 puts("true color dither");
323 #endif
324 rerr = (short*)alloca((image->width+2)*sizeof(short));
325 gerr = (short*)alloca((image->width+2)*sizeof(short));
326 berr = (short*)alloca((image->width+2)*sizeof(short));
327 nrerr = (short*)alloca((image->width+2)*sizeof(short));
328 ngerr = (short*)alloca((image->width+2)*sizeof(short));
329 nberr = (short*)alloca((image->width+2)*sizeof(short));
330 if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) {
331 RErrorCode = RERR_NOMEMORY;
332 RDestroyXImage(ctx, ximg);
333 return NULL;
335 for (x=0; x<image->width; x++) {
336 rerr[x] = red[x];
337 gerr[x] = grn[x];
338 berr[x] = blu[x];
340 rerr[x] = gerr[x] = berr[x] = 0;
341 /* convert and dither the image to XImage */
342 for (y=0, ofs=0; y<image->height; y++) {
343 if (y<image->height-1) {
344 int x1;
345 for (x=0, x1=ofs+image->width; x<image->width; x++, x1++) {
346 nrerr[x] = red[x1];
347 ngerr[x] = grn[x1];
348 nberr[x] = blu[x1];
350 /* last column */
351 x1--;
352 nrerr[x] = red[x1];
353 ngerr[x] = grn[x1];
354 nberr[x] = blu[x1];
356 for (x=0; x<image->width; x++) {
357 /* reduce pixel */
358 if (rerr[x]>0xff) rerr[x]=0xff; else if (rerr[x]<0) rerr[x]=0;
359 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
360 if (berr[x]>0xff) berr[x]=0xff; else if (berr[x]<0) berr[x]=0;
362 r = rtable[rerr[x]];
363 g = gtable[gerr[x]];
364 b = btable[berr[x]];
366 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
367 XPutPixel(ximg->image, x, y, pixel);
368 /* calc error */
369 rer = rerr[x] - r*dr;
370 ger = gerr[x] - g*dg;
371 ber = berr[x] - b*db;
373 /* distribute error */
374 r = (rer*3)/8;
375 g = (ger*3)/8;
376 b = (ber*3)/8;
377 /* x+1, y */
378 rerr[x+1]+=r;
379 gerr[x+1]+=g;
380 berr[x+1]+=b;
381 /* x, y+1 */
382 nrerr[x]+=r;
383 ngerr[x]+=g;
384 nberr[x]+=b;
385 /* x+1, y+1 */
386 nrerr[x+1]+=rer-2*r;
387 ngerr[x+1]+=ger-2*g;
388 nberr[x+1]+=ber-2*b;
390 ofs+=image->width;
391 /* skip to next line */
392 terr = rerr;
393 rerr = nrerr;
394 nrerr = terr;
396 terr = gerr;
397 gerr = ngerr;
398 ngerr = terr;
400 terr = berr;
401 berr = nberr;
402 nberr = terr;
405 return ximg;
411 static RXImage*
412 image2PseudoColor(RContext *ctx, RImage *image)
414 RXImage *ximg;
415 register int x, y, r, g, b;
416 unsigned char *red, *grn, *blu;
417 unsigned long pixel;
418 const int cpc=ctx->attribs->colors_per_channel;
419 const unsigned short rmask = cpc-1; /* different sizes could be used */
420 const unsigned short gmask = rmask; /* for r,g,b */
421 const unsigned short bmask = rmask;
422 unsigned short *rtable, *gtable, *btable;
423 const int cpccpc = cpc*cpc;
424 unsigned char *data;
425 int ofs;
426 /*register unsigned char maxrgb = 0xff;*/
428 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
429 if (!ximg) {
430 return NULL;
433 red = image->data[0];
434 grn = image->data[1];
435 blu = image->data[2];
437 data = (unsigned char *)ximg->image->data;
439 /* Tables are same at the moment because rmask==gmask==bmask. */
440 rtable = computeTable(rmask);
441 gtable = computeTable(gmask);
442 btable = computeTable(bmask);
444 if (rtable==NULL || gtable==NULL || btable==NULL) {
445 RErrorCode = RERR_NOMEMORY;
446 RDestroyXImage(ctx, ximg);
447 return NULL;
450 if (ctx->attribs->render_mode == RBestMatchRendering) {
451 /* fake match */
452 #ifdef DEBUG
453 printf("pseudo color match with %d colors per channel\n", cpc);
454 #endif
455 for (y=0, ofs = 0; y<image->height; y++) {
456 for (x=0; x<image->width; x++, ofs++) {
457 /* reduce pixel */
458 r = rtable[red[ofs]];
459 g = gtable[grn[ofs]];
460 b = btable[blu[ofs]];
461 pixel = r*cpccpc + g*cpc + b;
462 /*data[ofs] = ctx->colors[pixel].pixel;*/
463 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
466 } else {
467 /* dither */
468 short *rerr, *gerr, *berr;
469 short *nrerr, *ngerr, *nberr;
470 short *terr;
471 int rer, ger, ber;
472 const int dr=0xff/rmask;
473 const int dg=0xff/gmask;
474 const int db=0xff/bmask;
476 #ifdef DEBUG
477 printf("pseudo color dithering with %d colors per channel\n", cpc);
478 #endif
479 rerr = (short*)alloca((image->width+2)*sizeof(short));
480 gerr = (short*)alloca((image->width+2)*sizeof(short));
481 berr = (short*)alloca((image->width+2)*sizeof(short));
482 nrerr = (short*)alloca((image->width+2)*sizeof(short));
483 ngerr = (short*)alloca((image->width+2)*sizeof(short));
484 nberr = (short*)alloca((image->width+2)*sizeof(short));
485 if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) {
486 RErrorCode = RERR_NOMEMORY;
487 RDestroyXImage(ctx, ximg);
488 return NULL;
490 for (x=0; x<image->width; x++) {
491 rerr[x] = red[x];
492 gerr[x] = grn[x];
493 berr[x] = blu[x];
495 rerr[x] = gerr[x] = berr[x] = 0;
496 /* convert and dither the image to XImage */
497 for (y=0, ofs=0; y<image->height; y++) {
498 if (y<image->height-1) {
499 int x1;
500 for (x=0, x1=ofs+image->width; x<image->width; x++, x1++) {
501 nrerr[x] = red[x1];
502 ngerr[x] = grn[x1];
503 nberr[x] = blu[x1];
505 /* last column */
506 x1--;
507 nrerr[x] = red[x1];
508 ngerr[x] = grn[x1];
509 nberr[x] = blu[x1];
511 for (x=0; x<image->width; x++, ofs++) {
512 /* reduce pixel */
513 if (rerr[x]>0xff) rerr[x]=0xff; else if (rerr[x]<0) rerr[x]=0;
514 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
515 if (berr[x]>0xff) berr[x]=0xff; else if (berr[x]<0) berr[x]=0;
517 r = rtable[rerr[x]];
518 g = gtable[gerr[x]];
519 b = btable[berr[x]];
521 pixel = r*cpccpc + g*cpc + b;
522 /*data[ofs] = ctx->colors[pixel].pixel;*/
523 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
525 /* calc error */
526 rer = rerr[x] - r*dr;
527 ger = gerr[x] - g*dg;
528 ber = berr[x] - b*db;
530 /* distribute error */
531 rerr[x+1]+=(rer*7)/16;
532 gerr[x+1]+=(ger*7)/16;
533 berr[x+1]+=(ber*7)/16;
535 nrerr[x]+=(rer*5)/16;
536 ngerr[x]+=(ger*5)/16;
537 nberr[x]+=(ber*5)/16;
539 if (x>0) {
540 nrerr[x-1]+=(rer*3)/16;
541 ngerr[x-1]+=(ger*3)/16;
542 nberr[x-1]+=(ber*3)/16;
545 nrerr[x+1]+=rer/16;
546 ngerr[x+1]+=ger/16;
547 nberr[x+1]+=ber/16;
548 #if 0
549 /* distribute error */
550 r = (rer*3)/8;
551 g = (ger*3)/8;
552 b = (ber*3)/8;
553 /* x+1, y */
554 rerr[x+1]+=r;
555 gerr[x+1]+=g;
556 berr[x+1]+=b;
557 /* x, y+1 */
558 nrerr[x]+=r;
559 ngerr[x]+=g;
560 nberr[x]+=b;
561 /* x+1, y+1 */
562 nrerr[x+1]+=rer-2*r;
563 ngerr[x+1]+=ger-2*g;
564 nberr[x+1]+=ber-2*b;
565 #endif
567 /* skip to next line */
568 terr = rerr;
569 rerr = nrerr;
570 nrerr = terr;
572 terr = gerr;
573 gerr = ngerr;
574 ngerr = terr;
576 terr = berr;
577 berr = nberr;
578 nberr = terr;
581 ximg->image->data = (char*)data;
583 return ximg;
587 static RXImage*
588 image2GrayScale(RContext *ctx, RImage *image)
590 RXImage *ximg;
591 register int x, y, g;
592 unsigned char *red, *grn, *blu;
593 const int cpc=ctx->attribs->colors_per_channel;
594 unsigned short gmask;
595 unsigned short *table;
596 unsigned char *data;
597 int ofs;
598 /*register unsigned char maxrgb = 0xff;*/
600 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
601 if (!ximg) {
602 return NULL;
605 red = image->data[0];
606 grn = image->data[1];
607 blu = image->data[2];
609 data = (unsigned char *)ximg->image->data;
611 if (ctx->vclass == StaticGray)
612 gmask = (1<<ctx->depth) - 1; /* use all grays */
613 else
614 gmask = cpc*cpc*cpc-1;
616 table = computeTable(gmask);
618 if (table==NULL) {
619 RErrorCode = RERR_NOMEMORY;
620 RDestroyXImage(ctx, ximg);
621 return NULL;
624 if (ctx->attribs->render_mode == RBestMatchRendering) {
625 /* fake match */
626 #ifdef DEBUG
627 printf("grayscale match with %d colors per channel\n", cpc);
628 #endif
629 for (y=0, ofs = 0; y<image->height; y++) {
630 for (x=0; x<image->width; x++, ofs++) {
631 /* reduce pixel */
632 g = table[(red[ofs]*30+grn[ofs]*59+blu[ofs]*11)/100];
634 /*data[ofs] = ctx->colors[g].pixel;*/
635 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
638 } else {
639 /* dither */
640 short *gerr;
641 short *ngerr;
642 short *terr;
643 int ger;
644 const int dg=0xff/gmask;
646 #ifdef DEBUG
647 printf("grayscale dither with %d colors per channel\n", cpc);
648 #endif
649 gerr = (short*)alloca((image->width+2)*sizeof(short));
650 ngerr = (short*)alloca((image->width+2)*sizeof(short));
651 if (!gerr || !ngerr) {
652 RErrorCode = RERR_NOMEMORY;
653 RDestroyXImage(ctx, ximg);
654 return NULL;
656 for (x=0; x<image->width; x++) {
657 gerr[x] = (red[x]*30 + grn[x]*59 + blu[x]*11)/100;
659 gerr[x] = 0;
660 /* convert and dither the image to XImage */
661 for (y=0, ofs=0; y<image->height; y++) {
662 if (y<image->height-1) {
663 int x1;
664 for (x=0, x1=ofs+image->width; x<image->width; x++, x1++) {
665 ngerr[x] = (red[x1]*30 + grn[x1]*59 + blu[x1]*11)/100;
667 /* last column */
668 x1--;
669 ngerr[x] = (red[x1]*30 + grn[x1]*59 + blu[x1]*11)/100;
671 for (x=0; x<image->width; x++, ofs++) {
672 /* reduce pixel */
673 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
675 g = table[gerr[x]];
677 /*data[ofs] = ctx->colors[g].pixel;*/
678 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
679 /* calc error */
680 ger = gerr[x] - g*dg;
682 /* distribute error */
683 g = (ger*3)/8;
684 /* x+1, y */
685 gerr[x+1]+=g;
686 /* x, y+1 */
687 ngerr[x]+=g;
688 /* x+1, y+1 */
689 ngerr[x+1]+=ger-2*g;
691 /* skip to next line */
692 terr = gerr;
693 gerr = ngerr;
694 ngerr = terr;
697 ximg->image->data = (char*)data;
699 return ximg;
703 static RXImage*
704 image2Bitmap(RContext *ctx, RImage *image, int threshold)
706 RXImage *ximg;
707 unsigned char *alpha;
708 int x, y;
710 ximg = RCreateXImage(ctx, 1, image->width, image->height);
711 if (!ximg) {
712 return NULL;
714 alpha = image->data[3];
716 for (y = 0; y < image->height; y++) {
717 for (x = 0; x < image->width; x++) {
718 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
719 alpha++;
723 return ximg;
728 int
729 RConvertImage(RContext *context, RImage *image, Pixmap *pixmap)
731 RXImage *ximg=NULL;
732 #ifdef XSHM
733 Pixmap tmp;
734 #endif
736 assert(context!=NULL);
737 assert(image!=NULL);
738 assert(pixmap!=NULL);
740 /* clear error message */
741 if (context->vclass == TrueColor) {
743 if (context->attribs->render_mode == RDitheredRendering
744 && (context->depth == 15 || context->depth == 16))
745 ximg = image2TrueColorD16(context, image);
746 else
747 ximg = image2TrueColor(context, image);
749 } else if (context->vclass == PseudoColor || context->vclass == StaticColor)
750 ximg = image2PseudoColor(context, image);
751 else if (context->vclass == GrayScale || context->vclass == StaticGray)
752 ximg = image2GrayScale(context, image);
754 if (!ximg) {
755 #ifdef C_ALLOCA
756 alloca(0);
757 #endif
758 return False;
762 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width,
763 image->height, context->depth);
765 #ifdef XSHM
766 if (context->flags.use_shared_pixmap && ximg->is_shared)
767 tmp = R_CreateXImageMappedPixmap(context, ximg);
768 else
769 tmp = None;
770 if (tmp) {
772 * We have to copy the shm Pixmap into a normal Pixmap because
773 * otherwise, we would have to control when Pixmaps are freed so
774 * that we can detach their shm segments. This is a problem if the
775 * program crash, leaving stale shared memory segments in the
776 * system (lots of them). But with some work, we can optimize
777 * things and remove this XCopyArea. This will require
778 * explicitly freeing all pixmaps when exiting or restarting
779 * wmaker.
781 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0,
782 image->width, image->height, 0, 0);
783 XFreePixmap(context->dpy, tmp);
784 } else {
785 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
786 image->width, image->height);
788 #else /* !XSHM */
789 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
790 image->width, image->height);
791 #endif /* !XSHM */
793 RDestroyXImage(context, ximg);
795 #ifdef C_ALLOCA
796 alloca(0);
797 #endif
798 return True;
802 int
803 RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap,
804 Pixmap *mask, int threshold)
806 GC gc;
807 XGCValues gcv;
808 RXImage *ximg=NULL;
810 assert(context!=NULL);
811 assert(image!=NULL);
812 assert(pixmap!=NULL);
813 assert(mask!=NULL);
815 if (!RConvertImage(context, image, pixmap))
816 return False;
818 if (image->data[3]==NULL) {
819 *mask = None;
820 return True;
823 ximg = image2Bitmap(context, image, threshold);
825 if (!ximg) {
826 #ifdef C_ALLOCA
827 alloca(0);
828 #endif
829 return False;
831 *mask = XCreatePixmap(context->dpy, context->drawable, image->width,
832 image->height, 1);
833 gcv.foreground = context->black;
834 gcv.background = context->white;
835 gcv.graphics_exposures = False;
836 gc = XCreateGC(context->dpy, *mask, GCForeground|GCBackground
837 |GCGraphicsExposures, &gcv);
838 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0,
839 image->width, image->height);
840 RDestroyXImage(context, ximg);
842 #ifdef C_ALLOCA
843 alloca(0);
844 #endif
845 return True;
849 Bool
850 RGetClosestXColor(RContext *context, RColor *color, XColor *retColor)
852 if (context->vclass == TrueColor) {
853 unsigned short rmask, gmask, bmask;
854 unsigned short roffs, goffs, boffs;
855 unsigned short *rtable, *gtable, *btable;
857 roffs = context->red_offset;
858 goffs = context->green_offset;
859 boffs = context->blue_offset;
861 rmask = context->visual->red_mask >> roffs;
862 gmask = context->visual->green_mask >> goffs;
863 bmask = context->visual->blue_mask >> boffs;
865 rtable = computeTable(rmask);
866 gtable = computeTable(gmask);
867 btable = computeTable(bmask);
869 retColor->pixel = (rtable[color->red]<<roffs) |
870 (gtable[color->green]<<goffs) | (btable[color->blue]<<boffs);
872 retColor->red = color->red << 8;
873 retColor->green = color->green << 8;
874 retColor->blue = color->blue << 8;
875 retColor->flags = DoRed|DoGreen|DoBlue;
877 } else if (context->vclass == PseudoColor || context->vclass == StaticColor) {
878 const int cpc=context->attribs->colors_per_channel;
879 const unsigned short rmask = cpc-1; /* different sizes could be used */
880 const unsigned short gmask = rmask; /* for r,g,b */
881 const unsigned short bmask = rmask;
882 unsigned short *rtable, *gtable, *btable;
883 const int cpccpc = cpc*cpc;
884 int index;
886 rtable = computeTable(rmask);
887 gtable = computeTable(gmask);
888 btable = computeTable(bmask);
890 if (rtable==NULL || gtable==NULL || btable==NULL) {
891 RErrorCode = RERR_NOMEMORY;
892 return False;
894 index = rtable[color->red]*cpccpc + gtable[color->green]*cpc
895 + btable[color->blue];
896 *retColor = context->colors[index];
897 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
899 const int cpc = context->attribs->colors_per_channel;
900 unsigned short gmask;
901 unsigned short *table;
902 int index;
904 if (context->vclass == StaticGray)
905 gmask = (1<<context->depth) - 1; /* use all grays */
906 else
907 gmask = cpc*cpc*cpc-1;
909 table = computeTable(gmask);
910 if (!table)
911 return False;
913 index = table[(color->red*30 + color->green*59 + color->blue*11)/100];
915 *retColor = context->colors[index];
916 } else {
917 RErrorCode = RERR_INTERNAL;
918 return False;
921 return True;