fixed artifact pattern left in TrueColor dithering code (visible with
[wmaker-crm.git] / wrlib / convert.c
blob8577b600031e65e43212d7e0b109468c6d80f4d0
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);
158 /* convert and dither the image to XImage */
159 for (y=0; y<image->height; y++) {
160 nerr[0] = 0;
161 nerr[1] = 0;
162 nerr[2] = 0;
163 for (x=0; x<image->width; x++, ptr+=channels) {
165 /* reduce pixel */
166 pixel = *ptr + err[x];
167 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
168 r = rtable[pixel];
169 /* calc error */
170 rer = pixel - r*dr;
172 /* reduce pixel */
173 pixel = *(ptr+1) + err[x+1];
174 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
175 g = gtable[pixel];
176 /* calc error */
177 ger = pixel - g*dg;
179 /* reduce pixel */
180 pixel = *(ptr+2) + err[x+2];
181 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
182 b = btable[pixel];
183 /* calc error */
184 ber = pixel - b*db;
187 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
188 XPutPixel(ximg->image, x, y, pixel);
190 /* distribute error */
191 r = (rer*3)/8;
192 g = (ger*3)/8;
193 b = (ber*3)/8;
194 /* x+1, y */
195 err[x+3*1]+=r;
196 err[x+1+3*1]+=g;
197 err[x+2+3*1]+=b;
198 /* x, y+1 */
199 nerr[x]+=r;
200 nerr[x+1]+=g;
201 nerr[x+2]+=b;
202 /* x+1, y+1 */
203 nerr[x+3*1]=rer-2*r;
204 nerr[x+1+3*1]=ger-2*g;
205 nerr[x+2+3*1]=ber-2*b;
207 /* skip to next line */
208 terr = err;
209 err = nerr;
210 nerr = terr;
213 /* redither the 1st line to distribute error better */
214 ptr=image->data;
215 y=0;
216 nerr[0] = 0;
217 nerr[1] = 0;
218 nerr[2] = 0;
219 for (x=0; x<image->width; x++, ptr+=channels) {
221 /* reduce pixel */
222 pixel = *ptr + err[x];
223 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
224 r = rtable[pixel];
225 /* calc error */
226 rer = pixel - r*dr;
228 /* reduce pixel */
229 pixel = *(ptr+1) + err[x+1];
230 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
231 g = gtable[pixel];
232 /* calc error */
233 ger = pixel - g*dg;
235 /* reduce pixel */
236 pixel = *(ptr+2) + err[x+2];
237 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
238 b = btable[pixel];
239 /* calc error */
240 ber = pixel - b*db;
243 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
244 XPutPixel(ximg->image, x, y, pixel);
246 /* distribute error */
247 r = (rer*3)/8;
248 g = (ger*3)/8;
249 b = (ber*3)/8;
250 /* x+1, y */
251 err[x+3*1]+=r;
252 err[x+1+3*1]+=g;
253 err[x+2+3*1]+=b;
254 /* x, y+1 */
255 nerr[x]+=r;
256 nerr[x+1]+=g;
257 nerr[x+2]+=b;
258 /* x+1, y+1 */
259 nerr[x+3*1]=rer-2*r;
260 nerr[x+1+3*1]=ger-2*g;
261 nerr[x+2+3*1]=ber-2*b;
268 static RXImage*
269 image2TrueColor(RContext *ctx, RImage *image)
271 RXImage *ximg;
272 unsigned short rmask, gmask, bmask;
273 unsigned short roffs, goffs, boffs;
274 unsigned short *rtable, *gtable, *btable;
275 int channels = (image->format == RRGBAFormat ? 4 : 3);
277 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
278 if (!ximg) {
279 return NULL;
282 roffs = ctx->red_offset;
283 goffs = ctx->green_offset;
284 boffs = ctx->blue_offset;
286 rmask = ctx->visual->red_mask >> roffs;
287 gmask = ctx->visual->green_mask >> goffs;
288 bmask = ctx->visual->blue_mask >> boffs;
290 rtable = computeTable(rmask);
291 gtable = computeTable(gmask);
292 btable = computeTable(bmask);
294 if (rtable==NULL || gtable==NULL || btable==NULL) {
295 RErrorCode = RERR_NOMEMORY;
296 RDestroyXImage(ctx, ximg);
297 return NULL;
301 #ifdef BENCH
302 cycle_bench(1);
303 #endif
305 if (ctx->attribs->render_mode==RBestMatchRendering) {
306 int ofs, r, g, b;
307 int x, y;
308 unsigned long pixel;
309 unsigned char *ptr = image->data;
311 /* fake match */
312 #ifdef DEBUG
313 puts("true color match");
314 #endif
315 if (rmask==0xff && gmask==0xff && bmask==0xff) {
316 for (y=0; y < image->height; y++) {
317 for (x=0; x < image->width; x++, ptr+=channels) {
318 /* reduce pixel */
319 pixel = (*(ptr)<<roffs) | (*(ptr+1)<<goffs) | (*(ptr+2)<<boffs);
320 XPutPixel(ximg->image, x, y, pixel);
323 } else {
324 for (y=0, ofs=0; y < image->height; y++) {
325 for (x=0; x < image->width; x++, ofs+=channels-3) {
326 /* reduce pixel */
327 r = rtable[ptr[ofs++]];
328 g = gtable[ptr[ofs++]];
329 b = btable[ptr[ofs++]];
330 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
331 XPutPixel(ximg->image, x, y, pixel);
335 } else {
336 /* dither */
337 const int dr=0xff/rmask;
338 const int dg=0xff/gmask;
339 const int db=0xff/bmask;
341 #ifdef DEBUG
342 puts("true color dither");
343 #endif
345 char *err;
346 char *nerr;
347 int ch = (image->format == RRGBAFormat ? 4 : 3);
349 err = malloc(ch*(image->width+2));
350 nerr = malloc(ch*(image->width+2));
351 if (!err || !nerr) {
352 if (nerr)
353 free(nerr);
354 RErrorCode = RERR_NOMEMORY;
355 RDestroyXImage(ctx, ximg);
356 return NULL;
359 memset(err, 0, ch*(image->width+2));
360 memset(nerr, 0, ch*(image->width+2));
362 convertTrueColor_generic(ximg, image, err, nerr,
363 rtable, gtable, btable,
364 dr, dg, db, roffs, goffs, boffs);
365 free(err);
366 free(nerr);
371 #ifdef BENCH
372 cycle_bench(0);
373 #endif
375 return ximg;
379 /***************************************************************************/
381 static void
382 convertPseudoColor_to_8(RXImage *ximg, RImage *image,
383 signed char *err, signed char *nerr,
384 const short *rtable,
385 const short *gtable,
386 const short *btable,
387 const int dr, const int dg, const int db,
388 unsigned long *pixels,
389 int cpc)
391 signed char *terr;
392 int x, y, r, g, b;
393 int pixel;
394 int rer, ger, ber;
395 unsigned char *ptr = image->data;
396 unsigned char *optr = ximg->image->data;
397 int channels = (image->format == RRGBAFormat ? 4 : 3);
398 int cpcpc = cpc*cpc;
400 /* convert and dither the image to XImage */
401 for (y=0; y<image->height; y++) {
402 nerr[0] = 0;
403 nerr[1] = 0;
404 nerr[2] = 0;
405 for (x=0; x<image->width*3; x+=3, ptr+=channels) {
407 /* reduce pixel */
408 pixel = *ptr + err[x];
409 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
410 r = rtable[pixel];
411 /* calc error */
412 rer = pixel - r*dr;
414 /* reduce pixel */
415 pixel = *(ptr+1) + err[x+1];
416 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
417 g = gtable[pixel];
418 /* calc error */
419 ger = pixel - g*dg;
421 /* reduce pixel */
422 pixel = *(ptr+2) + err[x+2];
423 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
424 b = btable[pixel];
425 /* calc error */
426 ber = pixel - b*db;
428 *optr++ = pixels[r*cpcpc + g*cpc + b];
430 /* distribute error */
431 r = (rer*3)/8;
432 g = (ger*3)/8;
433 b = (ber*3)/8;
435 /* x+1, y */
436 err[x+3*1]+=r;
437 err[x+1+3*1]+=g;
438 err[x+2+3*1]+=b;
439 /* x, y+1 */
440 nerr[x]+=r;
441 nerr[x+1]+=g;
442 nerr[x+2]+=b;
443 /* x+1, y+1 */
444 nerr[x+3*1]=rer-2*r;
445 nerr[x+1+3*1]=ger-2*g;
446 nerr[x+2+3*1]=ber-2*b;
448 /* skip to next line */
449 terr = err;
450 err = nerr;
451 nerr = terr;
453 optr += ximg->image->bytes_per_line - image->width;
459 static RXImage*
460 image2PseudoColor(RContext *ctx, RImage *image)
462 RXImage *ximg;
463 register int x, y, r, g, b;
464 unsigned char *ptr;
465 unsigned long pixel;
466 const int cpc=ctx->attribs->colors_per_channel;
467 const unsigned short rmask = cpc-1; /* different sizes could be used */
468 const unsigned short gmask = rmask; /* for r,g,b */
469 const unsigned short bmask = rmask;
470 unsigned short *rtable, *gtable, *btable;
471 const int cpccpc = cpc*cpc;
472 int channels = (image->format == RRGBAFormat ? 4 : 3);
474 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
475 if (!ximg) {
476 return NULL;
479 ptr = image->data;
481 /* Tables are same at the moment because rmask==gmask==bmask. */
482 rtable = computeTable(rmask);
483 gtable = computeTable(gmask);
484 btable = computeTable(bmask);
486 if (rtable==NULL || gtable==NULL || btable==NULL) {
487 RErrorCode = RERR_NOMEMORY;
488 RDestroyXImage(ctx, ximg);
489 return NULL;
492 if (ctx->attribs->render_mode == RBestMatchRendering) {
493 /* fake match */
494 #ifdef DEBUG
495 printf("pseudo color match with %d colors per channel\n", cpc);
496 #endif
497 for (y=0; y<image->height; y++) {
498 for (x=0; x<image->width; x++, ptr+=channels-3) {
499 /* reduce pixel */
500 r = rtable[*ptr++];
501 g = gtable[*ptr++];
502 b = btable[*ptr++];
503 pixel = r*cpccpc + g*cpc + b;
504 /*data[ofs] = ctx->colors[pixel].pixel;*/
505 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
508 } else {
509 /* dither */
510 char *err;
511 char *nerr;
512 const int dr=0xff/rmask;
513 const int dg=0xff/gmask;
514 const int db=0xff/bmask;
517 #ifdef DEBUG
518 printf("pseudo color dithering with %d colors per channel\n", cpc);
519 #endif
520 err = malloc(4*(image->width+3));
521 nerr = malloc(4*(image->width+3));
522 if (!err || !nerr) {
523 if (nerr)
524 free(nerr);
525 RErrorCode = RERR_NOMEMORY;
526 RDestroyXImage(ctx, ximg);
527 return NULL;
529 memset(err, 0, 4*(image->width+3));
530 memset(nerr, 0, 4*(image->width+3));
532 convertPseudoColor_to_8(ximg, image, err+4, nerr+4,
533 rtable, gtable, btable,
534 dr, dg, db, ctx->pixels, cpc);
536 free(err);
537 free(nerr);
540 return ximg;
545 * For standard colormap
547 static RXImage*
548 image2StandardPseudoColor(RContext *ctx, RImage *image)
550 RXImage *ximg;
551 register int x, y, r, g, b;
552 unsigned char *ptr;
553 unsigned long pixel;
554 unsigned char *data;
555 unsigned int *rtable, *gtable, *btable;
556 unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
557 int channels = (image->format == RRGBAFormat ? 4 : 3);
560 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
561 if (!ximg) {
562 return NULL;
565 ptr = image->data;
567 data = (unsigned char *)ximg->image->data;
570 rtable = computeStdTable(ctx->std_rgb_map->red_mult,
571 ctx->std_rgb_map->red_max);
573 gtable = computeStdTable(ctx->std_rgb_map->green_mult,
574 ctx->std_rgb_map->green_max);
576 btable = computeStdTable(ctx->std_rgb_map->blue_mult,
577 ctx->std_rgb_map->blue_max);
579 if (rtable==NULL || gtable==NULL || btable==NULL) {
580 RErrorCode = RERR_NOMEMORY;
581 RDestroyXImage(ctx, ximg);
582 return NULL;
586 if (ctx->attribs->render_mode == RBestMatchRendering) {
587 for (y=0; y<image->height; y++) {
588 for (x=0; x<image->width; x++, ptr+=channels) {
589 /* reduce pixel */
590 pixel = (rtable[*ptr] + gtable[*(ptr+1)]
591 + btable[*(ptr+2)] + base_pixel) & 0xffffffff;
593 XPutPixel(ximg->image, x, y, pixel);
596 } else {
597 /* dither */
598 signed short *err, *nerr;
599 signed short *terr;
600 int rer, ger, ber;
601 int x1, ofs;
603 #ifdef DEBUG
604 printf("pseudo color dithering with %d colors per channel\n", cpc);
605 #endif
606 err = (short*)malloc(3*(image->width+2)*sizeof(short));
607 nerr = (short*)malloc(3*(image->width+2)*sizeof(short));
608 if (!err || !nerr) {
609 if (err)
610 free(err);
611 if (nerr)
612 free(nerr);
613 RErrorCode = RERR_NOMEMORY;
614 RDestroyXImage(ctx, ximg);
615 return NULL;
617 for (x=0, x1=0; x<image->width*3; x1+=channels-3) {
618 err[x++] = ptr[x1++];
619 err[x++] = ptr[x1++];
620 err[x++] = ptr[x1++];
622 err[x] = err[x+1] = err[x+2] = 0;
623 /* convert and dither the image to XImage */
624 for (y=0, ofs=0; y<image->height; y++) {
625 if (y<image->height-1) {
626 int x1;
627 for (x=0, x1=(y+1)*image->width*channels;
628 x<image->width*3;
629 x1+=channels-3) {
630 nerr[x++] = ptr[x1++];
631 nerr[x++] = ptr[x1++];
632 nerr[x++] = ptr[x1++];
634 /* last column */
635 x1-=channels;
636 nerr[x++] = ptr[x1++];
637 nerr[x++] = ptr[x1++];
638 nerr[x++] = ptr[x1++];
640 for (x=0; x<image->width*3; x+=3, ofs++) {
641 /* reduce pixel */
642 if (err[x]>0xff) err[x]=0xff; else if (err[x]<0) err[x]=0;
643 if (err[x+1]>0xff) err[x+1]=0xff; else if (err[x+1]<0) err[x+1]=0;
644 if (err[x+2]>0xff) err[x+2]=0xff; else if (err[x+2]<0) err[x+2]=0;
646 r = rtable[err[x]];
647 g = gtable[err[x+1]];
648 b = btable[err[x+2]];
650 pixel = r + g + b;
652 data[ofs] = base_pixel + pixel;
654 /* calc error */
655 rer = err[x] - (ctx->colors[pixel].red>>8);
656 ger = err[x+1] - (ctx->colors[pixel].green>>8);
657 ber = err[x+2] - (ctx->colors[pixel].blue>>8);
659 /* distribute error */
660 err[x+3*1]+=(rer*7)/16;
661 err[x+1+3*1]+=(ger*7)/16;
662 err[x+2+3*1]+=(ber*7)/16;
664 nerr[x]+=(rer*5)/16;
665 nerr[x+1]+=(ger*5)/16;
666 nerr[x+2]+=(ber*5)/16;
668 if (x>0) {
669 nerr[x-3*1]+=(rer*3)/16;
670 nerr[x-3*1+1]+=(ger*3)/16;
671 nerr[x-3*1+2]+=(ber*3)/16;
674 nerr[x+3*1]+=rer/16;
675 nerr[x+1+3*1]+=ger/16;
676 nerr[x+2+3*1]+=ber/16;
678 /* skip to next line */
679 terr = err;
680 err = nerr;
681 nerr = terr;
683 ofs += ximg->image->bytes_per_line - image->width;
685 free(err);
686 free(nerr);
688 ximg->image->data = (char*)data;
690 return ximg;
695 static RXImage*
696 image2GrayScale(RContext *ctx, RImage *image)
698 RXImage *ximg;
699 register int x, y, g;
700 unsigned char *ptr;
701 const int cpc=ctx->attribs->colors_per_channel;
702 unsigned short gmask;
703 unsigned short *table;
704 unsigned char *data;
705 int channels = (image->format == RRGBAFormat ? 4 : 3);
708 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
709 if (!ximg) {
710 return NULL;
713 ptr = image->data;
715 data = (unsigned char *)ximg->image->data;
717 if (ctx->vclass == StaticGray)
718 gmask = (1<<ctx->depth) - 1; /* use all grays */
719 else
720 gmask = cpc*cpc*cpc-1;
722 table = computeTable(gmask);
724 if (table==NULL) {
725 RErrorCode = RERR_NOMEMORY;
726 RDestroyXImage(ctx, ximg);
727 return NULL;
730 if (ctx->attribs->render_mode == RBestMatchRendering) {
731 /* fake match */
732 #ifdef DEBUG
733 printf("grayscale match with %d colors per channel\n", cpc);
734 #endif
735 for (y=0; y<image->height; y++) {
736 for (x=0; x<image->width; x++) {
737 /* reduce pixel */
738 g = table[(*ptr * 30 + *(ptr+1) * 59 + *(ptr+2) * 11)/100];
739 ptr += channels;
740 /*data[ofs] = ctx->colors[g].pixel;*/
741 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
744 } else {
745 /* dither */
746 short *gerr;
747 short *ngerr;
748 short *terr;
749 int ger;
750 const int dg=0xff/gmask;
752 #ifdef DEBUG
753 printf("grayscale dither with %d colors per channel\n", cpc);
754 #endif
755 gerr = (short*)malloc((image->width+2)*sizeof(short));
756 ngerr = (short*)malloc((image->width+2)*sizeof(short));
757 if (!gerr || !ngerr) {
758 if (ngerr)
759 free(ngerr);
760 RErrorCode = RERR_NOMEMORY;
761 RDestroyXImage(ctx, ximg);
762 return NULL;
764 for (x=0, y=0; x<image->width; x++, y+=channels) {
765 gerr[x] = (ptr[y]*30 + ptr[y+1]*59 + ptr[y+2]*11)/100;
767 gerr[x] = 0;
768 /* convert and dither the image to XImage */
769 for (y=0; y<image->height; y++) {
770 if (y<image->height-1) {
771 int x1;
772 for (x=0, x1=(y+1)*image->width*channels; x<image->width; x++, x1+=channels) {
773 ngerr[x] = (ptr[x1]*30 + ptr[x1+1]*59 + ptr[x1+2]*11)/100;
775 /* last column */
776 x1-=channels;
777 ngerr[x] = (ptr[x1]*30 + ptr[x1+1]*59 + ptr[x1+2]*11)/100;
779 for (x=0; x<image->width; x++) {
780 /* reduce pixel */
781 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
783 g = table[gerr[x]];
785 /*data[ofs] = ctx->colors[g].pixel;*/
786 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
787 /* calc error */
788 ger = gerr[x] - g*dg;
790 /* distribute error */
791 g = (ger*3)/8;
792 /* x+1, y */
793 gerr[x+1]+=g;
794 /* x, y+1 */
795 ngerr[x]+=g;
796 /* x+1, y+1 */
797 ngerr[x+1]+=ger-2*g;
799 /* skip to next line */
800 terr = gerr;
801 gerr = ngerr;
802 ngerr = terr;
804 free(gerr);
805 free(ngerr);
807 ximg->image->data = (char*)data;
809 return ximg;
813 static RXImage*
814 image2Bitmap(RContext *ctx, RImage *image, int threshold)
816 RXImage *ximg;
817 unsigned char *alpha;
818 int x, y;
820 ximg = RCreateXImage(ctx, 1, image->width, image->height);
821 if (!ximg) {
822 return NULL;
824 alpha = image->data+3;
826 for (y = 0; y < image->height; y++) {
827 for (x = 0; x < image->width; x++) {
828 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
829 alpha+=4;
833 return ximg;
837 #ifdef HAVE_HERMES
839 static RXImage*
840 hermesConvert(RContext *context, RImage *image)
842 HermesFormat source;
843 HermesFormat dest;
844 RXImage *ximage;
847 ximage = RCreateXImage(context, context->depth,
848 image->width, image->height);
849 if (!ximage) {
850 return NULL;
853 /* The masks look weird for images with alpha. but they work this way.
854 * wth does hermes do internally?
856 source.bits = (HAS_ALPHA(image) ? 32 : 24);
857 if (ximage->image->byte_order==LSBFirst) {
858 source.r = 0xff0000;
859 source.g = 0x00ff00;
860 source.b = 0x0000ff;
861 } else {
862 if (source.bits == 32) {
863 source.r = 0xff000000;
864 source.g = 0x00ff0000;
865 source.b = 0x0000ff00;
866 } else {
867 source.r = 0xff0000;
868 source.g = 0x00ff00;
869 source.b = 0x0000ff;
872 source.a = 0; /* Don't care about alpha */
873 source.indexed = 0;
874 source.has_colorkey = 0;
876 /* This is a hack and certainly looks weird, but it works :P
877 * it assumes though that green is inbetween red and blue (the mask) */
878 if (ximage->image->byte_order==LSBFirst) {
879 dest.r = context->visual->blue_mask;
880 dest.g = context->visual->green_mask;
881 dest.b = context->visual->red_mask;
882 } else {
883 dest.r = context->visual->red_mask;
884 dest.g = context->visual->green_mask;
885 dest.b = context->visual->blue_mask;
887 dest.a = 0;
888 dest.bits = ximage->image->bits_per_pixel;
889 if (context->vclass == TrueColor)
890 dest.indexed = 0;
891 else
892 dest.indexed = 1;
893 dest.has_colorkey = 0;
895 /*printf("source r=0x%x, g=0x%x, b=0x%x, a=0x%x, b=%d, i=%d, c=%d\n",
896 source.r, source.g, source.b, source.a,
897 source.bits, source.indexed, source.has_colorkey);
898 printf("dest r=0x%x, g=0x%x, b=0x%x, a=0x%x, b=%d, i=%d, c=%d\n",
899 dest.r, dest.g, dest.b, dest.a,
900 dest.bits, dest.indexed, dest.has_colorkey);
903 Hermes_ConverterRequest(context->hermes_data->converter, &source, &dest);
905 Hermes_ConverterPalette(context->hermes_data->converter,
906 context->hermes_data->palette, 0);
908 Hermes_ConverterCopy(context->hermes_data->converter,
909 image->data, 0, 0, image->width, image->height,
910 image->width * (image->format == RRGBFormat ? 3 : 4),
911 ximage->image->data, 0, 0,
912 image->width, image->height,
913 ximage->image->bytes_per_line);
915 return ximage;
917 #endif /* HAVE_HERMES */
920 int
921 RConvertImage(RContext *context, RImage *image, Pixmap *pixmap)
923 RXImage *ximg=NULL;
924 #ifdef XSHM
925 Pixmap tmp;
926 #endif
928 assert(context!=NULL);
929 assert(image!=NULL);
930 assert(pixmap!=NULL);
932 switch (context->vclass) {
933 case TrueColor:
934 #ifdef HAVE_HERMES
935 if (context->attribs->render_mode == RBestMatchRendering) {
936 ximg = hermesConvert(context, image);
937 } else {
938 ximg = image2TrueColor(context, image);
940 #else /* !HAVE_HERMES */
941 ximg = image2TrueColor(context, image);
942 #endif
943 break;
945 case PseudoColor:
946 case StaticColor:
947 /* For StaticColor we can also use hermes, but it doesn't dither */
948 #ifdef BENCH
949 cycle_bench(1);
950 #endif
951 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
952 ximg = image2StandardPseudoColor(context, image);
953 else
954 ximg = image2PseudoColor(context, image);
955 #ifdef BENCH
956 cycle_bench(0);
957 #endif
958 break;
960 case GrayScale:
961 case StaticGray:
962 ximg = image2GrayScale(context, image);
963 break;
967 if (!ximg) {
968 return False;
971 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width,
972 image->height, context->depth);
974 #ifdef XSHM
975 if (context->flags.use_shared_pixmap && ximg->is_shared)
976 tmp = R_CreateXImageMappedPixmap(context, ximg);
977 else
978 tmp = None;
979 if (tmp) {
981 * We have to copy the shm Pixmap into a normal Pixmap because
982 * otherwise, we would have to control when Pixmaps are freed so
983 * that we can detach their shm segments. This is a problem if the
984 * program crash, leaving stale shared memory segments in the
985 * system (lots of them). But with some work, we can optimize
986 * things and remove this XCopyArea. This will require
987 * explicitly freeing all pixmaps when exiting or restarting
988 * wmaker.
990 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0,
991 image->width, image->height, 0, 0);
992 XFreePixmap(context->dpy, tmp);
993 } else {
994 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
995 image->width, image->height);
997 #else /* !XSHM */
998 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
999 image->width, image->height);
1000 #endif /* !XSHM */
1002 RDestroyXImage(context, ximg);
1004 return True;
1008 int
1009 RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap,
1010 Pixmap *mask, int threshold)
1012 GC gc;
1013 XGCValues gcv;
1014 RXImage *ximg=NULL;
1016 assert(context!=NULL);
1017 assert(image!=NULL);
1018 assert(pixmap!=NULL);
1019 assert(mask!=NULL);
1021 if (!RConvertImage(context, image, pixmap))
1022 return False;
1024 if (image->format==RRGBFormat) {
1025 *mask = None;
1026 return True;
1029 ximg = image2Bitmap(context, image, threshold);
1031 if (!ximg) {
1032 return False;
1034 *mask = XCreatePixmap(context->dpy, context->drawable, image->width,
1035 image->height, 1);
1036 gcv.foreground = context->black;
1037 gcv.background = context->white;
1038 gcv.graphics_exposures = False;
1039 gc = XCreateGC(context->dpy, *mask, GCForeground|GCBackground
1040 |GCGraphicsExposures, &gcv);
1041 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0,
1042 image->width, image->height);
1043 RDestroyXImage(context, ximg);
1045 return True;
1049 Bool
1050 RGetClosestXColor(RContext *context, RColor *color, XColor *retColor)
1052 if (context->vclass == TrueColor) {
1053 unsigned short rmask, gmask, bmask;
1054 unsigned short roffs, goffs, boffs;
1055 unsigned short *rtable, *gtable, *btable;
1057 roffs = context->red_offset;
1058 goffs = context->green_offset;
1059 boffs = context->blue_offset;
1061 rmask = context->visual->red_mask >> roffs;
1062 gmask = context->visual->green_mask >> goffs;
1063 bmask = context->visual->blue_mask >> boffs;
1065 rtable = computeTable(rmask);
1066 gtable = computeTable(gmask);
1067 btable = computeTable(bmask);
1069 retColor->pixel = (rtable[color->red]<<roffs) |
1070 (gtable[color->green]<<goffs) | (btable[color->blue]<<boffs);
1072 retColor->red = color->red << 8;
1073 retColor->green = color->green << 8;
1074 retColor->blue = color->blue << 8;
1075 retColor->flags = DoRed|DoGreen|DoBlue;
1077 } else if (context->vclass == PseudoColor
1078 || context->vclass == StaticColor) {
1080 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
1081 unsigned int *rtable, *gtable, *btable;
1083 rtable = computeStdTable(context->std_rgb_map->red_mult,
1084 context->std_rgb_map->red_max);
1086 gtable = computeStdTable(context->std_rgb_map->green_mult,
1087 context->std_rgb_map->green_max);
1089 btable = computeStdTable(context->std_rgb_map->blue_mult,
1090 context->std_rgb_map->blue_max);
1092 if (rtable==NULL || gtable==NULL || btable==NULL) {
1093 RErrorCode = RERR_NOMEMORY;
1094 return False;
1097 retColor->pixel = (rtable[color->red]
1098 + gtable[color->green]
1099 + btable[color->blue]
1100 + context->std_rgb_map->base_pixel) & 0xffffffff;
1101 retColor->red = color->red<<8;
1102 retColor->green = color->green<<8;
1103 retColor->blue = color->blue<<8;
1104 retColor->flags = DoRed|DoGreen|DoBlue;
1106 } else {
1107 const int cpc=context->attribs->colors_per_channel;
1108 const unsigned short rmask = cpc-1; /* different sizes could be used */
1109 const unsigned short gmask = rmask; /* for r,g,b */
1110 const unsigned short bmask = rmask;
1111 unsigned short *rtable, *gtable, *btable;
1112 const int cpccpc = cpc*cpc;
1113 int index;
1115 rtable = computeTable(rmask);
1116 gtable = computeTable(gmask);
1117 btable = computeTable(bmask);
1119 if (rtable==NULL || gtable==NULL || btable==NULL) {
1120 RErrorCode = RERR_NOMEMORY;
1121 return False;
1123 index = rtable[color->red]*cpccpc + gtable[color->green]*cpc
1124 + btable[color->blue];
1125 *retColor = context->colors[index];
1128 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
1130 const int cpc = context->attribs->colors_per_channel;
1131 unsigned short gmask;
1132 unsigned short *table;
1133 int index;
1135 if (context->vclass == StaticGray)
1136 gmask = (1<<context->depth) - 1; /* use all grays */
1137 else
1138 gmask = cpc*cpc*cpc-1;
1140 table = computeTable(gmask);
1141 if (!table)
1142 return False;
1144 index = table[(color->red*30 + color->green*59 + color->blue*11)/100];
1146 *retColor = context->colors[index];
1147 } else {
1148 RErrorCode = RERR_INTERNAL;
1149 return False;
1152 return True;