- added standard colormap support
[wmaker-crm.git] / wrlib / convert.c
blob54ed6385f630157aaa31180b9f2df4e967b4d509
1 /* convert.c - convert RImage to Pixmap
2 *
3 * Raster graphics library
5 * Copyright (c) 1997 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.
21 #include <config.h>
23 /* AIX requires this to be the first thing in the file. */
24 #ifdef __GNUC__
25 # define alloca __builtin_alloca
26 #else
27 # if HAVE_ALLOCA_H
28 # include <alloca.h>
29 # else
30 # ifdef _AIX
31 # pragma alloca
32 # else
33 # ifndef alloca /* predefined by HP cc +Olibcalls */
34 char *alloca ();
35 # endif
36 # endif
37 # endif
38 #endif
41 #include <X11/Xlib.h>
42 #include <X11/Xutil.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
47 #include <assert.h>
49 #include "wraster.h"
51 #ifdef XSHM
52 Pixmap R_CreateXImageMappedPixmap(RContext *context, RXImage *ximage);
54 #endif
57 typedef struct RConversionTable {
58 unsigned short table[256];
59 unsigned short index;
61 struct RConversionTable *next;
62 } RConversionTable;
65 typedef struct RStdConversionTable {
66 unsigned int table[256];
68 unsigned short mult;
69 unsigned short max;
71 struct RStdConversionTable *next;
72 } RStdConversionTable;
76 static RConversionTable *conversionTable = NULL;
77 static RStdConversionTable *stdConversionTable = NULL;
80 static unsigned short*
81 computeTable(unsigned short mask)
83 RConversionTable *tmp = conversionTable;
84 int i;
86 while (tmp) {
87 if (tmp->index == mask)
88 break;
89 tmp = tmp->next;
92 if (tmp)
93 return tmp->table;
95 tmp = (RConversionTable *)malloc(sizeof(RConversionTable));
96 if (tmp == NULL)
97 return NULL;
99 for (i=0;i<256;i++)
100 tmp->table[i] = (i*mask + 0x7f)/0xff;
102 tmp->index = mask;
103 tmp->next = conversionTable;
104 conversionTable = tmp;
105 return tmp->table;
109 static unsigned int*
110 computeStdTable(unsigned int mult, unsigned int max)
112 RStdConversionTable *tmp = stdConversionTable;
113 unsigned int i;
115 while (tmp) {
116 if (tmp->mult == mult && tmp->max == max)
117 break;
118 tmp = tmp->next;
121 if (tmp)
122 return tmp->table;
124 tmp = (RStdConversionTable *)malloc(sizeof(RStdConversionTable));
125 if (tmp == NULL)
126 return NULL;
128 for (i=0; i<256; i++) {
129 tmp->table[i] = (i*max)/0xff * mult;
131 tmp->mult = mult;
132 tmp->max = max;
134 tmp->next = stdConversionTable;
135 stdConversionTable = tmp;
137 return tmp->table;
142 static RXImage*
143 image2TrueColorD16(RContext *ctx, RImage *image)
145 RXImage *ximg;
146 register int x, y, r, g, b;
147 unsigned char *red, *grn, *blu;
148 unsigned short rmask, gmask, bmask;
149 unsigned short roffs, goffs, boffs;
150 unsigned short *rtable, *gtable, *btable;
151 int ofs;
153 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
154 if (!ximg) {
155 return NULL;
158 red = image->data[0];
159 grn = image->data[1];
160 blu = image->data[2];
162 roffs = ctx->red_offset;
163 goffs = ctx->green_offset;
164 boffs = ctx->blue_offset;
166 rmask = ctx->visual->red_mask >> roffs;
167 gmask = ctx->visual->green_mask >> goffs;
168 bmask = ctx->visual->blue_mask >> boffs;
170 rtable = computeTable(rmask);
171 gtable = computeTable(gmask);
172 btable = computeTable(bmask);
174 if (rtable==NULL || gtable==NULL || btable==NULL) {
175 RErrorCode = RERR_NOMEMORY;
176 RDestroyXImage(ctx, ximg);
177 return NULL;
181 /* dither */
182 short *rerr, *gerr, *berr;
183 short *nrerr, *ngerr, *nberr;
184 short *terr;
185 unsigned short *dataP;
186 int line_offset;
187 int rer, ger, ber;
188 const int dr=0xff/rmask;
189 const int dg=0xff/gmask;
190 const int db=0xff/bmask;
192 rerr = (short*)alloca((image->width+2)*sizeof(short));
193 gerr = (short*)alloca((image->width+2)*sizeof(short));
194 berr = (short*)alloca((image->width+2)*sizeof(short));
195 nrerr = (short*)alloca((image->width+2)*sizeof(short));
196 ngerr = (short*)alloca((image->width+2)*sizeof(short));
197 nberr = (short*)alloca((image->width+2)*sizeof(short));
198 if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) {
199 RErrorCode = RERR_NOMEMORY;
200 RDestroyXImage(ctx, ximg);
201 return NULL;
203 for (x=0; x<image->width; x++) {
204 rerr[x] = red[x];
205 gerr[x] = grn[x];
206 berr[x] = blu[x];
208 rerr[x] = gerr[x] = berr[x] = 0;
210 dataP = (unsigned short*)ximg->image->data;
211 line_offset = ximg->image->bytes_per_line - image->width * 2;
213 /* convert and dither the image to XImage */
214 for (y=0, ofs=0; y<image->height; y++) {
215 if (y<image->height-1) {
216 int x1;
217 for (x=0, x1=ofs+image->width; x<image->width; x++, x1++) {
218 nrerr[x] = red[x1];
219 ngerr[x] = grn[x1];
220 nberr[x] = blu[x1];
222 /* last column */
223 x1--;
224 nrerr[x] = red[x1];
225 ngerr[x] = grn[x1];
226 nberr[x] = blu[x1];
228 for (x=0; x<image->width; x++) {
229 /* reduce pixel */
230 if (rerr[x]>0xff) rerr[x]=0xff; else if (rerr[x]<0) rerr[x]=0;
231 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
232 if (berr[x]>0xff) berr[x]=0xff; else if (berr[x]<0) berr[x]=0;
234 r = rtable[rerr[x]];
235 g = gtable[gerr[x]];
236 b = btable[berr[x]];
238 *(dataP++) = (r<<roffs) | (g<<goffs) | (b<<boffs);
240 /* calc error */
241 rer = rerr[x] - r*dr;
242 ger = gerr[x] - g*dg;
243 ber = berr[x] - b*db;
245 /* distribute error */
246 r = (rer*3)/8;
247 g = (ger*3)/8;
248 b = (ber*3)/8;
249 /* x+1, y */
250 rerr[x+1]+=r;
251 gerr[x+1]+=g;
252 berr[x+1]+=b;
253 /* x, y+1 */
254 nrerr[x]+=r;
255 ngerr[x]+=g;
256 nberr[x]+=b;
257 /* x+1, y+1 */
258 nrerr[x+1]+=rer-2*r;
259 ngerr[x+1]+=ger-2*g;
260 nberr[x+1]+=ber-2*b;
262 ofs += image->width;
263 /*(char*)dataP += line_offset;*/
264 dataP = (unsigned short *)((char *)dataP + line_offset);
266 /* skip to next line */
267 terr = rerr;
268 rerr = nrerr;
269 nrerr = terr;
271 terr = gerr;
272 gerr = ngerr;
273 ngerr = terr;
275 terr = berr;
276 berr = nberr;
277 nberr = terr;
280 return ximg;
284 static RXImage*
285 image2TrueColor(RContext *ctx, RImage *image)
287 RXImage *ximg;
288 register int x, y, r, g, b;
289 unsigned char *red, *grn, *blu;
290 unsigned long pixel;
291 unsigned short rmask, gmask, bmask;
292 unsigned short roffs, goffs, boffs;
293 unsigned short *rtable, *gtable, *btable;
294 int ofs;
296 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
297 if (!ximg) {
298 return NULL;
301 red = image->data[0];
302 grn = image->data[1];
303 blu = image->data[2];
305 roffs = ctx->red_offset;
306 goffs = ctx->green_offset;
307 boffs = ctx->blue_offset;
309 rmask = ctx->visual->red_mask >> roffs;
310 gmask = ctx->visual->green_mask >> goffs;
311 bmask = ctx->visual->blue_mask >> boffs;
313 #if 0
314 /* this do not seem to increase speed. Only 0.06 second faster in
315 * rendering a 800x600 image to pixmap. 1.12 sec instead of 1.18.
316 * But does not require a 256*256*256 lookup table.
318 if (ctx->depth==24) {
319 #ifdef DEBUG
320 puts("true color match for 24bpp");
321 #endif
322 for (y=0; y < image->height; y++) {
323 for (x=0; x < image->width; x++) {
324 pixel = (*(red++)<<roffs) | (*(grn++)<<goffs) | (*(blu++)<<boffs);
325 XPutPixel(ximg->image, x, y, pixel);
328 return ximg;
330 #endif
332 rtable = computeTable(rmask);
333 gtable = computeTable(gmask);
334 btable = computeTable(bmask);
336 if (rtable==NULL || gtable==NULL || btable==NULL) {
337 RErrorCode = RERR_NOMEMORY;
338 RDestroyXImage(ctx, ximg);
339 return NULL;
342 if (ctx->attribs->render_mode==RBestMatchRendering) {
343 /* fake match */
344 #ifdef DEBUG
345 puts("true color match");
346 #endif
347 for (y=0, ofs=0; y < image->height; y++) {
348 for (x=0; x < image->width; x++, ofs++) {
349 /* reduce pixel */
350 r = rtable[red[ofs]];
351 g = gtable[grn[ofs]];
352 b = btable[blu[ofs]];
353 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
354 XPutPixel(ximg->image, x, y, pixel);
357 } else {
358 /* dither */
359 short *rerr, *gerr, *berr;
360 short *nrerr, *ngerr, *nberr;
361 short *terr;
362 int rer, ger, ber;
363 const int dr=0xff/rmask;
364 const int dg=0xff/gmask;
365 const int db=0xff/bmask;
367 #ifdef DEBUG
368 puts("true color dither");
369 #endif
370 rerr = (short*)alloca((image->width+2)*sizeof(short));
371 gerr = (short*)alloca((image->width+2)*sizeof(short));
372 berr = (short*)alloca((image->width+2)*sizeof(short));
373 nrerr = (short*)alloca((image->width+2)*sizeof(short));
374 ngerr = (short*)alloca((image->width+2)*sizeof(short));
375 nberr = (short*)alloca((image->width+2)*sizeof(short));
376 if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) {
377 RErrorCode = RERR_NOMEMORY;
378 RDestroyXImage(ctx, ximg);
379 return NULL;
381 for (x=0; x<image->width; x++) {
382 rerr[x] = red[x];
383 gerr[x] = grn[x];
384 berr[x] = blu[x];
386 rerr[x] = gerr[x] = berr[x] = 0;
387 /* convert and dither the image to XImage */
388 for (y=0, ofs=0; y<image->height; y++) {
389 if (y<image->height-1) {
390 int x1;
391 for (x=0, x1=ofs+image->width; x<image->width; x++, x1++) {
392 nrerr[x] = red[x1];
393 ngerr[x] = grn[x1];
394 nberr[x] = blu[x1];
396 /* last column */
397 x1--;
398 nrerr[x] = red[x1];
399 ngerr[x] = grn[x1];
400 nberr[x] = blu[x1];
402 for (x=0; x<image->width; x++) {
403 /* reduce pixel */
404 if (rerr[x]>0xff) rerr[x]=0xff; else if (rerr[x]<0) rerr[x]=0;
405 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
406 if (berr[x]>0xff) berr[x]=0xff; else if (berr[x]<0) berr[x]=0;
408 r = rtable[rerr[x]];
409 g = gtable[gerr[x]];
410 b = btable[berr[x]];
412 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
413 XPutPixel(ximg->image, x, y, pixel);
414 /* calc error */
415 rer = rerr[x] - r*dr;
416 ger = gerr[x] - g*dg;
417 ber = berr[x] - b*db;
419 /* distribute error */
420 r = (rer*3)/8;
421 g = (ger*3)/8;
422 b = (ber*3)/8;
423 /* x+1, y */
424 rerr[x+1]+=r;
425 gerr[x+1]+=g;
426 berr[x+1]+=b;
427 /* x, y+1 */
428 nrerr[x]+=r;
429 ngerr[x]+=g;
430 nberr[x]+=b;
431 /* x+1, y+1 */
432 nrerr[x+1]+=rer-2*r;
433 ngerr[x+1]+=ger-2*g;
434 nberr[x+1]+=ber-2*b;
436 ofs+=image->width;
437 /* skip to next line */
438 terr = rerr;
439 rerr = nrerr;
440 nrerr = terr;
442 terr = gerr;
443 gerr = ngerr;
444 ngerr = terr;
446 terr = berr;
447 berr = nberr;
448 nberr = terr;
451 return ximg;
457 static RXImage*
458 image2PseudoColor(RContext *ctx, RImage *image)
460 RXImage *ximg;
461 register int x, y, r, g, b;
462 unsigned char *red, *grn, *blu;
463 unsigned long pixel;
464 const int cpc=ctx->attribs->colors_per_channel;
465 const unsigned short rmask = cpc-1; /* different sizes could be used */
466 const unsigned short gmask = rmask; /* for r,g,b */
467 const unsigned short bmask = rmask;
468 unsigned short *rtable, *gtable, *btable;
469 const int cpccpc = cpc*cpc;
470 unsigned char *data;
471 int ofs;
472 /*register unsigned char maxrgb = 0xff;*/
474 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
475 if (!ximg) {
476 return NULL;
479 red = image->data[0];
480 grn = image->data[1];
481 blu = image->data[2];
483 data = (unsigned char *)ximg->image->data;
485 /* Tables are same at the moment because rmask==gmask==bmask. */
486 rtable = computeTable(rmask);
487 gtable = computeTable(gmask);
488 btable = computeTable(bmask);
490 if (rtable==NULL || gtable==NULL || btable==NULL) {
491 RErrorCode = RERR_NOMEMORY;
492 RDestroyXImage(ctx, ximg);
493 return NULL;
496 if (ctx->attribs->render_mode == RBestMatchRendering) {
497 /* fake match */
498 #ifdef DEBUG
499 printf("pseudo color match with %d colors per channel\n", cpc);
500 #endif
501 for (y=0, ofs = 0; y<image->height; y++) {
502 for (x=0; x<image->width; x++, ofs++) {
503 /* reduce pixel */
504 r = rtable[red[ofs]];
505 g = gtable[grn[ofs]];
506 b = btable[blu[ofs]];
507 pixel = r*cpccpc + g*cpc + b;
508 /*data[ofs] = ctx->colors[pixel].pixel;*/
509 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
512 } else {
513 /* dither */
514 short *rerr, *gerr, *berr;
515 short *nrerr, *ngerr, *nberr;
516 short *terr;
517 int rer, ger, ber;
518 const int dr=0xff/rmask;
519 const int dg=0xff/gmask;
520 const int db=0xff/bmask;
522 #ifdef DEBUG
523 printf("pseudo color dithering with %d colors per channel\n", cpc);
524 #endif
525 rerr = (short*)alloca((image->width+2)*sizeof(short));
526 gerr = (short*)alloca((image->width+2)*sizeof(short));
527 berr = (short*)alloca((image->width+2)*sizeof(short));
528 nrerr = (short*)alloca((image->width+2)*sizeof(short));
529 ngerr = (short*)alloca((image->width+2)*sizeof(short));
530 nberr = (short*)alloca((image->width+2)*sizeof(short));
531 if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) {
532 RErrorCode = RERR_NOMEMORY;
533 RDestroyXImage(ctx, ximg);
534 return NULL;
536 for (x=0; x<image->width; x++) {
537 rerr[x] = red[x];
538 gerr[x] = grn[x];
539 berr[x] = blu[x];
541 rerr[x] = gerr[x] = berr[x] = 0;
542 /* convert and dither the image to XImage */
543 for (y=0, ofs=0; y<image->height; y++) {
544 if (y<image->height-1) {
545 int x1;
546 for (x=0, x1=ofs+image->width; x<image->width; x++, x1++) {
547 nrerr[x] = red[x1];
548 ngerr[x] = grn[x1];
549 nberr[x] = blu[x1];
551 /* last column */
552 x1--;
553 nrerr[x] = red[x1];
554 ngerr[x] = grn[x1];
555 nberr[x] = blu[x1];
557 for (x=0; x<image->width; x++, ofs++) {
558 /* reduce pixel */
559 if (rerr[x]>0xff) rerr[x]=0xff; else if (rerr[x]<0) rerr[x]=0;
560 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
561 if (berr[x]>0xff) berr[x]=0xff; else if (berr[x]<0) berr[x]=0;
563 r = rtable[rerr[x]];
564 g = gtable[gerr[x]];
565 b = btable[berr[x]];
567 pixel = r*cpccpc + g*cpc + b;
568 /*data[ofs] = ctx->colors[pixel].pixel;*/
569 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
571 /* calc error */
572 rer = rerr[x] - r*dr;
573 ger = gerr[x] - g*dg;
574 ber = berr[x] - b*db;
576 /* distribute error */
577 rerr[x+1]+=(rer*7)/16;
578 gerr[x+1]+=(ger*7)/16;
579 berr[x+1]+=(ber*7)/16;
581 nrerr[x]+=(rer*5)/16;
582 ngerr[x]+=(ger*5)/16;
583 nberr[x]+=(ber*5)/16;
585 if (x>0) {
586 nrerr[x-1]+=(rer*3)/16;
587 ngerr[x-1]+=(ger*3)/16;
588 nberr[x-1]+=(ber*3)/16;
591 nrerr[x+1]+=rer/16;
592 ngerr[x+1]+=ger/16;
593 nberr[x+1]+=ber/16;
594 #if 0
595 /* distribute error */
596 r = (rer*3)/8;
597 g = (ger*3)/8;
598 b = (ber*3)/8;
599 /* x+1, y */
600 rerr[x+1]+=r;
601 gerr[x+1]+=g;
602 berr[x+1]+=b;
603 /* x, y+1 */
604 nrerr[x]+=r;
605 ngerr[x]+=g;
606 nberr[x]+=b;
607 /* x+1, y+1 */
608 nrerr[x+1]+=rer-2*r;
609 ngerr[x+1]+=ger-2*g;
610 nberr[x+1]+=ber-2*b;
611 #endif
613 /* skip to next line */
614 terr = rerr;
615 rerr = nrerr;
616 nrerr = terr;
618 terr = gerr;
619 gerr = ngerr;
620 ngerr = terr;
622 terr = berr;
623 berr = nberr;
624 nberr = terr;
627 ximg->image->data = (char*)data;
629 return ximg;
634 * For standard colormap
636 static RXImage*
637 image2StandardPseudoColor(RContext *ctx, RImage *image)
639 RXImage *ximg;
640 register int x, y, r, g, b;
641 unsigned char *red, *grn, *blu;
642 unsigned long pixel;
643 unsigned char *data;
644 unsigned int *rtable, *gtable, *btable;
645 unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
646 int ofs;
647 /*register unsigned char maxrgb = 0xff;*/
649 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
650 if (!ximg) {
651 return NULL;
654 red = image->data[0];
655 grn = image->data[1];
656 blu = image->data[2];
658 data = (unsigned char *)ximg->image->data;
661 rtable = computeStdTable(ctx->std_rgb_map->red_mult,
662 ctx->std_rgb_map->red_max);
664 gtable = computeStdTable(ctx->std_rgb_map->green_mult,
665 ctx->std_rgb_map->green_max);
667 btable = computeStdTable(ctx->std_rgb_map->blue_mult,
668 ctx->std_rgb_map->blue_max);
670 if (rtable==NULL || gtable==NULL || btable==NULL) {
671 RErrorCode = RERR_NOMEMORY;
672 RDestroyXImage(ctx, ximg);
673 return NULL;
677 if (ctx->attribs->render_mode == RBestMatchRendering) {
678 for (y=0, ofs = 0; y<image->height; y++) {
679 for (x=0; x<image->width; x++, ofs++) {
680 /* reduce pixel */
682 pixel = (rtable[red[ofs]] + gtable[grn[ofs]]
683 + btable[blu[ofs]] + base_pixel) & 0xffffffff;
685 XPutPixel(ximg->image, x, y, pixel);
688 } else {
689 /* dither */
690 short *rerr, *gerr, *berr;
691 short *nrerr, *ngerr, *nberr;
692 short *terr;
693 int rer, ger, ber;
695 #ifdef DEBUG
696 printf("pseudo color dithering with %d colors per channel\n", cpc);
697 #endif
698 rerr = (short*)alloca((image->width+2)*sizeof(short));
699 gerr = (short*)alloca((image->width+2)*sizeof(short));
700 berr = (short*)alloca((image->width+2)*sizeof(short));
701 nrerr = (short*)alloca((image->width+2)*sizeof(short));
702 ngerr = (short*)alloca((image->width+2)*sizeof(short));
703 nberr = (short*)alloca((image->width+2)*sizeof(short));
704 if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) {
705 RErrorCode = RERR_NOMEMORY;
706 RDestroyXImage(ctx, ximg);
707 return NULL;
709 for (x=0; x<image->width; x++) {
710 rerr[x] = red[x];
711 gerr[x] = grn[x];
712 berr[x] = blu[x];
714 rerr[x] = gerr[x] = berr[x] = 0;
715 /* convert and dither the image to XImage */
716 for (y=0, ofs=0; y<image->height; y++) {
717 if (y<image->height-1) {
718 int x1;
719 for (x=0, x1=ofs+image->width; x<image->width; x++, x1++) {
720 nrerr[x] = red[x1];
721 ngerr[x] = grn[x1];
722 nberr[x] = blu[x1];
724 /* last column */
725 x1--;
726 nrerr[x] = red[x1];
727 ngerr[x] = grn[x1];
728 nberr[x] = blu[x1];
730 for (x=0; x<image->width; x++, ofs++) {
731 /* reduce pixel */
732 if (rerr[x]>0xff) rerr[x]=0xff; else if (rerr[x]<0) rerr[x]=0;
733 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
734 if (berr[x]>0xff) berr[x]=0xff; else if (berr[x]<0) berr[x]=0;
736 r = rtable[rerr[x]];
737 g = gtable[gerr[x]];
738 b = btable[berr[x]];
740 pixel = r + g + b;
742 XPutPixel(ximg->image, x, y, pixel+base_pixel);
744 /* calc error */
745 rer = rerr[x] - (ctx->colors[pixel].red>>8);
746 ger = gerr[x] - (ctx->colors[pixel].green>>8);
747 ber = berr[x] - (ctx->colors[pixel].blue>>8);
749 /* distribute error */
750 rerr[x+1]+=(rer*7)/16;
751 gerr[x+1]+=(ger*7)/16;
752 berr[x+1]+=(ber*7)/16;
754 nrerr[x]+=(rer*5)/16;
755 ngerr[x]+=(ger*5)/16;
756 nberr[x]+=(ber*5)/16;
758 if (x>0) {
759 nrerr[x-1]+=(rer*3)/16;
760 ngerr[x-1]+=(ger*3)/16;
761 nberr[x-1]+=(ber*3)/16;
764 nrerr[x+1]+=rer/16;
765 ngerr[x+1]+=ger/16;
766 nberr[x+1]+=ber/16;
768 /* skip to next line */
769 terr = rerr;
770 rerr = nrerr;
771 nrerr = terr;
773 terr = gerr;
774 gerr = ngerr;
775 ngerr = terr;
777 terr = berr;
778 berr = nberr;
779 nberr = terr;
782 ximg->image->data = (char*)data;
784 return ximg;
789 static RXImage*
790 image2GrayScale(RContext *ctx, RImage *image)
792 RXImage *ximg;
793 register int x, y, g;
794 unsigned char *red, *grn, *blu;
795 const int cpc=ctx->attribs->colors_per_channel;
796 unsigned short gmask;
797 unsigned short *table;
798 unsigned char *data;
799 int ofs;
800 /*register unsigned char maxrgb = 0xff;*/
802 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
803 if (!ximg) {
804 return NULL;
807 red = image->data[0];
808 grn = image->data[1];
809 blu = image->data[2];
811 data = (unsigned char *)ximg->image->data;
813 if (ctx->vclass == StaticGray)
814 gmask = (1<<ctx->depth) - 1; /* use all grays */
815 else
816 gmask = cpc*cpc*cpc-1;
818 table = computeTable(gmask);
820 if (table==NULL) {
821 RErrorCode = RERR_NOMEMORY;
822 RDestroyXImage(ctx, ximg);
823 return NULL;
826 if (ctx->attribs->render_mode == RBestMatchRendering) {
827 /* fake match */
828 #ifdef DEBUG
829 printf("grayscale match with %d colors per channel\n", cpc);
830 #endif
831 for (y=0, ofs = 0; y<image->height; y++) {
832 for (x=0; x<image->width; x++, ofs++) {
833 /* reduce pixel */
834 g = table[(red[ofs]*30+grn[ofs]*59+blu[ofs]*11)/100];
836 /*data[ofs] = ctx->colors[g].pixel;*/
837 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
840 } else {
841 /* dither */
842 short *gerr;
843 short *ngerr;
844 short *terr;
845 int ger;
846 const int dg=0xff/gmask;
848 #ifdef DEBUG
849 printf("grayscale dither with %d colors per channel\n", cpc);
850 #endif
851 gerr = (short*)alloca((image->width+2)*sizeof(short));
852 ngerr = (short*)alloca((image->width+2)*sizeof(short));
853 if (!gerr || !ngerr) {
854 RErrorCode = RERR_NOMEMORY;
855 RDestroyXImage(ctx, ximg);
856 return NULL;
858 for (x=0; x<image->width; x++) {
859 gerr[x] = (red[x]*30 + grn[x]*59 + blu[x]*11)/100;
861 gerr[x] = 0;
862 /* convert and dither the image to XImage */
863 for (y=0, ofs=0; y<image->height; y++) {
864 if (y<image->height-1) {
865 int x1;
866 for (x=0, x1=ofs+image->width; x<image->width; x++, x1++) {
867 ngerr[x] = (red[x1]*30 + grn[x1]*59 + blu[x1]*11)/100;
869 /* last column */
870 x1--;
871 ngerr[x] = (red[x1]*30 + grn[x1]*59 + blu[x1]*11)/100;
873 for (x=0; x<image->width; x++, ofs++) {
874 /* reduce pixel */
875 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
877 g = table[gerr[x]];
879 /*data[ofs] = ctx->colors[g].pixel;*/
880 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
881 /* calc error */
882 ger = gerr[x] - g*dg;
884 /* distribute error */
885 g = (ger*3)/8;
886 /* x+1, y */
887 gerr[x+1]+=g;
888 /* x, y+1 */
889 ngerr[x]+=g;
890 /* x+1, y+1 */
891 ngerr[x+1]+=ger-2*g;
893 /* skip to next line */
894 terr = gerr;
895 gerr = ngerr;
896 ngerr = terr;
899 ximg->image->data = (char*)data;
901 return ximg;
905 static RXImage*
906 image2Bitmap(RContext *ctx, RImage *image, int threshold)
908 RXImage *ximg;
909 unsigned char *alpha;
910 int x, y;
912 ximg = RCreateXImage(ctx, 1, image->width, image->height);
913 if (!ximg) {
914 return NULL;
916 alpha = image->data[3];
918 for (y = 0; y < image->height; y++) {
919 for (x = 0; x < image->width; x++) {
920 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
921 alpha++;
925 return ximg;
930 int
931 RConvertImage(RContext *context, RImage *image, Pixmap *pixmap)
933 RXImage *ximg=NULL;
934 #ifdef XSHM
935 Pixmap tmp;
936 #endif
938 assert(context!=NULL);
939 assert(image!=NULL);
940 assert(pixmap!=NULL);
942 /* clear error message */
943 if (context->vclass == TrueColor) {
945 if (context->attribs->render_mode == RDitheredRendering
946 && (context->depth == 15 || context->depth == 16))
947 ximg = image2TrueColorD16(context, image);
948 else
949 ximg = image2TrueColor(context, image);
951 } else if (context->vclass == PseudoColor
952 || context->vclass == StaticColor) {
954 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
955 ximg = image2StandardPseudoColor(context, image);
956 else
957 ximg = image2PseudoColor(context, image);
959 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
961 ximg = image2GrayScale(context, image);
964 if (!ximg) {
965 #ifdef C_ALLOCA
966 alloca(0);
967 #endif
968 return False;
972 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width,
973 image->height, context->depth);
975 #ifdef XSHM
976 if (context->flags.use_shared_pixmap && ximg->is_shared)
977 tmp = R_CreateXImageMappedPixmap(context, ximg);
978 else
979 tmp = None;
980 if (tmp) {
982 * We have to copy the shm Pixmap into a normal Pixmap because
983 * otherwise, we would have to control when Pixmaps are freed so
984 * that we can detach their shm segments. This is a problem if the
985 * program crash, leaving stale shared memory segments in the
986 * system (lots of them). But with some work, we can optimize
987 * things and remove this XCopyArea. This will require
988 * explicitly freeing all pixmaps when exiting or restarting
989 * wmaker.
991 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0,
992 image->width, image->height, 0, 0);
993 XFreePixmap(context->dpy, tmp);
994 } else {
995 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
996 image->width, image->height);
998 #else /* !XSHM */
999 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
1000 image->width, image->height);
1001 #endif /* !XSHM */
1003 RDestroyXImage(context, ximg);
1005 #ifdef C_ALLOCA
1006 alloca(0);
1007 #endif
1008 return True;
1012 int
1013 RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap,
1014 Pixmap *mask, int threshold)
1016 GC gc;
1017 XGCValues gcv;
1018 RXImage *ximg=NULL;
1020 assert(context!=NULL);
1021 assert(image!=NULL);
1022 assert(pixmap!=NULL);
1023 assert(mask!=NULL);
1025 if (!RConvertImage(context, image, pixmap))
1026 return False;
1028 if (image->data[3]==NULL) {
1029 *mask = None;
1030 return True;
1033 ximg = image2Bitmap(context, image, threshold);
1035 if (!ximg) {
1036 #ifdef C_ALLOCA
1037 alloca(0);
1038 #endif
1039 return False;
1041 *mask = XCreatePixmap(context->dpy, context->drawable, image->width,
1042 image->height, 1);
1043 gcv.foreground = context->black;
1044 gcv.background = context->white;
1045 gcv.graphics_exposures = False;
1046 gc = XCreateGC(context->dpy, *mask, GCForeground|GCBackground
1047 |GCGraphicsExposures, &gcv);
1048 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0,
1049 image->width, image->height);
1050 RDestroyXImage(context, ximg);
1052 #ifdef C_ALLOCA
1053 alloca(0);
1054 #endif
1055 return True;
1059 Bool
1060 RGetClosestXColor(RContext *context, RColor *color, XColor *retColor)
1062 if (context->vclass == TrueColor) {
1063 unsigned short rmask, gmask, bmask;
1064 unsigned short roffs, goffs, boffs;
1065 unsigned short *rtable, *gtable, *btable;
1067 roffs = context->red_offset;
1068 goffs = context->green_offset;
1069 boffs = context->blue_offset;
1071 rmask = context->visual->red_mask >> roffs;
1072 gmask = context->visual->green_mask >> goffs;
1073 bmask = context->visual->blue_mask >> boffs;
1075 rtable = computeTable(rmask);
1076 gtable = computeTable(gmask);
1077 btable = computeTable(bmask);
1079 retColor->pixel = (rtable[color->red]<<roffs) |
1080 (gtable[color->green]<<goffs) | (btable[color->blue]<<boffs);
1082 retColor->red = color->red << 8;
1083 retColor->green = color->green << 8;
1084 retColor->blue = color->blue << 8;
1085 retColor->flags = DoRed|DoGreen|DoBlue;
1087 } else if (context->vclass == PseudoColor
1088 || context->vclass == StaticColor) {
1090 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
1091 unsigned int *rtable, *gtable, *btable;
1093 rtable = computeStdTable(context->std_rgb_map->red_mult,
1094 context->std_rgb_map->red_max);
1096 gtable = computeStdTable(context->std_rgb_map->green_mult,
1097 context->std_rgb_map->green_max);
1099 btable = computeStdTable(context->std_rgb_map->blue_mult,
1100 context->std_rgb_map->blue_max);
1102 if (rtable==NULL || gtable==NULL || btable==NULL) {
1103 RErrorCode = RERR_NOMEMORY;
1104 return False;
1107 retColor->pixel = (rtable[color->red]
1108 + gtable[color->green]
1109 + btable[color->blue]
1110 + context->std_rgb_map->base_pixel) & 0xffffffff;
1111 retColor->red = color->red<<8;
1112 retColor->green = color->green<<8;
1113 retColor->blue = color->blue<<8;
1114 retColor->flags = DoRed|DoGreen|DoBlue;
1116 } else {
1117 const int cpc=context->attribs->colors_per_channel;
1118 const unsigned short rmask = cpc-1; /* different sizes could be used */
1119 const unsigned short gmask = rmask; /* for r,g,b */
1120 const unsigned short bmask = rmask;
1121 unsigned short *rtable, *gtable, *btable;
1122 const int cpccpc = cpc*cpc;
1123 int index;
1125 rtable = computeTable(rmask);
1126 gtable = computeTable(gmask);
1127 btable = computeTable(bmask);
1129 if (rtable==NULL || gtable==NULL || btable==NULL) {
1130 RErrorCode = RERR_NOMEMORY;
1131 return False;
1133 index = rtable[color->red]*cpccpc + gtable[color->green]*cpc
1134 + btable[color->blue];
1135 *retColor = context->colors[index];
1138 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
1140 const int cpc = context->attribs->colors_per_channel;
1141 unsigned short gmask;
1142 unsigned short *table;
1143 int index;
1145 if (context->vclass == StaticGray)
1146 gmask = (1<<context->depth) - 1; /* use all grays */
1147 else
1148 gmask = cpc*cpc*cpc-1;
1150 table = computeTable(gmask);
1151 if (!table)
1152 return False;
1154 index = table[(color->red*30 + color->green*59 + color->blue*11)/100];
1156 *retColor = context->colors[index];
1157 } else {
1158 RErrorCode = RERR_INTERNAL;
1159 return False;
1162 return True;