changed format of RImage, added x86 speicfic optimized code
[wmaker-crm.git] / wrlib / convert.c
blobf0b46b9ecf6299acfef998fbec615a2997016f7b
1 /* convert.c - convert RImage to Pixmap
2 *
3 * Raster graphics library
5 * Copyright (c) 1997-2000 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>
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
30 #include <assert.h>
32 #ifdef BENCH
33 #include "bench.h"
34 #endif
36 #include "wraster.h"
38 #ifdef XSHM
39 extern Pixmap R_CreateXImageMappedPixmap(RContext *context, RXImage *ximage);
41 #endif
44 #ifdef ASM_X86_MMX
46 extern int x86_check_mmx();
48 extern void x86_TrueColor_32_to_16(unsigned char *image,
49 unsigned short *ximage,
50 short *err, short *nerr,
51 short *rtable, short *gtable,
52 short *btable,
53 int dr, int dg, int db,
54 unsigned int roffs,
55 unsigned int goffs,
56 unsigned int boffs,
57 int width, int height,
58 int line_offset);
62 #endif /* X86_ASM */
66 typedef struct RConversionTable {
67 unsigned short table[256];
68 unsigned short index;
70 struct RConversionTable *next;
71 } RConversionTable;
74 typedef struct RStdConversionTable {
75 unsigned int table[256];
77 unsigned short mult;
78 unsigned short max;
80 struct RStdConversionTable *next;
81 } RStdConversionTable;
85 static RConversionTable *conversionTable = NULL;
86 static RStdConversionTable *stdConversionTable = NULL;
89 static unsigned short*
90 computeTable(unsigned short mask)
92 RConversionTable *tmp = conversionTable;
93 int i;
95 while (tmp) {
96 if (tmp->index == mask)
97 break;
98 tmp = tmp->next;
101 if (tmp)
102 return tmp->table;
104 tmp = (RConversionTable *)malloc(sizeof(RConversionTable));
105 if (tmp == NULL)
106 return NULL;
108 for (i=0;i<256;i++)
109 tmp->table[i] = (i*mask + 0x7f)/0xff;
111 tmp->index = mask;
112 tmp->next = conversionTable;
113 conversionTable = tmp;
114 return tmp->table;
118 static unsigned int*
119 computeStdTable(unsigned int mult, unsigned int max)
121 RStdConversionTable *tmp = stdConversionTable;
122 unsigned int i;
124 while (tmp) {
125 if (tmp->mult == mult && tmp->max == max)
126 break;
127 tmp = tmp->next;
130 if (tmp)
131 return tmp->table;
133 tmp = (RStdConversionTable *)malloc(sizeof(RStdConversionTable));
134 if (tmp == NULL)
135 return NULL;
137 for (i=0; i<256; i++) {
138 tmp->table[i] = (i*max)/0xff * mult;
140 tmp->mult = mult;
141 tmp->max = max;
143 tmp->next = stdConversionTable;
144 stdConversionTable = tmp;
146 return tmp->table;
149 /***************************************************************************/
152 static void
153 convertTrueColor_generic(RXImage *ximg, RImage *image,
154 char *err, char *nerr,
155 const short *rtable,
156 const short *gtable,
157 const short *btable,
158 const int dr, const int dg, const int db,
159 const unsigned short roffs,
160 const unsigned short goffs,
161 const unsigned short boffs)
163 char *terr;
164 int x, y, r, g, b;
165 int pixel;
166 int rer, ger, ber;
167 unsigned char *ptr = image->data;
168 int channels = image->format == RRGBAFormat ? 4 : 3;
170 /* convert and dither the image to XImage */
171 for (y=0; y<image->height; y++) {
172 nerr[0] = 0;
173 nerr[1] = 0;
174 nerr[2] = 0;
175 for (x=0; x<image->width; x++, ptr+=channels) {
177 /* reduce pixel */
178 pixel = *ptr + err[x];
179 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
180 r = rtable[pixel];
181 /* calc error */
182 rer = pixel - r*dr;
184 /* reduce pixel */
185 pixel = *(ptr+1) + err[x+1];
186 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
187 g = gtable[pixel];
188 /* calc error */
189 ger = pixel - g*dg;
191 /* reduce pixel */
192 pixel = *(ptr+2) + err[x+2];
193 if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
194 b = btable[pixel];
195 /* calc error */
196 ber = pixel - b*db;
199 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
200 XPutPixel(ximg->image, x, y, pixel);
202 /* distribute error */
203 r = (rer*3)/8;
204 g = (ger*3)/8;
205 b = (ber*3)/8;
206 /* x+1, y */
207 err[x+3*1]+=r;
208 err[x+1+3*1]+=g;
209 err[x+2+3*1]+=b;
210 /* x, y+1 */
211 nerr[x]+=r;
212 nerr[x+1]+=g;
213 nerr[x+2]+=b;
214 /* x+1, y+1 */
215 nerr[x+3*1]=rer-2*r;
216 nerr[x+1+3*1]=ger-2*g;
217 nerr[x+2+3*1]=ber-2*b;
219 /* skip to next line */
220 terr = err;
221 err = nerr;
222 nerr = terr;
229 static RXImage*
230 image2TrueColor(RContext *ctx, RImage *image)
232 RXImage *ximg;
233 unsigned short rmask, gmask, bmask;
234 unsigned short roffs, goffs, boffs;
235 unsigned short *rtable, *gtable, *btable;
236 int channels = (image->format == RRGBAFormat ? 4 : 3);
238 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
239 if (!ximg) {
240 return NULL;
243 roffs = ctx->red_offset;
244 goffs = ctx->green_offset;
245 boffs = ctx->blue_offset;
247 rmask = ctx->visual->red_mask >> roffs;
248 gmask = ctx->visual->green_mask >> goffs;
249 bmask = ctx->visual->blue_mask >> boffs;
251 rtable = computeTable(rmask);
252 gtable = computeTable(gmask);
253 btable = computeTable(bmask);
255 if (rtable==NULL || gtable==NULL || btable==NULL) {
256 RErrorCode = RERR_NOMEMORY;
257 RDestroyXImage(ctx, ximg);
258 return NULL;
262 if (ctx->attribs->render_mode==RBestMatchRendering) {
263 int ofs, r, g, b;
264 int x, y;
265 unsigned long pixel;
266 unsigned char *ptr = image->data;
268 /* fake match */
269 #ifdef DEBUG
270 puts("true color match");
271 #endif
272 for (y=0, ofs=0; y < image->height; y++) {
273 for (x=0; x < image->width; x++, ofs+=channels-3) {
274 /* reduce pixel */
275 r = rtable[ptr[ofs++]];
276 g = gtable[ptr[ofs++]];
277 b = btable[ptr[ofs++]];
278 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
279 XPutPixel(ximg->image, x, y, pixel);
282 } else {
283 /* dither */
284 const int dr=0xff/rmask;
285 const int dg=0xff/gmask;
286 const int db=0xff/bmask;
288 #ifdef DEBUG
289 puts("true color dither");
290 #endif
292 #ifdef BENCH
293 cycle_bench(1);
294 #endif
296 #ifdef ASM_X86_MMX
297 if (ctx->depth == 16 && image->format == RRGBAFormat
298 && x86_check_mmx()) {
299 short *err;
300 short *nerr;
302 err = malloc(8*(image->width+3));
303 nerr = malloc(8*(image->width+3));
304 if (!err || !nerr) {
305 if (nerr)
306 free(nerr);
307 RErrorCode = RERR_NOMEMORY;
308 RDestroyXImage(ctx, ximg);
309 return NULL;
311 memset(err, 0, 8*(image->width+3));
312 memset(nerr, 0, 8*(image->width+3));
314 x86_TrueColor_32_to_16(image->data,
315 (unsigned short*)ximg->image->data,
316 err+8, nerr+8,
317 rtable, gtable, btable,
318 dr, dg, db,
319 roffs, goffs, boffs,
320 image->width, image->height,
321 ximg->image->bytes_per_line - 2*image->width);
323 free(err);
324 free(nerr);
325 } else
326 #endif /* ASM_X86_MMX */
328 char *err;
329 char *nerr;
330 int ch = image->format == RRGBAFormat ? 4 : 3;
332 err = malloc(ch*(image->width+2));
333 nerr = malloc(ch*(image->width+2));
334 if (!err || !nerr) {
335 if (nerr)
336 free(nerr);
337 RErrorCode = RERR_NOMEMORY;
338 RDestroyXImage(ctx, ximg);
339 return NULL;
342 memset(err, 0, ch*(image->width+2));
343 memset(nerr, 0, ch*(image->width+2));
345 convertTrueColor_generic(ximg, image, err, nerr,
346 rtable, gtable, btable,
347 dr, dg, db, roffs, goffs, boffs);
348 free(err);
349 free(nerr);
354 #ifdef BENCH
355 cycle_bench(0);
356 #endif
358 return ximg;
362 /***************************************************************************/
365 static RXImage*
366 image2PseudoColor(RContext *ctx, RImage *image)
368 RXImage *ximg;
369 register int x, y, r, g, b;
370 unsigned char *ptr;
371 unsigned long pixel;
372 const int cpc=ctx->attribs->colors_per_channel;
373 const unsigned short rmask = cpc-1; /* different sizes could be used */
374 const unsigned short gmask = rmask; /* for r,g,b */
375 const unsigned short bmask = rmask;
376 unsigned short *rtable, *gtable, *btable;
377 const int cpccpc = cpc*cpc;
378 unsigned char *data;
379 int ofs;
380 int channels = image->format == RRGBAFormat ? 4 : 3;
381 /*register unsigned char maxrgb = 0xff;*/
383 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
384 if (!ximg) {
385 return NULL;
388 ptr = image->data;
390 data = (unsigned char *)ximg->image->data;
392 /* Tables are same at the moment because rmask==gmask==bmask. */
393 rtable = computeTable(rmask);
394 gtable = computeTable(gmask);
395 btable = computeTable(bmask);
397 if (rtable==NULL || gtable==NULL || btable==NULL) {
398 RErrorCode = RERR_NOMEMORY;
399 RDestroyXImage(ctx, ximg);
400 return NULL;
403 if (ctx->attribs->render_mode == RBestMatchRendering) {
404 /* fake match */
405 #ifdef DEBUG
406 printf("pseudo color match with %d colors per channel\n", cpc);
407 #endif
408 for (y=0; y<image->height; y++) {
409 for (x=0; x<image->width; x++, ptr+=channels-1) {
410 /* reduce pixel */
411 r = rtable[*ptr++];
412 g = gtable[*ptr++];
413 b = btable[*ptr++];
414 pixel = r*cpccpc + g*cpc + b;
415 /*data[ofs] = ctx->colors[pixel].pixel;*/
416 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
419 } else {
420 /* dither */
421 short *err;
422 short *nerr;
423 short *terr;
424 int rer, ger, ber;
425 const int dr=0xff/rmask;
426 const int dg=0xff/gmask;
427 const int db=0xff/bmask;
428 int i;
430 #ifdef DEBUG
431 printf("pseudo color dithering with %d colors per channel\n", cpc);
432 #endif
433 err = (short*)malloc(3*(image->width+2)*sizeof(short));
434 nerr = (short*)malloc(3*(image->width+2)*sizeof(short));
435 if (!err || !nerr) {
436 if (nerr)
437 free(nerr);
438 RErrorCode = RERR_NOMEMORY;
439 RDestroyXImage(ctx, ximg);
440 return NULL;
442 for (x=0, i=0; x<image->width*3; x+=channels-3) {
443 err[i++] = ptr[x++];
444 err[i++] = ptr[x++];
445 err[i++] = ptr[x++];
447 err[x++] = err[x++] = err[x++] = 0;
448 /* convert and dither the image to XImage */
449 for (ofs=0, y=0; y<image->height; y++) {
450 if (y<image->height-1) {
451 int x1;
452 for (x=0, x1=((y+1)*image->width)*channels;
453 x<image->width*3; x1+=channels-3) {
454 nerr[x++] = ptr[x1++];
455 nerr[x++] = ptr[x1++];
456 nerr[x++] = ptr[x1++];
458 /* last column */
459 x1-=channels;
460 nerr[x++] = ptr[x1++];
461 nerr[x++] = ptr[x1++];
462 nerr[x++] = ptr[x1++];
464 for (x=0; x<image->width*3; x+=3, ofs++) {
465 /* reduce pixel */
466 if (err[x]>0xff) err[x]=0xff; else if (err[x]<0) err[x]=0;
467 if (err[x+1]>0xff) err[x+1]=0xff; else if (err[x+1]<0) err[x+1]=0;
468 if (err[x+2]>0xff) err[x+2]=0xff; else if (err[x+2]<0) err[x+2]=0;
470 r = rtable[err[x]];
471 g = gtable[err[x+1]];
472 b = btable[err[x+2]];
474 pixel = r*cpccpc + g*cpc + b;
475 data[ofs] = ctx->colors[pixel].pixel;
477 /* calc error */
478 rer = err[x] - r*dr;
479 ger = err[x+1] - g*dg;
480 ber = err[x+2] - b*db;
482 /* distribute error */
483 err[x+3*1]+=(rer*7)/16;
484 err[x+1+3*1]+=(ger*7)/16;
485 err[x+2+3*1]+=(ber*7)/16;
487 nerr[x]+=(rer*5)/16;
488 nerr[x]+=(ger*5)/16;
489 nerr[x]+=(ber*5)/16;
491 if (x>0) {
492 nerr[x-3*1]+=(rer*3)/16;
493 nerr[x-(3*1)+1]+=(ger*3)/16;
494 nerr[x-(3*1)+2]+=(ber*3)/16;
497 nerr[x+3*1]+=rer/16;
498 nerr[x+1+3*1]+=ger/16;
499 nerr[x+2+3*1]+=ber/16;
501 /* skip to next line */
502 terr = err;
503 err = nerr;
504 nerr = terr;
506 ofs += ximg->image->bytes_per_line - image->width;
508 free(err);
509 free(nerr);
511 ximg->image->data = (char*)data;
513 return ximg;
518 * For standard colormap
520 static RXImage*
521 image2StandardPseudoColor(RContext *ctx, RImage *image)
523 RXImage *ximg;
524 register int x, y, r, g, b;
525 unsigned char *ptr;
526 unsigned long pixel;
527 unsigned char *data;
528 unsigned int *rtable, *gtable, *btable;
529 unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
530 int channels = image->format == RRGBAFormat ? 4 : 3;
531 /*register unsigned char maxrgb = 0xff;*/
533 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
534 if (!ximg) {
535 return NULL;
538 ptr = image->data;
540 data = (unsigned char *)ximg->image->data;
543 rtable = computeStdTable(ctx->std_rgb_map->red_mult,
544 ctx->std_rgb_map->red_max);
546 gtable = computeStdTable(ctx->std_rgb_map->green_mult,
547 ctx->std_rgb_map->green_max);
549 btable = computeStdTable(ctx->std_rgb_map->blue_mult,
550 ctx->std_rgb_map->blue_max);
552 if (rtable==NULL || gtable==NULL || btable==NULL) {
553 RErrorCode = RERR_NOMEMORY;
554 RDestroyXImage(ctx, ximg);
555 return NULL;
559 if (ctx->attribs->render_mode == RBestMatchRendering) {
560 for (y=0; y<image->height; y++) {
561 for (x=0; x<image->width; x++, ptr+=channels-3) {
562 /* reduce pixel */
563 pixel = (rtable[*ptr++] + gtable[*ptr++]
564 + btable[*ptr++] + base_pixel) & 0xffffffff;
566 XPutPixel(ximg->image, x, y, pixel);
569 } else {
570 /* dither */
571 short *err, *nerr;
572 short *terr;
573 int rer, ger, ber;
574 int x1, ofs;
576 #ifdef DEBUG
577 printf("pseudo color dithering with %d colors per channel\n", cpc);
578 #endif
579 err = (short*)malloc(3*(image->width+2)*sizeof(short));
580 nerr = (short*)malloc(3*(image->width+2)*sizeof(short));
581 if (!err || !nerr) {
582 if (nerr)
583 free(nerr);
584 RErrorCode = RERR_NOMEMORY;
585 RDestroyXImage(ctx, ximg);
586 return NULL;
588 for (x=0, x1=0; x<image->width*3; x1+=channels-3) {
589 err[x++] = ptr[x1++];
590 err[x++] = ptr[x1++];
591 err[x++] = ptr[x1++];
593 err[x++] = err[x++] = err[x++] = 0;
594 /* convert and dither the image to XImage */
595 for (y=0, ofs=0; y<image->height; y++) {
596 if (y<image->height-1) {
597 int x1;
598 for (x=0, x1=(y+1)*image->width*channels;
599 x<image->width*3;
600 x1+=channels-3) {
601 nerr[x++] = ptr[x1++];
602 nerr[x++] = ptr[x1++];
603 nerr[x++] = ptr[x1++];
605 /* last column */
606 x1-=channels;
607 nerr[x++] = ptr[x1++];
608 nerr[x++] = ptr[x1++];
609 nerr[x++] = ptr[x1++];
611 for (x=0; x<image->width*3; x+=3, ofs++) {
612 /* reduce pixel */
613 if (err[x]>0xff) err[x]=0xff; else if (err[x]<0) err[x]=0;
614 if (err[x+1]>0xff) err[x+1]=0xff; else if (err[x+1]<0) err[x+1]=0;
615 if (err[x+2]>0xff) err[x+2]=0xff; else if (err[x+2]<0) err[x+2]=0;
617 r = rtable[err[x]];
618 g = gtable[err[x+1]];
619 b = btable[err[x+2]];
621 pixel = r + g + b;
623 data[ofs] = base_pixel + pixel;
625 XPutPixel(ximg->image, x, y, pixel+base_pixel);
628 /* calc error */
629 rer = err[x] - (ctx->colors[pixel].red>>8);
630 ger = err[x+1] - (ctx->colors[pixel].green>>8);
631 ber = err[x+2] - (ctx->colors[pixel].blue>>8);
633 /* distribute error */
634 err[x+3*1]+=(rer*7)/16;
635 err[x+1+3*1]+=(ger*7)/16;
636 err[x+2+3*1]+=(ber*7)/16;
638 nerr[x]+=(rer*5)/16;
639 nerr[x+1]+=(ger*5)/16;
640 nerr[x+2]+=(ber*5)/16;
642 if (x>0) {
643 nerr[x-3*1]+=(rer*3)/16;
644 nerr[x-3*1+1]+=(ger*3)/16;
645 nerr[x-3*1+2]+=(ber*3)/16;
648 nerr[x+3*1]+=rer/16;
649 nerr[x+1+3*1]+=ger/16;
650 nerr[x+2+3*1]+=ber/16;
652 /* skip to next line */
653 terr = err;
654 err = nerr;
655 nerr = terr;
657 ofs += ximg->image->bytes_per_line - image->width;
659 free(err);
660 free(nerr);
662 ximg->image->data = (char*)data;
664 return ximg;
669 static RXImage*
670 image2GrayScale(RContext *ctx, RImage *image)
672 RXImage *ximg;
673 register int x, y, g;
674 unsigned char *ptr;
675 const int cpc=ctx->attribs->colors_per_channel;
676 unsigned short gmask;
677 unsigned short *table;
678 unsigned char *data;
679 int channels = image->format == RRGBAFormat ? 4 : 3;
681 /*register unsigned char maxrgb = 0xff;*/
683 ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
684 if (!ximg) {
685 return NULL;
688 ptr = image->data;
690 data = (unsigned char *)ximg->image->data;
692 if (ctx->vclass == StaticGray)
693 gmask = (1<<ctx->depth) - 1; /* use all grays */
694 else
695 gmask = cpc*cpc*cpc-1;
697 table = computeTable(gmask);
699 if (table==NULL) {
700 RErrorCode = RERR_NOMEMORY;
701 RDestroyXImage(ctx, ximg);
702 return NULL;
705 if (ctx->attribs->render_mode == RBestMatchRendering) {
706 /* fake match */
707 #ifdef DEBUG
708 printf("grayscale match with %d colors per channel\n", cpc);
709 #endif
710 for (y=0; y<image->height; y++) {
711 for (x=0; x<image->width; x++) {
712 /* reduce pixel */
713 g = table[(*ptr++ * 30 + *ptr++ * 59 + *ptr++ * 11)/100];
715 /*data[ofs] = ctx->colors[g].pixel;*/
716 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
719 } else {
720 /* dither */
721 short *gerr;
722 short *ngerr;
723 short *terr;
724 int ger;
725 const int dg=0xff/gmask;
727 #ifdef DEBUG
728 printf("grayscale dither with %d colors per channel\n", cpc);
729 #endif
730 gerr = (short*)malloc((image->width+2)*sizeof(short));
731 ngerr = (short*)malloc((image->width+2)*sizeof(short));
732 if (!gerr || !ngerr) {
733 if (ngerr)
734 free(ngerr);
735 RErrorCode = RERR_NOMEMORY;
736 RDestroyXImage(ctx, ximg);
737 return NULL;
739 for (x=0; x<image->width; x++) {
740 gerr[x] = (ptr[x*3]*30 + ptr[x*3+1]*59 + ptr[x*3+2]*11)/100;
742 gerr[x] = 0;
743 /* convert and dither the image to XImage */
744 for (y=0; y<image->height; y++) {
745 if (y<image->height-1) {
746 int x1;
747 for (x=0, x1=(y+1)*image->width*3;
748 x<image->width;
749 x1+=channels-3) {
750 ngerr[x] = (ptr[x1++]*30 + ptr[x1++]*59 + ptr[x1++]*11)/100;
752 /* last column */
753 x1-=channels;
754 ngerr[x] = (ptr[x1++]*30 + ptr[x1++]*59 + ptr[x1++]*11)/100;
756 for (x=0; x<image->width; x++) {
757 /* reduce pixel */
758 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
760 g = table[gerr[x]];
762 /*data[ofs] = ctx->colors[g].pixel;*/
763 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
764 /* calc error */
765 ger = gerr[x] - g*dg;
767 /* distribute error */
768 g = (ger*3)/8;
769 /* x+1, y */
770 gerr[x+1]+=g;
771 /* x, y+1 */
772 ngerr[x]+=g;
773 /* x+1, y+1 */
774 ngerr[x+1]+=ger-2*g;
776 /* skip to next line */
777 terr = gerr;
778 gerr = ngerr;
779 ngerr = terr;
781 free(gerr);
782 free(ngerr);
784 ximg->image->data = (char*)data;
786 return ximg;
790 static RXImage*
791 image2Bitmap(RContext *ctx, RImage *image, int threshold)
793 RXImage *ximg;
794 unsigned char *alpha;
795 int x, y;
797 ximg = RCreateXImage(ctx, 1, image->width, image->height);
798 if (!ximg) {
799 return NULL;
801 alpha = image->data+3;
803 for (y = 0; y < image->height; y++) {
804 for (x = 0; x < image->width; x++) {
805 XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
806 alpha+=4;
810 return ximg;
815 int
816 RConvertImage(RContext *context, RImage *image, Pixmap *pixmap)
818 RXImage *ximg=NULL;
819 #ifdef XSHM
820 Pixmap tmp;
821 #endif
823 assert(context!=NULL);
824 assert(image!=NULL);
825 assert(pixmap!=NULL);
827 /* clear error message */
828 if (context->vclass == TrueColor) {
830 ximg = image2TrueColor(context, image);
832 } else if (context->vclass == PseudoColor
833 || context->vclass == StaticColor) {
835 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
836 ximg = image2StandardPseudoColor(context, image);
837 else
838 ximg = image2PseudoColor(context, image);
840 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
842 ximg = image2GrayScale(context, image);
845 if (!ximg) {
846 return False;
850 *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width,
851 image->height, context->depth);
853 #ifdef XSHM
854 if (context->flags.use_shared_pixmap && ximg->is_shared)
855 tmp = R_CreateXImageMappedPixmap(context, ximg);
856 else
857 tmp = None;
858 if (tmp) {
860 * We have to copy the shm Pixmap into a normal Pixmap because
861 * otherwise, we would have to control when Pixmaps are freed so
862 * that we can detach their shm segments. This is a problem if the
863 * program crash, leaving stale shared memory segments in the
864 * system (lots of them). But with some work, we can optimize
865 * things and remove this XCopyArea. This will require
866 * explicitly freeing all pixmaps when exiting or restarting
867 * wmaker.
869 XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0,
870 image->width, image->height, 0, 0);
871 XFreePixmap(context->dpy, tmp);
872 } else {
873 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
874 image->width, image->height);
876 #else /* !XSHM */
877 RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
878 image->width, image->height);
879 #endif /* !XSHM */
881 RDestroyXImage(context, ximg);
883 return True;
887 int
888 RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap,
889 Pixmap *mask, int threshold)
891 GC gc;
892 XGCValues gcv;
893 RXImage *ximg=NULL;
895 assert(context!=NULL);
896 assert(image!=NULL);
897 assert(pixmap!=NULL);
898 assert(mask!=NULL);
900 if (!RConvertImage(context, image, pixmap))
901 return False;
903 if (image->format==RRGBFormat) {
904 *mask = None;
905 return True;
908 ximg = image2Bitmap(context, image, threshold);
910 if (!ximg) {
911 return False;
913 *mask = XCreatePixmap(context->dpy, context->drawable, image->width,
914 image->height, 1);
915 gcv.foreground = context->black;
916 gcv.background = context->white;
917 gcv.graphics_exposures = False;
918 gc = XCreateGC(context->dpy, *mask, GCForeground|GCBackground
919 |GCGraphicsExposures, &gcv);
920 RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0,
921 image->width, image->height);
922 RDestroyXImage(context, ximg);
924 return True;
928 Bool
929 RGetClosestXColor(RContext *context, RColor *color, XColor *retColor)
931 if (context->vclass == TrueColor) {
932 unsigned short rmask, gmask, bmask;
933 unsigned short roffs, goffs, boffs;
934 unsigned short *rtable, *gtable, *btable;
936 roffs = context->red_offset;
937 goffs = context->green_offset;
938 boffs = context->blue_offset;
940 rmask = context->visual->red_mask >> roffs;
941 gmask = context->visual->green_mask >> goffs;
942 bmask = context->visual->blue_mask >> boffs;
944 rtable = computeTable(rmask);
945 gtable = computeTable(gmask);
946 btable = computeTable(bmask);
948 retColor->pixel = (rtable[color->red]<<roffs) |
949 (gtable[color->green]<<goffs) | (btable[color->blue]<<boffs);
951 retColor->red = color->red << 8;
952 retColor->green = color->green << 8;
953 retColor->blue = color->blue << 8;
954 retColor->flags = DoRed|DoGreen|DoBlue;
956 } else if (context->vclass == PseudoColor
957 || context->vclass == StaticColor) {
959 if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
960 unsigned int *rtable, *gtable, *btable;
962 rtable = computeStdTable(context->std_rgb_map->red_mult,
963 context->std_rgb_map->red_max);
965 gtable = computeStdTable(context->std_rgb_map->green_mult,
966 context->std_rgb_map->green_max);
968 btable = computeStdTable(context->std_rgb_map->blue_mult,
969 context->std_rgb_map->blue_max);
971 if (rtable==NULL || gtable==NULL || btable==NULL) {
972 RErrorCode = RERR_NOMEMORY;
973 return False;
976 retColor->pixel = (rtable[color->red]
977 + gtable[color->green]
978 + btable[color->blue]
979 + context->std_rgb_map->base_pixel) & 0xffffffff;
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 {
986 const int cpc=context->attribs->colors_per_channel;
987 const unsigned short rmask = cpc-1; /* different sizes could be used */
988 const unsigned short gmask = rmask; /* for r,g,b */
989 const unsigned short bmask = rmask;
990 unsigned short *rtable, *gtable, *btable;
991 const int cpccpc = cpc*cpc;
992 int index;
994 rtable = computeTable(rmask);
995 gtable = computeTable(gmask);
996 btable = computeTable(bmask);
998 if (rtable==NULL || gtable==NULL || btable==NULL) {
999 RErrorCode = RERR_NOMEMORY;
1000 return False;
1002 index = rtable[color->red]*cpccpc + gtable[color->green]*cpc
1003 + btable[color->blue];
1004 *retColor = context->colors[index];
1007 } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
1009 const int cpc = context->attribs->colors_per_channel;
1010 unsigned short gmask;
1011 unsigned short *table;
1012 int index;
1014 if (context->vclass == StaticGray)
1015 gmask = (1<<context->depth) - 1; /* use all grays */
1016 else
1017 gmask = cpc*cpc*cpc-1;
1019 table = computeTable(gmask);
1020 if (!table)
1021 return False;
1023 index = table[(color->red*30 + color->green*59 + color->blue*11)/100];
1025 *retColor = context->colors[index];
1026 } else {
1027 RErrorCode = RERR_INTERNAL;
1028 return False;
1031 return True;