wmaker: Added 'const' attribute to function 'ShrinkString'
[wmaker-crm.git] / wrlib / convert.c
blobf690e1f76994c190320cd03382f5dadc845535e9
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"
38 #ifdef XSHM
39 extern Pixmap R_CreateXImageMappedPixmap(RContext * context, RXImage * ximage);
40 #endif
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 unsigned short *computeTable(unsigned short mask)
67 RConversionTable *tmp = conversionTable;
68 int i;
70 while (tmp) {
71 if (tmp->index == mask)
72 break;
73 tmp = tmp->next;
76 if (tmp)
77 return tmp->table;
79 tmp = (RConversionTable *) malloc(sizeof(RConversionTable));
80 if (tmp == NULL)
81 return NULL;
83 for (i = 0; i < 256; i++)
84 tmp->table[i] = (i * mask + 0x7f) / 0xff;
86 tmp->index = mask;
87 tmp->next = conversionTable;
88 conversionTable = tmp;
89 return tmp->table;
92 static unsigned int *computeStdTable(unsigned int mult, unsigned int max)
94 RStdConversionTable *tmp = stdConversionTable;
95 unsigned int i;
97 while (tmp) {
98 if (tmp->mult == mult && tmp->max == max)
99 break;
100 tmp = tmp->next;
103 if (tmp)
104 return tmp->table;
106 tmp = (RStdConversionTable *) malloc(sizeof(RStdConversionTable));
107 if (tmp == NULL)
108 return NULL;
110 for (i = 0; i < 256; i++) {
111 tmp->table[i] = (i * max) / 0xff * mult;
113 tmp->mult = mult;
114 tmp->max = max;
116 tmp->next = stdConversionTable;
117 stdConversionTable = tmp;
119 return tmp->table;
122 /***************************************************************************/
124 static void
125 convertTrueColor_generic(RXImage * ximg, RImage * image,
126 signed char *err, signed char *nerr,
127 const unsigned short *rtable,
128 const unsigned short *gtable,
129 const unsigned short *btable,
130 const int dr, const int dg, const int db,
131 const unsigned short roffs, const unsigned short goffs, const unsigned short boffs)
133 signed char *terr;
134 int x, y, r, g, b;
135 int pixel;
136 int rer, ger, ber;
137 unsigned char *ptr = image->data;
138 int channels = (HAS_ALPHA(image) ? 4 : 3);
140 /* convert and dither the image to XImage */
141 for (y = 0; y < image->height; y++) {
142 nerr[0] = 0;
143 nerr[1] = 0;
144 nerr[2] = 0;
145 for (x = 0; x < image->width; x++, ptr += channels) {
147 /* reduce pixel */
148 pixel = *ptr + err[x];
149 if (pixel < 0)
150 pixel = 0;
151 else if (pixel > 0xff)
152 pixel = 0xff;
153 r = rtable[pixel];
154 /* calc error */
155 rer = pixel - r * dr;
157 /* reduce pixel */
158 pixel = *(ptr + 1) + err[x + 1];
159 if (pixel < 0)
160 pixel = 0;
161 else if (pixel > 0xff)
162 pixel = 0xff;
163 g = gtable[pixel];
164 /* calc error */
165 ger = pixel - g * dg;
167 /* reduce pixel */
168 pixel = *(ptr + 2) + err[x + 2];
169 if (pixel < 0)
170 pixel = 0;
171 else if (pixel > 0xff)
172 pixel = 0xff;
173 b = btable[pixel];
174 /* calc error */
175 ber = pixel - b * db;
177 pixel = (r << roffs) | (g << goffs) | (b << boffs);
178 XPutPixel(ximg->image, x, y, pixel);
180 /* distribute error */
181 r = (rer * 3) / 8;
182 g = (ger * 3) / 8;
183 b = (ber * 3) / 8;
184 /* x+1, y */
185 err[x + 3 * 1] += r;
186 err[x + 1 + 3 * 1] += g;
187 err[x + 2 + 3 * 1] += b;
188 /* x, y+1 */
189 nerr[x] += r;
190 nerr[x + 1] += g;
191 nerr[x + 2] += b;
192 /* x+1, y+1 */
193 nerr[x + 3 * 1] = rer - 2 * r;
194 nerr[x + 1 + 3 * 1] = ger - 2 * g;
195 nerr[x + 2 + 3 * 1] = ber - 2 * b;
197 /* skip to next line */
198 terr = err;
199 err = nerr;
200 nerr = terr;
203 /* redither the 1st line to distribute error better */
204 ptr = image->data;
205 y = 0;
206 nerr[0] = 0;
207 nerr[1] = 0;
208 nerr[2] = 0;
209 for (x = 0; x < image->width; x++, ptr += channels) {
211 /* reduce pixel */
212 pixel = *ptr + err[x];
213 if (pixel < 0)
214 pixel = 0;
215 else if (pixel > 0xff)
216 pixel = 0xff;
217 r = rtable[pixel];
218 /* calc error */
219 rer = pixel - r * dr;
221 /* reduce pixel */
222 pixel = *(ptr + 1) + err[x + 1];
223 if (pixel < 0)
224 pixel = 0;
225 else if (pixel > 0xff)
226 pixel = 0xff;
227 g = gtable[pixel];
228 /* calc error */
229 ger = pixel - g * dg;
231 /* reduce pixel */
232 pixel = *(ptr + 2) + err[x + 2];
233 if (pixel < 0)
234 pixel = 0;
235 else if (pixel > 0xff)
236 pixel = 0xff;
237 b = btable[pixel];
238 /* calc error */
239 ber = pixel - b * db;
241 pixel = (r << roffs) | (g << goffs) | (b << boffs);
242 XPutPixel(ximg->image, x, y, pixel);
244 /* distribute error */
245 r = (rer * 3) / 8;
246 g = (ger * 3) / 8;
247 b = (ber * 3) / 8;
248 /* x+1, y */
249 err[x + 3 * 1] += r;
250 err[x + 1 + 3 * 1] += g;
251 err[x + 2 + 3 * 1] += b;
252 /* x, y+1 */
253 nerr[x] += r;
254 nerr[x + 1] += g;
255 nerr[x + 2] += b;
256 /* x+1, y+1 */
257 nerr[x + 3 * 1] = rer - 2 * r;
258 nerr[x + 1 + 3 * 1] = ger - 2 * g;
259 nerr[x + 2 + 3 * 1] = ber - 2 * b;
263 static RXImage *image2TrueColor(RContext * ctx, RImage * image)
265 RXImage *ximg;
266 unsigned short rmask, gmask, bmask;
267 unsigned short roffs, goffs, boffs;
268 unsigned short *rtable, *gtable, *btable;
269 int channels = (HAS_ALPHA(image) ? 4 : 3);
271 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
272 if (!ximg) {
273 return NULL;
276 roffs = ctx->red_offset;
277 goffs = ctx->green_offset;
278 boffs = ctx->blue_offset;
280 rmask = ctx->visual->red_mask >> roffs;
281 gmask = ctx->visual->green_mask >> goffs;
282 bmask = ctx->visual->blue_mask >> boffs;
284 rtable = computeTable(rmask);
285 gtable = computeTable(gmask);
286 btable = computeTable(bmask);
288 if (rtable == NULL || gtable == NULL || btable == NULL) {
289 RErrorCode = RERR_NOMEMORY;
290 RDestroyXImage(ctx, ximg);
291 return NULL;
294 if (ctx->attribs->render_mode == RBestMatchRendering) {
295 int ofs, r, g, b;
296 int x, y;
297 unsigned long pixel;
298 unsigned char *ptr = image->data;
300 /* fake match */
301 #ifdef WRLIB_DEBUG
302 fputs("true color match\n", stderr);
303 #endif
304 if (rmask == 0xff && gmask == 0xff && bmask == 0xff) {
305 for (y = 0; y < image->height; y++) {
306 for (x = 0; x < image->width; x++, ptr += channels) {
307 /* reduce pixel */
308 pixel = (*(ptr) << roffs) | (*(ptr + 1) << goffs) | (*(ptr + 2) << boffs);
309 XPutPixel(ximg->image, x, y, pixel);
312 } else {
313 for (y = 0, ofs = 0; y < image->height; y++) {
314 for (x = 0; x < image->width; x++, ofs += channels - 3) {
315 /* reduce pixel */
316 r = rtable[ptr[ofs++]];
317 g = gtable[ptr[ofs++]];
318 b = btable[ptr[ofs++]];
319 pixel = (r << roffs) | (g << goffs) | (b << boffs);
320 XPutPixel(ximg->image, x, y, pixel);
324 } else {
325 /* dither */
326 const int dr = 0xff / rmask;
327 const int dg = 0xff / gmask;
328 const int db = 0xff / bmask;
330 #ifdef WRLIB_DEBUG
331 fputs("true color dither\n", stderr);
332 #endif
335 signed char *err;
336 signed char *nerr;
337 int ch = (HAS_ALPHA(image) ? 4 : 3);
339 err = malloc(ch * (image->width + 2));
340 nerr = malloc(ch * (image->width + 2));
341 if (!err || !nerr) {
342 NFREE(err);
343 NFREE(nerr);
344 RErrorCode = RERR_NOMEMORY;
345 RDestroyXImage(ctx, ximg);
346 return NULL;
349 memset(err, 0, ch * (image->width + 2));
350 memset(nerr, 0, ch * (image->width + 2));
352 convertTrueColor_generic(ximg, image, err, nerr,
353 rtable, gtable, btable, dr, dg, db, roffs, goffs, boffs);
354 free(err);
355 free(nerr);
360 return ximg;
363 /***************************************************************************/
365 static void
366 convertPseudoColor_to_8(RXImage * ximg, RImage * image,
367 signed char *err, signed char *nerr,
368 const unsigned short *rtable,
369 const unsigned short *gtable,
370 const unsigned short *btable,
371 const int dr, const int dg, const int db, unsigned long *pixels, int cpc)
373 signed char *terr;
374 int x, y, r, g, b;
375 int pixel;
376 int rer, ger, ber;
377 unsigned char *ptr = image->data;
378 unsigned char *optr = (unsigned char *)ximg->image->data;
379 int channels = (HAS_ALPHA(image) ? 4 : 3);
380 int cpcpc = cpc * cpc;
382 /* convert and dither the image to XImage */
383 for (y = 0; y < image->height; y++) {
384 nerr[0] = 0;
385 nerr[1] = 0;
386 nerr[2] = 0;
387 for (x = 0; x < image->width * 3; x += 3, ptr += channels) {
389 /* reduce pixel */
390 pixel = *ptr + err[x];
391 if (pixel < 0)
392 pixel = 0;
393 else if (pixel > 0xff)
394 pixel = 0xff;
395 r = rtable[pixel];
396 /* calc error */
397 rer = pixel - r * dr;
399 /* reduce pixel */
400 pixel = *(ptr + 1) + err[x + 1];
401 if (pixel < 0)
402 pixel = 0;
403 else if (pixel > 0xff)
404 pixel = 0xff;
405 g = gtable[pixel];
406 /* calc error */
407 ger = pixel - g * dg;
409 /* reduce pixel */
410 pixel = *(ptr + 2) + err[x + 2];
411 if (pixel < 0)
412 pixel = 0;
413 else if (pixel > 0xff)
414 pixel = 0xff;
415 b = btable[pixel];
416 /* calc error */
417 ber = pixel - b * db;
419 *optr++ = pixels[r * cpcpc + g * cpc + b];
421 /* distribute error */
422 r = (rer * 3) / 8;
423 g = (ger * 3) / 8;
424 b = (ber * 3) / 8;
426 /* x+1, y */
427 err[x + 3 * 1] += r;
428 err[x + 1 + 3 * 1] += g;
429 err[x + 2 + 3 * 1] += b;
430 /* x, y+1 */
431 nerr[x] += r;
432 nerr[x + 1] += g;
433 nerr[x + 2] += b;
434 /* x+1, y+1 */
435 nerr[x + 3 * 1] = rer - 2 * r;
436 nerr[x + 1 + 3 * 1] = ger - 2 * g;
437 nerr[x + 2 + 3 * 1] = ber - 2 * b;
439 /* skip to next line */
440 terr = err;
441 err = nerr;
442 nerr = terr;
444 optr += ximg->image->bytes_per_line - image->width;
448 static RXImage *image2PseudoColor(RContext * ctx, RImage * image)
450 RXImage *ximg;
451 register int x, y, r, g, b;
452 unsigned char *ptr;
453 unsigned long pixel;
454 const int cpc = ctx->attribs->colors_per_channel;
455 const unsigned short rmask = cpc - 1; /* different sizes could be used */
456 const unsigned short gmask = rmask; /* for r,g,b */
457 const unsigned short bmask = rmask;
458 unsigned short *rtable, *gtable, *btable;
459 const int cpccpc = cpc * cpc;
460 int channels = (HAS_ALPHA(image) ? 4 : 3);
462 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
463 if (!ximg) {
464 return NULL;
467 ptr = image->data;
469 /* Tables are same at the moment because rmask==gmask==bmask. */
470 rtable = computeTable(rmask);
471 gtable = computeTable(gmask);
472 btable = computeTable(bmask);
474 if (rtable == NULL || gtable == NULL || btable == NULL) {
475 RErrorCode = RERR_NOMEMORY;
476 RDestroyXImage(ctx, ximg);
477 return NULL;
480 if (ctx->attribs->render_mode == RBestMatchRendering) {
481 /* fake match */
482 #ifdef WRLIB_DEBUG
483 fprintf(stderr, "pseudo color match with %d colors per channel\n", cpc);
484 #endif
485 for (y = 0; y < image->height; y++) {
486 for (x = 0; x < image->width; x++, ptr += channels - 3) {
487 /* reduce pixel */
488 r = rtable[*ptr++];
489 g = gtable[*ptr++];
490 b = btable[*ptr++];
491 pixel = r * cpccpc + g * cpc + b;
492 /*data[ofs] = ctx->colors[pixel].pixel; */
493 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
496 } else {
497 /* dither */
498 signed char *err;
499 signed char *nerr;
500 const int dr = 0xff / rmask;
501 const int dg = 0xff / gmask;
502 const int db = 0xff / bmask;
504 #ifdef WRLIB_DEBUG
505 fprintf(stderr, "pseudo color dithering with %d colors per channel\n", cpc);
506 #endif
507 err = malloc(4 * (image->width + 3));
508 nerr = malloc(4 * (image->width + 3));
509 if (!err || !nerr) {
510 NFREE(err);
511 NFREE(nerr);
512 RErrorCode = RERR_NOMEMORY;
513 RDestroyXImage(ctx, ximg);
514 return NULL;
516 memset(err, 0, 4 * (image->width + 3));
517 memset(nerr, 0, 4 * (image->width + 3));
519 convertPseudoColor_to_8(ximg, image, err + 4, nerr + 4,
520 rtable, gtable, btable, dr, dg, db, ctx->pixels, cpc);
522 free(err);
523 free(nerr);
526 return ximg;
530 * For standard colormap
532 static RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image)
534 RXImage *ximg;
535 register int x, y, r, g, b;
536 unsigned char *ptr;
537 unsigned long pixel;
538 unsigned char *data;
539 unsigned int *rtable, *gtable, *btable;
540 unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
541 int channels = (HAS_ALPHA(image) ? 4 : 3);
543 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
544 if (!ximg) {
545 return NULL;
548 ptr = image->data;
550 data = (unsigned char *)ximg->image->data;
552 rtable = computeStdTable(ctx->std_rgb_map->red_mult, ctx->std_rgb_map->red_max);
554 gtable = computeStdTable(ctx->std_rgb_map->green_mult, ctx->std_rgb_map->green_max);
556 btable = computeStdTable(ctx->std_rgb_map->blue_mult, ctx->std_rgb_map->blue_max);
558 if (rtable == NULL || gtable == NULL || btable == NULL) {
559 RErrorCode = RERR_NOMEMORY;
560 RDestroyXImage(ctx, ximg);
561 return NULL;
564 if (ctx->attribs->render_mode == RBestMatchRendering) {
565 for (y = 0; y < image->height; y++) {
566 for (x = 0; x < image->width; x++, ptr += channels) {
567 /* reduce pixel */
568 pixel = (rtable[*ptr] + gtable[*(ptr + 1)]
569 + btable[*(ptr + 2)] + base_pixel) & 0xffffffff;
571 XPutPixel(ximg->image, x, y, pixel);
574 } else {
575 /* dither */
576 signed short *err, *nerr;
577 signed short *terr;
578 int rer, ger, ber;
579 int x1, ofs;
581 #ifdef WRLIB_DEBUG
582 fprintf(stderr, "pseudo color dithering with %d colors per channel\n",
583 ctx->attribs->colors_per_channel);
584 #endif
585 err = (short *)malloc(3 * (image->width + 2) * sizeof(short));
586 nerr = (short *)malloc(3 * (image->width + 2) * sizeof(short));
587 if (!err || !nerr) {
588 NFREE(err);
589 NFREE(nerr);
590 RErrorCode = RERR_NOMEMORY;
591 RDestroyXImage(ctx, ximg);
592 return NULL;
594 for (x = 0, x1 = 0; x < image->width * 3; x1 += channels - 3) {
595 err[x++] = ptr[x1++];
596 err[x++] = ptr[x1++];
597 err[x++] = ptr[x1++];
599 err[x] = err[x + 1] = err[x + 2] = 0;
600 /* convert and dither the image to XImage */
601 for (y = 0, ofs = 0; y < image->height; y++) {
602 if (y < image->height - 1) {
603 int x1;
604 for (x = 0, x1 = (y + 1) * image->width * channels;
605 x < image->width * 3; x1 += channels - 3) {
606 nerr[x++] = ptr[x1++];
607 nerr[x++] = ptr[x1++];
608 nerr[x++] = ptr[x1++];
610 /* last column */
611 x1 -= channels;
612 nerr[x++] = ptr[x1++];
613 nerr[x++] = ptr[x1++];
614 nerr[x++] = ptr[x1++];
616 for (x = 0; x < image->width * 3; x += 3, ofs++) {
617 /* reduce pixel */
618 if (err[x] > 0xff)
619 err[x] = 0xff;
620 else if (err[x] < 0)
621 err[x] = 0;
622 if (err[x + 1] > 0xff)
623 err[x + 1] = 0xff;
624 else if (err[x + 1] < 0)
625 err[x + 1] = 0;
626 if (err[x + 2] > 0xff)
627 err[x + 2] = 0xff;
628 else if (err[x + 2] < 0)
629 err[x + 2] = 0;
631 r = rtable[err[x]];
632 g = gtable[err[x + 1]];
633 b = btable[err[x + 2]];
635 pixel = r + g + b;
637 data[ofs] = base_pixel + pixel;
639 /* calc error */
640 rer = err[x] - (ctx->colors[pixel].red >> 8);
641 ger = err[x + 1] - (ctx->colors[pixel].green >> 8);
642 ber = err[x + 2] - (ctx->colors[pixel].blue >> 8);
644 /* distribute error */
645 err[x + 3 * 1] += (rer * 7) / 16;
646 err[x + 1 + 3 * 1] += (ger * 7) / 16;
647 err[x + 2 + 3 * 1] += (ber * 7) / 16;
649 nerr[x] += (rer * 5) / 16;
650 nerr[x + 1] += (ger * 5) / 16;
651 nerr[x + 2] += (ber * 5) / 16;
653 if (x > 0) {
654 nerr[x - 3 * 1] += (rer * 3) / 16;
655 nerr[x - 3 * 1 + 1] += (ger * 3) / 16;
656 nerr[x - 3 * 1 + 2] += (ber * 3) / 16;
659 nerr[x + 3 * 1] += rer / 16;
660 nerr[x + 1 + 3 * 1] += ger / 16;
661 nerr[x + 2 + 3 * 1] += ber / 16;
663 /* skip to next line */
664 terr = err;
665 err = nerr;
666 nerr = terr;
668 ofs += ximg->image->bytes_per_line - image->width;
670 free(err);
671 free(nerr);
673 ximg->image->data = (char *)data;
675 return ximg;
678 static RXImage *image2GrayScale(RContext * ctx, RImage * image)
680 RXImage *ximg;
681 register int x, y, g;
682 unsigned char *ptr;
683 const int cpc = ctx->attribs->colors_per_channel;
684 unsigned short gmask;
685 unsigned short *table;
686 unsigned char *data;
687 int channels = (HAS_ALPHA(image) ? 4 : 3);
689 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
690 if (!ximg) {
691 return NULL;
694 ptr = image->data;
696 data = (unsigned char *)ximg->image->data;
698 if (ctx->vclass == StaticGray)
699 gmask = (1 << ctx->depth) - 1; /* use all grays */
700 else
701 gmask = cpc * cpc * cpc - 1;
703 table = computeTable(gmask);
705 if (table == NULL) {
706 RErrorCode = RERR_NOMEMORY;
707 RDestroyXImage(ctx, ximg);
708 return NULL;
711 if (ctx->attribs->render_mode == RBestMatchRendering) {
712 /* fake match */
713 #ifdef WRLIB_DEBUG
714 fprintf(stderr, "grayscale match with %d colors per channel\n", cpc);
715 #endif
716 for (y = 0; y < image->height; y++) {
717 for (x = 0; x < image->width; x++) {
718 /* reduce pixel */
719 g = table[(*ptr * 30 + *(ptr + 1) * 59 + *(ptr + 2) * 11) / 100];
720 ptr += channels;
721 /*data[ofs] = ctx->colors[g].pixel; */
722 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
725 } else {
726 /* dither */
727 short *gerr;
728 short *ngerr;
729 short *terr;
730 int ger;
731 const int dg = 0xff / gmask;
733 #ifdef WRLIB_DEBUG
734 fprintf(stderr, "grayscale dither with %d colors per channel\n", cpc);
735 #endif
736 gerr = (short *)malloc((image->width + 2) * sizeof(short));
737 ngerr = (short *)malloc((image->width + 2) * sizeof(short));
738 if (!gerr || !ngerr) {
739 NFREE(gerr);
740 NFREE(ngerr);
741 RErrorCode = RERR_NOMEMORY;
742 RDestroyXImage(ctx, ximg);
743 return NULL;
745 for (x = 0, y = 0; x < image->width; x++, y += channels) {
746 gerr[x] = (ptr[y] * 30 + ptr[y + 1] * 59 + ptr[y + 2] * 11) / 100;
748 gerr[x] = 0;
749 /* convert and dither the image to XImage */
750 for (y = 0; y < image->height; y++) {
751 if (y < image->height - 1) {
752 int x1;
753 for (x = 0, x1 = (y + 1) * image->width * channels; x < image->width;
754 x++, x1 += channels) {
755 ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
757 /* last column */
758 x1 -= channels;
759 ngerr[x] = (ptr[x1] * 30 + ptr[x1 + 1] * 59 + ptr[x1 + 2] * 11) / 100;
761 for (x = 0; x < image->width; x++) {
762 /* reduce pixel */
763 if (gerr[x] > 0xff)
764 gerr[x] = 0xff;
765 else if (gerr[x] < 0)
766 gerr[x] = 0;
768 g = table[gerr[x]];
770 /*data[ofs] = ctx->colors[g].pixel; */
771 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
772 /* calc error */
773 ger = gerr[x] - g * dg;
775 /* distribute error */
776 g = (ger * 3) / 8;
777 /* x+1, y */
778 gerr[x + 1] += g;
779 /* x, y+1 */
780 ngerr[x] += g;
781 /* x+1, y+1 */
782 ngerr[x + 1] += ger - 2 * g;
784 /* skip to next line */
785 terr = gerr;
786 gerr = ngerr;
787 ngerr = terr;
789 free(gerr);
790 free(ngerr);
792 ximg->image->data = (char *)data;
794 return ximg;
797 static RXImage *image2Bitmap(RContext * ctx, RImage * image, int threshold)
799 RXImage *ximg;
800 unsigned char *alpha;
801 int x, y;
803 ximg = RCreateXImage(ctx, 1, image->width, image->height);
804 if (!ximg) {
805 return NULL;
807 alpha = image->data + 3;
809 for (y = 0; y < image->height; y++) {
810 for (x = 0; x < image->width; x++) {
811 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
812 alpha += 4;
816 return ximg;
819 int RConvertImage(RContext * context, RImage * image, Pixmap * pixmap)
821 RXImage *ximg = NULL;
822 #ifdef XSHM
823 Pixmap tmp;
824 #endif
826 assert(context != NULL);
827 assert(image != NULL);
828 assert(pixmap != NULL);
830 switch (context->vclass) {
831 case TrueColor:
832 ximg = image2TrueColor(context, image);
833 break;
835 case PseudoColor:
836 case StaticColor:
837 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
838 ximg = image2StandardPseudoColor(context, image);
839 else
840 ximg = image2PseudoColor(context, image);
841 break;
843 case GrayScale:
844 case StaticGray:
845 ximg = image2GrayScale(context, image);
846 break;
849 if (!ximg) {
850 return False;
853 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, context->depth);
855 #ifdef XSHM
856 if (context->flags.use_shared_pixmap && ximg->is_shared)
857 tmp = R_CreateXImageMappedPixmap(context, ximg);
858 else
859 tmp = None;
860 if (tmp) {
862 * We have to copy the shm Pixmap into a normal Pixmap because
863 * otherwise, we would have to control when Pixmaps are freed so
864 * that we can detach their shm segments. This is a problem if the
865 * program crash, leaving stale shared memory segments in the
866 * system (lots of them). But with some work, we can optimize
867 * things and remove this XCopyArea. This will require
868 * explicitly freeing all pixmaps when exiting or restarting
869 * wmaker.
871 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0, image->width, image->height, 0, 0);
872 XFreePixmap(context->dpy, tmp);
873 } else {
874 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
876 #else /* !XSHM */
877 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, image->width, image->height);
878 #endif /* !XSHM */
880 RDestroyXImage(context, ximg);
882 return True;
885 /* make the gc permanent (create with context creation).
886 * GC creation is very expensive. altering its properties is not. -Dan
888 int RConvertImageMask(RContext * context, RImage * image, Pixmap * pixmap, Pixmap * mask, int threshold)
890 GC gc;
891 XGCValues gcv;
892 RXImage *ximg = NULL;
894 assert(context != NULL);
895 assert(image != NULL);
896 assert(pixmap != NULL);
897 assert(mask != NULL);
899 if (!RConvertImage(context, image, pixmap))
900 return False;
902 if (image->format == RRGBFormat) {
903 *mask = None;
904 return True;
907 ximg = image2Bitmap(context, image, threshold);
909 if (!ximg) {
910 return False;
912 *mask = XCreatePixmap(context->dpy, context->drawable, image->width, image->height, 1);
913 gcv.foreground = context->black;
914 gcv.background = context->white;
915 gcv.graphics_exposures = False;
916 gc = XCreateGC(context->dpy, *mask, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
917 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0, image->width, image->height);
918 RDestroyXImage(context, ximg);
919 XFreeGC(context->dpy, gc);
921 return True;
924 Bool RGetClosestXColor(RContext * context, const RColor * color, XColor * retColor)
926 if (context->vclass == TrueColor) {
927 unsigned short rmask, gmask, bmask;
928 unsigned short roffs, goffs, boffs;
929 unsigned short *rtable, *gtable, *btable;
931 roffs = context->red_offset;
932 goffs = context->green_offset;
933 boffs = context->blue_offset;
935 rmask = context->visual->red_mask >> roffs;
936 gmask = context->visual->green_mask >> goffs;
937 bmask = context->visual->blue_mask >> boffs;
939 rtable = computeTable(rmask);
940 gtable = computeTable(gmask);
941 btable = computeTable(bmask);
943 retColor->pixel = (rtable[color->red] << roffs) |
944 (gtable[color->green] << goffs) | (btable[color->blue] << boffs);
946 retColor->red = color->red << 8;
947 retColor->green = color->green << 8;
948 retColor->blue = color->blue << 8;
949 retColor->flags = DoRed | DoGreen | DoBlue;
951 } else if (context->vclass == PseudoColor || context->vclass == StaticColor) {
953 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
954 unsigned int *rtable, *gtable, *btable;
956 rtable = computeStdTable(context->std_rgb_map->red_mult, context->std_rgb_map->red_max);
958 gtable = computeStdTable(context->std_rgb_map->green_mult,
959 context->std_rgb_map->green_max);
961 btable = computeStdTable(context->std_rgb_map->blue_mult, context->std_rgb_map->blue_max);
963 if (rtable == NULL || gtable == NULL || btable == NULL) {
964 RErrorCode = RERR_NOMEMORY;
965 return False;
968 retColor->pixel = (rtable[color->red]
969 + gtable[color->green]
970 + btable[color->blue]
971 + context->std_rgb_map->base_pixel) & 0xffffffff;
972 retColor->red = color->red << 8;
973 retColor->green = color->green << 8;
974 retColor->blue = color->blue << 8;
975 retColor->flags = DoRed | DoGreen | DoBlue;
977 } else {
978 const int cpc = context->attribs->colors_per_channel;
979 const unsigned short rmask = cpc - 1; /* different sizes could be used */
980 const unsigned short gmask = rmask; /* for r,g,b */
981 const unsigned short bmask = rmask;
982 unsigned short *rtable, *gtable, *btable;
983 const int cpccpc = cpc * cpc;
984 int index;
986 rtable = computeTable(rmask);
987 gtable = computeTable(gmask);
988 btable = computeTable(bmask);
990 if (rtable == NULL || gtable == NULL || btable == NULL) {
991 RErrorCode = RERR_NOMEMORY;
992 return False;
994 index = rtable[color->red] * cpccpc + gtable[color->green] * cpc + btable[color->blue];
995 *retColor = context->colors[index];
998 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
1000 const int cpc = context->attribs->colors_per_channel;
1001 unsigned short gmask;
1002 unsigned short *table;
1003 int index;
1005 if (context->vclass == StaticGray)
1006 gmask = (1 << context->depth) - 1; /* use all grays */
1007 else
1008 gmask = cpc * cpc * cpc - 1;
1010 table = computeTable(gmask);
1011 if (!table)
1012 return False;
1014 index = table[(color->red * 30 + color->green * 59 + color->blue * 11) / 100];
1016 *retColor = context->colors[index];
1017 } else {
1018 RErrorCode = RERR_INTERNAL;
1019 return False;
1022 return True;