Change to the linux kernel coding style
[wmaker-crm.git] / wrlib / convert.c
1 /* convert.c - convert RImage to Pixmap
2  *
3  * Raster graphics library
4  *
5  * Copyright (c) 1997-2003 Alfredo K. Kojima
6  *
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.
11  *
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.
16  *
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.
20  */
21
22 /* Problems:
23  *   1. Using Grayscale visual with Dithering crashes wmaker
24  *   2. Ghost dock/appicon is wrong in Pseudocolor, Staticgray, Grayscale
25  */
26
27 #include <config.h>
28
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 #include <assert.h>
36
37 #ifdef BENCH
38 #include "bench.h"
39 #endif
40
41 #include "wraster.h"
42
43 #ifdef XSHM
44 extern Pixmap R_CreateXImageMappedPixmap(RContext * context, RXImage * ximage);
45
46 #endif
47
48 #ifdef ASM_X86
49 extern void x86_PseudoColor_32_to_8(unsigned char *image,
50                                     unsigned char *ximage,
51                                     char *err, char *nerr,
52                                     short *ctable,
53                                     int dr, int dg, int db,
54                                     unsigned long *pixels,
55                                     int cpc, int width, int height, int bytesPerPixel, int line_offset);
56 #endif                          /* ASM_X86 */
57
58 #ifdef ASM_X86_MMX
59
60 extern int x86_check_mmx();
61
62 extern void x86_mmx_TrueColor_32_to_16(unsigned char *image,
63                                        unsigned short *ximage,
64                                        short *err, short *nerr,
65                                        const unsigned short *rtable,
66                                        const unsigned short *gtable,
67                                        const unsigned short *btable,
68                                        int dr, int dg, int db,
69                                        unsigned int roffs,
70                                        unsigned int goffs,
71                                        unsigned int boffs, int width, int height, int line_offset);
72
73 #endif                          /* ASM_X86_MMX */
74
75 #define NFREE(n)  if (n) free(n)
76
77 #define HAS_ALPHA(I)    ((I)->format == RRGBAFormat)
78
79 typedef struct RConversionTable {
80         unsigned short table[256];
81         unsigned short index;
82
83         struct RConversionTable *next;
84 } RConversionTable;
85
86 typedef struct RStdConversionTable {
87         unsigned int table[256];
88
89         unsigned short mult;
90         unsigned short max;
91
92         struct RStdConversionTable *next;
93 } RStdConversionTable;
94
95 static RConversionTable *conversionTable = NULL;
96 static RStdConversionTable *stdConversionTable = NULL;
97
98 static unsigned short *computeTable(unsigned short mask)
99 {
100         RConversionTable *tmp = conversionTable;
101         int i;
102
103         while (tmp) {
104                 if (tmp->index == mask)
105                         break;
106                 tmp = tmp->next;
107         }
108
109         if (tmp)
110                 return tmp->table;
111
112         tmp = (RConversionTable *) malloc(sizeof(RConversionTable));
113         if (tmp == NULL)
114                 return NULL;
115
116         for (i = 0; i < 256; i++)
117                 tmp->table[i] = (i * mask + 0x7f) / 0xff;
118
119         tmp->index = mask;
120         tmp->next = conversionTable;
121         conversionTable = tmp;
122         return tmp->table;
123 }
124
125 static unsigned int *computeStdTable(unsigned int mult, unsigned int max)
126 {
127         RStdConversionTable *tmp = stdConversionTable;
128         unsigned int i;
129
130         while (tmp) {
131                 if (tmp->mult == mult && tmp->max == max)
132                         break;
133                 tmp = tmp->next;
134         }
135
136         if (tmp)
137                 return tmp->table;
138
139         tmp = (RStdConversionTable *) malloc(sizeof(RStdConversionTable));
140         if (tmp == NULL)
141                 return NULL;
142
143         for (i = 0; i < 256; i++) {
144                 tmp->table[i] = (i * max) / 0xff * mult;
145         }
146         tmp->mult = mult;
147         tmp->max = max;
148
149         tmp->next = stdConversionTable;
150         stdConversionTable = tmp;
151
152         return tmp->table;
153 }
154
155 /***************************************************************************/
156
157 static void
158 convertTrueColor_generic(RXImage * ximg, RImage * image,
159                          signed char *err, signed char *nerr,
160                          const unsigned short *rtable,
161                          const unsigned short *gtable,
162                          const unsigned short *btable,
163                          const int dr, const int dg, const int db,
164                          const unsigned short roffs, const unsigned short goffs, const unsigned short boffs)
165 {
166         signed char *terr;
167         int x, y, r, g, b;
168         int pixel;
169         int rer, ger, ber;
170         unsigned char *ptr = image->data;
171         int channels = (HAS_ALPHA(image) ? 4 : 3);
172
173         /* convert and dither the image to XImage */
174         for (y = 0; y < image->height; y++) {
175                 nerr[0] = 0;
176                 nerr[1] = 0;
177                 nerr[2] = 0;
178                 for (x = 0; x < image->width; x++, ptr += channels) {
179
180                         /* reduce pixel */
181                         pixel = *ptr + err[x];
182                         if (pixel < 0)
183                                 pixel = 0;
184                         else if (pixel > 0xff)
185                                 pixel = 0xff;
186                         r = rtable[pixel];
187                         /* calc error */
188                         rer = pixel - r * dr;
189
190                         /* reduce pixel */
191                         pixel = *(ptr + 1) + err[x + 1];
192                         if (pixel < 0)
193                                 pixel = 0;
194                         else if (pixel > 0xff)
195                                 pixel = 0xff;
196                         g = gtable[pixel];
197                         /* calc error */
198                         ger = pixel - g * dg;
199
200                         /* reduce pixel */
201                         pixel = *(ptr + 2) + err[x + 2];
202                         if (pixel < 0)
203                                 pixel = 0;
204                         else if (pixel > 0xff)
205                                 pixel = 0xff;
206                         b = btable[pixel];
207                         /* calc error */
208                         ber = pixel - b * db;
209
210                         pixel = (r << roffs) | (g << goffs) | (b << boffs);
211                         XPutPixel(ximg->image, x, y, pixel);
212
213                         /* distribute error */
214                         r = (rer * 3) / 8;
215                         g = (ger * 3) / 8;
216                         b = (ber * 3) / 8;
217                         /* x+1, y */
218                         err[x + 3 * 1] += r;
219                         err[x + 1 + 3 * 1] += g;
220                         err[x + 2 + 3 * 1] += b;
221                         /* x, y+1 */
222                         nerr[x] += r;
223                         nerr[x + 1] += g;
224                         nerr[x + 2] += b;
225                         /* x+1, y+1 */
226                         nerr[x + 3 * 1] = rer - 2 * r;
227                         nerr[x + 1 + 3 * 1] = ger - 2 * g;
228                         nerr[x + 2 + 3 * 1] = ber - 2 * b;
229                 }
230                 /* skip to next line */
231                 terr = err;
232                 err = nerr;
233                 nerr = terr;
234         }
235
236         /* redither the 1st line to distribute error better */
237         ptr = image->data;
238         y = 0;
239         nerr[0] = 0;
240         nerr[1] = 0;
241         nerr[2] = 0;
242         for (x = 0; x < image->width; x++, ptr += channels) {
243
244                 /* reduce pixel */
245                 pixel = *ptr + err[x];
246                 if (pixel < 0)
247                         pixel = 0;
248                 else if (pixel > 0xff)
249                         pixel = 0xff;
250                 r = rtable[pixel];
251                 /* calc error */
252                 rer = pixel - r * dr;
253
254                 /* reduce pixel */
255                 pixel = *(ptr + 1) + err[x + 1];
256                 if (pixel < 0)
257                         pixel = 0;
258                 else if (pixel > 0xff)
259                         pixel = 0xff;
260                 g = gtable[pixel];
261                 /* calc error */
262                 ger = pixel - g * dg;
263
264                 /* reduce pixel */
265                 pixel = *(ptr + 2) + err[x + 2];
266                 if (pixel < 0)
267                         pixel = 0;
268                 else if (pixel > 0xff)
269                         pixel = 0xff;
270                 b = btable[pixel];
271                 /* calc error */
272                 ber = pixel - b * db;
273
274                 pixel = (r << roffs) | (g << goffs) | (b << boffs);
275                 XPutPixel(ximg->image, x, y, pixel);
276
277                 /* distribute error */
278                 r = (rer * 3) / 8;
279                 g = (ger * 3) / 8;
280                 b = (ber * 3) / 8;
281                 /* x+1, y */
282                 err[x + 3 * 1] += r;
283                 err[x + 1 + 3 * 1] += g;
284                 err[x + 2 + 3 * 1] += b;
285                 /* x, y+1 */
286                 nerr[x] += r;
287                 nerr[x + 1] += g;
288                 nerr[x + 2] += b;
289                 /* x+1, y+1 */
290                 nerr[x + 3 * 1] = rer - 2 * r;
291                 nerr[x + 1 + 3 * 1] = ger - 2 * g;
292                 nerr[x + 2 + 3 * 1] = ber - 2 * b;
293         }
294 }
295
296 static RXImage *image2TrueColor(RContext * ctx, RImage * image)
297 {
298         RXImage *ximg;
299         unsigned short rmask, gmask, bmask;
300         unsigned short roffs, goffs, boffs;
301         unsigned short *rtable, *gtable, *btable;
302         int channels = (HAS_ALPHA(image) ? 4 : 3);
303
304         ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
305         if (!ximg) {
306                 return NULL;
307         }
308
309         roffs = ctx->red_offset;
310         goffs = ctx->green_offset;
311         boffs = ctx->blue_offset;
312
313         rmask = ctx->visual->red_mask >> roffs;
314         gmask = ctx->visual->green_mask >> goffs;
315         bmask = ctx->visual->blue_mask >> boffs;
316
317         rtable = computeTable(rmask);
318         gtable = computeTable(gmask);
319         btable = computeTable(bmask);
320
321         if (rtable == NULL || gtable == NULL || btable == NULL) {
322                 RErrorCode = RERR_NOMEMORY;
323                 RDestroyXImage(ctx, ximg);
324                 return NULL;
325         }
326
327 #ifdef BENCH
328         cycle_bench(1);
329 #endif
330
331         if (ctx->attribs->render_mode == RBestMatchRendering) {
332                 int ofs, r, g, b;
333                 int x, y;
334                 unsigned long pixel;
335                 unsigned char *ptr = image->data;
336
337                 /* fake match */
338 #ifdef DEBUG
339                 puts("true color match");
340 #endif
341                 if (rmask == 0xff && gmask == 0xff && bmask == 0xff) {
342                         for (y = 0; y < image->height; y++) {
343                                 for (x = 0; x < image->width; x++, ptr += channels) {
344                                         /* reduce pixel */
345                                         pixel = (*(ptr) << roffs) | (*(ptr + 1) << goffs) | (*(ptr + 2) << boffs);
346                                         XPutPixel(ximg->image, x, y, pixel);
347                                 }
348                         }
349                 } else {
350                         for (y = 0, ofs = 0; y < image->height; y++) {
351                                 for (x = 0; x < image->width; x++, ofs += channels - 3) {
352                                         /* reduce pixel */
353                                         r = rtable[ptr[ofs++]];
354                                         g = gtable[ptr[ofs++]];
355                                         b = btable[ptr[ofs++]];
356                                         pixel = (r << roffs) | (g << goffs) | (b << boffs);
357                                         XPutPixel(ximg->image, x, y, pixel);
358                                 }
359                         }
360                 }
361         } else {
362                 /* dither */
363                 const int dr = 0xff / rmask;
364                 const int dg = 0xff / gmask;
365                 const int db = 0xff / bmask;
366
367 #ifdef DEBUG
368                 puts("true color dither");
369 #endif
370
371 #ifdef ASM_X86_MMX
372                 if (ctx->depth == 16 && HAS_ALPHA(image) && x86_check_mmx()) {
373                         short *err;
374                         short *nerr;
375
376                         err = malloc(8 * (image->width + 3));
377                         nerr = malloc(8 * (image->width + 3));
378                         if (!err || !nerr) {
379                                 NFREE(err);
380                                 NFREE(nerr);
381                                 RErrorCode = RERR_NOMEMORY;
382                                 RDestroyXImage(ctx, ximg);
383                                 return NULL;
384                         }
385                         memset(err, 0, 8 * (image->width + 3));
386                         memset(nerr, 0, 8 * (image->width + 3));
387
388                         x86_mmx_TrueColor_32_to_16(image->data,
389                                                    (unsigned short *)ximg->image->data,
390                                                    err + 8, nerr + 8,
391                                                    rtable, gtable, btable,
392                                                    dr, dg, db,
393                                                    roffs, goffs, boffs,
394                                                    image->width, image->height,
395                                                    ximg->image->bytes_per_line - 2 * image->width);
396
397                         free(err);
398                         free(nerr);
399                 } else
400 #endif                          /* ASM_X86_MMX */
401                 {
402                         signed char *err;
403                         signed char *nerr;
404                         int ch = (HAS_ALPHA(image) ? 4 : 3);
405
406                         err = malloc(ch * (image->width + 2));
407                         nerr = malloc(ch * (image->width + 2));
408                         if (!err || !nerr) {
409                                 NFREE(err);
410                                 NFREE(nerr);
411                                 RErrorCode = RERR_NOMEMORY;
412                                 RDestroyXImage(ctx, ximg);
413                                 return NULL;
414                         }
415
416                         memset(err, 0, ch * (image->width + 2));
417                         memset(nerr, 0, ch * (image->width + 2));
418
419                         convertTrueColor_generic(ximg, image, err, nerr,
420                                                  rtable, gtable, btable, dr, dg, db, roffs, goffs, boffs);
421                         free(err);
422                         free(nerr);
423                 }
424
425         }
426
427 #ifdef BENCH
428         cycle_bench(0);
429 #endif
430
431         return ximg;
432 }
433
434 /***************************************************************************/
435
436 static void
437 convertPseudoColor_to_8(RXImage * ximg, RImage * image,
438                         signed char *err, signed char *nerr,
439                         const unsigned short *rtable,
440                         const unsigned short *gtable,
441                         const unsigned short *btable,
442                         const int dr, const int dg, const int db, unsigned long *pixels, int cpc)
443 {
444         signed char *terr;
445         int x, y, r, g, b;
446         int pixel;
447         int rer, ger, ber;
448         unsigned char *ptr = image->data;
449         unsigned char *optr = (unsigned char *)ximg->image->data;
450         int channels = (HAS_ALPHA(image) ? 4 : 3);
451         int cpcpc = cpc * cpc;
452
453         /* convert and dither the image to XImage */
454         for (y = 0; y < image->height; y++) {
455                 nerr[0] = 0;
456                 nerr[1] = 0;
457                 nerr[2] = 0;
458                 for (x = 0; x < image->width * 3; x += 3, ptr += channels) {
459
460                         /* reduce pixel */
461                         pixel = *ptr + err[x];
462                         if (pixel < 0)
463                                 pixel = 0;
464                         else if (pixel > 0xff)
465                                 pixel = 0xff;
466                         r = rtable[pixel];
467                         /* calc error */
468                         rer = pixel - r * dr;
469
470                         /* reduce pixel */
471                         pixel = *(ptr + 1) + err[x + 1];
472                         if (pixel < 0)
473                                 pixel = 0;
474                         else if (pixel > 0xff)
475                                 pixel = 0xff;
476                         g = gtable[pixel];
477                         /* calc error */
478                         ger = pixel - g * dg;
479
480                         /* reduce pixel */
481                         pixel = *(ptr + 2) + err[x + 2];
482                         if (pixel < 0)
483                                 pixel = 0;
484                         else if (pixel > 0xff)
485                                 pixel = 0xff;
486                         b = btable[pixel];
487                         /* calc error */
488                         ber = pixel - b * db;
489
490                         *optr++ = pixels[r * cpcpc + g * cpc + b];
491
492                         /* distribute error */
493                         r = (rer * 3) / 8;
494                         g = (ger * 3) / 8;
495                         b = (ber * 3) / 8;
496
497                         /* x+1, y */
498                         err[x + 3 * 1] += r;
499                         err[x + 1 + 3 * 1] += g;
500                         err[x + 2 + 3 * 1] += b;
501                         /* x, y+1 */
502                         nerr[x] += r;
503                         nerr[x + 1] += g;
504                         nerr[x + 2] += b;
505                         /* x+1, y+1 */
506                         nerr[x + 3 * 1] = rer - 2 * r;
507                         nerr[x + 1 + 3 * 1] = ger - 2 * g;
508                         nerr[x + 2 + 3 * 1] = ber - 2 * b;
509                 }
510                 /* skip to next line */
511                 terr = err;
512                 err = nerr;
513                 nerr = terr;
514
515                 optr += ximg->image->bytes_per_line - image->width;
516         }
517 }
518
519 static RXImage *image2PseudoColor(RContext * ctx, RImage * image)
520 {
521         RXImage *ximg;
522         register int x, y, r, g, b;
523         unsigned char *ptr;
524         unsigned long pixel;
525         const int cpc = ctx->attribs->colors_per_channel;
526         const unsigned short rmask = cpc - 1;   /* different sizes could be used */
527         const unsigned short gmask = rmask;     /* for r,g,b */
528         const unsigned short bmask = rmask;
529         unsigned short *rtable, *gtable, *btable;
530         const int cpccpc = cpc * cpc;
531         int channels = (HAS_ALPHA(image) ? 4 : 3);
532
533         ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
534         if (!ximg) {
535                 return NULL;
536         }
537
538         ptr = image->data;
539
540         /* Tables are same at the moment because rmask==gmask==bmask. */
541         rtable = computeTable(rmask);
542         gtable = computeTable(gmask);
543         btable = computeTable(bmask);
544
545         if (rtable == NULL || gtable == NULL || btable == NULL) {
546                 RErrorCode = RERR_NOMEMORY;
547                 RDestroyXImage(ctx, ximg);
548                 return NULL;
549         }
550
551         if (ctx->attribs->render_mode == RBestMatchRendering) {
552                 /* fake match */
553 #ifdef DEBUG
554                 printf("pseudo color match with %d colors per channel\n", cpc);
555 #endif
556                 for (y = 0; y < image->height; y++) {
557                         for (x = 0; x < image->width; x++, ptr += channels - 3) {
558                                 /* reduce pixel */
559                                 r = rtable[*ptr++];
560                                 g = gtable[*ptr++];
561                                 b = btable[*ptr++];
562                                 pixel = r * cpccpc + g * cpc + b;
563                                 /*data[ofs] = ctx->colors[pixel].pixel; */
564                                 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
565                         }
566                 }
567         } else {
568                 /* dither */
569                 signed char *err;
570                 signed char *nerr;
571                 const int dr = 0xff / rmask;
572                 const int dg = 0xff / gmask;
573                 const int db = 0xff / bmask;
574
575 #ifdef DEBUG
576                 printf("pseudo color dithering with %d colors per channel\n", cpc);
577 #endif
578                 err = malloc(4 * (image->width + 3));
579                 nerr = malloc(4 * (image->width + 3));
580                 if (!err || !nerr) {
581                         NFREE(err);
582                         NFREE(nerr);
583                         RErrorCode = RERR_NOMEMORY;
584                         RDestroyXImage(ctx, ximg);
585                         return NULL;
586                 }
587                 memset(err, 0, 4 * (image->width + 3));
588                 memset(nerr, 0, 4 * (image->width + 3));
589
590                 /*#ifdef ASM_X86 */
591 #if 0
592                 x86_PseudoColor_32_to_8(image->data, ximg->image->data,
593                                         err + 4, nerr + 4,
594                                         rtable,
595                                         dr, dg, db, ctx->pixels, cpc,
596                                         image->width, image->height,
597                                         channels, ximg->image->bytes_per_line - image->width);
598 #else
599                 convertPseudoColor_to_8(ximg, image, err + 4, nerr + 4,
600                                         rtable, gtable, btable, dr, dg, db, ctx->pixels, cpc);
601 #endif
602
603                 free(err);
604                 free(nerr);
605         }
606
607         return ximg;
608 }
609
610 /*
611  * For standard colormap
612  */
613 static RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image)
614 {
615         RXImage *ximg;
616         register int x, y, r, g, b;
617         unsigned char *ptr;
618         unsigned long pixel;
619         unsigned char *data;
620         unsigned int *rtable, *gtable, *btable;
621         unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
622         int channels = (HAS_ALPHA(image) ? 4 : 3);
623
624         ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
625         if (!ximg) {
626                 return NULL;
627         }
628
629         ptr = image->data;
630
631         data = (unsigned char *)ximg->image->data;
632
633         rtable = computeStdTable(ctx->std_rgb_map->red_mult, ctx->std_rgb_map->red_max);
634
635         gtable = computeStdTable(ctx->std_rgb_map->green_mult, ctx->std_rgb_map->green_max);
636
637         btable = computeStdTable(ctx->std_rgb_map->blue_mult, ctx->std_rgb_map->blue_max);
638
639         if (rtable == NULL || gtable == NULL || btable == NULL) {
640                 RErrorCode = RERR_NOMEMORY;
641                 RDestroyXImage(ctx, ximg);
642                 return NULL;
643         }
644
645         if (ctx->attribs->render_mode == RBestMatchRendering) {
646                 for (y = 0; y < image->height; y++) {
647                         for (x = 0; x < image->width; x++, ptr += channels) {
648                                 /* reduce pixel */
649                                 pixel = (rtable[*ptr] + gtable[*(ptr + 1)]
650                                          + btable[*(ptr + 2)] + base_pixel) & 0xffffffff;
651
652                                 XPutPixel(ximg->image, x, y, pixel);
653                         }
654                 }
655         } else {
656                 /* dither */
657                 signed short *err, *nerr;
658                 signed short *terr;
659                 int rer, ger, ber;
660                 int x1, ofs;
661
662 #ifdef DEBUG
663                 printf("pseudo color dithering with %d colors per channel\n", ctx->attribs->colors_per_channel);
664 #endif
665                 err = (short *)malloc(3 * (image->width + 2) * sizeof(short));
666                 nerr = (short *)malloc(3 * (image->width + 2) * sizeof(short));
667                 if (!err || !nerr) {
668                         NFREE(err);
669                         NFREE(nerr);
670                         RErrorCode = RERR_NOMEMORY;
671                         RDestroyXImage(ctx, ximg);
672                         return NULL;
673                 }
674                 for (x = 0, x1 = 0; x < image->width * 3; x1 += channels - 3) {
675                         err[x++] = ptr[x1++];
676                         err[x++] = ptr[x1++];
677                         err[x++] = ptr[x1++];
678                 }
679                 err[x] = err[x + 1] = err[x + 2] = 0;
680                 /* convert and dither the image to XImage */
681                 for (y = 0, ofs = 0; y < image->height; y++) {
682                         if (y < image->height - 1) {
683                                 int x1;
684                                 for (x = 0, x1 = (y + 1) * image->width * channels;
685                                      x < image->width * 3; x1 += channels - 3) {
686                                         nerr[x++] = ptr[x1++];
687                                         nerr[x++] = ptr[x1++];
688                                         nerr[x++] = ptr[x1++];
689                                 }
690                                 /* last column */
691                                 x1 -= channels;
692                                 nerr[x++] = ptr[x1++];
693                                 nerr[x++] = ptr[x1++];
694                                 nerr[x++] = ptr[x1++];
695                         }
696                         for (x = 0; x < image->width * 3; x += 3, ofs++) {
697                                 /* reduce pixel */
698                                 if (err[x] > 0xff)
699                                         err[x] = 0xff;
700                                 else if (err[x] < 0)
701                                         err[x] = 0;
702                                 if (err[x + 1] > 0xff)
703                                         err[x + 1] = 0xff;
704                                 else if (err[x + 1] < 0)
705                                         err[x + 1] = 0;
706                                 if (err[x + 2] > 0xff)
707                                         err[x + 2] = 0xff;
708                                 else if (err[x + 2] < 0)
709                                         err[x + 2] = 0;
710
711                                 r = rtable[err[x]];
712                                 g = gtable[err[x + 1]];
713                                 b = btable[err[x + 2]];
714
715                                 pixel = r + g + b;
716
717                                 data[ofs] = base_pixel + pixel;
718
719                                 /* calc error */
720                                 rer = err[x] - (ctx->colors[pixel].red >> 8);
721                                 ger = err[x + 1] - (ctx->colors[pixel].green >> 8);
722                                 ber = err[x + 2] - (ctx->colors[pixel].blue >> 8);
723
724                                 /* distribute error */
725                                 err[x + 3 * 1] += (rer * 7) / 16;
726                                 err[x + 1 + 3 * 1] += (ger * 7) / 16;
727                                 err[x + 2 + 3 * 1] += (ber * 7) / 16;
728
729                                 nerr[x] += (rer * 5) / 16;
730                                 nerr[x + 1] += (ger * 5) / 16;
731                                 nerr[x + 2] += (ber * 5) / 16;
732
733                                 if (x > 0) {
734                                         nerr[x - 3 * 1] += (rer * 3) / 16;
735                                         nerr[x - 3 * 1 + 1] += (ger * 3) / 16;
736                                         nerr[x - 3 * 1 + 2] += (ber * 3) / 16;
737                                 }
738
739                                 nerr[x + 3 * 1] += rer / 16;
740                                 nerr[x + 1 + 3 * 1] += ger / 16;
741                                 nerr[x + 2 + 3 * 1] += ber / 16;
742                         }
743                         /* skip to next line */
744                         terr = err;
745                         err = nerr;
746                         nerr = terr;
747
748                         ofs += ximg->image->bytes_per_line - image->width;
749                 }
750                 free(err);
751                 free(nerr);
752         }
753         ximg->image->data = (char *)data;
754
755         return ximg;
756 }
757
758 static RXImage *image2GrayScale(RContext * ctx, RImage * image)
759 {
760         RXImage *ximg;
761         register int x, y, g;
762         unsigned char *ptr;
763         const int cpc = ctx->attribs->colors_per_channel;
764         unsigned short gmask;
765         unsigned short *table;
766         unsigned char *data;
767         int channels = (HAS_ALPHA(image) ? 4 : 3);
768
769         ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
770         if (!ximg) {
771                 return NULL;
772         }
773
774         ptr = image->data;
775
776         data = (unsigned char *)ximg->image->data;
777
778         if (ctx->vclass == StaticGray)
779                 gmask = (1 << ctx->depth) - 1;  /* use all grays */
780         else
781                 gmask = cpc * cpc * cpc - 1;
782
783         table = computeTable(gmask);
784
785         if (table == NULL) {
786                 RErrorCode = RERR_NOMEMORY;
787                 RDestroyXImage(ctx, ximg);
788                 return NULL;
789         }
790
791         if (ctx->attribs->render_mode == RBestMatchRendering) {
792                 /* fake match */
793 #ifdef DEBUG
794                 printf("grayscale match with %d colors per channel\n", cpc);
795 #endif
796                 for (y = 0; y < image->height; y++) {
797                         for (x = 0; x < image->width; x++) {
798                                 /* reduce pixel */
799                                 g = table[(*ptr * 30 + *(ptr + 1) * 59 + *(ptr + 2) * 11) / 100];
800                                 ptr += channels;
801                                 /*data[ofs] = ctx->colors[g].pixel; */
802                                 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
803                         }
804                 }
805         } else {
806                 /* dither */
807                 short *gerr;
808                 short *ngerr;
809                 short *terr;
810                 int ger;
811                 const int dg = 0xff / gmask;
812
813 #ifdef DEBUG
814                 printf("grayscale dither with %d colors per channel\n", cpc);
815 #endif
816                 gerr = (short *)malloc((image->width + 2) * sizeof(short));
817                 ngerr = (short *)malloc((image->width + 2) * sizeof(short));
818                 if (!gerr || !ngerr) {
819                         NFREE(gerr);
820                         NFREE(ngerr);
821                         RErrorCode = RERR_NOMEMORY;
822                         RDestroyXImage(ctx, ximg);
823                         return NULL;
824                 }
825                 for (x = 0, y = 0; x < image->width; x++, y += channels) {
826                         gerr[x] = (ptr[y] * 30 + ptr[y + 1] * 59 + ptr[y + 2] * 11) / 100;
827                 }
828                 gerr[x] = 0;
829                 /* convert and dither the image to XImage */
830                 for (y = 0; y < image->height; y++) {
831                         if (y < image->height - 1) {
832                                 int x1;
833                                 for (x = 0, x1 = (y + 1) * image->width * channels; x < image->width;
834                                      x++, x1 += channels) {
835                                         ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
836                                 }
837                                 /* last column */
838                                 x1 -= channels;
839                                 ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
840                         }
841                         for (x = 0; x < image->width; x++) {
842                                 /* reduce pixel */
843                                 if (gerr[x] > 0xff)
844                                         gerr[x] = 0xff;
845                                 else if (gerr[x] < 0)
846                                         gerr[x] = 0;
847
848                                 g = table[gerr[x]];
849
850                                 /*data[ofs] = ctx->colors[g].pixel; */
851                                 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
852                                 /* calc error */
853                                 ger = gerr[x] - g * dg;
854
855                                 /* distribute error */
856                                 g = (ger * 3) / 8;
857                                 /* x+1, y */
858                                 gerr[x + 1] += g;
859                                 /* x, y+1 */
860                                 ngerr[x] += g;
861                                 /* x+1, y+1 */
862                                 ngerr[x + 1] += ger - 2 * g;
863                         }
864                         /* skip to next line */
865                         terr = gerr;
866                         gerr = ngerr;
867                         ngerr = terr;
868                 }
869                 free(gerr);
870                 free(ngerr);
871         }
872         ximg->image->data = (char *)data;
873
874         return ximg;
875 }
876
877 static RXImage *image2Bitmap(RContext * ctx, RImage * image, int threshold)
878 {
879         RXImage *ximg;
880         unsigned char *alpha;
881         int x, y;
882
883         ximg = RCreateXImage(ctx, 1, image->width, image->height);
884         if (!ximg) {
885                 return NULL;
886         }
887         alpha = image->data + 3;
888
889         for (y = 0; y < image->height; y++) {
890                 for (x = 0; x < image->width; x++) {
891                         XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
892                         alpha += 4;
893                 }
894         }
895
896         return ximg;
897 }
898
899 int RConvertImage(RContext * context, RImage * image, Pixmap * pixmap)
900 {
901         RXImage *ximg = NULL;
902 #ifdef XSHM
903         Pixmap tmp;
904 #endif
905
906         assert(context != NULL);
907         assert(image != NULL);
908         assert(pixmap != NULL);
909
910         switch (context->vclass) {
911         case TrueColor:
912 #ifdef BENCH
913                 cycle_bench(1);
914 #endif
915                 ximg = image2TrueColor(context, image);
916 #ifdef BENCH
917                 cycle_bench(0);
918 #endif
919                 break;
920
921         case PseudoColor:
922         case StaticColor:
923 #ifdef BENCH
924                 cycle_bench(1);
925 #endif
926                 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
927                         ximg = image2StandardPseudoColor(context, image);
928                 else
929                         ximg = image2PseudoColor(context, image);
930 #ifdef BENCH
931                 cycle_bench(0);
932 #endif
933                 break;
934
935         case GrayScale:
936         case StaticGray:
937                 ximg = image2GrayScale(context, image);
938                 break;
939         }
940
941         if (!ximg) {
942                 return False;
943         }
944
945         *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, context->depth);
946
947 #ifdef XSHM
948         if (context->flags.use_shared_pixmap && ximg->is_shared)
949                 tmp = R_CreateXImageMappedPixmap(context, ximg);
950         else
951                 tmp = None;
952         if (tmp) {
953                 /*
954                  * We have to copy the shm Pixmap into a normal Pixmap because
955                  * otherwise, we would have to control when Pixmaps are freed so
956                  * that we can detach their shm segments. This is a problem if the
957                  * program crash, leaving stale shared memory segments in the
958                  * system (lots of them). But with some work, we can optimize
959                  * things and remove this XCopyArea. This will require
960                  * explicitly freeing all pixmaps when exiting or restarting
961                  * wmaker.
962                  */
963                 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0, image->width, image->height, 0, 0);
964                 XFreePixmap(context->dpy, tmp);
965         } else {
966                 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
967         }
968 #else                           /* !XSHM */
969         RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
970 #endif                          /* !XSHM */
971
972         RDestroyXImage(context, ximg);
973
974         return True;
975 }
976
977 /* make the gc permanent (create with context creation).
978  * GC creation is very expensive. altering its properties is not. -Dan
979  */
980 int RConvertImageMask(RContext * context, RImage * image, Pixmap * pixmap, Pixmap * mask, int threshold)
981 {
982         GC gc;
983         XGCValues gcv;
984         RXImage *ximg = NULL;
985
986         assert(context != NULL);
987         assert(image != NULL);
988         assert(pixmap != NULL);
989         assert(mask != NULL);
990
991         if (!RConvertImage(context, image, pixmap))
992                 return False;
993
994         if (image->format == RRGBFormat) {
995                 *mask = None;
996                 return True;
997         }
998
999         ximg = image2Bitmap(context, image, threshold);
1000
1001         if (!ximg) {
1002                 return False;
1003         }
1004         *mask = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, 1);
1005         gcv.foreground = context->black;
1006         gcv.background = context->white;
1007         gcv.graphics_exposures = False;
1008         gc = XCreateGC(context->dpy, *mask, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
1009         RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0, image->width, image->height);
1010         RDestroyXImage(context, ximg);
1011         XFreeGC(context->dpy, gc);
1012
1013         return True;
1014 }
1015
1016 Bool RGetClosestXColor(RContext * context, RColor * color, XColor * retColor)
1017 {
1018         if (context->vclass == TrueColor) {
1019                 unsigned short rmask, gmask, bmask;
1020                 unsigned short roffs, goffs, boffs;
1021                 unsigned short *rtable, *gtable, *btable;
1022
1023                 roffs = context->red_offset;
1024                 goffs = context->green_offset;
1025                 boffs = context->blue_offset;
1026
1027                 rmask = context->visual->red_mask >> roffs;
1028                 gmask = context->visual->green_mask >> goffs;
1029                 bmask = context->visual->blue_mask >> boffs;
1030
1031                 rtable = computeTable(rmask);
1032                 gtable = computeTable(gmask);
1033                 btable = computeTable(bmask);
1034
1035                 retColor->pixel = (rtable[color->red] << roffs) |
1036                     (gtable[color->green] << goffs) | (btable[color->blue] << boffs);
1037
1038                 retColor->red = color->red << 8;
1039                 retColor->green = color->green << 8;
1040                 retColor->blue = color->blue << 8;
1041                 retColor->flags = DoRed | DoGreen | DoBlue;
1042
1043         } else if (context->vclass == PseudoColor || context->vclass == StaticColor) {
1044
1045                 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
1046                         unsigned int *rtable, *gtable, *btable;
1047
1048                         rtable = computeStdTable(context->std_rgb_map->red_mult, context->std_rgb_map->red_max);
1049
1050                         gtable = computeStdTable(context->std_rgb_map->green_mult,
1051                                                  context->std_rgb_map->green_max);
1052
1053                         btable = computeStdTable(context->std_rgb_map->blue_mult, context->std_rgb_map->blue_max);
1054
1055                         if (rtable == NULL || gtable == NULL || btable == NULL) {
1056                                 RErrorCode = RERR_NOMEMORY;
1057                                 return False;
1058                         }
1059
1060                         retColor->pixel = (rtable[color->red]
1061                                            + gtable[color->green]
1062                                            + btable[color->blue]
1063                                            + context->std_rgb_map->base_pixel) & 0xffffffff;
1064                         retColor->red = color->red << 8;
1065                         retColor->green = color->green << 8;
1066                         retColor->blue = color->blue << 8;
1067                         retColor->flags = DoRed | DoGreen | DoBlue;
1068
1069                 } else {
1070                         const int cpc = context->attribs->colors_per_channel;
1071                         const unsigned short rmask = cpc - 1;   /* different sizes could be used */
1072                         const unsigned short gmask = rmask;     /* for r,g,b */
1073                         const unsigned short bmask = rmask;
1074                         unsigned short *rtable, *gtable, *btable;
1075                         const int cpccpc = cpc * cpc;
1076                         int index;
1077
1078                         rtable = computeTable(rmask);
1079                         gtable = computeTable(gmask);
1080                         btable = computeTable(bmask);
1081
1082                         if (rtable == NULL || gtable == NULL || btable == NULL) {
1083                                 RErrorCode = RERR_NOMEMORY;
1084                                 return False;
1085                         }
1086                         index = rtable[color->red] * cpccpc + gtable[color->green] * cpc + btable[color->blue];
1087                         *retColor = context->colors[index];
1088                 }
1089
1090         } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
1091
1092                 const int cpc = context->attribs->colors_per_channel;
1093                 unsigned short gmask;
1094                 unsigned short *table;
1095                 int index;
1096
1097                 if (context->vclass == StaticGray)
1098                         gmask = (1 << context->depth) - 1;      /* use all grays */
1099                 else
1100                         gmask = cpc * cpc * cpc - 1;
1101
1102                 table = computeTable(gmask);
1103                 if (!table)
1104                         return False;
1105
1106                 index = table[(color->red * 30 + color->green * 59 + color->blue * 11) / 100];
1107
1108                 *retColor = context->colors[index];
1109         } else {
1110                 RErrorCode = RERR_INTERNAL;
1111                 return False;
1112         }
1113
1114         return True;
1115 }