- Fixed crashing bug in menu.c
[wmaker-crm.git] / wrlib / convert.c
blobba96643e3a568b391140c99f733d5dc6db7239c7
1 /* convert.c - convert RImage to Pixmap
2 *
3 * Raster graphics library
5 * Copyright (c) 1997-2003 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 "wraster.h"
45 #ifdef XSHM
46 extern Pixmap R_CreateXImageMappedPixmap(RContext *context, RXImage *ximage);
48 #endif
51 #ifdef ASM_X86
52 extern void x86_PseudoColor_32_to_8(unsigned char *image,
53 unsigned char *ximage,
54 char *err, char *nerr,
55 short *ctable,
56 int dr, int dg, int db,
57 unsigned long *pixels,
58 int cpc,
59 int width, int height,
60 int bytesPerPixel,
61 int line_offset);
62 #endif /* ASM_X86 */
64 #ifdef ASM_X86_MMX
66 extern int x86_check_mmx();
68 extern void x86_mmx_TrueColor_32_to_16(unsigned char *image,
69 unsigned short *ximage,
70 short *err, short *nerr,
71 short *rtable, short *gtable,
72 short *btable,
73 int dr, int dg, int db,
74 unsigned int roffs,
75 unsigned int goffs,
76 unsigned int boffs,
77 int width, int height,
78 int line_offset);
82 #endif /* ASM_X86_MMX */
84 #define NFREE(n) if (n) free(n)
86 #define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
89 typedef struct RConversionTable {
90 unsigned short table[256];
91 unsigned short index;
93 struct RConversionTable *next;
94 } RConversionTable;
97 typedef struct RStdConversionTable {
98 unsigned int table[256];
100 unsigned short mult;
101 unsigned short max;
103 struct RStdConversionTable *next;
104 } RStdConversionTable;
108 static RConversionTable *conversionTable = NULL;
109 static RStdConversionTable *stdConversionTable = NULL;
112 static unsigned short*
113 computeTable(unsigned short mask)
115 RConversionTable *tmp = conversionTable;
116 int i;
118 while (tmp) {
119 if (tmp->index == mask)
120 break;
121 tmp = tmp->next;
124 if (tmp)
125 return tmp->table;
127 tmp = (RConversionTable *)malloc(sizeof(RConversionTable));
128 if (tmp == NULL)
129 return NULL;
131 for (i=0;i<256;i++)
132 tmp->table[i] = (i*mask + 0x7f)/0xff;
134 tmp->index = mask;
135 tmp->next = conversionTable;
136 conversionTable = tmp;
137 return tmp->table;
141 static unsigned int*
142 computeStdTable(unsigned int mult, unsigned int max)
144 RStdConversionTable *tmp = stdConversionTable;
145 unsigned int i;
147 while (tmp) {
148 if (tmp->mult == mult && tmp->max == max)
149 break;
150 tmp = tmp->next;
153 if (tmp)
154 return tmp->table;
156 tmp = (RStdConversionTable *)malloc(sizeof(RStdConversionTable));
157 if (tmp == NULL)
158 return NULL;
160 for (i=0; i<256; i++) {
161 tmp->table[i] = (i*max)/0xff * mult;
163 tmp->mult = mult;
164 tmp->max = max;
166 tmp->next = stdConversionTable;
167 stdConversionTable = tmp;
169 return tmp->table;
172 /***************************************************************************/
175 static void
176 convertTrueColor_generic(RXImage *ximg, RImage *image,
177 signed char *err, signed char *nerr,
178 const short *rtable,
179 const short *gtable,
180 const short *btable,
181 const int dr, const int dg, const int db,
182 const unsigned short roffs,
183 const unsigned short goffs,
184 const unsigned short boffs)
186 signed char *terr;
187 int x, y, r, g, b;
188 int pixel;
189 int rer, ger, ber;
190 unsigned char *ptr = image->data;
191 int channels = (HAS_ALPHA(image) ? 4 : 3);
193 /* convert and dither the image to XImage */
194 for (y=0; y<image->height; y++) {
195 nerr[0] = 0;
196 nerr[1] = 0;
197 nerr[2] = 0;
198 for (x=0; x<image->width; x++, ptr+=channels) {
200 /* reduce pixel */
201 pixel = *ptr + err[x];
202 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
203 r = rtable[pixel];
204 /* calc error */
205 rer = pixel - r*dr;
207 /* reduce pixel */
208 pixel = *(ptr+1) + err[x+1];
209 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
210 g = gtable[pixel];
211 /* calc error */
212 ger = pixel - g*dg;
214 /* reduce pixel */
215 pixel = *(ptr+2) + err[x+2];
216 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
217 b = btable[pixel];
218 /* calc error */
219 ber = pixel - b*db;
222 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
223 XPutPixel(ximg->image, x, y, pixel);
225 /* distribute error */
226 r = (rer*3)/8;
227 g = (ger*3)/8;
228 b = (ber*3)/8;
229 /* x+1, y */
230 err[x+3*1]+=r;
231 err[x+1+3*1]+=g;
232 err[x+2+3*1]+=b;
233 /* x, y+1 */
234 nerr[x]+=r;
235 nerr[x+1]+=g;
236 nerr[x+2]+=b;
237 /* x+1, y+1 */
238 nerr[x+3*1]=rer-2*r;
239 nerr[x+1+3*1]=ger-2*g;
240 nerr[x+2+3*1]=ber-2*b;
242 /* skip to next line */
243 terr = err;
244 err = nerr;
245 nerr = terr;
248 /* redither the 1st line to distribute error better */
249 ptr=image->data;
250 y=0;
251 nerr[0] = 0;
252 nerr[1] = 0;
253 nerr[2] = 0;
254 for (x=0; x<image->width; x++, ptr+=channels) {
256 /* reduce pixel */
257 pixel = *ptr + err[x];
258 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
259 r = rtable[pixel];
260 /* calc error */
261 rer = pixel - r*dr;
263 /* reduce pixel */
264 pixel = *(ptr+1) + err[x+1];
265 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
266 g = gtable[pixel];
267 /* calc error */
268 ger = pixel - g*dg;
270 /* reduce pixel */
271 pixel = *(ptr+2) + err[x+2];
272 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
273 b = btable[pixel];
274 /* calc error */
275 ber = pixel - b*db;
278 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
279 XPutPixel(ximg->image, x, y, pixel);
281 /* distribute error */
282 r = (rer*3)/8;
283 g = (ger*3)/8;
284 b = (ber*3)/8;
285 /* x+1, y */
286 err[x+3*1]+=r;
287 err[x+1+3*1]+=g;
288 err[x+2+3*1]+=b;
289 /* x, y+1 */
290 nerr[x]+=r;
291 nerr[x+1]+=g;
292 nerr[x+2]+=b;
293 /* x+1, y+1 */
294 nerr[x+3*1]=rer-2*r;
295 nerr[x+1+3*1]=ger-2*g;
296 nerr[x+2+3*1]=ber-2*b;
303 static RXImage*
304 image2TrueColor(RContext *ctx, RImage *image)
306 RXImage *ximg;
307 unsigned short rmask, gmask, bmask;
308 unsigned short roffs, goffs, boffs;
309 unsigned short *rtable, *gtable, *btable;
310 int channels = (HAS_ALPHA(image) ? 4 : 3);
312 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
313 if (!ximg) {
314 return NULL;
317 roffs = ctx->red_offset;
318 goffs = ctx->green_offset;
319 boffs = ctx->blue_offset;
321 rmask = ctx->visual->red_mask >> roffs;
322 gmask = ctx->visual->green_mask >> goffs;
323 bmask = ctx->visual->blue_mask >> boffs;
325 rtable = computeTable(rmask);
326 gtable = computeTable(gmask);
327 btable = computeTable(bmask);
329 if (rtable==NULL || gtable==NULL || btable==NULL) {
330 RErrorCode = RERR_NOMEMORY;
331 RDestroyXImage(ctx, ximg);
332 return NULL;
336 #ifdef BENCH
337 cycle_bench(1);
338 #endif
340 if (ctx->attribs->render_mode==RBestMatchRendering) {
341 int ofs, r, g, b;
342 int x, y;
343 unsigned long pixel;
344 unsigned char *ptr = image->data;
346 /* fake match */
347 #ifdef DEBUG
348 puts("true color match");
349 #endif
350 if (rmask==0xff && gmask==0xff && bmask==0xff) {
351 for (y=0; y < image->height; y++) {
352 for (x=0; x < image->width; x++, ptr+=channels) {
353 /* reduce pixel */
354 pixel = (*(ptr)<<roffs) | (*(ptr+1)<<goffs) | (*(ptr+2)<<boffs);
355 XPutPixel(ximg->image, x, y, pixel);
358 } else {
359 for (y=0, ofs=0; y < image->height; y++) {
360 for (x=0; x < image->width; x++, ofs+=channels-3) {
361 /* reduce pixel */
362 r = rtable[ptr[ofs++]];
363 g = gtable[ptr[ofs++]];
364 b = btable[ptr[ofs++]];
365 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
366 XPutPixel(ximg->image, x, y, pixel);
370 } else {
371 /* dither */
372 const int dr=0xff/rmask;
373 const int dg=0xff/gmask;
374 const int db=0xff/bmask;
376 #ifdef DEBUG
377 puts("true color dither");
378 #endif
380 #ifdef ASM_X86_MMX
381 if (ctx->depth==16 && HAS_ALPHA(image) && x86_check_mmx()) {
382 short *err;
383 short *nerr;
385 err = malloc(8*(image->width+3));
386 nerr = malloc(8*(image->width+3));
387 if (!err || !nerr) {
388 NFREE(err);
389 NFREE(nerr);
390 RErrorCode = RERR_NOMEMORY;
391 RDestroyXImage(ctx, ximg);
392 return NULL;
394 memset(err, 0, 8*(image->width+3));
395 memset(nerr, 0, 8*(image->width+3));
397 x86_mmx_TrueColor_32_to_16(image->data,
398 (unsigned short*)ximg->image->data,
399 err+8, nerr+8,
400 rtable, gtable, btable,
401 dr, dg, db,
402 roffs, goffs, boffs,
403 image->width, image->height,
404 ximg->image->bytes_per_line - 2*image->width);
406 free(err);
407 free(nerr);
408 } else
409 #endif /* ASM_X86_MMX */
411 char *err;
412 char *nerr;
413 int ch = (HAS_ALPHA(image) ? 4 : 3);
415 err = malloc(ch*(image->width+2));
416 nerr = malloc(ch*(image->width+2));
417 if (!err || !nerr) {
418 NFREE(err);
419 NFREE(nerr);
420 RErrorCode = RERR_NOMEMORY;
421 RDestroyXImage(ctx, ximg);
422 return NULL;
425 memset(err, 0, ch*(image->width+2));
426 memset(nerr, 0, ch*(image->width+2));
428 convertTrueColor_generic(ximg, image, err, nerr,
429 rtable, gtable, btable,
430 dr, dg, db, roffs, goffs, boffs);
431 free(err);
432 free(nerr);
437 #ifdef BENCH
438 cycle_bench(0);
439 #endif
441 return ximg;
445 /***************************************************************************/
447 static void
448 convertPseudoColor_to_8(RXImage *ximg, RImage *image,
449 signed char *err, signed char *nerr,
450 const short *rtable,
451 const short *gtable,
452 const short *btable,
453 const int dr, const int dg, const int db,
454 unsigned long *pixels,
455 int cpc)
457 signed char *terr;
458 int x, y, r, g, b;
459 int pixel;
460 int rer, ger, ber;
461 unsigned char *ptr = image->data;
462 unsigned char *optr = ximg->image->data;
463 int channels = (HAS_ALPHA(image) ? 4 : 3);
464 int cpcpc = cpc*cpc;
466 /* convert and dither the image to XImage */
467 for (y=0; y<image->height; y++) {
468 nerr[0] = 0;
469 nerr[1] = 0;
470 nerr[2] = 0;
471 for (x=0; x<image->width*3; x+=3, ptr+=channels) {
473 /* reduce pixel */
474 pixel = *ptr + err[x];
475 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
476 r = rtable[pixel];
477 /* calc error */
478 rer = pixel - r*dr;
480 /* reduce pixel */
481 pixel = *(ptr+1) + err[x+1];
482 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
483 g = gtable[pixel];
484 /* calc error */
485 ger = pixel - g*dg;
487 /* reduce pixel */
488 pixel = *(ptr+2) + err[x+2];
489 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
490 b = btable[pixel];
491 /* calc error */
492 ber = pixel - b*db;
494 *optr++ = pixels[r*cpcpc + g*cpc + b];
496 /* distribute error */
497 r = (rer*3)/8;
498 g = (ger*3)/8;
499 b = (ber*3)/8;
501 /* x+1, y */
502 err[x+3*1]+=r;
503 err[x+1+3*1]+=g;
504 err[x+2+3*1]+=b;
505 /* x, y+1 */
506 nerr[x]+=r;
507 nerr[x+1]+=g;
508 nerr[x+2]+=b;
509 /* x+1, y+1 */
510 nerr[x+3*1]=rer-2*r;
511 nerr[x+1+3*1]=ger-2*g;
512 nerr[x+2+3*1]=ber-2*b;
514 /* skip to next line */
515 terr = err;
516 err = nerr;
517 nerr = terr;
519 optr += ximg->image->bytes_per_line - image->width;
525 static RXImage*
526 image2PseudoColor(RContext *ctx, RImage *image)
528 RXImage *ximg;
529 register int x, y, r, g, b;
530 unsigned char *ptr;
531 unsigned long pixel;
532 const int cpc=ctx->attribs->colors_per_channel;
533 const unsigned short rmask = cpc-1; /* different sizes could be used */
534 const unsigned short gmask = rmask; /* for r,g,b */
535 const unsigned short bmask = rmask;
536 unsigned short *rtable, *gtable, *btable;
537 const int cpccpc = cpc*cpc;
538 int channels = (HAS_ALPHA(image) ? 4 : 3);
540 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
541 if (!ximg) {
542 return NULL;
545 ptr = image->data;
547 /* Tables are same at the moment because rmask==gmask==bmask. */
548 rtable = computeTable(rmask);
549 gtable = computeTable(gmask);
550 btable = computeTable(bmask);
552 if (rtable==NULL || gtable==NULL || btable==NULL) {
553 RErrorCode = RERR_NOMEMORY;
554 RDestroyXImage(ctx, ximg);
555 return NULL;
558 if (ctx->attribs->render_mode == RBestMatchRendering) {
559 /* fake match */
560 #ifdef DEBUG
561 printf("pseudo color match with %d colors per channel\n", cpc);
562 #endif
563 for (y=0; y<image->height; y++) {
564 for (x=0; x<image->width; x++, ptr+=channels-3) {
565 /* reduce pixel */
566 r = rtable[*ptr++];
567 g = gtable[*ptr++];
568 b = btable[*ptr++];
569 pixel = r*cpccpc + g*cpc + b;
570 /*data[ofs] = ctx->colors[pixel].pixel;*/
571 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
574 } else {
575 /* dither */
576 char *err;
577 char *nerr;
578 const int dr=0xff/rmask;
579 const int dg=0xff/gmask;
580 const int db=0xff/bmask;
583 #ifdef DEBUG
584 printf("pseudo color dithering with %d colors per channel\n", cpc);
585 #endif
586 err = malloc(4*(image->width+3));
587 nerr = malloc(4*(image->width+3));
588 if (!err || !nerr) {
589 NFREE(err);
590 NFREE(nerr);
591 RErrorCode = RERR_NOMEMORY;
592 RDestroyXImage(ctx, ximg);
593 return NULL;
595 memset(err, 0, 4*(image->width+3));
596 memset(nerr, 0, 4*(image->width+3));
598 /*#ifdef ASM_X86*/
599 #if 0
600 x86_PseudoColor_32_to_8(image->data, ximg->image->data,
601 err+4, nerr+4,
602 rtable,
603 dr, dg, db, ctx->pixels, cpc,
604 image->width, image->height,
605 channels,
606 ximg->image->bytes_per_line - image->width);
607 #else
608 convertPseudoColor_to_8(ximg, image, err+4, nerr+4,
609 rtable, gtable, btable,
610 dr, dg, db, ctx->pixels, cpc);
611 #endif
613 free(err);
614 free(nerr);
617 return ximg;
622 * For standard colormap
624 static RXImage*
625 image2StandardPseudoColor(RContext *ctx, RImage *image)
627 RXImage *ximg;
628 register int x, y, r, g, b;
629 unsigned char *ptr;
630 unsigned long pixel;
631 unsigned char *data;
632 unsigned int *rtable, *gtable, *btable;
633 unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
634 int channels = (HAS_ALPHA(image) ? 4 : 3);
637 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
638 if (!ximg) {
639 return NULL;
642 ptr = image->data;
644 data = (unsigned char *)ximg->image->data;
647 rtable = computeStdTable(ctx->std_rgb_map->red_mult,
648 ctx->std_rgb_map->red_max);
650 gtable = computeStdTable(ctx->std_rgb_map->green_mult,
651 ctx->std_rgb_map->green_max);
653 btable = computeStdTable(ctx->std_rgb_map->blue_mult,
654 ctx->std_rgb_map->blue_max);
656 if (rtable==NULL || gtable==NULL || btable==NULL) {
657 RErrorCode = RERR_NOMEMORY;
658 RDestroyXImage(ctx, ximg);
659 return NULL;
663 if (ctx->attribs->render_mode == RBestMatchRendering) {
664 for (y=0; y<image->height; y++) {
665 for (x=0; x<image->width; x++, ptr+=channels) {
666 /* reduce pixel */
667 pixel = (rtable[*ptr] + gtable[*(ptr+1)]
668 + btable[*(ptr+2)] + base_pixel) & 0xffffffff;
670 XPutPixel(ximg->image, x, y, pixel);
673 } else {
674 /* dither */
675 signed short *err, *nerr;
676 signed short *terr;
677 int rer, ger, ber;
678 int x1, ofs;
680 #ifdef DEBUG
681 printf("pseudo color dithering with %d colors per channel\n", cpc);
682 #endif
683 err = (short*)malloc(3*(image->width+2)*sizeof(short));
684 nerr = (short*)malloc(3*(image->width+2)*sizeof(short));
685 if (!err || !nerr) {
686 NFREE(err);
687 NFREE(nerr);
688 RErrorCode = RERR_NOMEMORY;
689 RDestroyXImage(ctx, ximg);
690 return NULL;
692 for (x=0, x1=0; x<image->width*3; x1+=channels-3) {
693 err[x++] = ptr[x1++];
694 err[x++] = ptr[x1++];
695 err[x++] = ptr[x1++];
697 err[x] = err[x+1] = err[x+2] = 0;
698 /* convert and dither the image to XImage */
699 for (y=0, ofs=0; y<image->height; y++) {
700 if (y<image->height-1) {
701 int x1;
702 for (x=0, x1=(y+1)*image->width*channels;
703 x<image->width*3;
704 x1+=channels-3) {
705 nerr[x++] = ptr[x1++];
706 nerr[x++] = ptr[x1++];
707 nerr[x++] = ptr[x1++];
709 /* last column */
710 x1-=channels;
711 nerr[x++] = ptr[x1++];
712 nerr[x++] = ptr[x1++];
713 nerr[x++] = ptr[x1++];
715 for (x=0; x<image->width*3; x+=3, ofs++) {
716 /* reduce pixel */
717 if (err[x]>0xff) err[x]=0xff; else if (err[x]<0) err[x]=0;
718 if (err[x+1]>0xff) err[x+1]=0xff; else if (err[x+1]<0) err[x+1]=0;
719 if (err[x+2]>0xff) err[x+2]=0xff; else if (err[x+2]<0) err[x+2]=0;
721 r = rtable[err[x]];
722 g = gtable[err[x+1]];
723 b = btable[err[x+2]];
725 pixel = r + g + b;
727 data[ofs] = base_pixel + pixel;
729 /* calc error */
730 rer = err[x] - (ctx->colors[pixel].red>>8);
731 ger = err[x+1] - (ctx->colors[pixel].green>>8);
732 ber = err[x+2] - (ctx->colors[pixel].blue>>8);
734 /* distribute error */
735 err[x+3*1]+=(rer*7)/16;
736 err[x+1+3*1]+=(ger*7)/16;
737 err[x+2+3*1]+=(ber*7)/16;
739 nerr[x]+=(rer*5)/16;
740 nerr[x+1]+=(ger*5)/16;
741 nerr[x+2]+=(ber*5)/16;
743 if (x>0) {
744 nerr[x-3*1]+=(rer*3)/16;
745 nerr[x-3*1+1]+=(ger*3)/16;
746 nerr[x-3*1+2]+=(ber*3)/16;
749 nerr[x+3*1]+=rer/16;
750 nerr[x+1+3*1]+=ger/16;
751 nerr[x+2+3*1]+=ber/16;
753 /* skip to next line */
754 terr = err;
755 err = nerr;
756 nerr = terr;
758 ofs += ximg->image->bytes_per_line - image->width;
760 free(err);
761 free(nerr);
763 ximg->image->data = (char*)data;
765 return ximg;
770 static RXImage*
771 image2GrayScale(RContext *ctx, RImage *image)
773 RXImage *ximg;
774 register int x, y, g;
775 unsigned char *ptr;
776 const int cpc=ctx->attribs->colors_per_channel;
777 unsigned short gmask;
778 unsigned short *table;
779 unsigned char *data;
780 int channels = (HAS_ALPHA(image) ? 4 : 3);
783 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
784 if (!ximg) {
785 return NULL;
788 ptr = image->data;
790 data = (unsigned char *)ximg->image->data;
792 if (ctx->vclass == StaticGray)
793 gmask = (1<<ctx->depth) - 1; /* use all grays */
794 else
795 gmask = cpc*cpc*cpc-1;
797 table = computeTable(gmask);
799 if (table==NULL) {
800 RErrorCode = RERR_NOMEMORY;
801 RDestroyXImage(ctx, ximg);
802 return NULL;
805 if (ctx->attribs->render_mode == RBestMatchRendering) {
806 /* fake match */
807 #ifdef DEBUG
808 printf("grayscale match with %d colors per channel\n", cpc);
809 #endif
810 for (y=0; y<image->height; y++) {
811 for (x=0; x<image->width; x++) {
812 /* reduce pixel */
813 g = table[(*ptr * 30 + *(ptr+1) * 59 + *(ptr+2) * 11)/100];
814 ptr += channels;
815 /*data[ofs] = ctx->colors[g].pixel;*/
816 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
819 } else {
820 /* dither */
821 short *gerr;
822 short *ngerr;
823 short *terr;
824 int ger;
825 const int dg=0xff/gmask;
827 #ifdef DEBUG
828 printf("grayscale dither with %d colors per channel\n", cpc);
829 #endif
830 gerr = (short*)malloc((image->width+2)*sizeof(short));
831 ngerr = (short*)malloc((image->width+2)*sizeof(short));
832 if (!gerr || !ngerr) {
833 NFREE(gerr);
834 NFREE(ngerr);
835 RErrorCode = RERR_NOMEMORY;
836 RDestroyXImage(ctx, ximg);
837 return NULL;
839 for (x=0, y=0; x<image->width; x++, y+=channels) {
840 gerr[x] = (ptr[y]*30 + ptr[y+1]*59 + ptr[y+2]*11)/100;
842 gerr[x] = 0;
843 /* convert and dither the image to XImage */
844 for (y=0; y<image->height; y++) {
845 if (y<image->height-1) {
846 int x1;
847 for (x=0, x1=(y+1)*image->width*channels; x<image->width; x++, x1+=channels) {
848 ngerr[x] = (ptr[x1]*30 + ptr[x1+1]*59 + ptr[x1+2]*11)/100;
850 /* last column */
851 x1-=channels;
852 ngerr[x] = (ptr[x1]*30 + ptr[x1+1]*59 + ptr[x1+2]*11)/100;
854 for (x=0; x<image->width; x++) {
855 /* reduce pixel */
856 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
858 g = table[gerr[x]];
860 /*data[ofs] = ctx->colors[g].pixel;*/
861 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
862 /* calc error */
863 ger = gerr[x] - g*dg;
865 /* distribute error */
866 g = (ger*3)/8;
867 /* x+1, y */
868 gerr[x+1]+=g;
869 /* x, y+1 */
870 ngerr[x]+=g;
871 /* x+1, y+1 */
872 ngerr[x+1]+=ger-2*g;
874 /* skip to next line */
875 terr = gerr;
876 gerr = ngerr;
877 ngerr = terr;
879 free(gerr);
880 free(ngerr);
882 ximg->image->data = (char*)data;
884 return ximg;
888 static RXImage*
889 image2Bitmap(RContext *ctx, RImage *image, int threshold)
891 RXImage *ximg;
892 unsigned char *alpha;
893 int x, y;
895 ximg = RCreateXImage(ctx, 1, image->width, image->height);
896 if (!ximg) {
897 return NULL;
899 alpha = image->data+3;
901 for (y = 0; y < image->height; y++) {
902 for (x = 0; x < image->width; x++) {
903 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
904 alpha+=4;
908 return ximg;
912 int
913 RConvertImage(RContext *context, RImage *image, Pixmap *pixmap)
915 RXImage *ximg=NULL;
916 #ifdef XSHM
917 Pixmap tmp;
918 #endif
920 assert(context!=NULL);
921 assert(image!=NULL);
922 assert(pixmap!=NULL);
924 switch (context->vclass) {
925 case TrueColor:
926 #ifdef BENCH
927 cycle_bench(1);
928 #endif
929 ximg = image2TrueColor(context, image);
930 #ifdef BENCH
931 cycle_bench(0);
932 #endif
933 break;
935 case PseudoColor:
936 case StaticColor:
937 #ifdef BENCH
938 cycle_bench(1);
939 #endif
940 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
941 ximg = image2StandardPseudoColor(context, image);
942 else
943 ximg = image2PseudoColor(context, image);
944 #ifdef BENCH
945 cycle_bench(0);
946 #endif
947 break;
949 case GrayScale:
950 case StaticGray:
951 ximg = image2GrayScale(context, image);
952 break;
956 if (!ximg) {
957 return False;
960 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width,
961 image->height, context->depth);
963 #ifdef XSHM
964 if (context->flags.use_shared_pixmap && ximg->is_shared)
965 tmp = R_CreateXImageMappedPixmap(context, ximg);
966 else
967 tmp = None;
968 if (tmp) {
970 * We have to copy the shm Pixmap into a normal Pixmap because
971 * otherwise, we would have to control when Pixmaps are freed so
972 * that we can detach their shm segments. This is a problem if the
973 * program crash, leaving stale shared memory segments in the
974 * system (lots of them). But with some work, we can optimize
975 * things and remove this XCopyArea. This will require
976 * explicitly freeing all pixmaps when exiting or restarting
977 * wmaker.
979 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0,
980 image->width, image->height, 0, 0);
981 XFreePixmap(context->dpy, tmp);
982 } else {
983 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
984 image->width, image->height);
986 #else /* !XSHM */
987 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
988 image->width, image->height);
989 #endif /* !XSHM */
991 RDestroyXImage(context, ximg);
993 return True;
997 /* make the gc permanent (create with context creation).
998 * GC creation is very expensive. altering its properties is not. -Dan
1000 int
1001 RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap,
1002 Pixmap *mask, int threshold)
1004 GC gc;
1005 XGCValues gcv;
1006 RXImage *ximg=NULL;
1008 assert(context!=NULL);
1009 assert(image!=NULL);
1010 assert(pixmap!=NULL);
1011 assert(mask!=NULL);
1013 if (!RConvertImage(context, image, pixmap))
1014 return False;
1016 if (image->format==RRGBFormat) {
1017 *mask = None;
1018 return True;
1021 ximg = image2Bitmap(context, image, threshold);
1023 if (!ximg) {
1024 return False;
1026 *mask = XCreatePixmap(context->dpy, context->drawable, image->width,
1027 image->height, 1);
1028 gcv.foreground = context->black;
1029 gcv.background = context->white;
1030 gcv.graphics_exposures = False;
1031 gc = XCreateGC(context->dpy, *mask, GCForeground|GCBackground
1032 |GCGraphicsExposures, &gcv);
1033 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0,
1034 image->width, image->height);
1035 RDestroyXImage(context, ximg);
1036 XFreeGC(context->dpy, gc);
1038 return True;
1042 Bool
1043 RGetClosestXColor(RContext *context, RColor *color, XColor *retColor)
1045 if (context->vclass == TrueColor) {
1046 unsigned short rmask, gmask, bmask;
1047 unsigned short roffs, goffs, boffs;
1048 unsigned short *rtable, *gtable, *btable;
1050 roffs = context->red_offset;
1051 goffs = context->green_offset;
1052 boffs = context->blue_offset;
1054 rmask = context->visual->red_mask >> roffs;
1055 gmask = context->visual->green_mask >> goffs;
1056 bmask = context->visual->blue_mask >> boffs;
1058 rtable = computeTable(rmask);
1059 gtable = computeTable(gmask);
1060 btable = computeTable(bmask);
1062 retColor->pixel = (rtable[color->red]<<roffs) |
1063 (gtable[color->green]<<goffs) | (btable[color->blue]<<boffs);
1065 retColor->red = color->red << 8;
1066 retColor->green = color->green << 8;
1067 retColor->blue = color->blue << 8;
1068 retColor->flags = DoRed|DoGreen|DoBlue;
1070 } else if (context->vclass == PseudoColor
1071 || context->vclass == StaticColor) {
1073 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
1074 unsigned int *rtable, *gtable, *btable;
1076 rtable = computeStdTable(context->std_rgb_map->red_mult,
1077 context->std_rgb_map->red_max);
1079 gtable = computeStdTable(context->std_rgb_map->green_mult,
1080 context->std_rgb_map->green_max);
1082 btable = computeStdTable(context->std_rgb_map->blue_mult,
1083 context->std_rgb_map->blue_max);
1085 if (rtable==NULL || gtable==NULL || btable==NULL) {
1086 RErrorCode = RERR_NOMEMORY;
1087 return False;
1090 retColor->pixel = (rtable[color->red]
1091 + gtable[color->green]
1092 + btable[color->blue]
1093 + context->std_rgb_map->base_pixel) & 0xffffffff;
1094 retColor->red = color->red<<8;
1095 retColor->green = color->green<<8;
1096 retColor->blue = color->blue<<8;
1097 retColor->flags = DoRed|DoGreen|DoBlue;
1099 } else {
1100 const int cpc=context->attribs->colors_per_channel;
1101 const unsigned short rmask = cpc-1; /* different sizes could be used */
1102 const unsigned short gmask = rmask; /* for r,g,b */
1103 const unsigned short bmask = rmask;
1104 unsigned short *rtable, *gtable, *btable;
1105 const int cpccpc = cpc*cpc;
1106 int index;
1108 rtable = computeTable(rmask);
1109 gtable = computeTable(gmask);
1110 btable = computeTable(bmask);
1112 if (rtable==NULL || gtable==NULL || btable==NULL) {
1113 RErrorCode = RERR_NOMEMORY;
1114 return False;
1116 index = rtable[color->red]*cpccpc + gtable[color->green]*cpc
1117 + btable[color->blue];
1118 *retColor = context->colors[index];
1121 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
1123 const int cpc = context->attribs->colors_per_channel;
1124 unsigned short gmask;
1125 unsigned short *table;
1126 int index;
1128 if (context->vclass == StaticGray)
1129 gmask = (1<<context->depth) - 1; /* use all grays */
1130 else
1131 gmask = cpc*cpc*cpc-1;
1133 table = computeTable(gmask);
1134 if (!table)
1135 return False;
1137 index = table[(color->red*30 + color->green*59 + color->blue*11)/100];
1139 *retColor = context->colors[index];
1140 } else {
1141 RErrorCode = RERR_INTERNAL;
1142 return False;
1145 return True;