bag tree finished.. updated code to new bags
[wmaker-crm.git] / wrlib / convert.c
blob805f8090b4d15f82b2aa0e899d2cc046ab2a9853
1 /* convert.c - convert RImage to Pixmap
2 *
3 * Raster graphics library
5 * Copyright (c) 1997-2000 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>
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
30 #include <assert.h>
32 #ifdef BENCH
33 #include "bench.h"
34 #endif
36 #include "wraster.h"
38 #ifdef XSHM
39 extern Pixmap R_CreateXImageMappedPixmap(RContext *context, RXImage *ximage);
41 #endif
44 #ifdef ASM_X86
45 extern void x86_PseudoColor_32_to_8(unsigned char *image,
46 unsigned char *ximage,
47 char *err, char *nerr,
48 short *ctable,
49 int dr, int dg, int db,
50 unsigned long *pixels,
51 int cpc,
52 int width, int height,
53 int bytesPerPixel,
54 int line_offset);
55 #endif /* ASM_X86 */
57 #ifdef ASM_X86_MMX
59 extern int x86_check_mmx();
61 extern void x86_mmx_TrueColor_32_to_16(unsigned char *image,
62 unsigned short *ximage,
63 short *err, short *nerr,
64 short *rtable, short *gtable,
65 short *btable,
66 int dr, int dg, int db,
67 unsigned int roffs,
68 unsigned int goffs,
69 unsigned int boffs,
70 int width, int height,
71 int line_offset);
75 #endif /* ASM_X86_MMX */
79 typedef struct RConversionTable {
80 unsigned short table[256];
81 unsigned short index;
83 struct RConversionTable *next;
84 } RConversionTable;
87 typedef struct RStdConversionTable {
88 unsigned int table[256];
90 unsigned short mult;
91 unsigned short max;
93 struct RStdConversionTable *next;
94 } RStdConversionTable;
98 static RConversionTable *conversionTable = NULL;
99 static RStdConversionTable *stdConversionTable = NULL;
102 static unsigned short*
103 computeTable(unsigned short mask)
105 RConversionTable *tmp = conversionTable;
106 int i;
108 while (tmp) {
109 if (tmp->index == mask)
110 break;
111 tmp = tmp->next;
114 if (tmp)
115 return tmp->table;
117 tmp = (RConversionTable *)malloc(sizeof(RConversionTable));
118 if (tmp == NULL)
119 return NULL;
121 for (i=0;i<256;i++)
122 tmp->table[i] = (i*mask + 0x7f)/0xff;
124 tmp->index = mask;
125 tmp->next = conversionTable;
126 conversionTable = tmp;
127 return tmp->table;
131 static unsigned int*
132 computeStdTable(unsigned int mult, unsigned int max)
134 RStdConversionTable *tmp = stdConversionTable;
135 unsigned int i;
137 while (tmp) {
138 if (tmp->mult == mult && tmp->max == max)
139 break;
140 tmp = tmp->next;
143 if (tmp)
144 return tmp->table;
146 tmp = (RStdConversionTable *)malloc(sizeof(RStdConversionTable));
147 if (tmp == NULL)
148 return NULL;
150 for (i=0; i<256; i++) {
151 tmp->table[i] = (i*max)/0xff * mult;
153 tmp->mult = mult;
154 tmp->max = max;
156 tmp->next = stdConversionTable;
157 stdConversionTable = tmp;
159 return tmp->table;
162 /***************************************************************************/
165 static void
166 convertTrueColor_generic(RXImage *ximg, RImage *image,
167 char *err, char *nerr,
168 const short *rtable,
169 const short *gtable,
170 const short *btable,
171 const int dr, const int dg, const int db,
172 const unsigned short roffs,
173 const unsigned short goffs,
174 const unsigned short boffs)
176 char *terr;
177 int x, y, r, g, b;
178 int pixel;
179 int rer, ger, ber;
180 unsigned char *ptr = image->data;
181 int channels = image->format == RRGBAFormat ? 4 : 3;
183 /* convert and dither the image to XImage */
184 for (y=0; y<image->height; y++) {
185 nerr[0] = 0;
186 nerr[1] = 0;
187 nerr[2] = 0;
188 for (x=0; x<image->width; x++, ptr+=channels) {
190 /* reduce pixel */
191 pixel = *ptr + err[x];
192 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
193 r = rtable[pixel];
194 /* calc error */
195 rer = pixel - r*dr;
197 /* reduce pixel */
198 pixel = *(ptr+1) + err[x+1];
199 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
200 g = gtable[pixel];
201 /* calc error */
202 ger = pixel - g*dg;
204 /* reduce pixel */
205 pixel = *(ptr+2) + err[x+2];
206 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
207 b = btable[pixel];
208 /* calc error */
209 ber = pixel - b*db;
212 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
213 XPutPixel(ximg->image, x, y, pixel);
215 /* distribute error */
216 r = (rer*3)/8;
217 g = (ger*3)/8;
218 b = (ber*3)/8;
219 /* x+1, y */
220 err[x+3*1]+=r;
221 err[x+1+3*1]+=g;
222 err[x+2+3*1]+=b;
223 /* x, y+1 */
224 nerr[x]+=r;
225 nerr[x+1]+=g;
226 nerr[x+2]+=b;
227 /* x+1, y+1 */
228 nerr[x+3*1]=rer-2*r;
229 nerr[x+1+3*1]=ger-2*g;
230 nerr[x+2+3*1]=ber-2*b;
232 /* skip to next line */
233 terr = err;
234 err = nerr;
235 nerr = terr;
242 static RXImage*
243 image2TrueColor(RContext *ctx, RImage *image)
245 RXImage *ximg;
246 unsigned short rmask, gmask, bmask;
247 unsigned short roffs, goffs, boffs;
248 unsigned short *rtable, *gtable, *btable;
249 int channels = (image->format == RRGBAFormat ? 4 : 3);
251 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
252 if (!ximg) {
253 return NULL;
256 roffs = ctx->red_offset;
257 goffs = ctx->green_offset;
258 boffs = ctx->blue_offset;
260 rmask = ctx->visual->red_mask >> roffs;
261 gmask = ctx->visual->green_mask >> goffs;
262 bmask = ctx->visual->blue_mask >> boffs;
264 rtable = computeTable(rmask);
265 gtable = computeTable(gmask);
266 btable = computeTable(bmask);
268 if (rtable==NULL || gtable==NULL || btable==NULL) {
269 RErrorCode = RERR_NOMEMORY;
270 RDestroyXImage(ctx, ximg);
271 return NULL;
275 #ifdef BENCH
276 cycle_bench(1);
277 #endif
279 if (ctx->attribs->render_mode==RBestMatchRendering) {
280 int ofs, r, g, b;
281 int x, y;
282 unsigned long pixel;
283 unsigned char *ptr = image->data;
285 /* fake match */
286 #ifdef DEBUG
287 puts("true color match");
288 #endif
289 for (y=0, ofs=0; y < image->height; y++) {
290 for (x=0; x < image->width; x++, ofs+=channels-3) {
291 /* reduce pixel */
292 r = rtable[ptr[ofs++]];
293 g = gtable[ptr[ofs++]];
294 b = btable[ptr[ofs++]];
295 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
296 XPutPixel(ximg->image, x, y, pixel);
299 } else {
300 /* dither */
301 const int dr=0xff/rmask;
302 const int dg=0xff/gmask;
303 const int db=0xff/bmask;
305 #ifdef DEBUG
306 puts("true color dither");
307 #endif
309 #ifdef ASM_X86_MMX
310 if (ctx->depth == 16 && image->format == RRGBAFormat
311 && x86_check_mmx()) {
312 short *err;
313 short *nerr;
315 err = malloc(8*(image->width+3));
316 nerr = malloc(8*(image->width+3));
317 if (!err || !nerr) {
318 if (nerr)
319 free(nerr);
320 RErrorCode = RERR_NOMEMORY;
321 RDestroyXImage(ctx, ximg);
322 return NULL;
324 memset(err, 0, 8*(image->width+3));
325 memset(nerr, 0, 8*(image->width+3));
327 x86_mmx_TrueColor_32_to_16(image->data,
328 (unsigned short*)ximg->image->data,
329 err+8, nerr+8,
330 rtable, gtable, btable,
331 dr, dg, db,
332 roffs, goffs, boffs,
333 image->width, image->height,
334 ximg->image->bytes_per_line - 2*image->width);
336 free(err);
337 free(nerr);
338 } else
339 #endif /* ASM_X86_MMX */
341 char *err;
342 char *nerr;
343 int ch = image->format == RRGBAFormat ? 4 : 3;
345 err = malloc(ch*(image->width+2));
346 nerr = malloc(ch*(image->width+2));
347 if (!err || !nerr) {
348 if (nerr)
349 free(nerr);
350 RErrorCode = RERR_NOMEMORY;
351 RDestroyXImage(ctx, ximg);
352 return NULL;
355 memset(err, 0, ch*(image->width+2));
356 memset(nerr, 0, ch*(image->width+2));
358 convertTrueColor_generic(ximg, image, err, nerr,
359 rtable, gtable, btable,
360 dr, dg, db, roffs, goffs, boffs);
361 free(err);
362 free(nerr);
367 #ifdef BENCH
368 cycle_bench(0);
369 #endif
371 return ximg;
375 /***************************************************************************/
377 static void
378 convertPseudoColor_to_8(RXImage *ximg, RImage *image,
379 char *err, char *nerr,
380 const short *rtable,
381 const short *gtable,
382 const short *btable,
383 const int dr, const int dg, const int db,
384 unsigned long *pixels,
385 int cpc)
387 char *terr;
388 int x, y, r, g, b;
389 int pixel;
390 int rer, ger, ber;
391 unsigned char *ptr = image->data;
392 unsigned char *optr = ximg->image->data;
393 int channels = image->format == RRGBAFormat ? 4 : 3;
394 int cpcpc = cpc*cpc;
396 /* convert and dither the image to XImage */
397 for (y=0; y<image->height; y++) {
398 nerr[0] = 0;
399 nerr[1] = 0;
400 nerr[2] = 0;
401 for (x=0; x<image->width*3; x+=3, ptr+=channels) {
403 /* reduce pixel */
404 pixel = *ptr + err[x];
405 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
406 r = rtable[pixel];
407 /* calc error */
408 rer = pixel - r*dr;
410 /* reduce pixel */
411 pixel = *(ptr+1) + err[x+1];
412 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
413 g = gtable[pixel];
414 /* calc error */
415 ger = pixel - g*dg;
417 /* reduce pixel */
418 pixel = *(ptr+2) + err[x+2];
419 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
420 b = btable[pixel];
421 /* calc error */
422 ber = pixel - b*db;
424 *optr++ = pixels[r*cpcpc + g*cpc + b];
426 /* distribute error */
427 r = (rer*3)/8;
428 g = (ger*3)/8;
429 b = (ber*3)/8;
431 /* x+1, y */
432 err[x+3*1]+=r;
433 err[x+1+3*1]+=g;
434 err[x+2+3*1]+=b;
435 /* x, y+1 */
436 nerr[x]+=r;
437 nerr[x+1]+=g;
438 nerr[x+2]+=b;
439 /* x+1, y+1 */
440 nerr[x+3*1]=rer-2*r;
441 nerr[x+1+3*1]=ger-2*g;
442 nerr[x+2+3*1]=ber-2*b;
444 /* skip to next line */
445 terr = err;
446 err = nerr;
447 nerr = terr;
449 optr += ximg->image->bytes_per_line - image->width;
455 static RXImage*
456 image2PseudoColor(RContext *ctx, RImage *image)
458 RXImage *ximg;
459 register int x, y, r, g, b;
460 unsigned char *ptr;
461 unsigned long pixel;
462 const int cpc=ctx->attribs->colors_per_channel;
463 const unsigned short rmask = cpc-1; /* different sizes could be used */
464 const unsigned short gmask = rmask; /* for r,g,b */
465 const unsigned short bmask = rmask;
466 unsigned short *rtable, *gtable, *btable;
467 const int cpccpc = cpc*cpc;
468 int channels = image->format == RRGBAFormat ? 4 : 3;
470 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
471 if (!ximg) {
472 return NULL;
475 ptr = image->data;
477 /* Tables are same at the moment because rmask==gmask==bmask. */
478 rtable = computeTable(rmask);
479 gtable = computeTable(gmask);
480 btable = computeTable(bmask);
482 if (rtable==NULL || gtable==NULL || btable==NULL) {
483 RErrorCode = RERR_NOMEMORY;
484 RDestroyXImage(ctx, ximg);
485 return NULL;
488 if (ctx->attribs->render_mode == RBestMatchRendering) {
489 /* fake match */
490 #ifdef DEBUG
491 printf("pseudo color match with %d colors per channel\n", cpc);
492 #endif
493 for (y=0; y<image->height; y++) {
494 for (x=0; x<image->width; x++, ptr+=channels-1) {
495 /* reduce pixel */
496 r = rtable[*ptr++];
497 g = gtable[*ptr++];
498 b = btable[*ptr++];
499 pixel = r*cpccpc + g*cpc + b;
500 /*data[ofs] = ctx->colors[pixel].pixel;*/
501 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
504 } else {
505 /* dither */
506 char *err;
507 char *nerr;
508 const int dr=0xff/rmask;
509 const int dg=0xff/gmask;
510 const int db=0xff/bmask;
513 #ifdef DEBUG
514 printf("pseudo color dithering with %d colors per channel\n", cpc);
515 #endif
516 err = malloc(4*(image->width+3));
517 nerr = malloc(4*(image->width+3));
518 if (!err || !nerr) {
519 if (nerr)
520 free(nerr);
521 RErrorCode = RERR_NOMEMORY;
522 RDestroyXImage(ctx, ximg);
523 return NULL;
525 memset(err, 0, 4*(image->width+3));
526 memset(nerr, 0, 4*(image->width+3));
528 #ifdef ASM_X86
529 x86_PseudoColor_32_to_8(image->data, ximg->image->data,
530 err+4, nerr+4,
531 rtable,
532 dr, dg, db, ctx->pixels, cpc,
533 image->width, image->height,
534 channels,
535 ximg->image->bytes_per_line - image->width);
536 #else
537 convertPseudoColor_to_8(ximg, image, err+4, nerr+4,
538 rtable, gtable, btable,
539 dr, dg, db, ctx->pixels, cpc);
540 #endif
542 free(err);
543 free(nerr);
546 return ximg;
551 * For standard colormap
553 static RXImage*
554 image2StandardPseudoColor(RContext *ctx, RImage *image)
556 RXImage *ximg;
557 register int x, y, r, g, b;
558 unsigned char *ptr;
559 unsigned long pixel;
560 unsigned char *data;
561 unsigned int *rtable, *gtable, *btable;
562 unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
563 int channels = image->format == RRGBAFormat ? 4 : 3;
564 /*register unsigned char maxrgb = 0xff;*/
566 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
567 if (!ximg) {
568 return NULL;
571 ptr = image->data;
573 data = (unsigned char *)ximg->image->data;
576 rtable = computeStdTable(ctx->std_rgb_map->red_mult,
577 ctx->std_rgb_map->red_max);
579 gtable = computeStdTable(ctx->std_rgb_map->green_mult,
580 ctx->std_rgb_map->green_max);
582 btable = computeStdTable(ctx->std_rgb_map->blue_mult,
583 ctx->std_rgb_map->blue_max);
585 if (rtable==NULL || gtable==NULL || btable==NULL) {
586 RErrorCode = RERR_NOMEMORY;
587 RDestroyXImage(ctx, ximg);
588 return NULL;
592 if (ctx->attribs->render_mode == RBestMatchRendering) {
593 for (y=0; y<image->height; y++) {
594 for (x=0; x<image->width; x++, ptr+=channels-3) {
595 /* reduce pixel */
596 pixel = (rtable[*ptr++] + gtable[*ptr++]
597 + btable[*ptr++] + base_pixel) & 0xffffffff;
599 XPutPixel(ximg->image, x, y, pixel);
602 } else {
603 /* dither */
604 short *err, *nerr;
605 short *terr;
606 int rer, ger, ber;
607 int x1, ofs;
609 #ifdef DEBUG
610 printf("pseudo color dithering with %d colors per channel\n", cpc);
611 #endif
612 err = (short*)malloc(3*(image->width+2)*sizeof(short));
613 nerr = (short*)malloc(3*(image->width+2)*sizeof(short));
614 if (!err || !nerr) {
615 if (nerr)
616 free(nerr);
617 RErrorCode = RERR_NOMEMORY;
618 RDestroyXImage(ctx, ximg);
619 return NULL;
621 for (x=0, x1=0; x<image->width*3; x1+=channels-3) {
622 err[x++] = ptr[x1++];
623 err[x++] = ptr[x1++];
624 err[x++] = ptr[x1++];
626 err[x++] = err[x++] = err[x++] = 0;
627 /* convert and dither the image to XImage */
628 for (y=0, ofs=0; y<image->height; y++) {
629 if (y<image->height-1) {
630 int x1;
631 for (x=0, x1=(y+1)*image->width*channels;
632 x<image->width*3;
633 x1+=channels-3) {
634 nerr[x++] = ptr[x1++];
635 nerr[x++] = ptr[x1++];
636 nerr[x++] = ptr[x1++];
638 /* last column */
639 x1-=channels;
640 nerr[x++] = ptr[x1++];
641 nerr[x++] = ptr[x1++];
642 nerr[x++] = ptr[x1++];
644 for (x=0; x<image->width*3; x+=3, ofs++) {
645 /* reduce pixel */
646 if (err[x]>0xff) err[x]=0xff; else if (err[x]<0) err[x]=0;
647 if (err[x+1]>0xff) err[x+1]=0xff; else if (err[x+1]<0) err[x+1]=0;
648 if (err[x+2]>0xff) err[x+2]=0xff; else if (err[x+2]<0) err[x+2]=0;
650 r = rtable[err[x]];
651 g = gtable[err[x+1]];
652 b = btable[err[x+2]];
654 pixel = r + g + b;
656 data[ofs] = base_pixel + pixel;
658 /* calc error */
659 rer = err[x] - (ctx->colors[pixel].red>>8);
660 ger = err[x+1] - (ctx->colors[pixel].green>>8);
661 ber = err[x+2] - (ctx->colors[pixel].blue>>8);
663 /* distribute error */
664 err[x+3*1]+=(rer*7)/16;
665 err[x+1+3*1]+=(ger*7)/16;
666 err[x+2+3*1]+=(ber*7)/16;
668 nerr[x]+=(rer*5)/16;
669 nerr[x+1]+=(ger*5)/16;
670 nerr[x+2]+=(ber*5)/16;
672 if (x>0) {
673 nerr[x-3*1]+=(rer*3)/16;
674 nerr[x-3*1+1]+=(ger*3)/16;
675 nerr[x-3*1+2]+=(ber*3)/16;
678 nerr[x+3*1]+=rer/16;
679 nerr[x+1+3*1]+=ger/16;
680 nerr[x+2+3*1]+=ber/16;
682 /* skip to next line */
683 terr = err;
684 err = nerr;
685 nerr = terr;
687 ofs += ximg->image->bytes_per_line - image->width;
689 free(err);
690 free(nerr);
692 ximg->image->data = (char*)data;
694 return ximg;
699 static RXImage*
700 image2GrayScale(RContext *ctx, RImage *image)
702 RXImage *ximg;
703 register int x, y, g;
704 unsigned char *ptr;
705 const int cpc=ctx->attribs->colors_per_channel;
706 unsigned short gmask;
707 unsigned short *table;
708 unsigned char *data;
709 int channels = image->format == RRGBAFormat ? 4 : 3;
711 /*register unsigned char maxrgb = 0xff;*/
713 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
714 if (!ximg) {
715 return NULL;
718 ptr = image->data;
720 data = (unsigned char *)ximg->image->data;
722 if (ctx->vclass == StaticGray)
723 gmask = (1<<ctx->depth) - 1; /* use all grays */
724 else
725 gmask = cpc*cpc*cpc-1;
727 table = computeTable(gmask);
729 if (table==NULL) {
730 RErrorCode = RERR_NOMEMORY;
731 RDestroyXImage(ctx, ximg);
732 return NULL;
735 if (ctx->attribs->render_mode == RBestMatchRendering) {
736 /* fake match */
737 #ifdef DEBUG
738 printf("grayscale match with %d colors per channel\n", cpc);
739 #endif
740 for (y=0; y<image->height; y++) {
741 for (x=0; x<image->width; x++) {
742 /* reduce pixel */
743 g = table[(*ptr++ * 30 + *ptr++ * 59 + *ptr++ * 11)/100];
745 /*data[ofs] = ctx->colors[g].pixel;*/
746 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
749 } else {
750 /* dither */
751 short *gerr;
752 short *ngerr;
753 short *terr;
754 int ger;
755 const int dg=0xff/gmask;
757 #ifdef DEBUG
758 printf("grayscale dither with %d colors per channel\n", cpc);
759 #endif
760 gerr = (short*)malloc((image->width+2)*sizeof(short));
761 ngerr = (short*)malloc((image->width+2)*sizeof(short));
762 if (!gerr || !ngerr) {
763 if (ngerr)
764 free(ngerr);
765 RErrorCode = RERR_NOMEMORY;
766 RDestroyXImage(ctx, ximg);
767 return NULL;
769 for (x=0; x<image->width; x++) {
770 gerr[x] = (ptr[x*3]*30 + ptr[x*3+1]*59 + ptr[x*3+2]*11)/100;
772 gerr[x] = 0;
773 /* convert and dither the image to XImage */
774 for (y=0; y<image->height; y++) {
775 if (y<image->height-1) {
776 int x1;
777 for (x=0, x1=(y+1)*image->width*3;
778 x<image->width;
779 x1+=channels-3) {
780 ngerr[x] = (ptr[x1++]*30 + ptr[x1++]*59 + ptr[x1++]*11)/100;
782 /* last column */
783 x1-=channels;
784 ngerr[x] = (ptr[x1++]*30 + ptr[x1++]*59 + ptr[x1++]*11)/100;
786 for (x=0; x<image->width; x++) {
787 /* reduce pixel */
788 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
790 g = table[gerr[x]];
792 /*data[ofs] = ctx->colors[g].pixel;*/
793 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
794 /* calc error */
795 ger = gerr[x] - g*dg;
797 /* distribute error */
798 g = (ger*3)/8;
799 /* x+1, y */
800 gerr[x+1]+=g;
801 /* x, y+1 */
802 ngerr[x]+=g;
803 /* x+1, y+1 */
804 ngerr[x+1]+=ger-2*g;
806 /* skip to next line */
807 terr = gerr;
808 gerr = ngerr;
809 ngerr = terr;
811 free(gerr);
812 free(ngerr);
814 ximg->image->data = (char*)data;
816 return ximg;
820 static RXImage*
821 image2Bitmap(RContext *ctx, RImage *image, int threshold)
823 RXImage *ximg;
824 unsigned char *alpha;
825 int x, y;
827 ximg = RCreateXImage(ctx, 1, image->width, image->height);
828 if (!ximg) {
829 return NULL;
831 alpha = image->data+3;
833 for (y = 0; y < image->height; y++) {
834 for (x = 0; x < image->width; x++) {
835 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
836 alpha+=4;
840 return ximg;
845 int
846 RConvertImage(RContext *context, RImage *image, Pixmap *pixmap)
848 RXImage *ximg=NULL;
849 #ifdef XSHM
850 Pixmap tmp;
851 #endif
853 assert(context!=NULL);
854 assert(image!=NULL);
855 assert(pixmap!=NULL);
857 /* clear error message */
858 if (context->vclass == TrueColor) {
860 ximg = image2TrueColor(context, image);
862 } else if (context->vclass == PseudoColor
863 || context->vclass == StaticColor) {
865 #ifdef BENCH
866 cycle_bench(1);
867 #endif
868 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
869 ximg = image2StandardPseudoColor(context, image);
870 else
871 ximg = image2PseudoColor(context, image);
872 #ifdef BENCH
873 cycle_bench(0);
874 #endif
875 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
877 ximg = image2GrayScale(context, image);
880 if (!ximg) {
881 return False;
885 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width,
886 image->height, context->depth);
888 #ifdef XSHM
889 if (context->flags.use_shared_pixmap && ximg->is_shared)
890 tmp = R_CreateXImageMappedPixmap(context, ximg);
891 else
892 tmp = None;
893 if (tmp) {
895 * We have to copy the shm Pixmap into a normal Pixmap because
896 * otherwise, we would have to control when Pixmaps are freed so
897 * that we can detach their shm segments. This is a problem if the
898 * program crash, leaving stale shared memory segments in the
899 * system (lots of them). But with some work, we can optimize
900 * things and remove this XCopyArea. This will require
901 * explicitly freeing all pixmaps when exiting or restarting
902 * wmaker.
904 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0,
905 image->width, image->height, 0, 0);
906 XFreePixmap(context->dpy, tmp);
907 } else {
908 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
909 image->width, image->height);
911 #else /* !XSHM */
912 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
913 image->width, image->height);
914 #endif /* !XSHM */
916 RDestroyXImage(context, ximg);
918 return True;
922 int
923 RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap,
924 Pixmap *mask, int threshold)
926 GC gc;
927 XGCValues gcv;
928 RXImage *ximg=NULL;
930 assert(context!=NULL);
931 assert(image!=NULL);
932 assert(pixmap!=NULL);
933 assert(mask!=NULL);
935 if (!RConvertImage(context, image, pixmap))
936 return False;
938 if (image->format==RRGBFormat) {
939 *mask = None;
940 return True;
943 ximg = image2Bitmap(context, image, threshold);
945 if (!ximg) {
946 return False;
948 *mask = XCreatePixmap(context->dpy, context->drawable, image->width,
949 image->height, 1);
950 gcv.foreground = context->black;
951 gcv.background = context->white;
952 gcv.graphics_exposures = False;
953 gc = XCreateGC(context->dpy, *mask, GCForeground|GCBackground
954 |GCGraphicsExposures, &gcv);
955 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0,
956 image->width, image->height);
957 RDestroyXImage(context, ximg);
959 return True;
963 Bool
964 RGetClosestXColor(RContext *context, RColor *color, XColor *retColor)
966 if (context->vclass == TrueColor) {
967 unsigned short rmask, gmask, bmask;
968 unsigned short roffs, goffs, boffs;
969 unsigned short *rtable, *gtable, *btable;
971 roffs = context->red_offset;
972 goffs = context->green_offset;
973 boffs = context->blue_offset;
975 rmask = context->visual->red_mask >> roffs;
976 gmask = context->visual->green_mask >> goffs;
977 bmask = context->visual->blue_mask >> boffs;
979 rtable = computeTable(rmask);
980 gtable = computeTable(gmask);
981 btable = computeTable(bmask);
983 retColor->pixel = (rtable[color->red]<<roffs) |
984 (gtable[color->green]<<goffs) | (btable[color->blue]<<boffs);
986 retColor->red = color->red << 8;
987 retColor->green = color->green << 8;
988 retColor->blue = color->blue << 8;
989 retColor->flags = DoRed|DoGreen|DoBlue;
991 } else if (context->vclass == PseudoColor
992 || context->vclass == StaticColor) {
994 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
995 unsigned int *rtable, *gtable, *btable;
997 rtable = computeStdTable(context->std_rgb_map->red_mult,
998 context->std_rgb_map->red_max);
1000 gtable = computeStdTable(context->std_rgb_map->green_mult,
1001 context->std_rgb_map->green_max);
1003 btable = computeStdTable(context->std_rgb_map->blue_mult,
1004 context->std_rgb_map->blue_max);
1006 if (rtable==NULL || gtable==NULL || btable==NULL) {
1007 RErrorCode = RERR_NOMEMORY;
1008 return False;
1011 retColor->pixel = (rtable[color->red]
1012 + gtable[color->green]
1013 + btable[color->blue]
1014 + context->std_rgb_map->base_pixel) & 0xffffffff;
1015 retColor->red = color->red<<8;
1016 retColor->green = color->green<<8;
1017 retColor->blue = color->blue<<8;
1018 retColor->flags = DoRed|DoGreen|DoBlue;
1020 } else {
1021 const int cpc=context->attribs->colors_per_channel;
1022 const unsigned short rmask = cpc-1; /* different sizes could be used */
1023 const unsigned short gmask = rmask; /* for r,g,b */
1024 const unsigned short bmask = rmask;
1025 unsigned short *rtable, *gtable, *btable;
1026 const int cpccpc = cpc*cpc;
1027 int index;
1029 rtable = computeTable(rmask);
1030 gtable = computeTable(gmask);
1031 btable = computeTable(bmask);
1033 if (rtable==NULL || gtable==NULL || btable==NULL) {
1034 RErrorCode = RERR_NOMEMORY;
1035 return False;
1037 index = rtable[color->red]*cpccpc + gtable[color->green]*cpc
1038 + btable[color->blue];
1039 *retColor = context->colors[index];
1042 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
1044 const int cpc = context->attribs->colors_per_channel;
1045 unsigned short gmask;
1046 unsigned short *table;
1047 int index;
1049 if (context->vclass == StaticGray)
1050 gmask = (1<<context->depth) - 1; /* use all grays */
1051 else
1052 gmask = cpc*cpc*cpc-1;
1054 table = computeTable(gmask);
1055 if (!table)
1056 return False;
1058 index = table[(color->red*30 + color->green*59 + color->blue*11)/100];
1060 *retColor = context->colors[index];
1061 } else {
1062 RErrorCode = RERR_INTERNAL;
1063 return False;
1066 return True;