Coverity: fix RContextAttributes uninitialized variable
[wmaker-crm.git] / wrlib / convert.c
blob05a824877e2dd5d3a880ab4cd73975c374699717
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., 51 Franklin St, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
23 /* Problems:
24 * 1. Using Grayscale visual with Dithering crashes wmaker
25 * 2. Ghost dock/appicon is wrong in Pseudocolor, Staticgray, Grayscale
28 #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>
34 #include <assert.h>
36 #include "wraster.h"
37 #include "convert.h"
38 #include "xutil.h"
39 #include "wr_i18n.h"
42 #define NFREE(n) if (n) free(n)
44 #define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
46 typedef struct RConversionTable {
47 unsigned short table[256];
48 unsigned short index;
50 struct RConversionTable *next;
51 } RConversionTable;
53 typedef struct RStdConversionTable {
54 unsigned int table[256];
56 unsigned short mult;
57 unsigned short max;
59 struct RStdConversionTable *next;
60 } RStdConversionTable;
62 static RConversionTable *conversionTable = NULL;
63 static RStdConversionTable *stdConversionTable = NULL;
65 static void release_conversion_table(void)
67 RConversionTable *tmp = conversionTable;
69 while (tmp) {
70 RConversionTable *tmp_to_delete = tmp;
72 tmp = tmp->next;
73 free(tmp_to_delete);
75 conversionTable = NULL;
78 static void release_std_conversion_table(void)
80 RStdConversionTable *tmp = stdConversionTable;
82 while (tmp) {
83 RStdConversionTable *tmp_to_delete = tmp;
85 tmp = tmp->next;
86 free(tmp_to_delete);
88 stdConversionTable = NULL;
91 void r_destroy_conversion_tables(void)
93 release_conversion_table();
94 release_std_conversion_table();
97 static unsigned short *computeTable(unsigned short mask)
99 RConversionTable *tmp = conversionTable;
100 int i;
102 while (tmp) {
103 if (tmp->index == mask)
104 break;
105 tmp = tmp->next;
108 if (tmp)
109 return tmp->table;
111 tmp = (RConversionTable *) malloc(sizeof(RConversionTable));
112 if (tmp == NULL)
113 return NULL;
115 for (i = 0; i < 256; i++)
116 tmp->table[i] = (i * mask + 0x7f) / 0xff;
118 tmp->index = mask;
119 tmp->next = conversionTable;
120 conversionTable = tmp;
121 return tmp->table;
124 static unsigned int *computeStdTable(unsigned int mult, unsigned int max)
126 RStdConversionTable *tmp = stdConversionTable;
127 unsigned int i;
129 while (tmp) {
130 if (tmp->mult == mult && tmp->max == max)
131 break;
132 tmp = tmp->next;
135 if (tmp)
136 return tmp->table;
138 tmp = (RStdConversionTable *) malloc(sizeof(RStdConversionTable));
139 if (tmp == NULL)
140 return NULL;
142 for (i = 0; i < 256; i++) {
143 tmp->table[i] = (i * max) / 0xff * mult;
145 tmp->mult = mult;
146 tmp->max = max;
148 tmp->next = stdConversionTable;
149 stdConversionTable = tmp;
151 return tmp->table;
154 /***************************************************************************/
156 static void
157 convertTrueColor_generic(RXImage * ximg, RImage * image,
158 signed char *err, signed char *nerr,
159 const unsigned short *rtable,
160 const unsigned short *gtable,
161 const unsigned short *btable,
162 const int dr, const int dg, const int db,
163 const unsigned short roffs, const unsigned short goffs, const unsigned short boffs)
165 signed char *terr;
166 int x, y, r, g, b;
167 int pixel;
168 int rer, ger, ber;
169 unsigned char *ptr = image->data;
170 int channels = (HAS_ALPHA(image) ? 4 : 3);
172 /* convert and dither the image to XImage */
173 for (y = 0; y < image->height; y++) {
174 nerr[0] = 0;
175 nerr[1] = 0;
176 nerr[2] = 0;
177 for (x = 0; x < image->width; x++, ptr += channels) {
179 /* reduce pixel */
180 pixel = *ptr + err[x];
181 if (pixel < 0)
182 pixel = 0;
183 else if (pixel > 0xff)
184 pixel = 0xff;
185 r = rtable[pixel];
186 /* calc error */
187 rer = pixel - r * dr;
189 /* reduce pixel */
190 pixel = *(ptr + 1) + err[x + 1];
191 if (pixel < 0)
192 pixel = 0;
193 else if (pixel > 0xff)
194 pixel = 0xff;
195 g = gtable[pixel];
196 /* calc error */
197 ger = pixel - g * dg;
199 /* reduce pixel */
200 pixel = *(ptr + 2) + err[x + 2];
201 if (pixel < 0)
202 pixel = 0;
203 else if (pixel > 0xff)
204 pixel = 0xff;
205 b = btable[pixel];
206 /* calc error */
207 ber = pixel - b * db;
209 pixel = (r << roffs) | (g << goffs) | (b << boffs);
210 XPutPixel(ximg->image, x, y, pixel);
212 /* distribute error */
213 r = (rer * 3) / 8;
214 g = (ger * 3) / 8;
215 b = (ber * 3) / 8;
216 /* x+1, y */
217 err[x + 3 * 1] += r;
218 err[x + 1 + 3 * 1] += g;
219 err[x + 2 + 3 * 1] += b;
220 /* x, y+1 */
221 nerr[x] += r;
222 nerr[x + 1] += g;
223 nerr[x + 2] += b;
224 /* x+1, y+1 */
225 nerr[x + 3 * 1] = rer - 2 * r;
226 nerr[x + 1 + 3 * 1] = ger - 2 * g;
227 nerr[x + 2 + 3 * 1] = ber - 2 * b;
229 /* skip to next line */
230 terr = err;
231 err = nerr;
232 nerr = terr;
235 /* redither the 1st line to distribute error better */
236 ptr = image->data;
237 y = 0;
238 nerr[0] = 0;
239 nerr[1] = 0;
240 nerr[2] = 0;
241 for (x = 0; x < image->width; x++, ptr += channels) {
243 /* reduce pixel */
244 pixel = *ptr + err[x];
245 if (pixel < 0)
246 pixel = 0;
247 else if (pixel > 0xff)
248 pixel = 0xff;
249 r = rtable[pixel];
250 /* calc error */
251 rer = pixel - r * dr;
253 /* reduce pixel */
254 pixel = *(ptr + 1) + err[x + 1];
255 if (pixel < 0)
256 pixel = 0;
257 else if (pixel > 0xff)
258 pixel = 0xff;
259 g = gtable[pixel];
260 /* calc error */
261 ger = pixel - g * dg;
263 /* reduce pixel */
264 pixel = *(ptr + 2) + err[x + 2];
265 if (pixel < 0)
266 pixel = 0;
267 else if (pixel > 0xff)
268 pixel = 0xff;
269 b = btable[pixel];
270 /* calc error */
271 ber = pixel - b * db;
273 pixel = (r << roffs) | (g << goffs) | (b << boffs);
274 XPutPixel(ximg->image, x, y, pixel);
276 /* distribute error */
277 r = (rer * 3) / 8;
278 g = (ger * 3) / 8;
279 b = (ber * 3) / 8;
280 /* x+1, y */
281 err[x + 3 * 1] += r;
282 err[x + 1 + 3 * 1] += g;
283 err[x + 2 + 3 * 1] += b;
284 /* x, y+1 */
285 nerr[x] += r;
286 nerr[x + 1] += g;
287 nerr[x + 2] += b;
288 /* x+1, y+1 */
289 nerr[x + 3 * 1] = rer - 2 * r;
290 nerr[x + 1 + 3 * 1] = ger - 2 * g;
291 nerr[x + 2 + 3 * 1] = ber - 2 * b;
295 static RXImage *image2TrueColor(RContext * ctx, RImage * image)
297 RXImage *ximg;
298 unsigned short rmask, gmask, bmask;
299 unsigned short roffs, goffs, boffs;
300 unsigned short *rtable, *gtable, *btable;
301 int channels = (HAS_ALPHA(image) ? 4 : 3);
303 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
304 if (!ximg) {
305 return NULL;
308 roffs = ctx->red_offset;
309 goffs = ctx->green_offset;
310 boffs = ctx->blue_offset;
312 rmask = ctx->visual->red_mask >> roffs;
313 gmask = ctx->visual->green_mask >> goffs;
314 bmask = ctx->visual->blue_mask >> boffs;
316 rtable = computeTable(rmask);
317 gtable = computeTable(gmask);
318 btable = computeTable(bmask);
320 if (rtable == NULL || gtable == NULL || btable == NULL) {
321 RErrorCode = RERR_NOMEMORY;
322 RDestroyXImage(ctx, ximg);
323 return NULL;
326 if (ctx->attribs->render_mode == RBestMatchRendering) {
327 int ofs;
328 unsigned long r, g, b;
329 int x, y;
330 unsigned long pixel;
331 unsigned char *ptr = image->data;
333 /* fake match */
334 #ifdef WRLIB_DEBUG
335 fputs("true color match\n", stderr);
336 #endif
337 if (rmask == 0xff && gmask == 0xff && bmask == 0xff) {
338 for (y = 0; y < image->height; y++) {
339 for (x = 0; x < image->width; x++, ptr += channels) {
340 /* reduce pixel */
341 r = ptr[0];
342 g = ptr[1];
343 b = ptr[2];
344 pixel = (r << roffs) | (g << goffs) | (b << boffs);
345 XPutPixel(ximg->image, x, y, pixel);
348 } else {
349 for (y = 0, ofs = 0; y < image->height; y++) {
350 for (x = 0; x < image->width; x++, ofs += channels - 3) {
351 /* reduce pixel */
352 r = rtable[ptr[ofs++]];
353 g = gtable[ptr[ofs++]];
354 b = btable[ptr[ofs++]];
355 pixel = (r << roffs) | (g << goffs) | (b << boffs);
356 XPutPixel(ximg->image, x, y, pixel);
360 } else {
361 /* dither */
362 const int dr = 0xff / rmask;
363 const int dg = 0xff / gmask;
364 const int db = 0xff / bmask;
366 #ifdef WRLIB_DEBUG
367 fputs("true color dither\n", stderr);
368 #endif
371 signed char *err;
372 signed char *nerr;
373 int ch = (HAS_ALPHA(image) ? 4 : 3);
375 err = malloc(ch * (image->width + 2));
376 nerr = malloc(ch * (image->width + 2));
377 if (!err || !nerr) {
378 NFREE(err);
379 NFREE(nerr);
380 RErrorCode = RERR_NOMEMORY;
381 RDestroyXImage(ctx, ximg);
382 return NULL;
385 memset(err, 0, ch * (image->width + 2));
386 memset(nerr, 0, ch * (image->width + 2));
388 convertTrueColor_generic(ximg, image, err, nerr,
389 rtable, gtable, btable, dr, dg, db, roffs, goffs, boffs);
390 free(err);
391 free(nerr);
396 return ximg;
399 /***************************************************************************/
401 static void
402 convertPseudoColor_to_8(RXImage * ximg, RImage * image,
403 signed char *err, signed char *nerr,
404 const unsigned short *rtable,
405 const unsigned short *gtable,
406 const unsigned short *btable,
407 const int dr, const int dg, const int db, unsigned long *pixels, int cpc)
409 signed char *terr;
410 int x, y, r, g, b;
411 int pixel;
412 int rer, ger, ber;
413 unsigned char *ptr = image->data;
414 unsigned char *optr = (unsigned char *)ximg->image->data;
415 int channels = (HAS_ALPHA(image) ? 4 : 3);
416 int cpcpc = cpc * cpc;
418 /* convert and dither the image to XImage */
419 for (y = 0; y < image->height; y++) {
420 nerr[0] = 0;
421 nerr[1] = 0;
422 nerr[2] = 0;
423 for (x = 0; x < image->width * 3; x += 3, ptr += channels) {
425 /* reduce pixel */
426 pixel = *ptr + err[x];
427 if (pixel < 0)
428 pixel = 0;
429 else if (pixel > 0xff)
430 pixel = 0xff;
431 r = rtable[pixel];
432 /* calc error */
433 rer = pixel - r * dr;
435 /* reduce pixel */
436 pixel = *(ptr + 1) + err[x + 1];
437 if (pixel < 0)
438 pixel = 0;
439 else if (pixel > 0xff)
440 pixel = 0xff;
441 g = gtable[pixel];
442 /* calc error */
443 ger = pixel - g * dg;
445 /* reduce pixel */
446 pixel = *(ptr + 2) + err[x + 2];
447 if (pixel < 0)
448 pixel = 0;
449 else if (pixel > 0xff)
450 pixel = 0xff;
451 b = btable[pixel];
452 /* calc error */
453 ber = pixel - b * db;
455 *optr++ = pixels[r * cpcpc + g * cpc + b];
457 /* distribute error */
458 r = (rer * 3) / 8;
459 g = (ger * 3) / 8;
460 b = (ber * 3) / 8;
462 /* x+1, y */
463 err[x + 3 * 1] += r;
464 err[x + 1 + 3 * 1] += g;
465 err[x + 2 + 3 * 1] += b;
466 /* x, y+1 */
467 nerr[x] += r;
468 nerr[x + 1] += g;
469 nerr[x + 2] += b;
470 /* x+1, y+1 */
471 nerr[x + 3 * 1] = rer - 2 * r;
472 nerr[x + 1 + 3 * 1] = ger - 2 * g;
473 nerr[x + 2 + 3 * 1] = ber - 2 * b;
475 /* skip to next line */
476 terr = err;
477 err = nerr;
478 nerr = terr;
480 optr += ximg->image->bytes_per_line - image->width;
484 static RXImage *image2PseudoColor(RContext * ctx, RImage * image)
486 RXImage *ximg;
487 register int x, y, r, g, b;
488 unsigned char *ptr;
489 unsigned long pixel;
490 const int cpc = ctx->attribs->colors_per_channel;
491 const unsigned short rmask = cpc - 1; /* different sizes could be used */
492 const unsigned short gmask = rmask; /* for r,g,b */
493 const unsigned short bmask = rmask;
494 unsigned short *rtable, *gtable, *btable;
495 const int cpccpc = cpc * cpc;
496 int channels = (HAS_ALPHA(image) ? 4 : 3);
498 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
499 if (!ximg) {
500 return NULL;
503 ptr = image->data;
505 /* Tables are same at the moment because rmask==gmask==bmask. */
506 rtable = computeTable(rmask);
507 gtable = computeTable(gmask);
508 btable = computeTable(bmask);
510 if (rtable == NULL || gtable == NULL || btable == NULL) {
511 RErrorCode = RERR_NOMEMORY;
512 RDestroyXImage(ctx, ximg);
513 return NULL;
516 if (ctx->attribs->render_mode == RBestMatchRendering) {
517 /* fake match */
518 #ifdef WRLIB_DEBUG
519 fprintf(stderr, "pseudo color match with %d colors per channel\n", cpc);
520 #endif
521 for (y = 0; y < image->height; y++) {
522 for (x = 0; x < image->width; x++, ptr += channels - 3) {
523 /* reduce pixel */
524 r = rtable[*ptr++];
525 g = gtable[*ptr++];
526 b = btable[*ptr++];
527 pixel = r * cpccpc + g * cpc + b;
528 /*data[ofs] = ctx->colors[pixel].pixel; */
529 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
532 } else {
533 /* dither */
534 signed char *err;
535 signed char *nerr;
536 const int dr = 0xff / rmask;
537 const int dg = 0xff / gmask;
538 const int db = 0xff / bmask;
540 #ifdef WRLIB_DEBUG
541 fprintf(stderr, "pseudo color dithering with %d colors per channel\n", cpc);
542 #endif
543 err = malloc(4 * (image->width + 3));
544 nerr = malloc(4 * (image->width + 3));
545 if (!err || !nerr) {
546 NFREE(err);
547 NFREE(nerr);
548 RErrorCode = RERR_NOMEMORY;
549 RDestroyXImage(ctx, ximg);
550 return NULL;
552 memset(err, 0, 4 * (image->width + 3));
553 memset(nerr, 0, 4 * (image->width + 3));
555 convertPseudoColor_to_8(ximg, image, err + 4, nerr + 4,
556 rtable, gtable, btable, dr, dg, db, ctx->pixels, cpc);
558 free(err);
559 free(nerr);
562 return ximg;
566 * For standard colormap
568 static RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image)
570 RXImage *ximg;
571 register int x, y, r, g, b;
572 unsigned char *ptr;
573 unsigned long pixel;
574 unsigned char *data;
575 unsigned int *rtable, *gtable, *btable;
576 unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
577 int channels = (HAS_ALPHA(image) ? 4 : 3);
579 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
580 if (!ximg) {
581 return NULL;
584 ptr = image->data;
586 data = (unsigned char *)ximg->image->data;
588 rtable = computeStdTable(ctx->std_rgb_map->red_mult, ctx->std_rgb_map->red_max);
590 gtable = computeStdTable(ctx->std_rgb_map->green_mult, ctx->std_rgb_map->green_max);
592 btable = computeStdTable(ctx->std_rgb_map->blue_mult, ctx->std_rgb_map->blue_max);
594 if (rtable == NULL || gtable == NULL || btable == NULL) {
595 RErrorCode = RERR_NOMEMORY;
596 RDestroyXImage(ctx, ximg);
597 return NULL;
600 if (ctx->attribs->render_mode == RBestMatchRendering) {
601 for (y = 0; y < image->height; y++) {
602 for (x = 0; x < image->width; x++, ptr += channels) {
603 /* reduce pixel */
604 pixel = (rtable[*ptr] + gtable[*(ptr + 1)]
605 + btable[*(ptr + 2)] + base_pixel) & 0xffffffff;
607 XPutPixel(ximg->image, x, y, pixel);
610 } else {
611 /* dither */
612 signed short *err, *nerr;
613 signed short *terr;
614 int rer, ger, ber;
615 int x1, ofs;
617 #ifdef WRLIB_DEBUG
618 fprintf(stderr, "pseudo color dithering with %d colors per channel\n",
619 ctx->attribs->colors_per_channel);
620 #endif
621 err = (short *)malloc(3 * (image->width + 2) * sizeof(short));
622 nerr = (short *)malloc(3 * (image->width + 2) * sizeof(short));
623 if (!err || !nerr) {
624 NFREE(err);
625 NFREE(nerr);
626 RErrorCode = RERR_NOMEMORY;
627 RDestroyXImage(ctx, ximg);
628 return NULL;
630 for (x = 0, x1 = 0; x < image->width * 3; x1 += channels - 3) {
631 err[x++] = ptr[x1++];
632 err[x++] = ptr[x1++];
633 err[x++] = ptr[x1++];
635 err[x] = err[x + 1] = err[x + 2] = 0;
636 /* convert and dither the image to XImage */
637 for (y = 0, ofs = 0; y < image->height; y++) {
638 if (y < image->height - 1) {
639 int x1;
640 for (x = 0, x1 = (y + 1) * image->width * channels;
641 x < image->width * 3; x1 += channels - 3) {
642 nerr[x++] = ptr[x1++];
643 nerr[x++] = ptr[x1++];
644 nerr[x++] = ptr[x1++];
646 /* last column */
647 x1 -= channels;
648 nerr[x++] = ptr[x1++];
649 nerr[x++] = ptr[x1++];
650 nerr[x++] = ptr[x1++];
652 for (x = 0; x < image->width * 3; x += 3, ofs++) {
653 /* reduce pixel */
654 if (err[x] > 0xff)
655 err[x] = 0xff;
656 else if (err[x] < 0)
657 err[x] = 0;
658 if (err[x + 1] > 0xff)
659 err[x + 1] = 0xff;
660 else if (err[x + 1] < 0)
661 err[x + 1] = 0;
662 if (err[x + 2] > 0xff)
663 err[x + 2] = 0xff;
664 else if (err[x + 2] < 0)
665 err[x + 2] = 0;
667 r = rtable[err[x]];
668 g = gtable[err[x + 1]];
669 b = btable[err[x + 2]];
671 pixel = r + g + b;
673 data[ofs] = base_pixel + pixel;
675 /* calc error */
676 rer = err[x] - (ctx->colors[pixel].red >> 8);
677 ger = err[x + 1] - (ctx->colors[pixel].green >> 8);
678 ber = err[x + 2] - (ctx->colors[pixel].blue >> 8);
680 /* distribute error */
681 err[x + 3 * 1] += (rer * 7) / 16;
682 err[x + 1 + 3 * 1] += (ger * 7) / 16;
683 err[x + 2 + 3 * 1] += (ber * 7) / 16;
685 nerr[x] += (rer * 5) / 16;
686 nerr[x + 1] += (ger * 5) / 16;
687 nerr[x + 2] += (ber * 5) / 16;
689 if (x > 0) {
690 nerr[x - 3 * 1] += (rer * 3) / 16;
691 nerr[x - 3 * 1 + 1] += (ger * 3) / 16;
692 nerr[x - 3 * 1 + 2] += (ber * 3) / 16;
695 nerr[x + 3 * 1] += rer / 16;
696 nerr[x + 1 + 3 * 1] += ger / 16;
697 nerr[x + 2 + 3 * 1] += ber / 16;
699 /* skip to next line */
700 terr = err;
701 err = nerr;
702 nerr = terr;
704 ofs += ximg->image->bytes_per_line - image->width;
706 free(err);
707 free(nerr);
709 ximg->image->data = (char *)data;
711 return ximg;
714 static RXImage *image2GrayScale(RContext * ctx, RImage * image)
716 RXImage *ximg;
717 register int x, y, g;
718 unsigned char *ptr;
719 const int cpc = ctx->attribs->colors_per_channel;
720 unsigned short gmask;
721 unsigned short *table;
722 unsigned char *data;
723 int channels = (HAS_ALPHA(image) ? 4 : 3);
725 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
726 if (!ximg) {
727 return NULL;
730 ptr = image->data;
732 data = (unsigned char *)ximg->image->data;
734 if (ctx->vclass == StaticGray)
735 gmask = (1 << ctx->depth) - 1; /* use all grays */
736 else
737 gmask = cpc * cpc * cpc - 1;
739 table = computeTable(gmask);
741 if (table == NULL) {
742 RErrorCode = RERR_NOMEMORY;
743 RDestroyXImage(ctx, ximg);
744 return NULL;
747 if (ctx->attribs->render_mode == RBestMatchRendering) {
748 /* fake match */
749 #ifdef WRLIB_DEBUG
750 fprintf(stderr, "grayscale match with %d colors per channel\n", cpc);
751 #endif
752 for (y = 0; y < image->height; y++) {
753 for (x = 0; x < image->width; x++) {
754 /* reduce pixel */
755 g = table[(*ptr * 30 + *(ptr + 1) * 59 + *(ptr + 2) * 11) / 100];
756 ptr += channels;
757 /*data[ofs] = ctx->colors[g].pixel; */
758 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
761 } else {
762 /* dither */
763 short *gerr;
764 short *ngerr;
765 short *terr;
766 int ger;
767 const int dg = 0xff / gmask;
769 #ifdef WRLIB_DEBUG
770 fprintf(stderr, "grayscale dither with %d colors per channel\n", cpc);
771 #endif
772 gerr = (short *)malloc((image->width + 2) * sizeof(short));
773 ngerr = (short *)malloc((image->width + 2) * sizeof(short));
774 if (!gerr || !ngerr) {
775 NFREE(gerr);
776 NFREE(ngerr);
777 RErrorCode = RERR_NOMEMORY;
778 RDestroyXImage(ctx, ximg);
779 return NULL;
781 for (x = 0, y = 0; x < image->width; x++, y += channels) {
782 gerr[x] = (ptr[y] * 30 + ptr[y + 1] * 59 + ptr[y + 2] * 11) / 100;
784 gerr[x] = 0;
785 /* convert and dither the image to XImage */
786 for (y = 0; y < image->height; y++) {
787 if (y < image->height - 1) {
788 int x1;
789 for (x = 0, x1 = (y + 1) * image->width * channels; x < image->width;
790 x++, x1 += channels) {
791 ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
793 /* last column */
794 x1 -= channels;
795 ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
797 for (x = 0; x < image->width; x++) {
798 /* reduce pixel */
799 if (gerr[x] > 0xff)
800 gerr[x] = 0xff;
801 else if (gerr[x] < 0)
802 gerr[x] = 0;
804 g = table[gerr[x]];
806 /*data[ofs] = ctx->colors[g].pixel; */
807 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
808 /* calc error */
809 ger = gerr[x] - g * dg;
811 /* distribute error */
812 g = (ger * 3) / 8;
813 /* x+1, y */
814 gerr[x + 1] += g;
815 /* x, y+1 */
816 ngerr[x] += g;
817 /* x+1, y+1 */
818 ngerr[x + 1] += ger - 2 * g;
820 /* skip to next line */
821 terr = gerr;
822 gerr = ngerr;
823 ngerr = terr;
825 free(gerr);
826 free(ngerr);
828 ximg->image->data = (char *)data;
830 return ximg;
833 static RXImage *image2Bitmap(RContext * ctx, RImage * image, int threshold)
835 RXImage *ximg;
836 unsigned char *alpha;
837 int x, y;
839 ximg = RCreateXImage(ctx, 1, image->width, image->height);
840 if (!ximg) {
841 return NULL;
843 alpha = image->data + 3;
845 for (y = 0; y < image->height; y++) {
846 for (x = 0; x < image->width; x++) {
847 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
848 alpha += 4;
852 return ximg;
855 int RConvertImage(RContext * context, RImage * image, Pixmap * pixmap)
857 RXImage *ximg = NULL;
858 #ifdef USE_XSHM
859 Pixmap tmp;
860 #endif
862 assert(context != NULL);
863 assert(image != NULL);
864 assert(pixmap != NULL);
866 switch (context->vclass) {
867 case TrueColor:
868 ximg = image2TrueColor(context, image);
869 break;
871 case PseudoColor:
872 case StaticColor:
873 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
874 ximg = image2StandardPseudoColor(context, image);
875 else
876 ximg = image2PseudoColor(context, image);
877 break;
879 case GrayScale:
880 case StaticGray:
881 ximg = image2GrayScale(context, image);
882 break;
885 if (!ximg) {
886 return False;
889 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, context->depth);
891 #ifdef USE_XSHM
892 if (context->flags.use_shared_pixmap && ximg->is_shared)
893 tmp = R_CreateXImageMappedPixmap(context, ximg);
894 else
895 tmp = None;
896 if (tmp) {
898 * We have to copy the shm Pixmap into a normal Pixmap because
899 * otherwise, we would have to control when Pixmaps are freed so
900 * that we can detach their shm segments. This is a problem if the
901 * program crash, leaving stale shared memory segments in the
902 * system (lots of them). But with some work, we can optimize
903 * things and remove this XCopyArea. This will require
904 * explicitly freeing all pixmaps when exiting or restarting
905 * wmaker.
907 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0, image->width, image->height, 0, 0);
908 XFreePixmap(context->dpy, tmp);
909 } else {
910 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
912 #else /* !USE_XSHM */
913 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
914 #endif /* !USE_XSHM */
916 RDestroyXImage(context, ximg);
918 return True;
921 /* make the gc permanent (create with context creation).
922 * GC creation is very expensive. altering its properties is not. -Dan
924 int RConvertImageMask(RContext * context, RImage * image, Pixmap * pixmap, Pixmap * mask, int threshold)
926 GC gc;
927 XGCValues gcv;
928 RXImage *ximg = NULL;
930 assert(context != NULL);
931 assert(image != NULL);
932 assert(pixmap != NULL);
933 assert(mask != NULL);
935 if (!RConvertImage(context, image, pixmap))
936 return False;
938 if (image->format == RRGBFormat) {
939 *mask = None;
940 return True;
943 ximg = image2Bitmap(context, image, threshold);
945 if (!ximg) {
946 return False;
948 *mask = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, 1);
949 gcv.foreground = context->black;
950 gcv.background = context->white;
951 gcv.graphics_exposures = False;
952 gc = XCreateGC(context->dpy, *mask, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
953 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0, image->width, image->height);
954 RDestroyXImage(context, ximg);
955 XFreeGC(context->dpy, gc);
957 return True;
960 Bool RGetClosestXColor(RContext * context, const RColor * color, XColor * retColor)
962 if (context->vclass == TrueColor) {
963 unsigned short rmask, gmask, bmask;
964 unsigned short roffs, goffs, boffs;
965 unsigned short *rtable, *gtable, *btable;
967 roffs = context->red_offset;
968 goffs = context->green_offset;
969 boffs = context->blue_offset;
971 rmask = context->visual->red_mask >> roffs;
972 gmask = context->visual->green_mask >> goffs;
973 bmask = context->visual->blue_mask >> boffs;
975 rtable = computeTable(rmask);
976 gtable = computeTable(gmask);
977 btable = computeTable(bmask);
979 retColor->pixel = (((unsigned long) rtable[color->red]) << roffs)
980 | (((unsigned long) gtable[color->green]) << goffs)
981 | (((unsigned long) btable[color->blue]) << boffs);
983 retColor->red = color->red << 8;
984 retColor->green = color->green << 8;
985 retColor->blue = color->blue << 8;
986 retColor->flags = DoRed | DoGreen | DoBlue;
988 } else if (context->vclass == PseudoColor || context->vclass == StaticColor) {
990 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
991 unsigned int *rtable, *gtable, *btable;
993 rtable = computeStdTable(context->std_rgb_map->red_mult, context->std_rgb_map->red_max);
995 gtable = computeStdTable(context->std_rgb_map->green_mult,
996 context->std_rgb_map->green_max);
998 btable = computeStdTable(context->std_rgb_map->blue_mult, context->std_rgb_map->blue_max);
1000 if (rtable == NULL || gtable == NULL || btable == NULL) {
1001 RErrorCode = RERR_NOMEMORY;
1002 return False;
1005 retColor->pixel = (rtable[color->red]
1006 + gtable[color->green]
1007 + btable[color->blue]
1008 + context->std_rgb_map->base_pixel) & 0xffffffff;
1009 retColor->red = color->red << 8;
1010 retColor->green = color->green << 8;
1011 retColor->blue = color->blue << 8;
1012 retColor->flags = DoRed | DoGreen | DoBlue;
1014 } else {
1015 const int cpc = context->attribs->colors_per_channel;
1016 const unsigned short rmask = cpc - 1; /* different sizes could be used */
1017 const unsigned short gmask = rmask; /* for r,g,b */
1018 const unsigned short bmask = rmask;
1019 unsigned short *rtable, *gtable, *btable;
1020 const int cpccpc = cpc * cpc;
1021 int index;
1023 rtable = computeTable(rmask);
1024 gtable = computeTable(gmask);
1025 btable = computeTable(bmask);
1027 if (rtable == NULL || gtable == NULL || btable == NULL) {
1028 RErrorCode = RERR_NOMEMORY;
1029 return False;
1031 index = rtable[color->red] * cpccpc + gtable[color->green] * cpc + btable[color->blue];
1032 *retColor = context->colors[index];
1035 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
1037 const int cpc = context->attribs->colors_per_channel;
1038 unsigned short gmask;
1039 unsigned short *table;
1040 int index;
1042 if (context->vclass == StaticGray)
1043 gmask = (1 << context->depth) - 1; /* use all grays */
1044 else
1045 gmask = cpc * cpc * cpc - 1;
1047 table = computeTable(gmask);
1048 if (!table)
1049 return False;
1051 index = table[(color->red * 30 + color->green * 59 + color->blue * 11) / 100];
1053 *retColor = context->colors[index];
1054 } else {
1055 RErrorCode = RERR_INTERNAL;
1056 return False;
1059 return True;