1 /* convert.c - convert RImage to Pixmap
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.
23 /* AIX requires this to be the first thing in the file. */
25 # define alloca __builtin_alloca
33 # ifndef alloca /* predefined by HP cc +Olibcalls */
42 #include <X11/Xutil.h>
52 Pixmap
R_CreateXImageMappedPixmap(RContext
*context
, RXImage
*ximage
);
57 typedef struct RConversionTable
{
58 unsigned short table
[256];
60 struct RConversionTable
*next
;
64 static RConversionTable
*conversionTable
= NULL
;
67 static unsigned short*
68 computeTable(unsigned short mask
)
70 RConversionTable
*tmp
= conversionTable
;
74 if (tmp
->index
== mask
)
82 tmp
= (RConversionTable
*)malloc(sizeof(RConversionTable
));
87 tmp
->table
[i
] = (i
*mask
+ 0x7f)/0xff;
90 tmp
->next
= conversionTable
;
91 conversionTable
= tmp
;
97 image2TrueColor(RContext
*ctx
, RImage
*image
)
100 register int x
, y
, r
, g
, b
;
101 unsigned char *red
, *grn
, *blu
;
103 unsigned short rmask
, gmask
, bmask
;
104 unsigned short roffs
, goffs
, boffs
;
105 unsigned short *rtable
, *gtable
, *btable
;
108 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
113 red
= image
->data
[0];
114 grn
= image
->data
[1];
115 blu
= image
->data
[2];
117 roffs
= ctx
->red_offset
;
118 goffs
= ctx
->green_offset
;
119 boffs
= ctx
->blue_offset
;
121 rmask
= ctx
->visual
->red_mask
>> roffs
;
122 gmask
= ctx
->visual
->green_mask
>> goffs
;
123 bmask
= ctx
->visual
->blue_mask
>> boffs
;
126 /* this do not seem to increase speed. Only 0.06 second faster in
127 * rendering a 800x600 image to pixmap. 1.12 sec instead of 1.18.
128 * But does not require a 256*256*256 lookup table.
130 if (ctx
->depth
==24) {
132 puts("true color match for 24bpp");
134 for (y
=0; y
< image
->height
; y
++) {
135 for (x
=0; x
< image
->width
; x
++) {
136 pixel
= (*(red
++)<<roffs
) | (*(grn
++)<<goffs
) | (*(blu
++)<<boffs
);
137 XPutPixel(ximg
->image
, x
, y
, pixel
);
144 rtable
= computeTable(rmask
);
145 gtable
= computeTable(gmask
);
146 btable
= computeTable(bmask
);
148 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
149 RErrorCode
= RERR_NOMEMORY
;
150 RDestroyXImage(ctx
, ximg
);
154 if (ctx
->attribs
->render_mode
==RM_MATCH
) {
157 puts("true color match");
159 for (y
=0, ofs
=0; y
< image
->height
; y
++) {
160 for (x
=0; x
< image
->width
; x
++, ofs
++) {
162 r
= rtable
[red
[ofs
]];
163 g
= gtable
[grn
[ofs
]];
164 b
= btable
[blu
[ofs
]];
165 pixel
= (r
<<roffs
) | (g
<<goffs
) | (b
<<boffs
);
166 XPutPixel(ximg
->image
, x
, y
, pixel
);
171 short *rerr
, *gerr
, *berr
;
172 short *nrerr
, *ngerr
, *nberr
;
175 const int dr
=0xff/rmask
;
176 const int dg
=0xff/gmask
;
177 const int db
=0xff/bmask
;
180 puts("true color dither");
182 rerr
= (short*)alloca((image
->width
+2)*sizeof(short));
183 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
184 berr
= (short*)alloca((image
->width
+2)*sizeof(short));
185 nrerr
= (short*)alloca((image
->width
+2)*sizeof(short));
186 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
187 nberr
= (short*)alloca((image
->width
+2)*sizeof(short));
188 if (!rerr
|| !gerr
|| !berr
|| !nrerr
|| !ngerr
|| !nberr
) {
189 RErrorCode
= RERR_NOMEMORY
;
190 RDestroyXImage(ctx
, ximg
);
193 for (x
=0; x
<image
->width
; x
++) {
198 rerr
[x
] = gerr
[x
] = berr
[x
] = 0;
199 /* convert and dither the image to XImage */
200 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
201 if (y
<image
->height
-1) {
203 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
214 for (x
=0; x
<image
->width
; x
++) {
216 if (rerr
[x
]>0xff) rerr
[x
]=0xff; else if (rerr
[x
]<0) rerr
[x
]=0;
217 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
218 if (berr
[x
]>0xff) berr
[x
]=0xff; else if (berr
[x
]<0) berr
[x
]=0;
224 pixel
= (r
<<roffs
) | (g
<<goffs
) | (b
<<boffs
);
225 XPutPixel(ximg
->image
, x
, y
, pixel
);
227 rer
= rerr
[x
] - r
*dr
;
228 ger
= gerr
[x
] - g
*dg
;
229 ber
= berr
[x
] - b
*db
;
231 /* distribute error */
249 /* skip to next line */
268 image2PseudoColor(RContext
*ctx
, RImage
*image
)
271 register int x
, y
, r
, g
, b
;
272 unsigned char *red
, *grn
, *blu
;
274 const int cpc
=ctx
->attribs
->colors_per_channel
;
275 const unsigned short rmask
= cpc
-1; /* different sizes could be used */
276 const unsigned short gmask
= rmask
; /* for r,g,b */
277 const unsigned short bmask
= rmask
;
278 unsigned short *rtable
, *gtable
, *btable
;
279 const int cpccpc
= cpc
*cpc
;
282 /*register unsigned char maxrgb = 0xff;*/
284 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
289 red
= image
->data
[0];
290 grn
= image
->data
[1];
291 blu
= image
->data
[2];
293 data
= ximg
->image
->data
;
295 /* Tables are same at the moment because rmask==gmask==bmask. */
296 rtable
= computeTable(rmask
);
297 gtable
= computeTable(gmask
);
298 btable
= computeTable(bmask
);
300 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
301 RErrorCode
= RERR_NOMEMORY
;
302 RDestroyXImage(ctx
, ximg
);
306 if (ctx
->attribs
->render_mode
== RM_MATCH
) {
309 printf("pseudo color match with %d colors per channel\n", cpc
);
311 for (y
=0, ofs
= 0; y
<image
->height
; y
++) {
312 for (x
=0; x
<image
->width
; x
++, ofs
++) {
314 r
= rtable
[red
[ofs
]];
315 g
= gtable
[grn
[ofs
]];
316 b
= btable
[blu
[ofs
]];
317 pixel
= r
*cpccpc
+ g
*cpc
+ b
;
318 /*data[ofs] = ctx->colors[pixel].pixel;*/
319 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[pixel
].pixel
);
324 short *rerr
, *gerr
, *berr
;
325 short *nrerr
, *ngerr
, *nberr
;
328 const int dr
=0xff/rmask
;
329 const int dg
=0xff/gmask
;
330 const int db
=0xff/bmask
;
333 printf("pseudo color dithering with %d colors per channel\n", cpc
);
335 rerr
= (short*)alloca((image
->width
+2)*sizeof(short));
336 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
337 berr
= (short*)alloca((image
->width
+2)*sizeof(short));
338 nrerr
= (short*)alloca((image
->width
+2)*sizeof(short));
339 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
340 nberr
= (short*)alloca((image
->width
+2)*sizeof(short));
341 if (!rerr
|| !gerr
|| !berr
|| !nrerr
|| !ngerr
|| !nberr
) {
342 RErrorCode
= RERR_NOMEMORY
;
343 RDestroyXImage(ctx
, ximg
);
346 for (x
=0; x
<image
->width
; x
++) {
351 rerr
[x
] = gerr
[x
] = berr
[x
] = 0;
352 /* convert and dither the image to XImage */
353 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
354 if (y
<image
->height
-1) {
356 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
367 for (x
=0; x
<image
->width
; x
++, ofs
++) {
369 if (rerr
[x
]>0xff) rerr
[x
]=0xff; else if (rerr
[x
]<0) rerr
[x
]=0;
370 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
371 if (berr
[x
]>0xff) berr
[x
]=0xff; else if (berr
[x
]<0) berr
[x
]=0;
377 pixel
= r
*cpccpc
+ g
*cpc
+ b
;
378 /*data[ofs] = ctx->colors[pixel].pixel;*/
379 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[pixel
].pixel
);
382 rer
= rerr
[x
] - r
*dr
;
383 ger
= gerr
[x
] - g
*dg
;
384 ber
= berr
[x
] - b
*db
;
386 /* distribute error */
387 rerr
[x
+1]+=(rer
*7)/16;
388 gerr
[x
+1]+=(ger
*7)/16;
389 berr
[x
+1]+=(ber
*7)/16;
391 nrerr
[x
]+=(rer
*5)/16;
392 ngerr
[x
]+=(ger
*5)/16;
393 nberr
[x
]+=(ber
*5)/16;
396 nrerr
[x
-1]+=(rer
*3)/16;
397 ngerr
[x
-1]+=(ger
*3)/16;
398 nberr
[x
-1]+=(ber
*3)/16;
405 /* distribute error */
423 /* skip to next line */
437 ximg
->image
->data
= (char*)data
;
444 image2GrayScale(RContext
*ctx
, RImage
*image
)
447 register int x
, y
, g
;
448 unsigned char *red
, *grn
, *blu
;
449 const int cpc
=ctx
->attribs
->colors_per_channel
;
450 unsigned short gmask
;
451 unsigned short *table
;
454 /*register unsigned char maxrgb = 0xff;*/
456 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
461 red
= image
->data
[0];
462 grn
= image
->data
[1];
463 blu
= image
->data
[2];
465 data
= ximg
->image
->data
;
467 if (ctx
->vclass
== StaticGray
)
468 gmask
= (1<<ctx
->depth
) - 1; /* use all grays */
470 gmask
= cpc
*cpc
*cpc
-1;
472 table
= computeTable(gmask
);
475 RErrorCode
= RERR_NOMEMORY
;
476 RDestroyXImage(ctx
, ximg
);
480 if (ctx
->attribs
->render_mode
== RM_MATCH
) {
483 printf("grayscale match with %d colors per channel\n", cpc
);
485 for (y
=0, ofs
= 0; y
<image
->height
; y
++) {
486 for (x
=0; x
<image
->width
; x
++, ofs
++) {
488 g
= table
[(red
[ofs
]*30+grn
[ofs
]*59+blu
[ofs
]*11)/100];
490 /*data[ofs] = ctx->colors[g].pixel;*/
491 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[g
].pixel
);
500 const int dg
=0xff/gmask
;
503 printf("grayscale dither with %d colors per channel\n", cpc
);
505 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
506 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
507 if (!gerr
|| !ngerr
) {
508 RErrorCode
= RERR_NOMEMORY
;
509 RDestroyXImage(ctx
, ximg
);
512 for (x
=0; x
<image
->width
; x
++) {
513 gerr
[x
] = (red
[x
]*30 + grn
[x
]*59 + blu
[x
]*11)/100;
516 /* convert and dither the image to XImage */
517 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
518 if (y
<image
->height
-1) {
520 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
521 ngerr
[x
] = (red
[x1
]*30 + grn
[x1
]*59 + blu
[x1
]*11)/100;
525 ngerr
[x
] = (red
[x1
]*30 + grn
[x1
]*59 + blu
[x1
]*11)/100;
527 for (x
=0; x
<image
->width
; x
++, ofs
++) {
529 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
533 /*data[ofs] = ctx->colors[g].pixel;*/
534 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[g
].pixel
);
536 ger
= gerr
[x
] - g
*dg
;
538 /* distribute error */
547 /* skip to next line */
553 ximg
->image
->data
= (char*)data
;
560 image2Bitmap(RContext
*ctx
, RImage
*image
, int threshold
)
563 unsigned char *alpha
;
566 ximg
= RCreateXImage(ctx
, 1, image
->width
, image
->height
);
570 alpha
= image
->data
[3];
572 for (y
= 0; y
< image
->height
; y
++) {
573 for (x
= 0; x
< image
->width
; x
++) {
574 XPutPixel(ximg
->image
, x
, y
, (*alpha
<= threshold
? 0 : 1));
585 RConvertImage(RContext
*context
, RImage
*image
, Pixmap
*pixmap
)
592 assert(context
!=NULL
);
594 assert(pixmap
!=NULL
);
596 /* clear error message */
597 if (context
->vclass
== TrueColor
)
598 ximg
= image2TrueColor(context
, image
);
599 else if (context
->vclass
== PseudoColor
|| context
->vclass
== StaticColor
)
600 ximg
= image2PseudoColor(context
, image
);
601 else if (context
->vclass
== GrayScale
|| context
->vclass
== StaticGray
)
602 ximg
= image2GrayScale(context
, image
);
612 *pixmap
= XCreatePixmap(context
->dpy
, context
->drawable
, image
->width
,
613 image
->height
, context
->depth
);
616 if (context
->flags
.use_shared_pixmap
&& ximg
->is_shared
)
617 tmp
= R_CreateXImageMappedPixmap(context
, ximg
);
622 * We have to copy the shm Pixmap into a normal Pixmap because
623 * otherwise, we would have to control when Pixmaps are freed so
624 * that we can detach their shm segments. This is a problem if the
625 * program crash, leaving stale shared memory segments in the
626 * system (lots of them). But with some work, we can optimize
627 * things and remove this XCopyArea. This will require
628 * explicitly freeing all pixmaps when exiting or restarting
631 XCopyArea(context
->dpy
, tmp
, *pixmap
, context
->copy_gc
, 0, 0,
632 image
->width
, image
->height
, 0, 0);
633 XFreePixmap(context
->dpy
, tmp
);
635 RPutXImage(context
, *pixmap
, context
->copy_gc
, ximg
, 0, 0, 0, 0,
636 image
->width
, image
->height
);
639 RPutXImage(context
, *pixmap
, context
->copy_gc
, ximg
, 0, 0, 0, 0,
640 image
->width
, image
->height
);
643 RDestroyXImage(context
, ximg
);
653 RConvertImageMask(RContext
*context
, RImage
*image
, Pixmap
*pixmap
,
654 Pixmap
*mask
, int threshold
)
660 assert(context
!=NULL
);
662 assert(pixmap
!=NULL
);
665 if (!RConvertImage(context
, image
, pixmap
))
668 if (image
->data
[3]==NULL
) {
673 ximg
= image2Bitmap(context
, image
, threshold
);
681 *mask
= XCreatePixmap(context
->dpy
, context
->drawable
, image
->width
,
683 gcv
.foreground
= context
->black
;
684 gcv
.background
= context
->white
;
685 gcv
.graphics_exposures
= False
;
686 gc
= XCreateGC(context
->dpy
, *mask
, GCForeground
|GCBackground
687 |GCGraphicsExposures
, &gcv
);
688 RPutXImage(context
, *mask
, gc
, ximg
, 0, 0, 0, 0,
689 image
->width
, image
->height
);
690 RDestroyXImage(context
, ximg
);
700 RGetClosestXColor(RContext
*context
, RColor
*color
, XColor
*retColor
)
702 if (context
->vclass
== TrueColor
) {
703 unsigned short rmask
, gmask
, bmask
;
704 unsigned short roffs
, goffs
, boffs
;
705 unsigned short *rtable
, *gtable
, *btable
;
707 roffs
= context
->red_offset
;
708 goffs
= context
->green_offset
;
709 boffs
= context
->blue_offset
;
711 rmask
= context
->visual
->red_mask
>> roffs
;
712 gmask
= context
->visual
->green_mask
>> goffs
;
713 bmask
= context
->visual
->blue_mask
>> boffs
;
715 rtable
= computeTable(rmask
);
716 gtable
= computeTable(gmask
);
717 btable
= computeTable(bmask
);
719 retColor
->pixel
= (rtable
[color
->red
]<<roffs
) |
720 (gtable
[color
->green
]<<goffs
) | (btable
[color
->blue
]<<boffs
);
722 retColor
->red
= color
->red
<< 8;
723 retColor
->green
= color
->green
<< 8;
724 retColor
->blue
= color
->blue
<< 8;
725 retColor
->flags
= DoRed
|DoGreen
|DoBlue
;
727 } else if (context
->vclass
== PseudoColor
|| context
->vclass
== StaticColor
) {
728 const int cpc
=context
->attribs
->colors_per_channel
;
729 const unsigned short rmask
= cpc
-1; /* different sizes could be used */
730 const unsigned short gmask
= rmask
; /* for r,g,b */
731 const unsigned short bmask
= rmask
;
732 unsigned short *rtable
, *gtable
, *btable
;
733 const int cpccpc
= cpc
*cpc
;
736 rtable
= computeTable(rmask
);
737 gtable
= computeTable(gmask
);
738 btable
= computeTable(bmask
);
740 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
741 RErrorCode
= RERR_NOMEMORY
;
744 index
= rtable
[color
->red
]*cpccpc
+ gtable
[color
->green
]*cpc
745 + btable
[color
->blue
];
746 *retColor
= context
->colors
[index
];
747 } else if (context
->vclass
== GrayScale
|| context
->vclass
== StaticGray
) {
749 const int cpc
= context
->attribs
->colors_per_channel
;
750 unsigned short gmask
;
751 unsigned short *table
;
754 if (context
->vclass
== StaticGray
)
755 gmask
= (1<<context
->depth
) - 1; /* use all grays */
757 gmask
= cpc
*cpc
*cpc
-1;
759 table
= computeTable(gmask
);
763 index
= table
[(color
->red
*30 + color
->green
*59 + color
->blue
*11)/100];
765 *retColor
= context
->colors
[index
];
767 RErrorCode
= RERR_INTERNAL
;