declare get_pixmap_icon_from_* as static functions
[wmaker-crm.git] / wrlib / convert.c
bloba05e36332d63f0adc763c02c9f374cc7a2ed18be
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>
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <assert.h>
35 #include "wraster.h"
37 #ifdef XSHM
38 extern Pixmap R_CreateXImageMappedPixmap(RContext * context, RXImage * ximage);
39 #endif
41 #define NFREE(n) if (n) free(n)
43 #define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
45 typedef struct RConversionTable {
46 unsigned short table[256];
47 unsigned short index;
49 struct RConversionTable *next;
50 } RConversionTable;
52 typedef struct RStdConversionTable {
53 unsigned int table[256];
55 unsigned short mult;
56 unsigned short max;
58 struct RStdConversionTable *next;
59 } RStdConversionTable;
61 static RConversionTable *conversionTable = NULL;
62 static RStdConversionTable *stdConversionTable = NULL;
64 static unsigned short *computeTable(unsigned short mask)
66 RConversionTable *tmp = conversionTable;
67 int i;
69 while (tmp) {
70 if (tmp->index == mask)
71 break;
72 tmp = tmp->next;
75 if (tmp)
76 return tmp->table;
78 tmp = (RConversionTable *) malloc(sizeof(RConversionTable));
79 if (tmp == NULL)
80 return NULL;
82 for (i = 0; i < 256; i++)
83 tmp->table[i] = (i * mask + 0x7f) / 0xff;
85 tmp->index = mask;
86 tmp->next = conversionTable;
87 conversionTable = tmp;
88 return tmp->table;
91 static unsigned int *computeStdTable(unsigned int mult, unsigned int max)
93 RStdConversionTable *tmp = stdConversionTable;
94 unsigned int i;
96 while (tmp) {
97 if (tmp->mult == mult && tmp->max == max)
98 break;
99 tmp = tmp->next;
102 if (tmp)
103 return tmp->table;
105 tmp = (RStdConversionTable *) malloc(sizeof(RStdConversionTable));
106 if (tmp == NULL)
107 return NULL;
109 for (i = 0; i < 256; i++) {
110 tmp->table[i] = (i * max) / 0xff * mult;
112 tmp->mult = mult;
113 tmp->max = max;
115 tmp->next = stdConversionTable;
116 stdConversionTable = tmp;
118 return tmp->table;
121 /***************************************************************************/
123 static void
124 convertTrueColor_generic(RXImage * ximg, RImage * image,
125 signed char *err, signed char *nerr,
126 const unsigned short *rtable,
127 const unsigned short *gtable,
128 const unsigned short *btable,
129 const int dr, const int dg, const int db,
130 const unsigned short roffs, const unsigned short goffs, const unsigned short boffs)
132 signed char *terr;
133 int x, y, r, g, b;
134 int pixel;
135 int rer, ger, ber;
136 unsigned char *ptr = image->data;
137 int channels = (HAS_ALPHA(image) ? 4 : 3);
139 /* convert and dither the image to XImage */
140 for (y = 0; y < image->height; y++) {
141 nerr[0] = 0;
142 nerr[1] = 0;
143 nerr[2] = 0;
144 for (x = 0; x < image->width; x++, ptr += channels) {
146 /* reduce pixel */
147 pixel = *ptr + err[x];
148 if (pixel < 0)
149 pixel = 0;
150 else if (pixel > 0xff)
151 pixel = 0xff;
152 r = rtable[pixel];
153 /* calc error */
154 rer = pixel - r * dr;
156 /* reduce pixel */
157 pixel = *(ptr + 1) + err[x + 1];
158 if (pixel < 0)
159 pixel = 0;
160 else if (pixel > 0xff)
161 pixel = 0xff;
162 g = gtable[pixel];
163 /* calc error */
164 ger = pixel - g * dg;
166 /* reduce pixel */
167 pixel = *(ptr + 2) + err[x + 2];
168 if (pixel < 0)
169 pixel = 0;
170 else if (pixel > 0xff)
171 pixel = 0xff;
172 b = btable[pixel];
173 /* calc error */
174 ber = pixel - b * db;
176 pixel = (r << roffs) | (g << goffs) | (b << boffs);
177 XPutPixel(ximg->image, x, y, pixel);
179 /* distribute error */
180 r = (rer * 3) / 8;
181 g = (ger * 3) / 8;
182 b = (ber * 3) / 8;
183 /* x+1, y */
184 err[x + 3 * 1] += r;
185 err[x + 1 + 3 * 1] += g;
186 err[x + 2 + 3 * 1] += b;
187 /* x, y+1 */
188 nerr[x] += r;
189 nerr[x + 1] += g;
190 nerr[x + 2] += b;
191 /* x+1, y+1 */
192 nerr[x + 3 * 1] = rer - 2 * r;
193 nerr[x + 1 + 3 * 1] = ger - 2 * g;
194 nerr[x + 2 + 3 * 1] = ber - 2 * b;
196 /* skip to next line */
197 terr = err;
198 err = nerr;
199 nerr = terr;
202 /* redither the 1st line to distribute error better */
203 ptr = image->data;
204 y = 0;
205 nerr[0] = 0;
206 nerr[1] = 0;
207 nerr[2] = 0;
208 for (x = 0; x < image->width; x++, ptr += channels) {
210 /* reduce pixel */
211 pixel = *ptr + err[x];
212 if (pixel < 0)
213 pixel = 0;
214 else if (pixel > 0xff)
215 pixel = 0xff;
216 r = rtable[pixel];
217 /* calc error */
218 rer = pixel - r * dr;
220 /* reduce pixel */
221 pixel = *(ptr + 1) + err[x + 1];
222 if (pixel < 0)
223 pixel = 0;
224 else if (pixel > 0xff)
225 pixel = 0xff;
226 g = gtable[pixel];
227 /* calc error */
228 ger = pixel - g * dg;
230 /* reduce pixel */
231 pixel = *(ptr + 2) + err[x + 2];
232 if (pixel < 0)
233 pixel = 0;
234 else if (pixel > 0xff)
235 pixel = 0xff;
236 b = btable[pixel];
237 /* calc error */
238 ber = pixel - b * db;
240 pixel = (r << roffs) | (g << goffs) | (b << boffs);
241 XPutPixel(ximg->image, x, y, pixel);
243 /* distribute error */
244 r = (rer * 3) / 8;
245 g = (ger * 3) / 8;
246 b = (ber * 3) / 8;
247 /* x+1, y */
248 err[x + 3 * 1] += r;
249 err[x + 1 + 3 * 1] += g;
250 err[x + 2 + 3 * 1] += b;
251 /* x, y+1 */
252 nerr[x] += r;
253 nerr[x + 1] += g;
254 nerr[x + 2] += b;
255 /* x+1, y+1 */
256 nerr[x + 3 * 1] = rer - 2 * r;
257 nerr[x + 1 + 3 * 1] = ger - 2 * g;
258 nerr[x + 2 + 3 * 1] = ber - 2 * b;
262 static RXImage *image2TrueColor(RContext * ctx, RImage * image)
264 RXImage *ximg;
265 unsigned short rmask, gmask, bmask;
266 unsigned short roffs, goffs, boffs;
267 unsigned short *rtable, *gtable, *btable;
268 int channels = (HAS_ALPHA(image) ? 4 : 3);
270 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
271 if (!ximg) {
272 return NULL;
275 roffs = ctx->red_offset;
276 goffs = ctx->green_offset;
277 boffs = ctx->blue_offset;
279 rmask = ctx->visual->red_mask >> roffs;
280 gmask = ctx->visual->green_mask >> goffs;
281 bmask = ctx->visual->blue_mask >> boffs;
283 rtable = computeTable(rmask);
284 gtable = computeTable(gmask);
285 btable = computeTable(bmask);
287 if (rtable == NULL || gtable == NULL || btable == NULL) {
288 RErrorCode = RERR_NOMEMORY;
289 RDestroyXImage(ctx, ximg);
290 return NULL;
293 if (ctx->attribs->render_mode == RBestMatchRendering) {
294 int ofs, r, g, b;
295 int x, y;
296 unsigned long pixel;
297 unsigned char *ptr = image->data;
299 /* fake match */
300 #ifdef WRLIB_DEBUG
301 fputs("true color match\n", stderr);
302 #endif
303 if (rmask == 0xff && gmask == 0xff && bmask == 0xff) {
304 for (y = 0; y < image->height; y++) {
305 for (x = 0; x < image->width; x++, ptr += channels) {
306 /* reduce pixel */
307 pixel = (*(ptr) << roffs) | (*(ptr + 1) << goffs) | (*(ptr + 2) << boffs);
308 XPutPixel(ximg->image, x, y, pixel);
311 } else {
312 for (y = 0, ofs = 0; y < image->height; y++) {
313 for (x = 0; x < image->width; x++, ofs += channels - 3) {
314 /* reduce pixel */
315 r = rtable[ptr[ofs++]];
316 g = gtable[ptr[ofs++]];
317 b = btable[ptr[ofs++]];
318 pixel = (r << roffs) | (g << goffs) | (b << boffs);
319 XPutPixel(ximg->image, x, y, pixel);
323 } else {
324 /* dither */
325 const int dr = 0xff / rmask;
326 const int dg = 0xff / gmask;
327 const int db = 0xff / bmask;
329 #ifdef WRLIB_DEBUG
330 fputs("true color dither\n", stderr);
331 #endif
334 signed char *err;
335 signed char *nerr;
336 int ch = (HAS_ALPHA(image) ? 4 : 3);
338 err = malloc(ch * (image->width + 2));
339 nerr = malloc(ch * (image->width + 2));
340 if (!err || !nerr) {
341 NFREE(err);
342 NFREE(nerr);
343 RErrorCode = RERR_NOMEMORY;
344 RDestroyXImage(ctx, ximg);
345 return NULL;
348 memset(err, 0, ch * (image->width + 2));
349 memset(nerr, 0, ch * (image->width + 2));
351 convertTrueColor_generic(ximg, image, err, nerr,
352 rtable, gtable, btable, dr, dg, db, roffs, goffs, boffs);
353 free(err);
354 free(nerr);
359 return ximg;
362 /***************************************************************************/
364 static void
365 convertPseudoColor_to_8(RXImage * ximg, RImage * image,
366 signed char *err, signed char *nerr,
367 const unsigned short *rtable,
368 const unsigned short *gtable,
369 const unsigned short *btable,
370 const int dr, const int dg, const int db, unsigned long *pixels, int cpc)
372 signed char *terr;
373 int x, y, r, g, b;
374 int pixel;
375 int rer, ger, ber;
376 unsigned char *ptr = image->data;
377 unsigned char *optr = (unsigned char *)ximg->image->data;
378 int channels = (HAS_ALPHA(image) ? 4 : 3);
379 int cpcpc = cpc * cpc;
381 /* convert and dither the image to XImage */
382 for (y = 0; y < image->height; y++) {
383 nerr[0] = 0;
384 nerr[1] = 0;
385 nerr[2] = 0;
386 for (x = 0; x < image->width * 3; x += 3, ptr += channels) {
388 /* reduce pixel */
389 pixel = *ptr + err[x];
390 if (pixel < 0)
391 pixel = 0;
392 else if (pixel > 0xff)
393 pixel = 0xff;
394 r = rtable[pixel];
395 /* calc error */
396 rer = pixel - r * dr;
398 /* reduce pixel */
399 pixel = *(ptr + 1) + err[x + 1];
400 if (pixel < 0)
401 pixel = 0;
402 else if (pixel > 0xff)
403 pixel = 0xff;
404 g = gtable[pixel];
405 /* calc error */
406 ger = pixel - g * dg;
408 /* reduce pixel */
409 pixel = *(ptr + 2) + err[x + 2];
410 if (pixel < 0)
411 pixel = 0;
412 else if (pixel > 0xff)
413 pixel = 0xff;
414 b = btable[pixel];
415 /* calc error */
416 ber = pixel - b * db;
418 *optr++ = pixels[r * cpcpc + g * cpc + b];
420 /* distribute error */
421 r = (rer * 3) / 8;
422 g = (ger * 3) / 8;
423 b = (ber * 3) / 8;
425 /* x+1, y */
426 err[x + 3 * 1] += r;
427 err[x + 1 + 3 * 1] += g;
428 err[x + 2 + 3 * 1] += b;
429 /* x, y+1 */
430 nerr[x] += r;
431 nerr[x + 1] += g;
432 nerr[x + 2] += b;
433 /* x+1, y+1 */
434 nerr[x + 3 * 1] = rer - 2 * r;
435 nerr[x + 1 + 3 * 1] = ger - 2 * g;
436 nerr[x + 2 + 3 * 1] = ber - 2 * b;
438 /* skip to next line */
439 terr = err;
440 err = nerr;
441 nerr = terr;
443 optr += ximg->image->bytes_per_line - image->width;
447 static RXImage *image2PseudoColor(RContext * ctx, RImage * image)
449 RXImage *ximg;
450 register int x, y, r, g, b;
451 unsigned char *ptr;
452 unsigned long pixel;
453 const int cpc = ctx->attribs->colors_per_channel;
454 const unsigned short rmask = cpc - 1; /* different sizes could be used */
455 const unsigned short gmask = rmask; /* for r,g,b */
456 const unsigned short bmask = rmask;
457 unsigned short *rtable, *gtable, *btable;
458 const int cpccpc = cpc * cpc;
459 int channels = (HAS_ALPHA(image) ? 4 : 3);
461 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
462 if (!ximg) {
463 return NULL;
466 ptr = image->data;
468 /* Tables are same at the moment because rmask==gmask==bmask. */
469 rtable = computeTable(rmask);
470 gtable = computeTable(gmask);
471 btable = computeTable(bmask);
473 if (rtable == NULL || gtable == NULL || btable == NULL) {
474 RErrorCode = RERR_NOMEMORY;
475 RDestroyXImage(ctx, ximg);
476 return NULL;
479 if (ctx->attribs->render_mode == RBestMatchRendering) {
480 /* fake match */
481 #ifdef WRLIB_DEBUG
482 fprintf(stderr, "pseudo color match with %d colors per channel\n", cpc);
483 #endif
484 for (y = 0; y < image->height; y++) {
485 for (x = 0; x < image->width; x++, ptr += channels - 3) {
486 /* reduce pixel */
487 r = rtable[*ptr++];
488 g = gtable[*ptr++];
489 b = btable[*ptr++];
490 pixel = r * cpccpc + g * cpc + b;
491 /*data[ofs] = ctx->colors[pixel].pixel; */
492 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
495 } else {
496 /* dither */
497 signed char *err;
498 signed char *nerr;
499 const int dr = 0xff / rmask;
500 const int dg = 0xff / gmask;
501 const int db = 0xff / bmask;
503 #ifdef WRLIB_DEBUG
504 fprintf(stderr, "pseudo color dithering with %d colors per channel\n", cpc);
505 #endif
506 err = malloc(4 * (image->width + 3));
507 nerr = malloc(4 * (image->width + 3));
508 if (!err || !nerr) {
509 NFREE(err);
510 NFREE(nerr);
511 RErrorCode = RERR_NOMEMORY;
512 RDestroyXImage(ctx, ximg);
513 return NULL;
515 memset(err, 0, 4 * (image->width + 3));
516 memset(nerr, 0, 4 * (image->width + 3));
518 convertPseudoColor_to_8(ximg, image, err + 4, nerr + 4,
519 rtable, gtable, btable, dr, dg, db, ctx->pixels, cpc);
521 free(err);
522 free(nerr);
525 return ximg;
529 * For standard colormap
531 static RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image)
533 RXImage *ximg;
534 register int x, y, r, g, b;
535 unsigned char *ptr;
536 unsigned long pixel;
537 unsigned char *data;
538 unsigned int *rtable, *gtable, *btable;
539 unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
540 int channels = (HAS_ALPHA(image) ? 4 : 3);
542 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
543 if (!ximg) {
544 return NULL;
547 ptr = image->data;
549 data = (unsigned char *)ximg->image->data;
551 rtable = computeStdTable(ctx->std_rgb_map->red_mult, ctx->std_rgb_map->red_max);
553 gtable = computeStdTable(ctx->std_rgb_map->green_mult, ctx->std_rgb_map->green_max);
555 btable = computeStdTable(ctx->std_rgb_map->blue_mult, ctx->std_rgb_map->blue_max);
557 if (rtable == NULL || gtable == NULL || btable == NULL) {
558 RErrorCode = RERR_NOMEMORY;
559 RDestroyXImage(ctx, ximg);
560 return NULL;
563 if (ctx->attribs->render_mode == RBestMatchRendering) {
564 for (y = 0; y < image->height; y++) {
565 for (x = 0; x < image->width; x++, ptr += channels) {
566 /* reduce pixel */
567 pixel = (rtable[*ptr] + gtable[*(ptr + 1)]
568 + btable[*(ptr + 2)] + base_pixel) & 0xffffffff;
570 XPutPixel(ximg->image, x, y, pixel);
573 } else {
574 /* dither */
575 signed short *err, *nerr;
576 signed short *terr;
577 int rer, ger, ber;
578 int x1, ofs;
580 #ifdef WRLIB_DEBUG
581 fprintf(stderr, "pseudo color dithering with %d colors per channel\n",
582 ctx->attribs->colors_per_channel);
583 #endif
584 err = (short *)malloc(3 * (image->width + 2) * sizeof(short));
585 nerr = (short *)malloc(3 * (image->width + 2) * sizeof(short));
586 if (!err || !nerr) {
587 NFREE(err);
588 NFREE(nerr);
589 RErrorCode = RERR_NOMEMORY;
590 RDestroyXImage(ctx, ximg);
591 return NULL;
593 for (x = 0, x1 = 0; x < image->width * 3; x1 += channels - 3) {
594 err[x++] = ptr[x1++];
595 err[x++] = ptr[x1++];
596 err[x++] = ptr[x1++];
598 err[x] = err[x + 1] = err[x + 2] = 0;
599 /* convert and dither the image to XImage */
600 for (y = 0, ofs = 0; y < image->height; y++) {
601 if (y < image->height - 1) {
602 int x1;
603 for (x = 0, x1 = (y + 1) * image->width * channels;
604 x < image->width * 3; x1 += channels - 3) {
605 nerr[x++] = ptr[x1++];
606 nerr[x++] = ptr[x1++];
607 nerr[x++] = ptr[x1++];
609 /* last column */
610 x1 -= channels;
611 nerr[x++] = ptr[x1++];
612 nerr[x++] = ptr[x1++];
613 nerr[x++] = ptr[x1++];
615 for (x = 0; x < image->width * 3; x += 3, ofs++) {
616 /* reduce pixel */
617 if (err[x] > 0xff)
618 err[x] = 0xff;
619 else if (err[x] < 0)
620 err[x] = 0;
621 if (err[x + 1] > 0xff)
622 err[x + 1] = 0xff;
623 else if (err[x + 1] < 0)
624 err[x + 1] = 0;
625 if (err[x + 2] > 0xff)
626 err[x + 2] = 0xff;
627 else if (err[x + 2] < 0)
628 err[x + 2] = 0;
630 r = rtable[err[x]];
631 g = gtable[err[x + 1]];
632 b = btable[err[x + 2]];
634 pixel = r + g + b;
636 data[ofs] = base_pixel + pixel;
638 /* calc error */
639 rer = err[x] - (ctx->colors[pixel].red >> 8);
640 ger = err[x + 1] - (ctx->colors[pixel].green >> 8);
641 ber = err[x + 2] - (ctx->colors[pixel].blue >> 8);
643 /* distribute error */
644 err[x + 3 * 1] += (rer * 7) / 16;
645 err[x + 1 + 3 * 1] += (ger * 7) / 16;
646 err[x + 2 + 3 * 1] += (ber * 7) / 16;
648 nerr[x] += (rer * 5) / 16;
649 nerr[x + 1] += (ger * 5) / 16;
650 nerr[x + 2] += (ber * 5) / 16;
652 if (x > 0) {
653 nerr[x - 3 * 1] += (rer * 3) / 16;
654 nerr[x - 3 * 1 + 1] += (ger * 3) / 16;
655 nerr[x - 3 * 1 + 2] += (ber * 3) / 16;
658 nerr[x + 3 * 1] += rer / 16;
659 nerr[x + 1 + 3 * 1] += ger / 16;
660 nerr[x + 2 + 3 * 1] += ber / 16;
662 /* skip to next line */
663 terr = err;
664 err = nerr;
665 nerr = terr;
667 ofs += ximg->image->bytes_per_line - image->width;
669 free(err);
670 free(nerr);
672 ximg->image->data = (char *)data;
674 return ximg;
677 static RXImage *image2GrayScale(RContext * ctx, RImage * image)
679 RXImage *ximg;
680 register int x, y, g;
681 unsigned char *ptr;
682 const int cpc = ctx->attribs->colors_per_channel;
683 unsigned short gmask;
684 unsigned short *table;
685 unsigned char *data;
686 int channels = (HAS_ALPHA(image) ? 4 : 3);
688 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
689 if (!ximg) {
690 return NULL;
693 ptr = image->data;
695 data = (unsigned char *)ximg->image->data;
697 if (ctx->vclass == StaticGray)
698 gmask = (1 << ctx->depth) - 1; /* use all grays */
699 else
700 gmask = cpc * cpc * cpc - 1;
702 table = computeTable(gmask);
704 if (table == NULL) {
705 RErrorCode = RERR_NOMEMORY;
706 RDestroyXImage(ctx, ximg);
707 return NULL;
710 if (ctx->attribs->render_mode == RBestMatchRendering) {
711 /* fake match */
712 #ifdef WRLIB_DEBUG
713 fprintf(stderr, "grayscale match with %d colors per channel\n", cpc);
714 #endif
715 for (y = 0; y < image->height; y++) {
716 for (x = 0; x < image->width; x++) {
717 /* reduce pixel */
718 g = table[(*ptr * 30 + *(ptr + 1) * 59 + *(ptr + 2) * 11) / 100];
719 ptr += channels;
720 /*data[ofs] = ctx->colors[g].pixel; */
721 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
724 } else {
725 /* dither */
726 short *gerr;
727 short *ngerr;
728 short *terr;
729 int ger;
730 const int dg = 0xff / gmask;
732 #ifdef WRLIB_DEBUG
733 fprintf(stderr, "grayscale dither with %d colors per channel\n", cpc);
734 #endif
735 gerr = (short *)malloc((image->width + 2) * sizeof(short));
736 ngerr = (short *)malloc((image->width + 2) * sizeof(short));
737 if (!gerr || !ngerr) {
738 NFREE(gerr);
739 NFREE(ngerr);
740 RErrorCode = RERR_NOMEMORY;
741 RDestroyXImage(ctx, ximg);
742 return NULL;
744 for (x = 0, y = 0; x < image->width; x++, y += channels) {
745 gerr[x] = (ptr[y] * 30 + ptr[y + 1] * 59 + ptr[y + 2] * 11) / 100;
747 gerr[x] = 0;
748 /* convert and dither the image to XImage */
749 for (y = 0; y < image->height; y++) {
750 if (y < image->height - 1) {
751 int x1;
752 for (x = 0, x1 = (y + 1) * image->width * channels; x < image->width;
753 x++, x1 += channels) {
754 ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
756 /* last column */
757 x1 -= channels;
758 ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
760 for (x = 0; x < image->width; x++) {
761 /* reduce pixel */
762 if (gerr[x] > 0xff)
763 gerr[x] = 0xff;
764 else if (gerr[x] < 0)
765 gerr[x] = 0;
767 g = table[gerr[x]];
769 /*data[ofs] = ctx->colors[g].pixel; */
770 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
771 /* calc error */
772 ger = gerr[x] - g * dg;
774 /* distribute error */
775 g = (ger * 3) / 8;
776 /* x+1, y */
777 gerr[x + 1] += g;
778 /* x, y+1 */
779 ngerr[x] += g;
780 /* x+1, y+1 */
781 ngerr[x + 1] += ger - 2 * g;
783 /* skip to next line */
784 terr = gerr;
785 gerr = ngerr;
786 ngerr = terr;
788 free(gerr);
789 free(ngerr);
791 ximg->image->data = (char *)data;
793 return ximg;
796 static RXImage *image2Bitmap(RContext * ctx, RImage * image, int threshold)
798 RXImage *ximg;
799 unsigned char *alpha;
800 int x, y;
802 ximg = RCreateXImage(ctx, 1, image->width, image->height);
803 if (!ximg) {
804 return NULL;
806 alpha = image->data + 3;
808 for (y = 0; y < image->height; y++) {
809 for (x = 0; x < image->width; x++) {
810 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
811 alpha += 4;
815 return ximg;
818 int RConvertImage(RContext * context, RImage * image, Pixmap * pixmap)
820 RXImage *ximg = NULL;
821 #ifdef XSHM
822 Pixmap tmp;
823 #endif
825 assert(context != NULL);
826 assert(image != NULL);
827 assert(pixmap != NULL);
829 switch (context->vclass) {
830 case TrueColor:
831 ximg = image2TrueColor(context, image);
832 break;
834 case PseudoColor:
835 case StaticColor:
836 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
837 ximg = image2StandardPseudoColor(context, image);
838 else
839 ximg = image2PseudoColor(context, image);
840 break;
842 case GrayScale:
843 case StaticGray:
844 ximg = image2GrayScale(context, image);
845 break;
848 if (!ximg) {
849 return False;
852 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, context->depth);
854 #ifdef XSHM
855 if (context->flags.use_shared_pixmap && ximg->is_shared)
856 tmp = R_CreateXImageMappedPixmap(context, ximg);
857 else
858 tmp = None;
859 if (tmp) {
861 * We have to copy the shm Pixmap into a normal Pixmap because
862 * otherwise, we would have to control when Pixmaps are freed so
863 * that we can detach their shm segments. This is a problem if the
864 * program crash, leaving stale shared memory segments in the
865 * system (lots of them). But with some work, we can optimize
866 * things and remove this XCopyArea. This will require
867 * explicitly freeing all pixmaps when exiting or restarting
868 * wmaker.
870 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0, image->width, image->height, 0, 0);
871 XFreePixmap(context->dpy, tmp);
872 } else {
873 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
875 #else /* !XSHM */
876 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
877 #endif /* !XSHM */
879 RDestroyXImage(context, ximg);
881 return True;
884 /* make the gc permanent (create with context creation).
885 * GC creation is very expensive. altering its properties is not. -Dan
887 int RConvertImageMask(RContext * context, RImage * image, Pixmap * pixmap, Pixmap * mask, int threshold)
889 GC gc;
890 XGCValues gcv;
891 RXImage *ximg = NULL;
893 assert(context != NULL);
894 assert(image != NULL);
895 assert(pixmap != NULL);
896 assert(mask != NULL);
898 if (!RConvertImage(context, image, pixmap))
899 return False;
901 if (image->format == RRGBFormat) {
902 *mask = None;
903 return True;
906 ximg = image2Bitmap(context, image, threshold);
908 if (!ximg) {
909 return False;
911 *mask = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, 1);
912 gcv.foreground = context->black;
913 gcv.background = context->white;
914 gcv.graphics_exposures = False;
915 gc = XCreateGC(context->dpy, *mask, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
916 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0, image->width, image->height);
917 RDestroyXImage(context, ximg);
918 XFreeGC(context->dpy, gc);
920 return True;
923 Bool RGetClosestXColor(RContext * context, RColor * color, XColor * retColor)
925 if (context->vclass == TrueColor) {
926 unsigned short rmask, gmask, bmask;
927 unsigned short roffs, goffs, boffs;
928 unsigned short *rtable, *gtable, *btable;
930 roffs = context->red_offset;
931 goffs = context->green_offset;
932 boffs = context->blue_offset;
934 rmask = context->visual->red_mask >> roffs;
935 gmask = context->visual->green_mask >> goffs;
936 bmask = context->visual->blue_mask >> boffs;
938 rtable = computeTable(rmask);
939 gtable = computeTable(gmask);
940 btable = computeTable(bmask);
942 retColor->pixel = (rtable[color->red] << roffs) |
943 (gtable[color->green] << goffs) | (btable[color->blue] << boffs);
945 retColor->red = color->red << 8;
946 retColor->green = color->green << 8;
947 retColor->blue = color->blue << 8;
948 retColor->flags = DoRed | DoGreen | DoBlue;
950 } else if (context->vclass == PseudoColor || context->vclass == StaticColor) {
952 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
953 unsigned int *rtable, *gtable, *btable;
955 rtable = computeStdTable(context->std_rgb_map->red_mult, context->std_rgb_map->red_max);
957 gtable = computeStdTable(context->std_rgb_map->green_mult,
958 context->std_rgb_map->green_max);
960 btable = computeStdTable(context->std_rgb_map->blue_mult, context->std_rgb_map->blue_max);
962 if (rtable == NULL || gtable == NULL || btable == NULL) {
963 RErrorCode = RERR_NOMEMORY;
964 return False;
967 retColor->pixel = (rtable[color->red]
968 + gtable[color->green]
969 + btable[color->blue]
970 + context->std_rgb_map->base_pixel) & 0xffffffff;
971 retColor->red = color->red << 8;
972 retColor->green = color->green << 8;
973 retColor->blue = color->blue << 8;
974 retColor->flags = DoRed | DoGreen | DoBlue;
976 } else {
977 const int cpc = context->attribs->colors_per_channel;
978 const unsigned short rmask = cpc - 1; /* different sizes could be used */
979 const unsigned short gmask = rmask; /* for r,g,b */
980 const unsigned short bmask = rmask;
981 unsigned short *rtable, *gtable, *btable;
982 const int cpccpc = cpc * cpc;
983 int index;
985 rtable = computeTable(rmask);
986 gtable = computeTable(gmask);
987 btable = computeTable(bmask);
989 if (rtable == NULL || gtable == NULL || btable == NULL) {
990 RErrorCode = RERR_NOMEMORY;
991 return False;
993 index = rtable[color->red] * cpccpc + gtable[color->green] * cpc + btable[color->blue];
994 *retColor = context->colors[index];
997 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
999 const int cpc = context->attribs->colors_per_channel;
1000 unsigned short gmask;
1001 unsigned short *table;
1002 int index;
1004 if (context->vclass == StaticGray)
1005 gmask = (1 << context->depth) - 1; /* use all grays */
1006 else
1007 gmask = cpc * cpc * cpc - 1;
1009 table = computeTable(gmask);
1010 if (!table)
1011 return False;
1013 index = table[(color->red * 30 + color->green * 59 + color->blue * 11) / 100];
1015 *retColor = context->colors[index];
1016 } else {
1017 RErrorCode = RERR_INTERNAL;
1018 return False;
1021 return True;