WINGs: fix possible NULL pointer dereference (Coverity #50197)
[wmaker-crm.git] / wrlib / convert.c
blob95a14d45519501c8975e2bb433a86453059b55d9
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"
40 #ifdef USE_XSHM
41 extern Pixmap R_CreateXImageMappedPixmap(RContext * context, RXImage * ximage);
42 #endif
44 #define NFREE(n) if (n) free(n)
46 #define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
48 typedef struct RConversionTable {
49 unsigned short table[256];
50 unsigned short index;
52 struct RConversionTable *next;
53 } RConversionTable;
55 typedef struct RStdConversionTable {
56 unsigned int table[256];
58 unsigned short mult;
59 unsigned short max;
61 struct RStdConversionTable *next;
62 } RStdConversionTable;
64 static RConversionTable *conversionTable = NULL;
65 static RStdConversionTable *stdConversionTable = NULL;
67 static void release_conversion_table(void)
69 RConversionTable *tmp = conversionTable;
71 while (tmp) {
72 RConversionTable *tmp_to_delete = tmp;
74 tmp = tmp->next;
75 free(tmp_to_delete);
77 conversionTable = NULL;
80 static void release_std_conversion_table(void)
82 RStdConversionTable *tmp = stdConversionTable;
84 while (tmp) {
85 RStdConversionTable *tmp_to_delete = tmp;
87 tmp = tmp->next;
88 free(tmp_to_delete);
90 stdConversionTable = NULL;
93 void r_destroy_conversion_tables(void)
95 release_conversion_table();
96 release_std_conversion_table();
99 static unsigned short *computeTable(unsigned short mask)
101 RConversionTable *tmp = conversionTable;
102 int i;
104 while (tmp) {
105 if (tmp->index == mask)
106 break;
107 tmp = tmp->next;
110 if (tmp)
111 return tmp->table;
113 tmp = (RConversionTable *) malloc(sizeof(RConversionTable));
114 if (tmp == NULL)
115 return NULL;
117 for (i = 0; i < 256; i++)
118 tmp->table[i] = (i * mask + 0x7f) / 0xff;
120 tmp->index = mask;
121 tmp->next = conversionTable;
122 conversionTable = tmp;
123 return tmp->table;
126 static unsigned int *computeStdTable(unsigned int mult, unsigned int max)
128 RStdConversionTable *tmp = stdConversionTable;
129 unsigned int i;
131 while (tmp) {
132 if (tmp->mult == mult && tmp->max == max)
133 break;
134 tmp = tmp->next;
137 if (tmp)
138 return tmp->table;
140 tmp = (RStdConversionTable *) malloc(sizeof(RStdConversionTable));
141 if (tmp == NULL)
142 return NULL;
144 for (i = 0; i < 256; i++) {
145 tmp->table[i] = (i * max) / 0xff * mult;
147 tmp->mult = mult;
148 tmp->max = max;
150 tmp->next = stdConversionTable;
151 stdConversionTable = tmp;
153 return tmp->table;
156 /***************************************************************************/
158 static void
159 convertTrueColor_generic(RXImage * ximg, RImage * image,
160 signed char *err, signed char *nerr,
161 const unsigned short *rtable,
162 const unsigned short *gtable,
163 const unsigned short *btable,
164 const int dr, const int dg, const int db,
165 const unsigned short roffs, const unsigned short goffs, const unsigned short boffs)
167 signed char *terr;
168 int x, y, r, g, b;
169 int pixel;
170 int rer, ger, ber;
171 unsigned char *ptr = image->data;
172 int channels = (HAS_ALPHA(image) ? 4 : 3);
174 /* convert and dither the image to XImage */
175 for (y = 0; y < image->height; y++) {
176 nerr[0] = 0;
177 nerr[1] = 0;
178 nerr[2] = 0;
179 for (x = 0; x < image->width; x++, ptr += channels) {
181 /* reduce pixel */
182 pixel = *ptr + err[x];
183 if (pixel < 0)
184 pixel = 0;
185 else if (pixel > 0xff)
186 pixel = 0xff;
187 r = rtable[pixel];
188 /* calc error */
189 rer = pixel - r * dr;
191 /* reduce pixel */
192 pixel = *(ptr + 1) + err[x + 1];
193 if (pixel < 0)
194 pixel = 0;
195 else if (pixel > 0xff)
196 pixel = 0xff;
197 g = gtable[pixel];
198 /* calc error */
199 ger = pixel - g * dg;
201 /* reduce pixel */
202 pixel = *(ptr + 2) + err[x + 2];
203 if (pixel < 0)
204 pixel = 0;
205 else if (pixel > 0xff)
206 pixel = 0xff;
207 b = btable[pixel];
208 /* calc error */
209 ber = pixel - b * db;
211 pixel = (r << roffs) | (g << goffs) | (b << boffs);
212 XPutPixel(ximg->image, x, y, pixel);
214 /* distribute error */
215 r = (rer * 3) / 8;
216 g = (ger * 3) / 8;
217 b = (ber * 3) / 8;
218 /* x+1, y */
219 err[x + 3 * 1] += r;
220 err[x + 1 + 3 * 1] += g;
221 err[x + 2 + 3 * 1] += b;
222 /* x, y+1 */
223 nerr[x] += r;
224 nerr[x + 1] += g;
225 nerr[x + 2] += b;
226 /* x+1, y+1 */
227 nerr[x + 3 * 1] = rer - 2 * r;
228 nerr[x + 1 + 3 * 1] = ger - 2 * g;
229 nerr[x + 2 + 3 * 1] = ber - 2 * b;
231 /* skip to next line */
232 terr = err;
233 err = nerr;
234 nerr = terr;
237 /* redither the 1st line to distribute error better */
238 ptr = image->data;
239 y = 0;
240 nerr[0] = 0;
241 nerr[1] = 0;
242 nerr[2] = 0;
243 for (x = 0; x < image->width; x++, ptr += channels) {
245 /* reduce pixel */
246 pixel = *ptr + err[x];
247 if (pixel < 0)
248 pixel = 0;
249 else if (pixel > 0xff)
250 pixel = 0xff;
251 r = rtable[pixel];
252 /* calc error */
253 rer = pixel - r * dr;
255 /* reduce pixel */
256 pixel = *(ptr + 1) + err[x + 1];
257 if (pixel < 0)
258 pixel = 0;
259 else if (pixel > 0xff)
260 pixel = 0xff;
261 g = gtable[pixel];
262 /* calc error */
263 ger = pixel - g * dg;
265 /* reduce pixel */
266 pixel = *(ptr + 2) + err[x + 2];
267 if (pixel < 0)
268 pixel = 0;
269 else if (pixel > 0xff)
270 pixel = 0xff;
271 b = btable[pixel];
272 /* calc error */
273 ber = pixel - b * db;
275 pixel = (r << roffs) | (g << goffs) | (b << boffs);
276 XPutPixel(ximg->image, x, y, pixel);
278 /* distribute error */
279 r = (rer * 3) / 8;
280 g = (ger * 3) / 8;
281 b = (ber * 3) / 8;
282 /* x+1, y */
283 err[x + 3 * 1] += r;
284 err[x + 1 + 3 * 1] += g;
285 err[x + 2 + 3 * 1] += b;
286 /* x, y+1 */
287 nerr[x] += r;
288 nerr[x + 1] += g;
289 nerr[x + 2] += b;
290 /* x+1, y+1 */
291 nerr[x + 3 * 1] = rer - 2 * r;
292 nerr[x + 1 + 3 * 1] = ger - 2 * g;
293 nerr[x + 2 + 3 * 1] = ber - 2 * b;
297 static RXImage *image2TrueColor(RContext * ctx, RImage * image)
299 RXImage *ximg;
300 unsigned short rmask, gmask, bmask;
301 unsigned short roffs, goffs, boffs;
302 unsigned short *rtable, *gtable, *btable;
303 int channels = (HAS_ALPHA(image) ? 4 : 3);
305 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
306 if (!ximg) {
307 return NULL;
310 roffs = ctx->red_offset;
311 goffs = ctx->green_offset;
312 boffs = ctx->blue_offset;
314 rmask = ctx->visual->red_mask >> roffs;
315 gmask = ctx->visual->green_mask >> goffs;
316 bmask = ctx->visual->blue_mask >> boffs;
318 rtable = computeTable(rmask);
319 gtable = computeTable(gmask);
320 btable = computeTable(bmask);
322 if (rtable == NULL || gtable == NULL || btable == NULL) {
323 RErrorCode = RERR_NOMEMORY;
324 RDestroyXImage(ctx, ximg);
325 return NULL;
328 if (ctx->attribs->render_mode == RBestMatchRendering) {
329 int ofs, r, g, b;
330 int x, y;
331 unsigned long pixel;
332 unsigned char *ptr = image->data;
334 /* fake match */
335 #ifdef WRLIB_DEBUG
336 fputs("true color match\n", stderr);
337 #endif
338 if (rmask == 0xff && gmask == 0xff && bmask == 0xff) {
339 for (y = 0; y < image->height; y++) {
340 for (x = 0; x < image->width; x++, ptr += channels) {
341 /* reduce pixel */
342 pixel = (*(ptr) << roffs) | (*(ptr + 1) << goffs) | (*(ptr + 2) << boffs);
343 XPutPixel(ximg->image, x, y, pixel);
346 } else {
347 for (y = 0, ofs = 0; y < image->height; y++) {
348 for (x = 0; x < image->width; x++, ofs += channels - 3) {
349 /* reduce pixel */
350 r = rtable[ptr[ofs++]];
351 g = gtable[ptr[ofs++]];
352 b = btable[ptr[ofs++]];
353 pixel = (r << roffs) | (g << goffs) | (b << boffs);
354 XPutPixel(ximg->image, x, y, pixel);
358 } else {
359 /* dither */
360 const int dr = 0xff / rmask;
361 const int dg = 0xff / gmask;
362 const int db = 0xff / bmask;
364 #ifdef WRLIB_DEBUG
365 fputs("true color dither\n", stderr);
366 #endif
369 signed char *err;
370 signed char *nerr;
371 int ch = (HAS_ALPHA(image) ? 4 : 3);
373 err = malloc(ch * (image->width + 2));
374 nerr = malloc(ch * (image->width + 2));
375 if (!err || !nerr) {
376 NFREE(err);
377 NFREE(nerr);
378 RErrorCode = RERR_NOMEMORY;
379 RDestroyXImage(ctx, ximg);
380 return NULL;
383 memset(err, 0, ch * (image->width + 2));
384 memset(nerr, 0, ch * (image->width + 2));
386 convertTrueColor_generic(ximg, image, err, nerr,
387 rtable, gtable, btable, dr, dg, db, roffs, goffs, boffs);
388 free(err);
389 free(nerr);
394 return ximg;
397 /***************************************************************************/
399 static void
400 convertPseudoColor_to_8(RXImage * ximg, RImage * image,
401 signed char *err, signed char *nerr,
402 const unsigned short *rtable,
403 const unsigned short *gtable,
404 const unsigned short *btable,
405 const int dr, const int dg, const int db, unsigned long *pixels, int cpc)
407 signed char *terr;
408 int x, y, r, g, b;
409 int pixel;
410 int rer, ger, ber;
411 unsigned char *ptr = image->data;
412 unsigned char *optr = (unsigned char *)ximg->image->data;
413 int channels = (HAS_ALPHA(image) ? 4 : 3);
414 int cpcpc = cpc * cpc;
416 /* convert and dither the image to XImage */
417 for (y = 0; y < image->height; y++) {
418 nerr[0] = 0;
419 nerr[1] = 0;
420 nerr[2] = 0;
421 for (x = 0; x < image->width * 3; x += 3, ptr += channels) {
423 /* reduce pixel */
424 pixel = *ptr + err[x];
425 if (pixel < 0)
426 pixel = 0;
427 else if (pixel > 0xff)
428 pixel = 0xff;
429 r = rtable[pixel];
430 /* calc error */
431 rer = pixel - r * dr;
433 /* reduce pixel */
434 pixel = *(ptr + 1) + err[x + 1];
435 if (pixel < 0)
436 pixel = 0;
437 else if (pixel > 0xff)
438 pixel = 0xff;
439 g = gtable[pixel];
440 /* calc error */
441 ger = pixel - g * dg;
443 /* reduce pixel */
444 pixel = *(ptr + 2) + err[x + 2];
445 if (pixel < 0)
446 pixel = 0;
447 else if (pixel > 0xff)
448 pixel = 0xff;
449 b = btable[pixel];
450 /* calc error */
451 ber = pixel - b * db;
453 *optr++ = pixels[r * cpcpc + g * cpc + b];
455 /* distribute error */
456 r = (rer * 3) / 8;
457 g = (ger * 3) / 8;
458 b = (ber * 3) / 8;
460 /* x+1, y */
461 err[x + 3 * 1] += r;
462 err[x + 1 + 3 * 1] += g;
463 err[x + 2 + 3 * 1] += b;
464 /* x, y+1 */
465 nerr[x] += r;
466 nerr[x + 1] += g;
467 nerr[x + 2] += b;
468 /* x+1, y+1 */
469 nerr[x + 3 * 1] = rer - 2 * r;
470 nerr[x + 1 + 3 * 1] = ger - 2 * g;
471 nerr[x + 2 + 3 * 1] = ber - 2 * b;
473 /* skip to next line */
474 terr = err;
475 err = nerr;
476 nerr = terr;
478 optr += ximg->image->bytes_per_line - image->width;
482 static RXImage *image2PseudoColor(RContext * ctx, RImage * image)
484 RXImage *ximg;
485 register int x, y, r, g, b;
486 unsigned char *ptr;
487 unsigned long pixel;
488 const int cpc = ctx->attribs->colors_per_channel;
489 const unsigned short rmask = cpc - 1; /* different sizes could be used */
490 const unsigned short gmask = rmask; /* for r,g,b */
491 const unsigned short bmask = rmask;
492 unsigned short *rtable, *gtable, *btable;
493 const int cpccpc = cpc * cpc;
494 int channels = (HAS_ALPHA(image) ? 4 : 3);
496 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
497 if (!ximg) {
498 return NULL;
501 ptr = image->data;
503 /* Tables are same at the moment because rmask==gmask==bmask. */
504 rtable = computeTable(rmask);
505 gtable = computeTable(gmask);
506 btable = computeTable(bmask);
508 if (rtable == NULL || gtable == NULL || btable == NULL) {
509 RErrorCode = RERR_NOMEMORY;
510 RDestroyXImage(ctx, ximg);
511 return NULL;
514 if (ctx->attribs->render_mode == RBestMatchRendering) {
515 /* fake match */
516 #ifdef WRLIB_DEBUG
517 fprintf(stderr, "pseudo color match with %d colors per channel\n", cpc);
518 #endif
519 for (y = 0; y < image->height; y++) {
520 for (x = 0; x < image->width; x++, ptr += channels - 3) {
521 /* reduce pixel */
522 r = rtable[*ptr++];
523 g = gtable[*ptr++];
524 b = btable[*ptr++];
525 pixel = r * cpccpc + g * cpc + b;
526 /*data[ofs] = ctx->colors[pixel].pixel; */
527 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
530 } else {
531 /* dither */
532 signed char *err;
533 signed char *nerr;
534 const int dr = 0xff / rmask;
535 const int dg = 0xff / gmask;
536 const int db = 0xff / bmask;
538 #ifdef WRLIB_DEBUG
539 fprintf(stderr, "pseudo color dithering with %d colors per channel\n", cpc);
540 #endif
541 err = malloc(4 * (image->width + 3));
542 nerr = malloc(4 * (image->width + 3));
543 if (!err || !nerr) {
544 NFREE(err);
545 NFREE(nerr);
546 RErrorCode = RERR_NOMEMORY;
547 RDestroyXImage(ctx, ximg);
548 return NULL;
550 memset(err, 0, 4 * (image->width + 3));
551 memset(nerr, 0, 4 * (image->width + 3));
553 convertPseudoColor_to_8(ximg, image, err + 4, nerr + 4,
554 rtable, gtable, btable, dr, dg, db, ctx->pixels, cpc);
556 free(err);
557 free(nerr);
560 return ximg;
564 * For standard colormap
566 static RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image)
568 RXImage *ximg;
569 register int x, y, r, g, b;
570 unsigned char *ptr;
571 unsigned long pixel;
572 unsigned char *data;
573 unsigned int *rtable, *gtable, *btable;
574 unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
575 int channels = (HAS_ALPHA(image) ? 4 : 3);
577 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
578 if (!ximg) {
579 return NULL;
582 ptr = image->data;
584 data = (unsigned char *)ximg->image->data;
586 rtable = computeStdTable(ctx->std_rgb_map->red_mult, ctx->std_rgb_map->red_max);
588 gtable = computeStdTable(ctx->std_rgb_map->green_mult, ctx->std_rgb_map->green_max);
590 btable = computeStdTable(ctx->std_rgb_map->blue_mult, ctx->std_rgb_map->blue_max);
592 if (rtable == NULL || gtable == NULL || btable == NULL) {
593 RErrorCode = RERR_NOMEMORY;
594 RDestroyXImage(ctx, ximg);
595 return NULL;
598 if (ctx->attribs->render_mode == RBestMatchRendering) {
599 for (y = 0; y < image->height; y++) {
600 for (x = 0; x < image->width; x++, ptr += channels) {
601 /* reduce pixel */
602 pixel = (rtable[*ptr] + gtable[*(ptr + 1)]
603 + btable[*(ptr + 2)] + base_pixel) & 0xffffffff;
605 XPutPixel(ximg->image, x, y, pixel);
608 } else {
609 /* dither */
610 signed short *err, *nerr;
611 signed short *terr;
612 int rer, ger, ber;
613 int x1, ofs;
615 #ifdef WRLIB_DEBUG
616 fprintf(stderr, "pseudo color dithering with %d colors per channel\n",
617 ctx->attribs->colors_per_channel);
618 #endif
619 err = (short *)malloc(3 * (image->width + 2) * sizeof(short));
620 nerr = (short *)malloc(3 * (image->width + 2) * sizeof(short));
621 if (!err || !nerr) {
622 NFREE(err);
623 NFREE(nerr);
624 RErrorCode = RERR_NOMEMORY;
625 RDestroyXImage(ctx, ximg);
626 return NULL;
628 for (x = 0, x1 = 0; x < image->width * 3; x1 += channels - 3) {
629 err[x++] = ptr[x1++];
630 err[x++] = ptr[x1++];
631 err[x++] = ptr[x1++];
633 err[x] = err[x + 1] = err[x + 2] = 0;
634 /* convert and dither the image to XImage */
635 for (y = 0, ofs = 0; y < image->height; y++) {
636 if (y < image->height - 1) {
637 int x1;
638 for (x = 0, x1 = (y + 1) * image->width * channels;
639 x < image->width * 3; x1 += channels - 3) {
640 nerr[x++] = ptr[x1++];
641 nerr[x++] = ptr[x1++];
642 nerr[x++] = ptr[x1++];
644 /* last column */
645 x1 -= channels;
646 nerr[x++] = ptr[x1++];
647 nerr[x++] = ptr[x1++];
648 nerr[x++] = ptr[x1++];
650 for (x = 0; x < image->width * 3; x += 3, ofs++) {
651 /* reduce pixel */
652 if (err[x] > 0xff)
653 err[x] = 0xff;
654 else if (err[x] < 0)
655 err[x] = 0;
656 if (err[x + 1] > 0xff)
657 err[x + 1] = 0xff;
658 else if (err[x + 1] < 0)
659 err[x + 1] = 0;
660 if (err[x + 2] > 0xff)
661 err[x + 2] = 0xff;
662 else if (err[x + 2] < 0)
663 err[x + 2] = 0;
665 r = rtable[err[x]];
666 g = gtable[err[x + 1]];
667 b = btable[err[x + 2]];
669 pixel = r + g + b;
671 data[ofs] = base_pixel + pixel;
673 /* calc error */
674 rer = err[x] - (ctx->colors[pixel].red >> 8);
675 ger = err[x + 1] - (ctx->colors[pixel].green >> 8);
676 ber = err[x + 2] - (ctx->colors[pixel].blue >> 8);
678 /* distribute error */
679 err[x + 3 * 1] += (rer * 7) / 16;
680 err[x + 1 + 3 * 1] += (ger * 7) / 16;
681 err[x + 2 + 3 * 1] += (ber * 7) / 16;
683 nerr[x] += (rer * 5) / 16;
684 nerr[x + 1] += (ger * 5) / 16;
685 nerr[x + 2] += (ber * 5) / 16;
687 if (x > 0) {
688 nerr[x - 3 * 1] += (rer * 3) / 16;
689 nerr[x - 3 * 1 + 1] += (ger * 3) / 16;
690 nerr[x - 3 * 1 + 2] += (ber * 3) / 16;
693 nerr[x + 3 * 1] += rer / 16;
694 nerr[x + 1 + 3 * 1] += ger / 16;
695 nerr[x + 2 + 3 * 1] += ber / 16;
697 /* skip to next line */
698 terr = err;
699 err = nerr;
700 nerr = terr;
702 ofs += ximg->image->bytes_per_line - image->width;
704 free(err);
705 free(nerr);
707 ximg->image->data = (char *)data;
709 return ximg;
712 static RXImage *image2GrayScale(RContext * ctx, RImage * image)
714 RXImage *ximg;
715 register int x, y, g;
716 unsigned char *ptr;
717 const int cpc = ctx->attribs->colors_per_channel;
718 unsigned short gmask;
719 unsigned short *table;
720 unsigned char *data;
721 int channels = (HAS_ALPHA(image) ? 4 : 3);
723 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
724 if (!ximg) {
725 return NULL;
728 ptr = image->data;
730 data = (unsigned char *)ximg->image->data;
732 if (ctx->vclass == StaticGray)
733 gmask = (1 << ctx->depth) - 1; /* use all grays */
734 else
735 gmask = cpc * cpc * cpc - 1;
737 table = computeTable(gmask);
739 if (table == NULL) {
740 RErrorCode = RERR_NOMEMORY;
741 RDestroyXImage(ctx, ximg);
742 return NULL;
745 if (ctx->attribs->render_mode == RBestMatchRendering) {
746 /* fake match */
747 #ifdef WRLIB_DEBUG
748 fprintf(stderr, "grayscale match with %d colors per channel\n", cpc);
749 #endif
750 for (y = 0; y < image->height; y++) {
751 for (x = 0; x < image->width; x++) {
752 /* reduce pixel */
753 g = table[(*ptr * 30 + *(ptr + 1) * 59 + *(ptr + 2) * 11) / 100];
754 ptr += channels;
755 /*data[ofs] = ctx->colors[g].pixel; */
756 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
759 } else {
760 /* dither */
761 short *gerr;
762 short *ngerr;
763 short *terr;
764 int ger;
765 const int dg = 0xff / gmask;
767 #ifdef WRLIB_DEBUG
768 fprintf(stderr, "grayscale dither with %d colors per channel\n", cpc);
769 #endif
770 gerr = (short *)malloc((image->width + 2) * sizeof(short));
771 ngerr = (short *)malloc((image->width + 2) * sizeof(short));
772 if (!gerr || !ngerr) {
773 NFREE(gerr);
774 NFREE(ngerr);
775 RErrorCode = RERR_NOMEMORY;
776 RDestroyXImage(ctx, ximg);
777 return NULL;
779 for (x = 0, y = 0; x < image->width; x++, y += channels) {
780 gerr[x] = (ptr[y] * 30 + ptr[y + 1] * 59 + ptr[y + 2] * 11) / 100;
782 gerr[x] = 0;
783 /* convert and dither the image to XImage */
784 for (y = 0; y < image->height; y++) {
785 if (y < image->height - 1) {
786 int x1;
787 for (x = 0, x1 = (y + 1) * image->width * channels; x < image->width;
788 x++, x1 += channels) {
789 ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
791 /* last column */
792 x1 -= channels;
793 ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
795 for (x = 0; x < image->width; x++) {
796 /* reduce pixel */
797 if (gerr[x] > 0xff)
798 gerr[x] = 0xff;
799 else if (gerr[x] < 0)
800 gerr[x] = 0;
802 g = table[gerr[x]];
804 /*data[ofs] = ctx->colors[g].pixel; */
805 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
806 /* calc error */
807 ger = gerr[x] - g * dg;
809 /* distribute error */
810 g = (ger * 3) / 8;
811 /* x+1, y */
812 gerr[x + 1] += g;
813 /* x, y+1 */
814 ngerr[x] += g;
815 /* x+1, y+1 */
816 ngerr[x + 1] += ger - 2 * g;
818 /* skip to next line */
819 terr = gerr;
820 gerr = ngerr;
821 ngerr = terr;
823 free(gerr);
824 free(ngerr);
826 ximg->image->data = (char *)data;
828 return ximg;
831 static RXImage *image2Bitmap(RContext * ctx, RImage * image, int threshold)
833 RXImage *ximg;
834 unsigned char *alpha;
835 int x, y;
837 ximg = RCreateXImage(ctx, 1, image->width, image->height);
838 if (!ximg) {
839 return NULL;
841 alpha = image->data + 3;
843 for (y = 0; y < image->height; y++) {
844 for (x = 0; x < image->width; x++) {
845 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
846 alpha += 4;
850 return ximg;
853 int RConvertImage(RContext * context, RImage * image, Pixmap * pixmap)
855 RXImage *ximg = NULL;
856 #ifdef USE_XSHM
857 Pixmap tmp;
858 #endif
860 assert(context != NULL);
861 assert(image != NULL);
862 assert(pixmap != NULL);
864 switch (context->vclass) {
865 case TrueColor:
866 ximg = image2TrueColor(context, image);
867 break;
869 case PseudoColor:
870 case StaticColor:
871 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
872 ximg = image2StandardPseudoColor(context, image);
873 else
874 ximg = image2PseudoColor(context, image);
875 break;
877 case GrayScale:
878 case StaticGray:
879 ximg = image2GrayScale(context, image);
880 break;
883 if (!ximg) {
884 return False;
887 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, context->depth);
889 #ifdef USE_XSHM
890 if (context->flags.use_shared_pixmap && ximg->is_shared)
891 tmp = R_CreateXImageMappedPixmap(context, ximg);
892 else
893 tmp = None;
894 if (tmp) {
896 * We have to copy the shm Pixmap into a normal Pixmap because
897 * otherwise, we would have to control when Pixmaps are freed so
898 * that we can detach their shm segments. This is a problem if the
899 * program crash, leaving stale shared memory segments in the
900 * system (lots of them). But with some work, we can optimize
901 * things and remove this XCopyArea. This will require
902 * explicitly freeing all pixmaps when exiting or restarting
903 * wmaker.
905 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0, image->width, image->height, 0, 0);
906 XFreePixmap(context->dpy, tmp);
907 } else {
908 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
910 #else /* !USE_XSHM */
911 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
912 #endif /* !USE_XSHM */
914 RDestroyXImage(context, ximg);
916 return True;
919 /* make the gc permanent (create with context creation).
920 * GC creation is very expensive. altering its properties is not. -Dan
922 int RConvertImageMask(RContext * context, RImage * image, Pixmap * pixmap, Pixmap * mask, int threshold)
924 GC gc;
925 XGCValues gcv;
926 RXImage *ximg = NULL;
928 assert(context != NULL);
929 assert(image != NULL);
930 assert(pixmap != NULL);
931 assert(mask != NULL);
933 if (!RConvertImage(context, image, pixmap))
934 return False;
936 if (image->format == RRGBFormat) {
937 *mask = None;
938 return True;
941 ximg = image2Bitmap(context, image, threshold);
943 if (!ximg) {
944 return False;
946 *mask = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, 1);
947 gcv.foreground = context->black;
948 gcv.background = context->white;
949 gcv.graphics_exposures = False;
950 gc = XCreateGC(context->dpy, *mask, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
951 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0, image->width, image->height);
952 RDestroyXImage(context, ximg);
953 XFreeGC(context->dpy, gc);
955 return True;
958 Bool RGetClosestXColor(RContext * context, const RColor * color, XColor * retColor)
960 if (context->vclass == TrueColor) {
961 unsigned short rmask, gmask, bmask;
962 unsigned short roffs, goffs, boffs;
963 unsigned short *rtable, *gtable, *btable;
965 roffs = context->red_offset;
966 goffs = context->green_offset;
967 boffs = context->blue_offset;
969 rmask = context->visual->red_mask >> roffs;
970 gmask = context->visual->green_mask >> goffs;
971 bmask = context->visual->blue_mask >> boffs;
973 rtable = computeTable(rmask);
974 gtable = computeTable(gmask);
975 btable = computeTable(bmask);
977 retColor->pixel = (rtable[color->red] << roffs) |
978 (gtable[color->green] << goffs) | (btable[color->blue] << boffs);
980 retColor->red = color->red << 8;
981 retColor->green = color->green << 8;
982 retColor->blue = color->blue << 8;
983 retColor->flags = DoRed | DoGreen | DoBlue;
985 } else if (context->vclass == PseudoColor || context->vclass == StaticColor) {
987 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
988 unsigned int *rtable, *gtable, *btable;
990 rtable = computeStdTable(context->std_rgb_map->red_mult, context->std_rgb_map->red_max);
992 gtable = computeStdTable(context->std_rgb_map->green_mult,
993 context->std_rgb_map->green_max);
995 btable = computeStdTable(context->std_rgb_map->blue_mult, context->std_rgb_map->blue_max);
997 if (rtable == NULL || gtable == NULL || btable == NULL) {
998 RErrorCode = RERR_NOMEMORY;
999 return False;
1002 retColor->pixel = (rtable[color->red]
1003 + gtable[color->green]
1004 + btable[color->blue]
1005 + context->std_rgb_map->base_pixel) & 0xffffffff;
1006 retColor->red = color->red << 8;
1007 retColor->green = color->green << 8;
1008 retColor->blue = color->blue << 8;
1009 retColor->flags = DoRed | DoGreen | DoBlue;
1011 } else {
1012 const int cpc = context->attribs->colors_per_channel;
1013 const unsigned short rmask = cpc - 1; /* different sizes could be used */
1014 const unsigned short gmask = rmask; /* for r,g,b */
1015 const unsigned short bmask = rmask;
1016 unsigned short *rtable, *gtable, *btable;
1017 const int cpccpc = cpc * cpc;
1018 int index;
1020 rtable = computeTable(rmask);
1021 gtable = computeTable(gmask);
1022 btable = computeTable(bmask);
1024 if (rtable == NULL || gtable == NULL || btable == NULL) {
1025 RErrorCode = RERR_NOMEMORY;
1026 return False;
1028 index = rtable[color->red] * cpccpc + gtable[color->green] * cpc + btable[color->blue];
1029 *retColor = context->colors[index];
1032 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
1034 const int cpc = context->attribs->colors_per_channel;
1035 unsigned short gmask;
1036 unsigned short *table;
1037 int index;
1039 if (context->vclass == StaticGray)
1040 gmask = (1 << context->depth) - 1; /* use all grays */
1041 else
1042 gmask = cpc * cpc * cpc - 1;
1044 table = computeTable(gmask);
1045 if (!table)
1046 return False;
1048 index = table[(color->red * 30 + color->green * 59 + color->blue * 11) / 100];
1050 *retColor = context->colors[index];
1051 } else {
1052 RErrorCode = RERR_INTERNAL;
1053 return False;
1056 return True;