Bouncing appicon effect
[wmaker-crm.git] / wrlib / convert.c
blob4b15cc559e6df8e1dd5243c1483248d7dc0163c7
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>
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
35 #include <assert.h>
37 #ifdef BENCH
38 #include "bench.h"
39 #endif
41 #include "wraster.h"
43 #ifdef XSHM
44 extern Pixmap R_CreateXImageMappedPixmap(RContext * context, RXImage * ximage);
46 #endif
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 */
58 #ifdef ASM_X86_MMX
60 extern int x86_check_mmx();
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);
73 #endif /* ASM_X86_MMX */
75 #define NFREE(n) if (n) free(n)
77 #define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
79 typedef struct RConversionTable {
80 unsigned short table[256];
81 unsigned short index;
83 struct RConversionTable *next;
84 } RConversionTable;
86 typedef struct RStdConversionTable {
87 unsigned int table[256];
89 unsigned short mult;
90 unsigned short max;
92 struct RStdConversionTable *next;
93 } RStdConversionTable;
95 static RConversionTable *conversionTable = NULL;
96 static RStdConversionTable *stdConversionTable = NULL;
98 static unsigned short *computeTable(unsigned short mask)
100 RConversionTable *tmp = conversionTable;
101 int i;
103 while (tmp) {
104 if (tmp->index == mask)
105 break;
106 tmp = tmp->next;
109 if (tmp)
110 return tmp->table;
112 tmp = (RConversionTable *) malloc(sizeof(RConversionTable));
113 if (tmp == NULL)
114 return NULL;
116 for (i = 0; i < 256; i++)
117 tmp->table[i] = (i * mask + 0x7f) / 0xff;
119 tmp->index = mask;
120 tmp->next = conversionTable;
121 conversionTable = tmp;
122 return tmp->table;
125 static unsigned int *computeStdTable(unsigned int mult, unsigned int max)
127 RStdConversionTable *tmp = stdConversionTable;
128 unsigned int i;
130 while (tmp) {
131 if (tmp->mult == mult && tmp->max == max)
132 break;
133 tmp = tmp->next;
136 if (tmp)
137 return tmp->table;
139 tmp = (RStdConversionTable *) malloc(sizeof(RStdConversionTable));
140 if (tmp == NULL)
141 return NULL;
143 for (i = 0; i < 256; i++) {
144 tmp->table[i] = (i * max) / 0xff * mult;
146 tmp->mult = mult;
147 tmp->max = max;
149 tmp->next = stdConversionTable;
150 stdConversionTable = tmp;
152 return tmp->table;
155 /***************************************************************************/
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)
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);
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) {
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;
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;
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;
210 pixel = (r << roffs) | (g << goffs) | (b << boffs);
211 XPutPixel(ximg->image, x, y, pixel);
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;
230 /* skip to next line */
231 terr = err;
232 err = nerr;
233 nerr = terr;
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) {
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;
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;
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;
274 pixel = (r << roffs) | (g << goffs) | (b << boffs);
275 XPutPixel(ximg->image, x, y, pixel);
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;
296 static RXImage *image2TrueColor(RContext * ctx, RImage * image)
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);
304 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
305 if (!ximg) {
306 return NULL;
309 roffs = ctx->red_offset;
310 goffs = ctx->green_offset;
311 boffs = ctx->blue_offset;
313 rmask = ctx->visual->red_mask >> roffs;
314 gmask = ctx->visual->green_mask >> goffs;
315 bmask = ctx->visual->blue_mask >> boffs;
317 rtable = computeTable(rmask);
318 gtable = computeTable(gmask);
319 btable = computeTable(bmask);
321 if (rtable == NULL || gtable == NULL || btable == NULL) {
322 RErrorCode = RERR_NOMEMORY;
323 RDestroyXImage(ctx, ximg);
324 return NULL;
327 #ifdef BENCH
328 cycle_bench(1);
329 #endif
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;
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);
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);
361 } else {
362 /* dither */
363 const int dr = 0xff / rmask;
364 const int dg = 0xff / gmask;
365 const int db = 0xff / bmask;
367 #ifdef DEBUG
368 puts("true color dither");
369 #endif
371 #ifdef ASM_X86_MMX
372 if (ctx->depth == 16 && HAS_ALPHA(image) && x86_check_mmx()) {
373 short *err;
374 short *nerr;
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;
385 memset(err, 0, 8 * (image->width + 3));
386 memset(nerr, 0, 8 * (image->width + 3));
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);
397 free(err);
398 free(nerr);
399 } else
400 #endif /* ASM_X86_MMX */
402 signed char *err;
403 signed char *nerr;
404 int ch = (HAS_ALPHA(image) ? 4 : 3);
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;
416 memset(err, 0, ch * (image->width + 2));
417 memset(nerr, 0, ch * (image->width + 2));
419 convertTrueColor_generic(ximg, image, err, nerr,
420 rtable, gtable, btable, dr, dg, db, roffs, goffs, boffs);
421 free(err);
422 free(nerr);
427 #ifdef BENCH
428 cycle_bench(0);
429 #endif
431 return ximg;
434 /***************************************************************************/
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)
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;
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) {
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;
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;
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;
490 *optr++ = pixels[r * cpcpc + g * cpc + b];
492 /* distribute error */
493 r = (rer * 3) / 8;
494 g = (ger * 3) / 8;
495 b = (ber * 3) / 8;
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;
510 /* skip to next line */
511 terr = err;
512 err = nerr;
513 nerr = terr;
515 optr += ximg->image->bytes_per_line - image->width;
519 static RXImage *image2PseudoColor(RContext * ctx, RImage * image)
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);
533 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
534 if (!ximg) {
535 return NULL;
538 ptr = image->data;
540 /* Tables are same at the moment because rmask==gmask==bmask. */
541 rtable = computeTable(rmask);
542 gtable = computeTable(gmask);
543 btable = computeTable(bmask);
545 if (rtable == NULL || gtable == NULL || btable == NULL) {
546 RErrorCode = RERR_NOMEMORY;
547 RDestroyXImage(ctx, ximg);
548 return NULL;
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);
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;
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;
587 memset(err, 0, 4 * (image->width + 3));
588 memset(nerr, 0, 4 * (image->width + 3));
590 /*#ifdef ASM_X86 */
591 convertPseudoColor_to_8(ximg, image, err + 4, nerr + 4,
592 rtable, gtable, btable, dr, dg, db, ctx->pixels, cpc);
594 free(err);
595 free(nerr);
598 return ximg;
602 * For standard colormap
604 static RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image)
606 RXImage *ximg;
607 register int x, y, r, g, b;
608 unsigned char *ptr;
609 unsigned long pixel;
610 unsigned char *data;
611 unsigned int *rtable, *gtable, *btable;
612 unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
613 int channels = (HAS_ALPHA(image) ? 4 : 3);
615 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
616 if (!ximg) {
617 return NULL;
620 ptr = image->data;
622 data = (unsigned char *)ximg->image->data;
624 rtable = computeStdTable(ctx->std_rgb_map->red_mult, ctx->std_rgb_map->red_max);
626 gtable = computeStdTable(ctx->std_rgb_map->green_mult, ctx->std_rgb_map->green_max);
628 btable = computeStdTable(ctx->std_rgb_map->blue_mult, ctx->std_rgb_map->blue_max);
630 if (rtable == NULL || gtable == NULL || btable == NULL) {
631 RErrorCode = RERR_NOMEMORY;
632 RDestroyXImage(ctx, ximg);
633 return NULL;
636 if (ctx->attribs->render_mode == RBestMatchRendering) {
637 for (y = 0; y < image->height; y++) {
638 for (x = 0; x < image->width; x++, ptr += channels) {
639 /* reduce pixel */
640 pixel = (rtable[*ptr] + gtable[*(ptr + 1)]
641 + btable[*(ptr + 2)] + base_pixel) & 0xffffffff;
643 XPutPixel(ximg->image, x, y, pixel);
646 } else {
647 /* dither */
648 signed short *err, *nerr;
649 signed short *terr;
650 int rer, ger, ber;
651 int x1, ofs;
653 #ifdef DEBUG
654 printf("pseudo color dithering with %d colors per channel\n", ctx->attribs->colors_per_channel);
655 #endif
656 err = (short *)malloc(3 * (image->width + 2) * sizeof(short));
657 nerr = (short *)malloc(3 * (image->width + 2) * sizeof(short));
658 if (!err || !nerr) {
659 NFREE(err);
660 NFREE(nerr);
661 RErrorCode = RERR_NOMEMORY;
662 RDestroyXImage(ctx, ximg);
663 return NULL;
665 for (x = 0, x1 = 0; x < image->width * 3; x1 += channels - 3) {
666 err[x++] = ptr[x1++];
667 err[x++] = ptr[x1++];
668 err[x++] = ptr[x1++];
670 err[x] = err[x + 1] = err[x + 2] = 0;
671 /* convert and dither the image to XImage */
672 for (y = 0, ofs = 0; y < image->height; y++) {
673 if (y < image->height - 1) {
674 int x1;
675 for (x = 0, x1 = (y + 1) * image->width * channels;
676 x < image->width * 3; x1 += channels - 3) {
677 nerr[x++] = ptr[x1++];
678 nerr[x++] = ptr[x1++];
679 nerr[x++] = ptr[x1++];
681 /* last column */
682 x1 -= channels;
683 nerr[x++] = ptr[x1++];
684 nerr[x++] = ptr[x1++];
685 nerr[x++] = ptr[x1++];
687 for (x = 0; x < image->width * 3; x += 3, ofs++) {
688 /* reduce pixel */
689 if (err[x] > 0xff)
690 err[x] = 0xff;
691 else if (err[x] < 0)
692 err[x] = 0;
693 if (err[x + 1] > 0xff)
694 err[x + 1] = 0xff;
695 else if (err[x + 1] < 0)
696 err[x + 1] = 0;
697 if (err[x + 2] > 0xff)
698 err[x + 2] = 0xff;
699 else if (err[x + 2] < 0)
700 err[x + 2] = 0;
702 r = rtable[err[x]];
703 g = gtable[err[x + 1]];
704 b = btable[err[x + 2]];
706 pixel = r + g + b;
708 data[ofs] = base_pixel + pixel;
710 /* calc error */
711 rer = err[x] - (ctx->colors[pixel].red >> 8);
712 ger = err[x + 1] - (ctx->colors[pixel].green >> 8);
713 ber = err[x + 2] - (ctx->colors[pixel].blue >> 8);
715 /* distribute error */
716 err[x + 3 * 1] += (rer * 7) / 16;
717 err[x + 1 + 3 * 1] += (ger * 7) / 16;
718 err[x + 2 + 3 * 1] += (ber * 7) / 16;
720 nerr[x] += (rer * 5) / 16;
721 nerr[x + 1] += (ger * 5) / 16;
722 nerr[x + 2] += (ber * 5) / 16;
724 if (x > 0) {
725 nerr[x - 3 * 1] += (rer * 3) / 16;
726 nerr[x - 3 * 1 + 1] += (ger * 3) / 16;
727 nerr[x - 3 * 1 + 2] += (ber * 3) / 16;
730 nerr[x + 3 * 1] += rer / 16;
731 nerr[x + 1 + 3 * 1] += ger / 16;
732 nerr[x + 2 + 3 * 1] += ber / 16;
734 /* skip to next line */
735 terr = err;
736 err = nerr;
737 nerr = terr;
739 ofs += ximg->image->bytes_per_line - image->width;
741 free(err);
742 free(nerr);
744 ximg->image->data = (char *)data;
746 return ximg;
749 static RXImage *image2GrayScale(RContext * ctx, RImage * image)
751 RXImage *ximg;
752 register int x, y, g;
753 unsigned char *ptr;
754 const int cpc = ctx->attribs->colors_per_channel;
755 unsigned short gmask;
756 unsigned short *table;
757 unsigned char *data;
758 int channels = (HAS_ALPHA(image) ? 4 : 3);
760 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
761 if (!ximg) {
762 return NULL;
765 ptr = image->data;
767 data = (unsigned char *)ximg->image->data;
769 if (ctx->vclass == StaticGray)
770 gmask = (1 << ctx->depth) - 1; /* use all grays */
771 else
772 gmask = cpc * cpc * cpc - 1;
774 table = computeTable(gmask);
776 if (table == NULL) {
777 RErrorCode = RERR_NOMEMORY;
778 RDestroyXImage(ctx, ximg);
779 return NULL;
782 if (ctx->attribs->render_mode == RBestMatchRendering) {
783 /* fake match */
784 #ifdef DEBUG
785 printf("grayscale match with %d colors per channel\n", cpc);
786 #endif
787 for (y = 0; y < image->height; y++) {
788 for (x = 0; x < image->width; x++) {
789 /* reduce pixel */
790 g = table[(*ptr * 30 + *(ptr + 1) * 59 + *(ptr + 2) * 11) / 100];
791 ptr += channels;
792 /*data[ofs] = ctx->colors[g].pixel; */
793 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
796 } else {
797 /* dither */
798 short *gerr;
799 short *ngerr;
800 short *terr;
801 int ger;
802 const int dg = 0xff / gmask;
804 #ifdef DEBUG
805 printf("grayscale dither with %d colors per channel\n", cpc);
806 #endif
807 gerr = (short *)malloc((image->width + 2) * sizeof(short));
808 ngerr = (short *)malloc((image->width + 2) * sizeof(short));
809 if (!gerr || !ngerr) {
810 NFREE(gerr);
811 NFREE(ngerr);
812 RErrorCode = RERR_NOMEMORY;
813 RDestroyXImage(ctx, ximg);
814 return NULL;
816 for (x = 0, y = 0; x < image->width; x++, y += channels) {
817 gerr[x] = (ptr[y] * 30 + ptr[y + 1] * 59 + ptr[y + 2] * 11) / 100;
819 gerr[x] = 0;
820 /* convert and dither the image to XImage */
821 for (y = 0; y < image->height; y++) {
822 if (y < image->height - 1) {
823 int x1;
824 for (x = 0, x1 = (y + 1) * image->width * channels; x < image->width;
825 x++, x1 += channels) {
826 ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
828 /* last column */
829 x1 -= channels;
830 ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
832 for (x = 0; x < image->width; x++) {
833 /* reduce pixel */
834 if (gerr[x] > 0xff)
835 gerr[x] = 0xff;
836 else if (gerr[x] < 0)
837 gerr[x] = 0;
839 g = table[gerr[x]];
841 /*data[ofs] = ctx->colors[g].pixel; */
842 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
843 /* calc error */
844 ger = gerr[x] - g * dg;
846 /* distribute error */
847 g = (ger * 3) / 8;
848 /* x+1, y */
849 gerr[x + 1] += g;
850 /* x, y+1 */
851 ngerr[x] += g;
852 /* x+1, y+1 */
853 ngerr[x + 1] += ger - 2 * g;
855 /* skip to next line */
856 terr = gerr;
857 gerr = ngerr;
858 ngerr = terr;
860 free(gerr);
861 free(ngerr);
863 ximg->image->data = (char *)data;
865 return ximg;
868 static RXImage *image2Bitmap(RContext * ctx, RImage * image, int threshold)
870 RXImage *ximg;
871 unsigned char *alpha;
872 int x, y;
874 ximg = RCreateXImage(ctx, 1, image->width, image->height);
875 if (!ximg) {
876 return NULL;
878 alpha = image->data + 3;
880 for (y = 0; y < image->height; y++) {
881 for (x = 0; x < image->width; x++) {
882 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
883 alpha += 4;
887 return ximg;
890 int RConvertImage(RContext * context, RImage * image, Pixmap * pixmap)
892 RXImage *ximg = NULL;
893 #ifdef XSHM
894 Pixmap tmp;
895 #endif
897 assert(context != NULL);
898 assert(image != NULL);
899 assert(pixmap != NULL);
901 switch (context->vclass) {
902 case TrueColor:
903 #ifdef BENCH
904 cycle_bench(1);
905 #endif
906 ximg = image2TrueColor(context, image);
907 #ifdef BENCH
908 cycle_bench(0);
909 #endif
910 break;
912 case PseudoColor:
913 case StaticColor:
914 #ifdef BENCH
915 cycle_bench(1);
916 #endif
917 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
918 ximg = image2StandardPseudoColor(context, image);
919 else
920 ximg = image2PseudoColor(context, image);
921 #ifdef BENCH
922 cycle_bench(0);
923 #endif
924 break;
926 case GrayScale:
927 case StaticGray:
928 ximg = image2GrayScale(context, image);
929 break;
932 if (!ximg) {
933 return False;
936 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, context->depth);
938 #ifdef XSHM
939 if (context->flags.use_shared_pixmap && ximg->is_shared)
940 tmp = R_CreateXImageMappedPixmap(context, ximg);
941 else
942 tmp = None;
943 if (tmp) {
945 * We have to copy the shm Pixmap into a normal Pixmap because
946 * otherwise, we would have to control when Pixmaps are freed so
947 * that we can detach their shm segments. This is a problem if the
948 * program crash, leaving stale shared memory segments in the
949 * system (lots of them). But with some work, we can optimize
950 * things and remove this XCopyArea. This will require
951 * explicitly freeing all pixmaps when exiting or restarting
952 * wmaker.
954 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0, image->width, image->height, 0, 0);
955 XFreePixmap(context->dpy, tmp);
956 } else {
957 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
959 #else /* !XSHM */
960 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
961 #endif /* !XSHM */
963 RDestroyXImage(context, ximg);
965 return True;
968 /* make the gc permanent (create with context creation).
969 * GC creation is very expensive. altering its properties is not. -Dan
971 int RConvertImageMask(RContext * context, RImage * image, Pixmap * pixmap, Pixmap * mask, int threshold)
973 GC gc;
974 XGCValues gcv;
975 RXImage *ximg = NULL;
977 assert(context != NULL);
978 assert(image != NULL);
979 assert(pixmap != NULL);
980 assert(mask != NULL);
982 if (!RConvertImage(context, image, pixmap))
983 return False;
985 if (image->format == RRGBFormat) {
986 *mask = None;
987 return True;
990 ximg = image2Bitmap(context, image, threshold);
992 if (!ximg) {
993 return False;
995 *mask = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, 1);
996 gcv.foreground = context->black;
997 gcv.background = context->white;
998 gcv.graphics_exposures = False;
999 gc = XCreateGC(context->dpy, *mask, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
1000 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0, image->width, image->height);
1001 RDestroyXImage(context, ximg);
1002 XFreeGC(context->dpy, gc);
1004 return True;
1007 Bool RGetClosestXColor(RContext * context, RColor * color, XColor * retColor)
1009 if (context->vclass == TrueColor) {
1010 unsigned short rmask, gmask, bmask;
1011 unsigned short roffs, goffs, boffs;
1012 unsigned short *rtable, *gtable, *btable;
1014 roffs = context->red_offset;
1015 goffs = context->green_offset;
1016 boffs = context->blue_offset;
1018 rmask = context->visual->red_mask >> roffs;
1019 gmask = context->visual->green_mask >> goffs;
1020 bmask = context->visual->blue_mask >> boffs;
1022 rtable = computeTable(rmask);
1023 gtable = computeTable(gmask);
1024 btable = computeTable(bmask);
1026 retColor->pixel = (rtable[color->red] << roffs) |
1027 (gtable[color->green] << goffs) | (btable[color->blue] << boffs);
1029 retColor->red = color->red << 8;
1030 retColor->green = color->green << 8;
1031 retColor->blue = color->blue << 8;
1032 retColor->flags = DoRed | DoGreen | DoBlue;
1034 } else if (context->vclass == PseudoColor || context->vclass == StaticColor) {
1036 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
1037 unsigned int *rtable, *gtable, *btable;
1039 rtable = computeStdTable(context->std_rgb_map->red_mult, context->std_rgb_map->red_max);
1041 gtable = computeStdTable(context->std_rgb_map->green_mult,
1042 context->std_rgb_map->green_max);
1044 btable = computeStdTable(context->std_rgb_map->blue_mult, context->std_rgb_map->blue_max);
1046 if (rtable == NULL || gtable == NULL || btable == NULL) {
1047 RErrorCode = RERR_NOMEMORY;
1048 return False;
1051 retColor->pixel = (rtable[color->red]
1052 + gtable[color->green]
1053 + btable[color->blue]
1054 + context->std_rgb_map->base_pixel) & 0xffffffff;
1055 retColor->red = color->red << 8;
1056 retColor->green = color->green << 8;
1057 retColor->blue = color->blue << 8;
1058 retColor->flags = DoRed | DoGreen | DoBlue;
1060 } else {
1061 const int cpc = context->attribs->colors_per_channel;
1062 const unsigned short rmask = cpc - 1; /* different sizes could be used */
1063 const unsigned short gmask = rmask; /* for r,g,b */
1064 const unsigned short bmask = rmask;
1065 unsigned short *rtable, *gtable, *btable;
1066 const int cpccpc = cpc * cpc;
1067 int index;
1069 rtable = computeTable(rmask);
1070 gtable = computeTable(gmask);
1071 btable = computeTable(bmask);
1073 if (rtable == NULL || gtable == NULL || btable == NULL) {
1074 RErrorCode = RERR_NOMEMORY;
1075 return False;
1077 index = rtable[color->red] * cpccpc + gtable[color->green] * cpc + btable[color->blue];
1078 *retColor = context->colors[index];
1081 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
1083 const int cpc = context->attribs->colors_per_channel;
1084 unsigned short gmask;
1085 unsigned short *table;
1086 int index;
1088 if (context->vclass == StaticGray)
1089 gmask = (1 << context->depth) - 1; /* use all grays */
1090 else
1091 gmask = cpc * cpc * cpc - 1;
1093 table = computeTable(gmask);
1094 if (!table)
1095 return False;
1097 index = table[(color->red * 30 + color->green * 59 + color->blue * 11) / 100];
1099 *retColor = context->colors[index];
1100 } else {
1101 RErrorCode = RERR_INTERNAL;
1102 return False;
1105 return True;