- fixed speckles (white dots) on dithered images (bug still present on the
[wmaker-crm.git] / wrlib / convert.c
blobebd5e1065e3cad67eab156ea361ed7c4342f3610
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.
22 /* Problems:
23 * 1. Using Grayscale visual with Dithering crashes wmaker
24 * 2. Ghost dock/appicon is wrong in Pseudocolor, Staticgray, Grayscale
27 #include <config.h>
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
36 #include <assert.h>
39 #ifdef BENCH
40 #include "bench.h"
41 #endif
43 #include "wrasterP.h"
45 #ifdef XSHM
46 extern Pixmap R_CreateXImageMappedPixmap(RContext *context, RXImage *ximage);
48 #endif
51 #define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
54 typedef struct RConversionTable {
55 unsigned short table[256];
56 unsigned short index;
58 struct RConversionTable *next;
59 } RConversionTable;
62 typedef struct RStdConversionTable {
63 unsigned int table[256];
65 unsigned short mult;
66 unsigned short max;
68 struct RStdConversionTable *next;
69 } RStdConversionTable;
73 static RConversionTable *conversionTable = NULL;
74 static RStdConversionTable *stdConversionTable = NULL;
77 static unsigned short*
78 computeTable(unsigned short mask)
80 RConversionTable *tmp = conversionTable;
81 int i;
83 while (tmp) {
84 if (tmp->index == mask)
85 break;
86 tmp = tmp->next;
89 if (tmp)
90 return tmp->table;
92 tmp = (RConversionTable *)malloc(sizeof(RConversionTable));
93 if (tmp == NULL)
94 return NULL;
96 for (i=0;i<256;i++)
97 tmp->table[i] = (i*mask + 0x7f)/0xff;
99 tmp->index = mask;
100 tmp->next = conversionTable;
101 conversionTable = tmp;
102 return tmp->table;
106 static unsigned int*
107 computeStdTable(unsigned int mult, unsigned int max)
109 RStdConversionTable *tmp = stdConversionTable;
110 unsigned int i;
112 while (tmp) {
113 if (tmp->mult == mult && tmp->max == max)
114 break;
115 tmp = tmp->next;
118 if (tmp)
119 return tmp->table;
121 tmp = (RStdConversionTable *)malloc(sizeof(RStdConversionTable));
122 if (tmp == NULL)
123 return NULL;
125 for (i=0; i<256; i++) {
126 tmp->table[i] = (i*max)/0xff * mult;
128 tmp->mult = mult;
129 tmp->max = max;
131 tmp->next = stdConversionTable;
132 stdConversionTable = tmp;
134 return tmp->table;
137 /***************************************************************************/
140 static void
141 convertTrueColor_generic(RXImage *ximg, RImage *image,
142 signed char *err, signed char *nerr,
143 const short *rtable,
144 const short *gtable,
145 const short *btable,
146 const int dr, const int dg, const int db,
147 const unsigned short roffs,
148 const unsigned short goffs,
149 const unsigned short boffs)
151 signed char *terr;
152 int x, y, r, g, b;
153 int pixel;
154 int rer, ger, ber;
155 unsigned char *ptr = image->data;
156 int channels = image->format == RRGBAFormat ? 4 : 3;
159 /* convert and dither the image to XImage */
160 for (y=0; y<image->height; y++) {
161 nerr[0] = 0;
162 nerr[1] = 0;
163 nerr[2] = 0;
164 for (x=0; x<image->width; x++, ptr+=channels) {
166 /* reduce pixel */
167 pixel = *ptr + err[x];
168 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
169 r = rtable[pixel];
170 /* calc error */
171 rer = pixel - r*dr;
173 /* reduce pixel */
174 pixel = *(ptr+1) + err[x+1];
175 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
176 g = gtable[pixel];
177 /* calc error */
178 ger = pixel - g*dg;
180 /* reduce pixel */
181 pixel = *(ptr+2) + err[x+2];
182 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
183 b = btable[pixel];
184 /* calc error */
185 ber = pixel - b*db;
188 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
189 XPutPixel(ximg->image, x, y, pixel);
191 /* distribute error */
192 r = (rer*3)/8;
193 g = (ger*3)/8;
194 b = (ber*3)/8;
195 /* x+1, y */
196 err[x+3*1]+=r;
197 err[x+1+3*1]+=g;
198 err[x+2+3*1]+=b;
199 /* x, y+1 */
200 nerr[x]+=r;
201 nerr[x+1]+=g;
202 nerr[x+2]+=b;
203 /* x+1, y+1 */
204 nerr[x+3*1]=rer-2*r;
205 nerr[x+1+3*1]=ger-2*g;
206 nerr[x+2+3*1]=ber-2*b;
208 /* skip to next line */
209 terr = err;
210 err = nerr;
211 nerr = terr;
218 static RXImage*
219 image2TrueColor(RContext *ctx, RImage *image)
221 RXImage *ximg;
222 unsigned short rmask, gmask, bmask;
223 unsigned short roffs, goffs, boffs;
224 unsigned short *rtable, *gtable, *btable;
225 int channels = (image->format == RRGBAFormat ? 4 : 3);
227 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
228 if (!ximg) {
229 return NULL;
232 roffs = ctx->red_offset;
233 goffs = ctx->green_offset;
234 boffs = ctx->blue_offset;
236 rmask = ctx->visual->red_mask >> roffs;
237 gmask = ctx->visual->green_mask >> goffs;
238 bmask = ctx->visual->blue_mask >> boffs;
240 rtable = computeTable(rmask);
241 gtable = computeTable(gmask);
242 btable = computeTable(bmask);
244 if (rtable==NULL || gtable==NULL || btable==NULL) {
245 RErrorCode = RERR_NOMEMORY;
246 RDestroyXImage(ctx, ximg);
247 return NULL;
251 #ifdef BENCH
252 cycle_bench(1);
253 #endif
255 if (ctx->attribs->render_mode==RBestMatchRendering) {
256 int ofs, r, g, b;
257 int x, y;
258 unsigned long pixel;
259 unsigned char *ptr = image->data;
261 /* fake match */
262 #ifdef DEBUG
263 puts("true color match");
264 #endif
265 if (rmask==0xff && gmask==0xff && bmask==0xff) {
266 for (y=0; y < image->height; y++) {
267 for (x=0; x < image->width; x++, ptr+=channels) {
268 /* reduce pixel */
269 pixel = (*(ptr)<<roffs) | (*(ptr+1)<<goffs) | (*(ptr+2)<<boffs);
270 XPutPixel(ximg->image, x, y, pixel);
273 } else {
274 for (y=0, ofs=0; y < image->height; y++) {
275 for (x=0; x < image->width; x++, ofs+=channels-3) {
276 /* reduce pixel */
277 r = rtable[ptr[ofs++]];
278 g = gtable[ptr[ofs++]];
279 b = btable[ptr[ofs++]];
280 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
281 XPutPixel(ximg->image, x, y, pixel);
285 } else {
286 /* dither */
287 const int dr=0xff/rmask;
288 const int dg=0xff/gmask;
289 const int db=0xff/bmask;
291 #ifdef DEBUG
292 puts("true color dither");
293 #endif
295 char *err;
296 char *nerr;
297 int ch = image->format == RRGBAFormat ? 4 : 3;
299 err = malloc(ch*(image->width+2));
300 nerr = malloc(ch*(image->width+2));
301 if (!err || !nerr) {
302 if (nerr)
303 free(nerr);
304 RErrorCode = RERR_NOMEMORY;
305 RDestroyXImage(ctx, ximg);
306 return NULL;
309 memset(err, 0, ch*(image->width+2));
310 memset(nerr, 0, ch*(image->width+2));
312 convertTrueColor_generic(ximg, image, err, nerr,
313 rtable, gtable, btable,
314 dr, dg, db, roffs, goffs, boffs);
315 free(err);
316 free(nerr);
321 #ifdef BENCH
322 cycle_bench(0);
323 #endif
325 return ximg;
329 /***************************************************************************/
331 static void
332 convertPseudoColor_to_8(RXImage *ximg, RImage *image,
333 signed char *err, signed char *nerr,
334 const short *rtable,
335 const short *gtable,
336 const short *btable,
337 const int dr, const int dg, const int db,
338 unsigned long *pixels,
339 int cpc)
341 signed char *terr;
342 int x, y, r, g, b;
343 int pixel;
344 int rer, ger, ber;
345 unsigned char *ptr = image->data;
346 unsigned char *optr = ximg->image->data;
347 int channels = image->format == RRGBAFormat ? 4 : 3;
348 int cpcpc = cpc*cpc;
350 /* convert and dither the image to XImage */
351 for (y=0; y<image->height; y++) {
352 nerr[0] = 0;
353 nerr[1] = 0;
354 nerr[2] = 0;
355 for (x=0; x<image->width*3; x+=3, ptr+=channels) {
357 /* reduce pixel */
358 pixel = *ptr + err[x];
359 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
360 r = rtable[pixel];
361 /* calc error */
362 rer = pixel - r*dr;
364 /* reduce pixel */
365 pixel = *(ptr+1) + err[x+1];
366 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
367 g = gtable[pixel];
368 /* calc error */
369 ger = pixel - g*dg;
371 /* reduce pixel */
372 pixel = *(ptr+2) + err[x+2];
373 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
374 b = btable[pixel];
375 /* calc error */
376 ber = pixel - b*db;
378 *optr++ = pixels[r*cpcpc + g*cpc + b];
380 /* distribute error */
381 r = (rer*3)/8;
382 g = (ger*3)/8;
383 b = (ber*3)/8;
385 /* x+1, y */
386 err[x+3*1]+=r;
387 err[x+1+3*1]+=g;
388 err[x+2+3*1]+=b;
389 /* x, y+1 */
390 nerr[x]+=r;
391 nerr[x+1]+=g;
392 nerr[x+2]+=b;
393 /* x+1, y+1 */
394 nerr[x+3*1]=rer-2*r;
395 nerr[x+1+3*1]=ger-2*g;
396 nerr[x+2+3*1]=ber-2*b;
398 /* skip to next line */
399 terr = err;
400 err = nerr;
401 nerr = terr;
403 optr += ximg->image->bytes_per_line - image->width;
409 static RXImage*
410 image2PseudoColor(RContext *ctx, RImage *image)
412 RXImage *ximg;
413 register int x, y, r, g, b;
414 unsigned char *ptr;
415 unsigned long pixel;
416 const int cpc=ctx->attribs->colors_per_channel;
417 const unsigned short rmask = cpc-1; /* different sizes could be used */
418 const unsigned short gmask = rmask; /* for r,g,b */
419 const unsigned short bmask = rmask;
420 unsigned short *rtable, *gtable, *btable;
421 const int cpccpc = cpc*cpc;
422 int channels = image->format == RRGBAFormat ? 4 : 3;
424 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
425 if (!ximg) {
426 return NULL;
429 ptr = image->data;
431 /* Tables are same at the moment because rmask==gmask==bmask. */
432 rtable = computeTable(rmask);
433 gtable = computeTable(gmask);
434 btable = computeTable(bmask);
436 if (rtable==NULL || gtable==NULL || btable==NULL) {
437 RErrorCode = RERR_NOMEMORY;
438 RDestroyXImage(ctx, ximg);
439 return NULL;
442 if (ctx->attribs->render_mode == RBestMatchRendering) {
443 /* fake match */
444 #ifdef DEBUG
445 printf("pseudo color match with %d colors per channel\n", cpc);
446 #endif
447 for (y=0; y<image->height; y++) {
448 for (x=0; x<image->width; x++, ptr+=channels-3) {
449 /* reduce pixel */
450 r = rtable[*ptr++];
451 g = gtable[*ptr++];
452 b = btable[*ptr++];
453 pixel = r*cpccpc + g*cpc + b;
454 /*data[ofs] = ctx->colors[pixel].pixel;*/
455 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
458 } else {
459 /* dither */
460 char *err;
461 char *nerr;
462 const int dr=0xff/rmask;
463 const int dg=0xff/gmask;
464 const int db=0xff/bmask;
467 #ifdef DEBUG
468 printf("pseudo color dithering with %d colors per channel\n", cpc);
469 #endif
470 err = malloc(4*(image->width+3));
471 nerr = malloc(4*(image->width+3));
472 if (!err || !nerr) {
473 if (nerr)
474 free(nerr);
475 RErrorCode = RERR_NOMEMORY;
476 RDestroyXImage(ctx, ximg);
477 return NULL;
479 memset(err, 0, 4*(image->width+3));
480 memset(nerr, 0, 4*(image->width+3));
482 convertPseudoColor_to_8(ximg, image, err+4, nerr+4,
483 rtable, gtable, btable,
484 dr, dg, db, ctx->pixels, cpc);
486 free(err);
487 free(nerr);
490 return ximg;
495 * For standard colormap
497 static RXImage*
498 image2StandardPseudoColor(RContext *ctx, RImage *image)
500 RXImage *ximg;
501 register int x, y, r, g, b;
502 unsigned char *ptr;
503 unsigned long pixel;
504 unsigned char *data;
505 unsigned int *rtable, *gtable, *btable;
506 unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
507 int channels = image->format == RRGBAFormat ? 4 : 3;
508 /*register unsigned char maxrgb = 0xff;*/
510 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
511 if (!ximg) {
512 return NULL;
515 ptr = image->data;
517 data = (unsigned char *)ximg->image->data;
520 rtable = computeStdTable(ctx->std_rgb_map->red_mult,
521 ctx->std_rgb_map->red_max);
523 gtable = computeStdTable(ctx->std_rgb_map->green_mult,
524 ctx->std_rgb_map->green_max);
526 btable = computeStdTable(ctx->std_rgb_map->blue_mult,
527 ctx->std_rgb_map->blue_max);
529 if (rtable==NULL || gtable==NULL || btable==NULL) {
530 RErrorCode = RERR_NOMEMORY;
531 RDestroyXImage(ctx, ximg);
532 return NULL;
536 if (ctx->attribs->render_mode == RBestMatchRendering) {
537 for (y=0; y<image->height; y++) {
538 for (x=0; x<image->width; x++, ptr+=channels) {
539 /* reduce pixel */
540 pixel = (rtable[*ptr] + gtable[*(ptr+1)]
541 + btable[*(ptr+2)] + base_pixel) & 0xffffffff;
543 XPutPixel(ximg->image, x, y, pixel);
546 } else {
547 /* dither */
548 signed short *err, *nerr;
549 signed short *terr;
550 int rer, ger, ber;
551 int x1, ofs;
553 #ifdef DEBUG
554 printf("pseudo color dithering with %d colors per channel\n", cpc);
555 #endif
556 err = (short*)malloc(3*(image->width+2)*sizeof(short));
557 nerr = (short*)malloc(3*(image->width+2)*sizeof(short));
558 if (!err || !nerr) {
559 if (err)
560 free(err);
561 if (nerr)
562 free(nerr);
563 RErrorCode = RERR_NOMEMORY;
564 RDestroyXImage(ctx, ximg);
565 return NULL;
567 for (x=0, x1=0; x<image->width*3; x1+=channels-3) {
568 err[x++] = ptr[x1++];
569 err[x++] = ptr[x1++];
570 err[x++] = ptr[x1++];
572 err[x] = err[x+1] = err[x+2] = 0;
573 /* convert and dither the image to XImage */
574 for (y=0, ofs=0; y<image->height; y++) {
575 if (y<image->height-1) {
576 int x1;
577 for (x=0, x1=(y+1)*image->width*channels;
578 x<image->width*3;
579 x1+=channels-3) {
580 nerr[x++] = ptr[x1++];
581 nerr[x++] = ptr[x1++];
582 nerr[x++] = ptr[x1++];
584 /* last column */
585 x1-=channels;
586 nerr[x++] = ptr[x1++];
587 nerr[x++] = ptr[x1++];
588 nerr[x++] = ptr[x1++];
590 for (x=0; x<image->width*3; x+=3, ofs++) {
591 /* reduce pixel */
592 if (err[x]>0xff) err[x]=0xff; else if (err[x]<0) err[x]=0;
593 if (err[x+1]>0xff) err[x+1]=0xff; else if (err[x+1]<0) err[x+1]=0;
594 if (err[x+2]>0xff) err[x+2]=0xff; else if (err[x+2]<0) err[x+2]=0;
596 r = rtable[err[x]];
597 g = gtable[err[x+1]];
598 b = btable[err[x+2]];
600 pixel = r + g + b;
602 data[ofs] = base_pixel + pixel;
604 /* calc error */
605 rer = err[x] - (ctx->colors[pixel].red>>8);
606 ger = err[x+1] - (ctx->colors[pixel].green>>8);
607 ber = err[x+2] - (ctx->colors[pixel].blue>>8);
609 /* distribute error */
610 err[x+3*1]+=(rer*7)/16;
611 err[x+1+3*1]+=(ger*7)/16;
612 err[x+2+3*1]+=(ber*7)/16;
614 nerr[x]+=(rer*5)/16;
615 nerr[x+1]+=(ger*5)/16;
616 nerr[x+2]+=(ber*5)/16;
618 if (x>0) {
619 nerr[x-3*1]+=(rer*3)/16;
620 nerr[x-3*1+1]+=(ger*3)/16;
621 nerr[x-3*1+2]+=(ber*3)/16;
624 nerr[x+3*1]+=rer/16;
625 nerr[x+1+3*1]+=ger/16;
626 nerr[x+2+3*1]+=ber/16;
628 /* skip to next line */
629 terr = err;
630 err = nerr;
631 nerr = terr;
633 ofs += ximg->image->bytes_per_line - image->width;
635 free(err);
636 free(nerr);
638 ximg->image->data = (char*)data;
640 return ximg;
645 static RXImage*
646 image2GrayScale(RContext *ctx, RImage *image)
648 RXImage *ximg;
649 register int x, y, g;
650 unsigned char *ptr;
651 const int cpc=ctx->attribs->colors_per_channel;
652 unsigned short gmask;
653 unsigned short *table;
654 unsigned char *data;
655 int channels = image->format == RRGBAFormat ? 4 : 3;
657 /*register unsigned char maxrgb = 0xff;*/
659 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
660 if (!ximg) {
661 return NULL;
664 ptr = image->data;
666 data = (unsigned char *)ximg->image->data;
668 if (ctx->vclass == StaticGray)
669 gmask = (1<<ctx->depth) - 1; /* use all grays */
670 else
671 gmask = cpc*cpc*cpc-1;
673 table = computeTable(gmask);
675 if (table==NULL) {
676 RErrorCode = RERR_NOMEMORY;
677 RDestroyXImage(ctx, ximg);
678 return NULL;
681 if (ctx->attribs->render_mode == RBestMatchRendering) {
682 /* fake match */
683 #ifdef DEBUG
684 printf("grayscale match with %d colors per channel\n", cpc);
685 #endif
686 for (y=0; y<image->height; y++) {
687 for (x=0; x<image->width; x++) {
688 /* reduce pixel */
689 g = table[(*ptr * 30 + *(ptr+1) * 59 + *(ptr+2) * 11)/100];
690 ptr += 3;
691 /*data[ofs] = ctx->colors[g].pixel;*/
692 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
695 } else {
696 /* dither */
697 short *gerr;
698 short *ngerr;
699 short *terr;
700 int ger;
701 const int dg=0xff/gmask;
703 #ifdef DEBUG
704 printf("grayscale dither with %d colors per channel\n", cpc);
705 #endif
706 gerr = (short*)malloc((image->width+2)*sizeof(short));
707 ngerr = (short*)malloc((image->width+2)*sizeof(short));
708 if (!gerr || !ngerr) {
709 if (ngerr)
710 free(ngerr);
711 RErrorCode = RERR_NOMEMORY;
712 RDestroyXImage(ctx, ximg);
713 return NULL;
715 for (x=0; x<image->width; x++) {
716 gerr[x] = (ptr[x*3]*30 + ptr[x*3+1]*59 + ptr[x*3+2]*11)/100;
718 gerr[x] = 0;
719 /* convert and dither the image to XImage */
720 for (y=0; y<image->height; y++) {
721 if (y<image->height-1) {
722 int x1;
723 for (x=0, x1=(y+1)*image->width*3; x<image->width; x1+=channels) {
724 ngerr[x] = (ptr[x1]*30 + ptr[x1+1]*59 + ptr[x1+2]*11)/100;
726 /* last column */
727 x1-=channels;
728 ngerr[x] = (ptr[x1]*30 + ptr[x1+1]*59 + ptr[x1+2]*11)/100;
730 for (x=0; x<image->width; x++) {
731 /* reduce pixel */
732 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
734 g = table[gerr[x]];
736 /*data[ofs] = ctx->colors[g].pixel;*/
737 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
738 /* calc error */
739 ger = gerr[x] - g*dg;
741 /* distribute error */
742 g = (ger*3)/8;
743 /* x+1, y */
744 gerr[x+1]+=g;
745 /* x, y+1 */
746 ngerr[x]+=g;
747 /* x+1, y+1 */
748 ngerr[x+1]+=ger-2*g;
750 /* skip to next line */
751 terr = gerr;
752 gerr = ngerr;
753 ngerr = terr;
755 free(gerr);
756 free(ngerr);
758 ximg->image->data = (char*)data;
760 return ximg;
764 static RXImage*
765 image2Bitmap(RContext *ctx, RImage *image, int threshold)
767 RXImage *ximg;
768 unsigned char *alpha;
769 int x, y;
771 ximg = RCreateXImage(ctx, 1, image->width, image->height);
772 if (!ximg) {
773 return NULL;
775 alpha = image->data+3;
777 for (y = 0; y < image->height; y++) {
778 for (x = 0; x < image->width; x++) {
779 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
780 alpha+=4;
784 return ximg;
788 #ifdef HAVE_HERMES
790 static RXImage*
791 hermesConvert(RContext *context, RImage *image)
793 HermesFormat source;
794 HermesFormat dest;
795 RXImage *ximage;
798 ximage = RCreateXImage(context, context->depth,
799 image->width, image->height);
800 if (!ximage) {
801 return NULL;
804 if (HAS_ALPHA(image)) {
805 if (ximage->image->byte_order==LSBFirst) {
806 source.r = 0x000000ff;
807 source.g = 0x0000ff00;
808 source.b = 0x00ff0000;
809 source.a = 0xff000000;
810 } else {
811 source.r = 0xff000000;
812 source.g = 0x00ff0000;
813 source.b = 0x0000ff00;
814 source.a = 0x000000ff;
816 source.bits = 32;
817 } else {
818 if (ximage->image->byte_order==LSBFirst) {
819 source.r = 0x0000ff;
820 source.g = 0x00ff00;
821 source.b = 0xff0000;
822 } else {
823 source.r = 0xff0000;
824 source.g = 0x00ff00;
825 source.b = 0x0000ff;
827 source.a = 0x000000;
828 source.bits = 24;
831 source.indexed = 0;
832 source.has_colorkey = 0;
834 dest.r = context->visual->red_mask;
835 dest.g = context->visual->green_mask;
836 dest.b = context->visual->blue_mask;
837 dest.a = 0;
838 dest.bits = ximage->image->bits_per_pixel;
839 if (context->vclass == TrueColor)
840 dest.indexed = 0;
841 else
842 dest.indexed = 1;
843 dest.has_colorkey = 0;
845 /*printf("source r=0x%x, g=0x%x, b=0x%x, a=0x%x, b=%d, i=%d, c=%d\n",
846 source.r, source.g, source.b, source.a,
847 source.bits, source.indexed, source.has_colorkey);
848 printf("dest r=0x%x, g=0x%x, b=0x%x, a=0x%x, b=%d, i=%d, c=%d\n",
849 dest.r, dest.g, dest.b, dest.a,
850 dest.bits, dest.indexed, dest.has_colorkey);
853 Hermes_ConverterRequest(context->hermes_data->converter, &source, &dest);
855 Hermes_ConverterPalette(context->hermes_data->converter,
856 context->hermes_data->palette, 0);
858 Hermes_ConverterCopy(context->hermes_data->converter,
859 image->data, 0, 0, image->width, image->height,
860 image->width * (image->format == RRGBFormat ? 3 : 4),
861 ximage->image->data, 0, 0,
862 image->width, image->height,
863 ximage->image->bytes_per_line);
865 return ximage;
867 #endif /* HAVE_HERMES */
870 int
871 RConvertImage(RContext *context, RImage *image, Pixmap *pixmap)
873 RXImage *ximg=NULL;
874 #ifdef XSHM
875 Pixmap tmp;
876 #endif
878 assert(context!=NULL);
879 assert(image!=NULL);
880 assert(pixmap!=NULL);
882 #ifdef HAVE_HERMES
883 ximg = hermesConvert(context, image);
884 #else /* !HAVE_HERMES */
885 /* clear error message */
886 switch (context->vclass) {
887 case TrueColor:
888 ximg = image2TrueColor(context, image);
889 break;
891 case PseudoColor:
892 case StaticColor:
893 #ifdef BENCH
894 cycle_bench(1);
895 #endif
896 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
897 ximg = image2StandardPseudoColor(context, image);
898 else
899 ximg = image2PseudoColor(context, image);
900 #ifdef BENCH
901 cycle_bench(0);
902 #endif
903 break;
905 case GrayScale:
906 case StaticGray:
907 ximg = image2GrayScale(context, image);
908 break;
910 #endif /* !HAVE_HERMES */
912 if (!ximg) {
913 return False;
917 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width,
918 image->height, context->depth);
920 #ifdef XSHM
921 if (context->flags.use_shared_pixmap && ximg->is_shared)
922 tmp = R_CreateXImageMappedPixmap(context, ximg);
923 else
924 tmp = None;
925 if (tmp) {
927 * We have to copy the shm Pixmap into a normal Pixmap because
928 * otherwise, we would have to control when Pixmaps are freed so
929 * that we can detach their shm segments. This is a problem if the
930 * program crash, leaving stale shared memory segments in the
931 * system (lots of them). But with some work, we can optimize
932 * things and remove this XCopyArea. This will require
933 * explicitly freeing all pixmaps when exiting or restarting
934 * wmaker.
936 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0,
937 image->width, image->height, 0, 0);
938 XFreePixmap(context->dpy, tmp);
939 } else {
940 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
941 image->width, image->height);
943 #else /* !XSHM */
944 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
945 image->width, image->height);
946 #endif /* !XSHM */
948 RDestroyXImage(context, ximg);
950 return True;
954 int
955 RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap,
956 Pixmap *mask, int threshold)
958 GC gc;
959 XGCValues gcv;
960 RXImage *ximg=NULL;
962 assert(context!=NULL);
963 assert(image!=NULL);
964 assert(pixmap!=NULL);
965 assert(mask!=NULL);
967 if (!RConvertImage(context, image, pixmap))
968 return False;
970 if (image->format==RRGBFormat) {
971 *mask = None;
972 return True;
975 ximg = image2Bitmap(context, image, threshold);
977 if (!ximg) {
978 return False;
980 *mask = XCreatePixmap(context->dpy, context->drawable, image->width,
981 image->height, 1);
982 gcv.foreground = context->black;
983 gcv.background = context->white;
984 gcv.graphics_exposures = False;
985 gc = XCreateGC(context->dpy, *mask, GCForeground|GCBackground
986 |GCGraphicsExposures, &gcv);
987 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0,
988 image->width, image->height);
989 RDestroyXImage(context, ximg);
991 return True;
995 Bool
996 RGetClosestXColor(RContext *context, RColor *color, XColor *retColor)
998 if (context->vclass == TrueColor) {
999 unsigned short rmask, gmask, bmask;
1000 unsigned short roffs, goffs, boffs;
1001 unsigned short *rtable, *gtable, *btable;
1003 roffs = context->red_offset;
1004 goffs = context->green_offset;
1005 boffs = context->blue_offset;
1007 rmask = context->visual->red_mask >> roffs;
1008 gmask = context->visual->green_mask >> goffs;
1009 bmask = context->visual->blue_mask >> boffs;
1011 rtable = computeTable(rmask);
1012 gtable = computeTable(gmask);
1013 btable = computeTable(bmask);
1015 retColor->pixel = (rtable[color->red]<<roffs) |
1016 (gtable[color->green]<<goffs) | (btable[color->blue]<<boffs);
1018 retColor->red = color->red << 8;
1019 retColor->green = color->green << 8;
1020 retColor->blue = color->blue << 8;
1021 retColor->flags = DoRed|DoGreen|DoBlue;
1023 } else if (context->vclass == PseudoColor
1024 || context->vclass == StaticColor) {
1026 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
1027 unsigned int *rtable, *gtable, *btable;
1029 rtable = computeStdTable(context->std_rgb_map->red_mult,
1030 context->std_rgb_map->red_max);
1032 gtable = computeStdTable(context->std_rgb_map->green_mult,
1033 context->std_rgb_map->green_max);
1035 btable = computeStdTable(context->std_rgb_map->blue_mult,
1036 context->std_rgb_map->blue_max);
1038 if (rtable==NULL || gtable==NULL || btable==NULL) {
1039 RErrorCode = RERR_NOMEMORY;
1040 return False;
1043 retColor->pixel = (rtable[color->red]
1044 + gtable[color->green]
1045 + btable[color->blue]
1046 + context->std_rgb_map->base_pixel) & 0xffffffff;
1047 retColor->red = color->red<<8;
1048 retColor->green = color->green<<8;
1049 retColor->blue = color->blue<<8;
1050 retColor->flags = DoRed|DoGreen|DoBlue;
1052 } else {
1053 const int cpc=context->attribs->colors_per_channel;
1054 const unsigned short rmask = cpc-1; /* different sizes could be used */
1055 const unsigned short gmask = rmask; /* for r,g,b */
1056 const unsigned short bmask = rmask;
1057 unsigned short *rtable, *gtable, *btable;
1058 const int cpccpc = cpc*cpc;
1059 int index;
1061 rtable = computeTable(rmask);
1062 gtable = computeTable(gmask);
1063 btable = computeTable(bmask);
1065 if (rtable==NULL || gtable==NULL || btable==NULL) {
1066 RErrorCode = RERR_NOMEMORY;
1067 return False;
1069 index = rtable[color->red]*cpccpc + gtable[color->green]*cpc
1070 + btable[color->blue];
1071 *retColor = context->colors[index];
1074 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
1076 const int cpc = context->attribs->colors_per_channel;
1077 unsigned short gmask;
1078 unsigned short *table;
1079 int index;
1081 if (context->vclass == StaticGray)
1082 gmask = (1<<context->depth) - 1; /* use all grays */
1083 else
1084 gmask = cpc*cpc*cpc-1;
1086 table = computeTable(gmask);
1087 if (!table)
1088 return False;
1090 index = table[(color->red*30 + color->green*59 + color->blue*11)/100];
1092 *retColor = context->colors[index];
1093 } else {
1094 RErrorCode = RERR_INTERNAL;
1095 return False;
1098 return True;