Use inotify to check for changes to the defaults database. Workaround for
[wmaker-crm.git] / wrlib / convert.c
blobcd5430478b1a441a7167516eaf8297e2a8b444ae
1 /* convert.c - convert RImage to Pixmap
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 const unsigned short *rtable,
72 const unsigned short *gtable,
73 const unsigned short *btable,
74 int dr, int dg, int db,
75 unsigned int roffs,
76 unsigned int goffs,
77 unsigned int boffs,
78 int width, int height,
79 int line_offset);
83 #endif /* ASM_X86_MMX */
85 #define NFREE(n) if (n) free(n)
87 #define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
90 typedef struct RConversionTable {
91 unsigned short table[256];
92 unsigned short index;
94 struct RConversionTable *next;
95 } RConversionTable;
98 typedef struct RStdConversionTable {
99 unsigned int table[256];
101 unsigned short mult;
102 unsigned short max;
104 struct RStdConversionTable *next;
105 } RStdConversionTable;
109 static RConversionTable *conversionTable = NULL;
110 static RStdConversionTable *stdConversionTable = NULL;
113 static unsigned short*
114 computeTable(unsigned short mask)
116 RConversionTable *tmp = conversionTable;
117 int i;
119 while (tmp) {
120 if (tmp->index == mask)
121 break;
122 tmp = tmp->next;
125 if (tmp)
126 return tmp->table;
128 tmp = (RConversionTable *)malloc(sizeof(RConversionTable));
129 if (tmp == NULL)
130 return NULL;
132 for (i=0;i<256;i++)
133 tmp->table[i] = (i*mask + 0x7f)/0xff;
135 tmp->index = mask;
136 tmp->next = conversionTable;
137 conversionTable = tmp;
138 return tmp->table;
142 static unsigned int*
143 computeStdTable(unsigned int mult, unsigned int max)
145 RStdConversionTable *tmp = stdConversionTable;
146 unsigned int i;
148 while (tmp) {
149 if (tmp->mult == mult && tmp->max == max)
150 break;
151 tmp = tmp->next;
154 if (tmp)
155 return tmp->table;
157 tmp = (RStdConversionTable *)malloc(sizeof(RStdConversionTable));
158 if (tmp == NULL)
159 return NULL;
161 for (i=0; i<256; i++) {
162 tmp->table[i] = (i*max)/0xff * mult;
164 tmp->mult = mult;
165 tmp->max = max;
167 tmp->next = stdConversionTable;
168 stdConversionTable = tmp;
170 return tmp->table;
173 /***************************************************************************/
176 static void
177 convertTrueColor_generic(RXImage *ximg, RImage *image,
178 signed char *err, signed char *nerr,
179 const unsigned short *rtable,
180 const unsigned short *gtable,
181 const unsigned short *btable,
182 const int dr, const int dg, const int db,
183 const unsigned short roffs,
184 const unsigned short goffs,
185 const unsigned short boffs)
187 signed char *terr;
188 int x, y, r, g, b;
189 int pixel;
190 int rer, ger, ber;
191 unsigned char *ptr = image->data;
192 int channels = (HAS_ALPHA(image) ? 4 : 3);
194 /* convert and dither the image to XImage */
195 for (y=0; y<image->height; y++) {
196 nerr[0] = 0;
197 nerr[1] = 0;
198 nerr[2] = 0;
199 for (x=0; x<image->width; x++, ptr+=channels) {
201 /* reduce pixel */
202 pixel = *ptr + err[x];
203 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
204 r = rtable[pixel];
205 /* calc error */
206 rer = pixel - r*dr;
208 /* reduce pixel */
209 pixel = *(ptr+1) + err[x+1];
210 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
211 g = gtable[pixel];
212 /* calc error */
213 ger = pixel - g*dg;
215 /* reduce pixel */
216 pixel = *(ptr+2) + err[x+2];
217 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
218 b = btable[pixel];
219 /* calc error */
220 ber = pixel - b*db;
223 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
224 XPutPixel(ximg->image, x, y, pixel);
226 /* distribute error */
227 r = (rer*3)/8;
228 g = (ger*3)/8;
229 b = (ber*3)/8;
230 /* x+1, y */
231 err[x+3*1]+=r;
232 err[x+1+3*1]+=g;
233 err[x+2+3*1]+=b;
234 /* x, y+1 */
235 nerr[x]+=r;
236 nerr[x+1]+=g;
237 nerr[x+2]+=b;
238 /* x+1, y+1 */
239 nerr[x+3*1]=rer-2*r;
240 nerr[x+1+3*1]=ger-2*g;
241 nerr[x+2+3*1]=ber-2*b;
243 /* skip to next line */
244 terr = err;
245 err = nerr;
246 nerr = terr;
249 /* redither the 1st line to distribute error better */
250 ptr=image->data;
251 y=0;
252 nerr[0] = 0;
253 nerr[1] = 0;
254 nerr[2] = 0;
255 for (x=0; x<image->width; x++, ptr+=channels) {
257 /* reduce pixel */
258 pixel = *ptr + err[x];
259 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
260 r = rtable[pixel];
261 /* calc error */
262 rer = pixel - r*dr;
264 /* reduce pixel */
265 pixel = *(ptr+1) + err[x+1];
266 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
267 g = gtable[pixel];
268 /* calc error */
269 ger = pixel - g*dg;
271 /* reduce pixel */
272 pixel = *(ptr+2) + err[x+2];
273 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
274 b = btable[pixel];
275 /* calc error */
276 ber = pixel - b*db;
279 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
280 XPutPixel(ximg->image, x, y, pixel);
282 /* distribute error */
283 r = (rer*3)/8;
284 g = (ger*3)/8;
285 b = (ber*3)/8;
286 /* x+1, y */
287 err[x+3*1]+=r;
288 err[x+1+3*1]+=g;
289 err[x+2+3*1]+=b;
290 /* x, y+1 */
291 nerr[x]+=r;
292 nerr[x+1]+=g;
293 nerr[x+2]+=b;
294 /* x+1, y+1 */
295 nerr[x+3*1]=rer-2*r;
296 nerr[x+1+3*1]=ger-2*g;
297 nerr[x+2+3*1]=ber-2*b;
304 static RXImage*
305 image2TrueColor(RContext *ctx, RImage *image)
307 RXImage *ximg;
308 unsigned short rmask, gmask, bmask;
309 unsigned short roffs, goffs, boffs;
310 unsigned short *rtable, *gtable, *btable;
311 int channels = (HAS_ALPHA(image) ? 4 : 3);
313 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
314 if (!ximg) {
315 return NULL;
318 roffs = ctx->red_offset;
319 goffs = ctx->green_offset;
320 boffs = ctx->blue_offset;
322 rmask = ctx->visual->red_mask >> roffs;
323 gmask = ctx->visual->green_mask >> goffs;
324 bmask = ctx->visual->blue_mask >> boffs;
326 rtable = computeTable(rmask);
327 gtable = computeTable(gmask);
328 btable = computeTable(bmask);
330 if (rtable==NULL || gtable==NULL || btable==NULL) {
331 RErrorCode = RERR_NOMEMORY;
332 RDestroyXImage(ctx, ximg);
333 return NULL;
337 #ifdef BENCH
338 cycle_bench(1);
339 #endif
341 if (ctx->attribs->render_mode==RBestMatchRendering) {
342 int ofs, r, g, b;
343 int x, y;
344 unsigned long pixel;
345 unsigned char *ptr = image->data;
347 /* fake match */
348 #ifdef DEBUG
349 puts("true color match");
350 #endif
351 if (rmask==0xff && gmask==0xff && bmask==0xff) {
352 for (y=0; y < image->height; y++) {
353 for (x=0; x < image->width; x++, ptr+=channels) {
354 /* reduce pixel */
355 pixel = (*(ptr)<<roffs) | (*(ptr+1)<<goffs) | (*(ptr+2)<<boffs);
356 XPutPixel(ximg->image, x, y, pixel);
359 } else {
360 for (y=0, ofs=0; y < image->height; y++) {
361 for (x=0; x < image->width; x++, ofs+=channels-3) {
362 /* reduce pixel */
363 r = rtable[ptr[ofs++]];
364 g = gtable[ptr[ofs++]];
365 b = btable[ptr[ofs++]];
366 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
367 XPutPixel(ximg->image, x, y, pixel);
371 } else {
372 /* dither */
373 const int dr=0xff/rmask;
374 const int dg=0xff/gmask;
375 const int db=0xff/bmask;
377 #ifdef DEBUG
378 puts("true color dither");
379 #endif
381 #ifdef ASM_X86_MMX
382 if (ctx->depth==16 && HAS_ALPHA(image) && x86_check_mmx()) {
383 short *err;
384 short *nerr;
386 err = malloc(8*(image->width+3));
387 nerr = malloc(8*(image->width+3));
388 if (!err || !nerr) {
389 NFREE(err);
390 NFREE(nerr);
391 RErrorCode = RERR_NOMEMORY;
392 RDestroyXImage(ctx, ximg);
393 return NULL;
395 memset(err, 0, 8*(image->width+3));
396 memset(nerr, 0, 8*(image->width+3));
398 x86_mmx_TrueColor_32_to_16(image->data,
399 (unsigned short*)ximg->image->data,
400 err+8, nerr+8,
401 rtable, gtable, btable,
402 dr, dg, db,
403 roffs, goffs, boffs,
404 image->width, image->height,
405 ximg->image->bytes_per_line - 2*image->width);
407 free(err);
408 free(nerr);
409 } else
410 #endif /* ASM_X86_MMX */
412 signed char *err;
413 signed char *nerr;
414 int ch = (HAS_ALPHA(image) ? 4 : 3);
416 err = malloc(ch*(image->width+2));
417 nerr = malloc(ch*(image->width+2));
418 if (!err || !nerr) {
419 NFREE(err);
420 NFREE(nerr);
421 RErrorCode = RERR_NOMEMORY;
422 RDestroyXImage(ctx, ximg);
423 return NULL;
426 memset(err, 0, ch*(image->width+2));
427 memset(nerr, 0, ch*(image->width+2));
429 convertTrueColor_generic(ximg, image, err, nerr,
430 rtable, gtable, btable,
431 dr, dg, db, roffs, goffs, boffs);
432 free(err);
433 free(nerr);
438 #ifdef BENCH
439 cycle_bench(0);
440 #endif
442 return ximg;
446 /***************************************************************************/
448 static void
449 convertPseudoColor_to_8(RXImage *ximg, RImage *image,
450 signed char *err, signed char *nerr,
451 const unsigned short *rtable,
452 const unsigned short *gtable,
453 const unsigned short *btable,
454 const int dr, const int dg, const int db,
455 unsigned long *pixels,
456 int cpc)
458 signed char *terr;
459 int x, y, r, g, b;
460 int pixel;
461 int rer, ger, ber;
462 unsigned char *ptr = image->data;
463 unsigned char *optr = (unsigned char*)ximg->image->data;
464 int channels = (HAS_ALPHA(image) ? 4 : 3);
465 int cpcpc = cpc*cpc;
467 /* convert and dither the image to XImage */
468 for (y=0; y<image->height; y++) {
469 nerr[0] = 0;
470 nerr[1] = 0;
471 nerr[2] = 0;
472 for (x=0; x<image->width*3; x+=3, ptr+=channels) {
474 /* reduce pixel */
475 pixel = *ptr + err[x];
476 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
477 r = rtable[pixel];
478 /* calc error */
479 rer = pixel - r*dr;
481 /* reduce pixel */
482 pixel = *(ptr+1) + err[x+1];
483 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
484 g = gtable[pixel];
485 /* calc error */
486 ger = pixel - g*dg;
488 /* reduce pixel */
489 pixel = *(ptr+2) + err[x+2];
490 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
491 b = btable[pixel];
492 /* calc error */
493 ber = pixel - b*db;
495 *optr++ = pixels[r*cpcpc + g*cpc + b];
497 /* distribute error */
498 r = (rer*3)/8;
499 g = (ger*3)/8;
500 b = (ber*3)/8;
502 /* x+1, y */
503 err[x+3*1]+=r;
504 err[x+1+3*1]+=g;
505 err[x+2+3*1]+=b;
506 /* x, y+1 */
507 nerr[x]+=r;
508 nerr[x+1]+=g;
509 nerr[x+2]+=b;
510 /* x+1, y+1 */
511 nerr[x+3*1]=rer-2*r;
512 nerr[x+1+3*1]=ger-2*g;
513 nerr[x+2+3*1]=ber-2*b;
515 /* skip to next line */
516 terr = err;
517 err = nerr;
518 nerr = terr;
520 optr += ximg->image->bytes_per_line - image->width;
526 static RXImage*
527 image2PseudoColor(RContext *ctx, RImage *image)
529 RXImage *ximg;
530 register int x, y, r, g, b;
531 unsigned char *ptr;
532 unsigned long pixel;
533 const int cpc=ctx->attribs->colors_per_channel;
534 const unsigned short rmask = cpc-1; /* different sizes could be used */
535 const unsigned short gmask = rmask; /* for r,g,b */
536 const unsigned short bmask = rmask;
537 unsigned short *rtable, *gtable, *btable;
538 const int cpccpc = cpc*cpc;
539 int channels = (HAS_ALPHA(image) ? 4 : 3);
541 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
542 if (!ximg) {
543 return NULL;
546 ptr = image->data;
548 /* Tables are same at the moment because rmask==gmask==bmask. */
549 rtable = computeTable(rmask);
550 gtable = computeTable(gmask);
551 btable = computeTable(bmask);
553 if (rtable==NULL || gtable==NULL || btable==NULL) {
554 RErrorCode = RERR_NOMEMORY;
555 RDestroyXImage(ctx, ximg);
556 return NULL;
559 if (ctx->attribs->render_mode == RBestMatchRendering) {
560 /* fake match */
561 #ifdef DEBUG
562 printf("pseudo color match with %d colors per channel\n", cpc);
563 #endif
564 for (y=0; y<image->height; y++) {
565 for (x=0; x<image->width; x++, ptr+=channels-3) {
566 /* reduce pixel */
567 r = rtable[*ptr++];
568 g = gtable[*ptr++];
569 b = btable[*ptr++];
570 pixel = r*cpccpc + g*cpc + b;
571 /*data[ofs] = ctx->colors[pixel].pixel;*/
572 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
575 } else {
576 /* dither */
577 signed char *err;
578 signed char *nerr;
579 const int dr=0xff/rmask;
580 const int dg=0xff/gmask;
581 const int db=0xff/bmask;
584 #ifdef DEBUG
585 printf("pseudo color dithering with %d colors per channel\n", cpc);
586 #endif
587 err = malloc(4*(image->width+3));
588 nerr = malloc(4*(image->width+3));
589 if (!err || !nerr) {
590 NFREE(err);
591 NFREE(nerr);
592 RErrorCode = RERR_NOMEMORY;
593 RDestroyXImage(ctx, ximg);
594 return NULL;
596 memset(err, 0, 4*(image->width+3));
597 memset(nerr, 0, 4*(image->width+3));
599 /*#ifdef ASM_X86*/
600 #if 0
601 x86_PseudoColor_32_to_8(image->data, ximg->image->data,
602 err+4, nerr+4,
603 rtable,
604 dr, dg, db, ctx->pixels, cpc,
605 image->width, image->height,
606 channels,
607 ximg->image->bytes_per_line - image->width);
608 #else
609 convertPseudoColor_to_8(ximg, image, err+4, nerr+4,
610 rtable, gtable, btable,
611 dr, dg, db, ctx->pixels, cpc);
612 #endif
614 free(err);
615 free(nerr);
618 return ximg;
623 * For standard colormap
625 static RXImage*
626 image2StandardPseudoColor(RContext *ctx, RImage *image)
628 RXImage *ximg;
629 register int x, y, r, g, b;
630 unsigned char *ptr;
631 unsigned long pixel;
632 unsigned char *data;
633 unsigned int *rtable, *gtable, *btable;
634 unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
635 int channels = (HAS_ALPHA(image) ? 4 : 3);
638 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
639 if (!ximg) {
640 return NULL;
643 ptr = image->data;
645 data = (unsigned char *)ximg->image->data;
648 rtable = computeStdTable(ctx->std_rgb_map->red_mult,
649 ctx->std_rgb_map->red_max);
651 gtable = computeStdTable(ctx->std_rgb_map->green_mult,
652 ctx->std_rgb_map->green_max);
654 btable = computeStdTable(ctx->std_rgb_map->blue_mult,
655 ctx->std_rgb_map->blue_max);
657 if (rtable==NULL || gtable==NULL || btable==NULL) {
658 RErrorCode = RERR_NOMEMORY;
659 RDestroyXImage(ctx, ximg);
660 return NULL;
664 if (ctx->attribs->render_mode == RBestMatchRendering) {
665 for (y=0; y<image->height; y++) {
666 for (x=0; x<image->width; x++, ptr+=channels) {
667 /* reduce pixel */
668 pixel = (rtable[*ptr] + gtable[*(ptr+1)]
669 + btable[*(ptr+2)] + base_pixel) & 0xffffffff;
671 XPutPixel(ximg->image, x, y, pixel);
674 } else {
675 /* dither */
676 signed short *err, *nerr;
677 signed short *terr;
678 int rer, ger, ber;
679 int x1, ofs;
681 #ifdef DEBUG
682 printf("pseudo color dithering with %d colors per channel\n",
683 ctx->attribs->colors_per_channel);
684 #endif
685 err = (short*)malloc(3*(image->width+2)*sizeof(short));
686 nerr = (short*)malloc(3*(image->width+2)*sizeof(short));
687 if (!err || !nerr) {
688 NFREE(err);
689 NFREE(nerr);
690 RErrorCode = RERR_NOMEMORY;
691 RDestroyXImage(ctx, ximg);
692 return NULL;
694 for (x=0, x1=0; x<image->width*3; x1+=channels-3) {
695 err[x++] = ptr[x1++];
696 err[x++] = ptr[x1++];
697 err[x++] = ptr[x1++];
699 err[x] = err[x+1] = err[x+2] = 0;
700 /* convert and dither the image to XImage */
701 for (y=0, ofs=0; y<image->height; y++) {
702 if (y<image->height-1) {
703 int x1;
704 for (x=0, x1=(y+1)*image->width*channels;
705 x<image->width*3;
706 x1+=channels-3) {
707 nerr[x++] = ptr[x1++];
708 nerr[x++] = ptr[x1++];
709 nerr[x++] = ptr[x1++];
711 /* last column */
712 x1-=channels;
713 nerr[x++] = ptr[x1++];
714 nerr[x++] = ptr[x1++];
715 nerr[x++] = ptr[x1++];
717 for (x=0; x<image->width*3; x+=3, ofs++) {
718 /* reduce pixel */
719 if (err[x]>0xff) err[x]=0xff; else if (err[x]<0) err[x]=0;
720 if (err[x+1]>0xff) err[x+1]=0xff; else if (err[x+1]<0) err[x+1]=0;
721 if (err[x+2]>0xff) err[x+2]=0xff; else if (err[x+2]<0) err[x+2]=0;
723 r = rtable[err[x]];
724 g = gtable[err[x+1]];
725 b = btable[err[x+2]];
727 pixel = r + g + b;
729 data[ofs] = base_pixel + pixel;
731 /* calc error */
732 rer = err[x] - (ctx->colors[pixel].red>>8);
733 ger = err[x+1] - (ctx->colors[pixel].green>>8);
734 ber = err[x+2] - (ctx->colors[pixel].blue>>8);
736 /* distribute error */
737 err[x+3*1]+=(rer*7)/16;
738 err[x+1+3*1]+=(ger*7)/16;
739 err[x+2+3*1]+=(ber*7)/16;
741 nerr[x]+=(rer*5)/16;
742 nerr[x+1]+=(ger*5)/16;
743 nerr[x+2]+=(ber*5)/16;
745 if (x>0) {
746 nerr[x-3*1]+=(rer*3)/16;
747 nerr[x-3*1+1]+=(ger*3)/16;
748 nerr[x-3*1+2]+=(ber*3)/16;
751 nerr[x+3*1]+=rer/16;
752 nerr[x+1+3*1]+=ger/16;
753 nerr[x+2+3*1]+=ber/16;
755 /* skip to next line */
756 terr = err;
757 err = nerr;
758 nerr = terr;
760 ofs += ximg->image->bytes_per_line - image->width;
762 free(err);
763 free(nerr);
765 ximg->image->data = (char*)data;
767 return ximg;
772 static RXImage*
773 image2GrayScale(RContext *ctx, RImage *image)
775 RXImage *ximg;
776 register int x, y, g;
777 unsigned char *ptr;
778 const int cpc=ctx->attribs->colors_per_channel;
779 unsigned short gmask;
780 unsigned short *table;
781 unsigned char *data;
782 int channels = (HAS_ALPHA(image) ? 4 : 3);
785 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
786 if (!ximg) {
787 return NULL;
790 ptr = image->data;
792 data = (unsigned char *)ximg->image->data;
794 if (ctx->vclass == StaticGray)
795 gmask = (1<<ctx->depth) - 1; /* use all grays */
796 else
797 gmask = cpc*cpc*cpc-1;
799 table = computeTable(gmask);
801 if (table==NULL) {
802 RErrorCode = RERR_NOMEMORY;
803 RDestroyXImage(ctx, ximg);
804 return NULL;
807 if (ctx->attribs->render_mode == RBestMatchRendering) {
808 /* fake match */
809 #ifdef DEBUG
810 printf("grayscale match with %d colors per channel\n", cpc);
811 #endif
812 for (y=0; y<image->height; y++) {
813 for (x=0; x<image->width; x++) {
814 /* reduce pixel */
815 g = table[(*ptr * 30 + *(ptr+1) * 59 + *(ptr+2) * 11)/100];
816 ptr += channels;
817 /*data[ofs] = ctx->colors[g].pixel;*/
818 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
821 } else {
822 /* dither */
823 short *gerr;
824 short *ngerr;
825 short *terr;
826 int ger;
827 const int dg=0xff/gmask;
829 #ifdef DEBUG
830 printf("grayscale dither with %d colors per channel\n", cpc);
831 #endif
832 gerr = (short*)malloc((image->width+2)*sizeof(short));
833 ngerr = (short*)malloc((image->width+2)*sizeof(short));
834 if (!gerr || !ngerr) {
835 NFREE(gerr);
836 NFREE(ngerr);
837 RErrorCode = RERR_NOMEMORY;
838 RDestroyXImage(ctx, ximg);
839 return NULL;
841 for (x=0, y=0; x<image->width; x++, y+=channels) {
842 gerr[x] = (ptr[y]*30 + ptr[y+1]*59 + ptr[y+2]*11)/100;
844 gerr[x] = 0;
845 /* convert and dither the image to XImage */
846 for (y=0; y<image->height; y++) {
847 if (y<image->height-1) {
848 int x1;
849 for (x=0, x1=(y+1)*image->width*channels; x<image->width; x++, x1+=channels) {
850 ngerr[x] = (ptr[x1]*30 + ptr[x1+1]*59 + ptr[x1+2]*11)/100;
852 /* last column */
853 x1-=channels;
854 ngerr[x] = (ptr[x1]*30 + ptr[x1+1]*59 + ptr[x1+2]*11)/100;
856 for (x=0; x<image->width; x++) {
857 /* reduce pixel */
858 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
860 g = table[gerr[x]];
862 /*data[ofs] = ctx->colors[g].pixel;*/
863 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
864 /* calc error */
865 ger = gerr[x] - g*dg;
867 /* distribute error */
868 g = (ger*3)/8;
869 /* x+1, y */
870 gerr[x+1]+=g;
871 /* x, y+1 */
872 ngerr[x]+=g;
873 /* x+1, y+1 */
874 ngerr[x+1]+=ger-2*g;
876 /* skip to next line */
877 terr = gerr;
878 gerr = ngerr;
879 ngerr = terr;
881 free(gerr);
882 free(ngerr);
884 ximg->image->data = (char*)data;
886 return ximg;
890 static RXImage*
891 image2Bitmap(RContext *ctx, RImage *image, int threshold)
893 RXImage *ximg;
894 unsigned char *alpha;
895 int x, y;
897 ximg = RCreateXImage(ctx, 1, image->width, image->height);
898 if (!ximg) {
899 return NULL;
901 alpha = image->data+3;
903 for (y = 0; y < image->height; y++) {
904 for (x = 0; x < image->width; x++) {
905 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
906 alpha+=4;
910 return ximg;
915 RConvertImage(RContext *context, RImage *image, Pixmap *pixmap)
917 RXImage *ximg=NULL;
918 #ifdef XSHM
919 Pixmap tmp;
920 #endif
922 assert(context!=NULL);
923 assert(image!=NULL);
924 assert(pixmap!=NULL);
926 switch (context->vclass) {
927 case TrueColor:
928 #ifdef BENCH
929 cycle_bench(1);
930 #endif
931 ximg = image2TrueColor(context, image);
932 #ifdef BENCH
933 cycle_bench(0);
934 #endif
935 break;
937 case PseudoColor:
938 case StaticColor:
939 #ifdef BENCH
940 cycle_bench(1);
941 #endif
942 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
943 ximg = image2StandardPseudoColor(context, image);
944 else
945 ximg = image2PseudoColor(context, image);
946 #ifdef BENCH
947 cycle_bench(0);
948 #endif
949 break;
951 case GrayScale:
952 case StaticGray:
953 ximg = image2GrayScale(context, image);
954 break;
958 if (!ximg) {
959 return False;
962 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width,
963 image->height, context->depth);
965 #ifdef XSHM
966 if (context->flags.use_shared_pixmap && ximg->is_shared)
967 tmp = R_CreateXImageMappedPixmap(context, ximg);
968 else
969 tmp = None;
970 if (tmp) {
972 * We have to copy the shm Pixmap into a normal Pixmap because
973 * otherwise, we would have to control when Pixmaps are freed so
974 * that we can detach their shm segments. This is a problem if the
975 * program crash, leaving stale shared memory segments in the
976 * system (lots of them). But with some work, we can optimize
977 * things and remove this XCopyArea. This will require
978 * explicitly freeing all pixmaps when exiting or restarting
979 * wmaker.
981 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0,
982 image->width, image->height, 0, 0);
983 XFreePixmap(context->dpy, tmp);
984 } else {
985 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
986 image->width, image->height);
988 #else /* !XSHM */
989 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
990 image->width, image->height);
991 #endif /* !XSHM */
993 RDestroyXImage(context, ximg);
995 return True;
999 /* make the gc permanent (create with context creation).
1000 * GC creation is very expensive. altering its properties is not. -Dan
1003 RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap,
1004 Pixmap *mask, int threshold)
1006 GC gc;
1007 XGCValues gcv;
1008 RXImage *ximg=NULL;
1010 assert(context!=NULL);
1011 assert(image!=NULL);
1012 assert(pixmap!=NULL);
1013 assert(mask!=NULL);
1015 if (!RConvertImage(context, image, pixmap))
1016 return False;
1018 if (image->format==RRGBFormat) {
1019 *mask = None;
1020 return True;
1023 ximg = image2Bitmap(context, image, threshold);
1025 if (!ximg) {
1026 return False;
1028 *mask = XCreatePixmap(context->dpy, context->drawable, image->width,
1029 image->height, 1);
1030 gcv.foreground = context->black;
1031 gcv.background = context->white;
1032 gcv.graphics_exposures = False;
1033 gc = XCreateGC(context->dpy, *mask, GCForeground|GCBackground
1034 |GCGraphicsExposures, &gcv);
1035 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0,
1036 image->width, image->height);
1037 RDestroyXImage(context, ximg);
1038 XFreeGC(context->dpy, gc);
1040 return True;
1044 Bool
1045 RGetClosestXColor(RContext *context, RColor *color, XColor *retColor)
1047 if (context->vclass == TrueColor) {
1048 unsigned short rmask, gmask, bmask;
1049 unsigned short roffs, goffs, boffs;
1050 unsigned short *rtable, *gtable, *btable;
1052 roffs = context->red_offset;
1053 goffs = context->green_offset;
1054 boffs = context->blue_offset;
1056 rmask = context->visual->red_mask >> roffs;
1057 gmask = context->visual->green_mask >> goffs;
1058 bmask = context->visual->blue_mask >> boffs;
1060 rtable = computeTable(rmask);
1061 gtable = computeTable(gmask);
1062 btable = computeTable(bmask);
1064 retColor->pixel = (rtable[color->red]<<roffs) |
1065 (gtable[color->green]<<goffs) | (btable[color->blue]<<boffs);
1067 retColor->red = color->red << 8;
1068 retColor->green = color->green << 8;
1069 retColor->blue = color->blue << 8;
1070 retColor->flags = DoRed|DoGreen|DoBlue;
1072 } else if (context->vclass == PseudoColor
1073 || context->vclass == StaticColor) {
1075 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
1076 unsigned int *rtable, *gtable, *btable;
1078 rtable = computeStdTable(context->std_rgb_map->red_mult,
1079 context->std_rgb_map->red_max);
1081 gtable = computeStdTable(context->std_rgb_map->green_mult,
1082 context->std_rgb_map->green_max);
1084 btable = computeStdTable(context->std_rgb_map->blue_mult,
1085 context->std_rgb_map->blue_max);
1087 if (rtable==NULL || gtable==NULL || btable==NULL) {
1088 RErrorCode = RERR_NOMEMORY;
1089 return False;
1092 retColor->pixel = (rtable[color->red]
1093 + gtable[color->green]
1094 + btable[color->blue]
1095 + context->std_rgb_map->base_pixel) & 0xffffffff;
1096 retColor->red = color->red<<8;
1097 retColor->green = color->green<<8;
1098 retColor->blue = color->blue<<8;
1099 retColor->flags = DoRed|DoGreen|DoBlue;
1101 } else {
1102 const int cpc=context->attribs->colors_per_channel;
1103 const unsigned short rmask = cpc-1; /* different sizes could be used */
1104 const unsigned short gmask = rmask; /* for r,g,b */
1105 const unsigned short bmask = rmask;
1106 unsigned short *rtable, *gtable, *btable;
1107 const int cpccpc = cpc*cpc;
1108 int index;
1110 rtable = computeTable(rmask);
1111 gtable = computeTable(gmask);
1112 btable = computeTable(bmask);
1114 if (rtable==NULL || gtable==NULL || btable==NULL) {
1115 RErrorCode = RERR_NOMEMORY;
1116 return False;
1118 index = rtable[color->red]*cpccpc + gtable[color->green]*cpc
1119 + btable[color->blue];
1120 *retColor = context->colors[index];
1123 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
1125 const int cpc = context->attribs->colors_per_channel;
1126 unsigned short gmask;
1127 unsigned short *table;
1128 int index;
1130 if (context->vclass == StaticGray)
1131 gmask = (1<<context->depth) - 1; /* use all grays */
1132 else
1133 gmask = cpc*cpc*cpc-1;
1135 table = computeTable(gmask);
1136 if (!table)
1137 return False;
1139 index = table[(color->red*30 + color->green*59 + color->blue*11)/100];
1141 *retColor = context->colors[index];
1142 } else {
1143 RErrorCode = RERR_INTERNAL;
1144 return False;
1147 return True;