Optimized some of the previous changes related to order of evaluation.
[wmaker-crm.git] / wrlib / convert.c
blob2837a914e5bfd9506ac7576bab9b0996e8b7a48a
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;
184 /* convert and dither the image to XImage */
185 for (y=0; y<image->height; y++) {
186 nerr[0] = 0;
187 nerr[1] = 0;
188 nerr[2] = 0;
189 for (x=0; x<image->width; x++, ptr+=channels) {
191 /* reduce pixel */
192 pixel = *ptr + err[x];
193 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
194 r = rtable[pixel];
195 /* calc error */
196 rer = pixel - r*dr;
198 /* reduce pixel */
199 pixel = *(ptr+1) + err[x+1];
200 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
201 g = gtable[pixel];
202 /* calc error */
203 ger = pixel - g*dg;
205 /* reduce pixel */
206 pixel = *(ptr+2) + err[x+2];
207 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
208 b = btable[pixel];
209 /* calc error */
210 ber = pixel - b*db;
213 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
214 XPutPixel(ximg->image, x, y, pixel);
216 /* distribute error */
217 r = (rer*3)/8;
218 g = (ger*3)/8;
219 b = (ber*3)/8;
220 /* x+1, y */
221 err[x+3*1]+=r;
222 err[x+1+3*1]+=g;
223 err[x+2+3*1]+=b;
224 /* x, y+1 */
225 nerr[x]+=r;
226 nerr[x+1]+=g;
227 nerr[x+2]+=b;
228 /* x+1, y+1 */
229 nerr[x+3*1]=rer-2*r;
230 nerr[x+1+3*1]=ger-2*g;
231 nerr[x+2+3*1]=ber-2*b;
233 /* skip to next line */
234 terr = err;
235 err = nerr;
236 nerr = terr;
243 static RXImage*
244 image2TrueColor(RContext *ctx, RImage *image)
246 RXImage *ximg;
247 unsigned short rmask, gmask, bmask;
248 unsigned short roffs, goffs, boffs;
249 unsigned short *rtable, *gtable, *btable;
250 int channels = (image->format == RRGBAFormat ? 4 : 3);
252 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
253 if (!ximg) {
254 return NULL;
257 roffs = ctx->red_offset;
258 goffs = ctx->green_offset;
259 boffs = ctx->blue_offset;
261 rmask = ctx->visual->red_mask >> roffs;
262 gmask = ctx->visual->green_mask >> goffs;
263 bmask = ctx->visual->blue_mask >> boffs;
265 rtable = computeTable(rmask);
266 gtable = computeTable(gmask);
267 btable = computeTable(bmask);
269 if (rtable==NULL || gtable==NULL || btable==NULL) {
270 RErrorCode = RERR_NOMEMORY;
271 RDestroyXImage(ctx, ximg);
272 return NULL;
276 #ifdef BENCH
277 cycle_bench(1);
278 #endif
280 if (ctx->attribs->render_mode==RBestMatchRendering) {
281 int ofs, r, g, b;
282 int x, y;
283 unsigned long pixel;
284 unsigned char *ptr = image->data;
286 /* fake match */
287 #ifdef DEBUG
288 puts("true color match");
289 #endif
290 for (y=0, ofs=0; y < image->height; y++) {
291 for (x=0; x < image->width; x++, ofs+=channels-3) {
292 /* reduce pixel */
293 r = rtable[ptr[ofs++]];
294 g = gtable[ptr[ofs++]];
295 b = btable[ptr[ofs++]];
296 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
297 XPutPixel(ximg->image, x, y, pixel);
300 } else {
301 /* dither */
302 const int dr=0xff/rmask;
303 const int dg=0xff/gmask;
304 const int db=0xff/bmask;
306 #ifdef DEBUG
307 puts("true color dither");
308 #endif
310 #ifdef ASM_X86_MMX
311 if (ctx->depth == 16 && image->format == RRGBAFormat
312 && x86_check_mmx()) {
313 short *err;
314 short *nerr;
316 err = malloc(8*(image->width+3));
317 nerr = malloc(8*(image->width+3));
318 if (!err || !nerr) {
319 if (nerr)
320 free(nerr);
321 RErrorCode = RERR_NOMEMORY;
322 RDestroyXImage(ctx, ximg);
323 return NULL;
325 memset(err, 0, 8*(image->width+3));
326 memset(nerr, 0, 8*(image->width+3));
328 x86_mmx_TrueColor_32_to_16(image->data,
329 (unsigned short*)ximg->image->data,
330 err+8, nerr+8,
331 rtable, gtable, btable,
332 dr, dg, db,
333 roffs, goffs, boffs,
334 image->width, image->height,
335 ximg->image->bytes_per_line - 2*image->width);
337 free(err);
338 free(nerr);
339 } else
340 #endif /* ASM_X86_MMX */
342 char *err;
343 char *nerr;
344 int ch = image->format == RRGBAFormat ? 4 : 3;
346 err = malloc(ch*(image->width+2));
347 nerr = malloc(ch*(image->width+2));
348 if (!err || !nerr) {
349 if (nerr)
350 free(nerr);
351 RErrorCode = RERR_NOMEMORY;
352 RDestroyXImage(ctx, ximg);
353 return NULL;
356 memset(err, 0, ch*(image->width+2));
357 memset(nerr, 0, ch*(image->width+2));
359 convertTrueColor_generic(ximg, image, err, nerr,
360 rtable, gtable, btable,
361 dr, dg, db, roffs, goffs, boffs);
362 free(err);
363 free(nerr);
368 #ifdef BENCH
369 cycle_bench(0);
370 #endif
372 return ximg;
376 /***************************************************************************/
378 static void
379 convertPseudoColor_to_8(RXImage *ximg, RImage *image,
380 char *err, char *nerr,
381 const short *rtable,
382 const short *gtable,
383 const short *btable,
384 const int dr, const int dg, const int db,
385 unsigned long *pixels,
386 int cpc)
388 char *terr;
389 int x, y, r, g, b;
390 int pixel;
391 int rer, ger, ber;
392 unsigned char *ptr = image->data;
393 unsigned char *optr = ximg->image->data;
394 int channels = image->format == RRGBAFormat ? 4 : 3;
395 int cpcpc = cpc*cpc;
397 /* convert and dither the image to XImage */
398 for (y=0; y<image->height; y++) {
399 nerr[0] = 0;
400 nerr[1] = 0;
401 nerr[2] = 0;
402 for (x=0; x<image->width*3; x+=3, ptr+=channels) {
404 /* reduce pixel */
405 pixel = *ptr + err[x];
406 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
407 r = rtable[pixel];
408 /* calc error */
409 rer = pixel - r*dr;
411 /* reduce pixel */
412 pixel = *(ptr+1) + err[x+1];
413 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
414 g = gtable[pixel];
415 /* calc error */
416 ger = pixel - g*dg;
418 /* reduce pixel */
419 pixel = *(ptr+2) + err[x+2];
420 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
421 b = btable[pixel];
422 /* calc error */
423 ber = pixel - b*db;
425 *optr++ = pixels[r*cpcpc + g*cpc + b];
427 /* distribute error */
428 r = (rer*3)/8;
429 g = (ger*3)/8;
430 b = (ber*3)/8;
432 /* x+1, y */
433 err[x+3*1]+=r;
434 err[x+1+3*1]+=g;
435 err[x+2+3*1]+=b;
436 /* x, y+1 */
437 nerr[x]+=r;
438 nerr[x+1]+=g;
439 nerr[x+2]+=b;
440 /* x+1, y+1 */
441 nerr[x+3*1]=rer-2*r;
442 nerr[x+1+3*1]=ger-2*g;
443 nerr[x+2+3*1]=ber-2*b;
445 /* skip to next line */
446 terr = err;
447 err = nerr;
448 nerr = terr;
450 optr += ximg->image->bytes_per_line - image->width;
456 static RXImage*
457 image2PseudoColor(RContext *ctx, RImage *image)
459 RXImage *ximg;
460 register int x, y, r, g, b;
461 unsigned char *ptr;
462 unsigned long pixel;
463 const int cpc=ctx->attribs->colors_per_channel;
464 const unsigned short rmask = cpc-1; /* different sizes could be used */
465 const unsigned short gmask = rmask; /* for r,g,b */
466 const unsigned short bmask = rmask;
467 unsigned short *rtable, *gtable, *btable;
468 const int cpccpc = cpc*cpc;
469 int channels = image->format == RRGBAFormat ? 4 : 3;
471 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
472 if (!ximg) {
473 return NULL;
476 ptr = image->data;
478 /* Tables are same at the moment because rmask==gmask==bmask. */
479 rtable = computeTable(rmask);
480 gtable = computeTable(gmask);
481 btable = computeTable(bmask);
483 if (rtable==NULL || gtable==NULL || btable==NULL) {
484 RErrorCode = RERR_NOMEMORY;
485 RDestroyXImage(ctx, ximg);
486 return NULL;
489 if (ctx->attribs->render_mode == RBestMatchRendering) {
490 /* fake match */
491 #ifdef DEBUG
492 printf("pseudo color match with %d colors per channel\n", cpc);
493 #endif
494 for (y=0; y<image->height; y++) {
495 for (x=0; x<image->width; x++, ptr+=channels-1) {
496 /* reduce pixel */
497 r = rtable[*ptr++];
498 g = gtable[*ptr++];
499 b = btable[*ptr++];
500 pixel = r*cpccpc + g*cpc + b;
501 /*data[ofs] = ctx->colors[pixel].pixel;*/
502 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
505 } else {
506 /* dither */
507 char *err;
508 char *nerr;
509 const int dr=0xff/rmask;
510 const int dg=0xff/gmask;
511 const int db=0xff/bmask;
514 #ifdef DEBUG
515 printf("pseudo color dithering with %d colors per channel\n", cpc);
516 #endif
517 err = malloc(4*(image->width+3));
518 nerr = malloc(4*(image->width+3));
519 if (!err || !nerr) {
520 if (nerr)
521 free(nerr);
522 RErrorCode = RERR_NOMEMORY;
523 RDestroyXImage(ctx, ximg);
524 return NULL;
526 memset(err, 0, 4*(image->width+3));
527 memset(nerr, 0, 4*(image->width+3));
529 /*#ifdef ASM_X86*/
530 #if 0
531 x86_PseudoColor_32_to_8(image->data, ximg->image->data,
532 err+4, nerr+4,
533 rtable,
534 dr, dg, db, ctx->pixels, cpc,
535 image->width, image->height,
536 channels,
537 ximg->image->bytes_per_line - image->width);
538 #else
539 convertPseudoColor_to_8(ximg, image, err+4, nerr+4,
540 rtable, gtable, btable,
541 dr, dg, db, ctx->pixels, cpc);
542 #endif
544 free(err);
545 free(nerr);
548 return ximg;
553 * For standard colormap
555 static RXImage*
556 image2StandardPseudoColor(RContext *ctx, RImage *image)
558 RXImage *ximg;
559 register int x, y, r, g, b;
560 unsigned char *ptr;
561 unsigned long pixel;
562 unsigned char *data;
563 unsigned int *rtable, *gtable, *btable;
564 unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
565 int channels = image->format == RRGBAFormat ? 4 : 3;
566 /*register unsigned char maxrgb = 0xff;*/
568 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
569 if (!ximg) {
570 return NULL;
573 ptr = image->data;
575 data = (unsigned char *)ximg->image->data;
578 rtable = computeStdTable(ctx->std_rgb_map->red_mult,
579 ctx->std_rgb_map->red_max);
581 gtable = computeStdTable(ctx->std_rgb_map->green_mult,
582 ctx->std_rgb_map->green_max);
584 btable = computeStdTable(ctx->std_rgb_map->blue_mult,
585 ctx->std_rgb_map->blue_max);
587 if (rtable==NULL || gtable==NULL || btable==NULL) {
588 RErrorCode = RERR_NOMEMORY;
589 RDestroyXImage(ctx, ximg);
590 return NULL;
594 if (ctx->attribs->render_mode == RBestMatchRendering) {
595 for (y=0; y<image->height; y++) {
596 for (x=0; x<image->width; x++, ptr+=channels) {
597 /* reduce pixel */
598 pixel = (rtable[*ptr] + gtable[*(ptr+1)]
599 + btable[*(ptr+2)] + base_pixel) & 0xffffffff;
601 XPutPixel(ximg->image, x, y, pixel);
604 } else {
605 /* dither */
606 short *err, *nerr;
607 short *terr;
608 int rer, ger, ber;
609 int x1, ofs;
611 #ifdef DEBUG
612 printf("pseudo color dithering with %d colors per channel\n", cpc);
613 #endif
614 err = (short*)malloc(3*(image->width+2)*sizeof(short));
615 nerr = (short*)malloc(3*(image->width+2)*sizeof(short));
616 if (!err || !nerr) {
617 if (err)
618 free(err);
619 if (nerr)
620 free(nerr);
621 RErrorCode = RERR_NOMEMORY;
622 RDestroyXImage(ctx, ximg);
623 return NULL;
625 for (x=0, x1=0; x<image->width*3; x1+=channels-3) {
626 err[x++] = ptr[x1++];
627 err[x++] = ptr[x1++];
628 err[x++] = ptr[x1++];
630 err[x] = err[x+1] = err[x+2] = 0;
631 /* convert and dither the image to XImage */
632 for (y=0, ofs=0; y<image->height; y++) {
633 if (y<image->height-1) {
634 int x1;
635 for (x=0, x1=(y+1)*image->width*channels;
636 x<image->width*3;
637 x1+=channels-3) {
638 nerr[x++] = ptr[x1++];
639 nerr[x++] = ptr[x1++];
640 nerr[x++] = ptr[x1++];
642 /* last column */
643 x1-=channels;
644 nerr[x++] = ptr[x1++];
645 nerr[x++] = ptr[x1++];
646 nerr[x++] = ptr[x1++];
648 for (x=0; x<image->width*3; x+=3, ofs++) {
649 /* reduce pixel */
650 if (err[x]>0xff) err[x]=0xff; else if (err[x]<0) err[x]=0;
651 if (err[x+1]>0xff) err[x+1]=0xff; else if (err[x+1]<0) err[x+1]=0;
652 if (err[x+2]>0xff) err[x+2]=0xff; else if (err[x+2]<0) err[x+2]=0;
654 r = rtable[err[x]];
655 g = gtable[err[x+1]];
656 b = btable[err[x+2]];
658 pixel = r + g + b;
660 data[ofs] = base_pixel + pixel;
662 /* calc error */
663 rer = err[x] - (ctx->colors[pixel].red>>8);
664 ger = err[x+1] - (ctx->colors[pixel].green>>8);
665 ber = err[x+2] - (ctx->colors[pixel].blue>>8);
667 /* distribute error */
668 err[x+3*1]+=(rer*7)/16;
669 err[x+1+3*1]+=(ger*7)/16;
670 err[x+2+3*1]+=(ber*7)/16;
672 nerr[x]+=(rer*5)/16;
673 nerr[x+1]+=(ger*5)/16;
674 nerr[x+2]+=(ber*5)/16;
676 if (x>0) {
677 nerr[x-3*1]+=(rer*3)/16;
678 nerr[x-3*1+1]+=(ger*3)/16;
679 nerr[x-3*1+2]+=(ber*3)/16;
682 nerr[x+3*1]+=rer/16;
683 nerr[x+1+3*1]+=ger/16;
684 nerr[x+2+3*1]+=ber/16;
686 /* skip to next line */
687 terr = err;
688 err = nerr;
689 nerr = terr;
691 ofs += ximg->image->bytes_per_line - image->width;
693 free(err);
694 free(nerr);
696 ximg->image->data = (char*)data;
698 return ximg;
703 static RXImage*
704 image2GrayScale(RContext *ctx, RImage *image)
706 RXImage *ximg;
707 register int x, y, g;
708 unsigned char *ptr;
709 const int cpc=ctx->attribs->colors_per_channel;
710 unsigned short gmask;
711 unsigned short *table;
712 unsigned char *data;
713 int channels = image->format == RRGBAFormat ? 4 : 3;
715 /*register unsigned char maxrgb = 0xff;*/
717 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
718 if (!ximg) {
719 return NULL;
722 ptr = image->data;
724 data = (unsigned char *)ximg->image->data;
726 if (ctx->vclass == StaticGray)
727 gmask = (1<<ctx->depth) - 1; /* use all grays */
728 else
729 gmask = cpc*cpc*cpc-1;
731 table = computeTable(gmask);
733 if (table==NULL) {
734 RErrorCode = RERR_NOMEMORY;
735 RDestroyXImage(ctx, ximg);
736 return NULL;
739 if (ctx->attribs->render_mode == RBestMatchRendering) {
740 /* fake match */
741 #ifdef DEBUG
742 printf("grayscale match with %d colors per channel\n", cpc);
743 #endif
744 for (y=0; y<image->height; y++) {
745 for (x=0; x<image->width; x++) {
746 /* reduce pixel */
747 g = table[(*ptr * 30 + *(ptr+1) * 59 + *(ptr+2) * 11)/100];
748 ptr += 3;
749 /*data[ofs] = ctx->colors[g].pixel;*/
750 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
753 } else {
754 /* dither */
755 short *gerr;
756 short *ngerr;
757 short *terr;
758 int ger;
759 const int dg=0xff/gmask;
761 #ifdef DEBUG
762 printf("grayscale dither with %d colors per channel\n", cpc);
763 #endif
764 gerr = (short*)malloc((image->width+2)*sizeof(short));
765 ngerr = (short*)malloc((image->width+2)*sizeof(short));
766 if (!gerr || !ngerr) {
767 if (ngerr)
768 free(ngerr);
769 RErrorCode = RERR_NOMEMORY;
770 RDestroyXImage(ctx, ximg);
771 return NULL;
773 for (x=0; x<image->width; x++) {
774 gerr[x] = (ptr[x*3]*30 + ptr[x*3+1]*59 + ptr[x*3+2]*11)/100;
776 gerr[x] = 0;
777 /* convert and dither the image to XImage */
778 for (y=0; y<image->height; y++) {
779 if (y<image->height-1) {
780 int x1;
781 for (x=0, x1=(y+1)*image->width*3; x<image->width; x1+=channels) {
782 ngerr[x] = (ptr[x1]*30 + ptr[x1+1]*59 + ptr[x1+2]*11)/100;
784 /* last column */
785 x1-=channels;
786 ngerr[x] = (ptr[x1]*30 + ptr[x1+1]*59 + ptr[x1+2]*11)/100;
788 for (x=0; x<image->width; x++) {
789 /* reduce pixel */
790 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
792 g = table[gerr[x]];
794 /*data[ofs] = ctx->colors[g].pixel;*/
795 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
796 /* calc error */
797 ger = gerr[x] - g*dg;
799 /* distribute error */
800 g = (ger*3)/8;
801 /* x+1, y */
802 gerr[x+1]+=g;
803 /* x, y+1 */
804 ngerr[x]+=g;
805 /* x+1, y+1 */
806 ngerr[x+1]+=ger-2*g;
808 /* skip to next line */
809 terr = gerr;
810 gerr = ngerr;
811 ngerr = terr;
813 free(gerr);
814 free(ngerr);
816 ximg->image->data = (char*)data;
818 return ximg;
822 static RXImage*
823 image2Bitmap(RContext *ctx, RImage *image, int threshold)
825 RXImage *ximg;
826 unsigned char *alpha;
827 int x, y;
829 ximg = RCreateXImage(ctx, 1, image->width, image->height);
830 if (!ximg) {
831 return NULL;
833 alpha = image->data+3;
835 for (y = 0; y < image->height; y++) {
836 for (x = 0; x < image->width; x++) {
837 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
838 alpha+=4;
842 return ximg;
847 int
848 RConvertImage(RContext *context, RImage *image, Pixmap *pixmap)
850 RXImage *ximg=NULL;
851 #ifdef XSHM
852 Pixmap tmp;
853 #endif
855 assert(context!=NULL);
856 assert(image!=NULL);
857 assert(pixmap!=NULL);
859 /* clear error message */
860 if (context->vclass == TrueColor) {
862 ximg = image2TrueColor(context, image);
864 } else if (context->vclass == PseudoColor
865 || context->vclass == StaticColor) {
867 #ifdef BENCH
868 cycle_bench(1);
869 #endif
870 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
871 ximg = image2StandardPseudoColor(context, image);
872 else
873 ximg = image2PseudoColor(context, image);
874 #ifdef BENCH
875 cycle_bench(0);
876 #endif
877 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
879 ximg = image2GrayScale(context, image);
882 if (!ximg) {
883 return False;
887 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width,
888 image->height, context->depth);
890 #ifdef XSHM
891 if (context->flags.use_shared_pixmap && ximg->is_shared)
892 tmp = R_CreateXImageMappedPixmap(context, ximg);
893 else
894 tmp = None;
895 if (tmp) {
897 * We have to copy the shm Pixmap into a normal Pixmap because
898 * otherwise, we would have to control when Pixmaps are freed so
899 * that we can detach their shm segments. This is a problem if the
900 * program crash, leaving stale shared memory segments in the
901 * system (lots of them). But with some work, we can optimize
902 * things and remove this XCopyArea. This will require
903 * explicitly freeing all pixmaps when exiting or restarting
904 * wmaker.
906 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0,
907 image->width, image->height, 0, 0);
908 XFreePixmap(context->dpy, tmp);
909 } else {
910 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
911 image->width, image->height);
913 #else /* !XSHM */
914 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
915 image->width, image->height);
916 #endif /* !XSHM */
918 RDestroyXImage(context, ximg);
920 return True;
924 int
925 RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap,
926 Pixmap *mask, int threshold)
928 GC gc;
929 XGCValues gcv;
930 RXImage *ximg=NULL;
932 assert(context!=NULL);
933 assert(image!=NULL);
934 assert(pixmap!=NULL);
935 assert(mask!=NULL);
937 if (!RConvertImage(context, image, pixmap))
938 return False;
940 if (image->format==RRGBFormat) {
941 *mask = None;
942 return True;
945 ximg = image2Bitmap(context, image, threshold);
947 if (!ximg) {
948 return False;
950 *mask = XCreatePixmap(context->dpy, context->drawable, image->width,
951 image->height, 1);
952 gcv.foreground = context->black;
953 gcv.background = context->white;
954 gcv.graphics_exposures = False;
955 gc = XCreateGC(context->dpy, *mask, GCForeground|GCBackground
956 |GCGraphicsExposures, &gcv);
957 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0,
958 image->width, image->height);
959 RDestroyXImage(context, ximg);
961 return True;
965 Bool
966 RGetClosestXColor(RContext *context, RColor *color, XColor *retColor)
968 if (context->vclass == TrueColor) {
969 unsigned short rmask, gmask, bmask;
970 unsigned short roffs, goffs, boffs;
971 unsigned short *rtable, *gtable, *btable;
973 roffs = context->red_offset;
974 goffs = context->green_offset;
975 boffs = context->blue_offset;
977 rmask = context->visual->red_mask >> roffs;
978 gmask = context->visual->green_mask >> goffs;
979 bmask = context->visual->blue_mask >> boffs;
981 rtable = computeTable(rmask);
982 gtable = computeTable(gmask);
983 btable = computeTable(bmask);
985 retColor->pixel = (rtable[color->red]<<roffs) |
986 (gtable[color->green]<<goffs) | (btable[color->blue]<<boffs);
988 retColor->red = color->red << 8;
989 retColor->green = color->green << 8;
990 retColor->blue = color->blue << 8;
991 retColor->flags = DoRed|DoGreen|DoBlue;
993 } else if (context->vclass == PseudoColor
994 || context->vclass == StaticColor) {
996 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
997 unsigned int *rtable, *gtable, *btable;
999 rtable = computeStdTable(context->std_rgb_map->red_mult,
1000 context->std_rgb_map->red_max);
1002 gtable = computeStdTable(context->std_rgb_map->green_mult,
1003 context->std_rgb_map->green_max);
1005 btable = computeStdTable(context->std_rgb_map->blue_mult,
1006 context->std_rgb_map->blue_max);
1008 if (rtable==NULL || gtable==NULL || btable==NULL) {
1009 RErrorCode = RERR_NOMEMORY;
1010 return False;
1013 retColor->pixel = (rtable[color->red]
1014 + gtable[color->green]
1015 + btable[color->blue]
1016 + context->std_rgb_map->base_pixel) & 0xffffffff;
1017 retColor->red = color->red<<8;
1018 retColor->green = color->green<<8;
1019 retColor->blue = color->blue<<8;
1020 retColor->flags = DoRed|DoGreen|DoBlue;
1022 } else {
1023 const int cpc=context->attribs->colors_per_channel;
1024 const unsigned short rmask = cpc-1; /* different sizes could be used */
1025 const unsigned short gmask = rmask; /* for r,g,b */
1026 const unsigned short bmask = rmask;
1027 unsigned short *rtable, *gtable, *btable;
1028 const int cpccpc = cpc*cpc;
1029 int index;
1031 rtable = computeTable(rmask);
1032 gtable = computeTable(gmask);
1033 btable = computeTable(bmask);
1035 if (rtable==NULL || gtable==NULL || btable==NULL) {
1036 RErrorCode = RERR_NOMEMORY;
1037 return False;
1039 index = rtable[color->red]*cpccpc + gtable[color->green]*cpc
1040 + btable[color->blue];
1041 *retColor = context->colors[index];
1044 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
1046 const int cpc = context->attribs->colors_per_channel;
1047 unsigned short gmask;
1048 unsigned short *table;
1049 int index;
1051 if (context->vclass == StaticGray)
1052 gmask = (1<<context->depth) - 1; /* use all grays */
1053 else
1054 gmask = cpc*cpc*cpc-1;
1056 table = computeTable(gmask);
1057 if (!table)
1058 return False;
1060 index = table[(color->red*30 + color->green*59 + color->blue*11)/100];
1062 *retColor = context->colors[index];
1063 } else {
1064 RErrorCode = RERR_INTERNAL;
1065 return False;
1068 return True;