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
;
98 image2TrueColorD16(RContext
*ctx
, RImage
*image
)
101 register int x
, y
, r
, g
, b
;
102 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
;
125 rtable
= computeTable(rmask
);
126 gtable
= computeTable(gmask
);
127 btable
= computeTable(bmask
);
129 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
130 RErrorCode
= RERR_NOMEMORY
;
131 RDestroyXImage(ctx
, ximg
);
137 short *rerr
, *gerr
, *berr
;
138 short *nrerr
, *ngerr
, *nberr
;
140 unsigned short *dataP
;
143 const int dr
=0xff/rmask
;
144 const int dg
=0xff/gmask
;
145 const int db
=0xff/bmask
;
147 rerr
= (short*)alloca((image
->width
+2)*sizeof(short));
148 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
149 berr
= (short*)alloca((image
->width
+2)*sizeof(short));
150 nrerr
= (short*)alloca((image
->width
+2)*sizeof(short));
151 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
152 nberr
= (short*)alloca((image
->width
+2)*sizeof(short));
153 if (!rerr
|| !gerr
|| !berr
|| !nrerr
|| !ngerr
|| !nberr
) {
154 RErrorCode
= RERR_NOMEMORY
;
155 RDestroyXImage(ctx
, ximg
);
158 for (x
=0; x
<image
->width
; x
++) {
163 rerr
[x
] = gerr
[x
] = berr
[x
] = 0;
165 dataP
= (unsigned short*)ximg
->image
->data
;
166 line_offset
= ximg
->image
->bytes_per_line
- image
->width
* 2;
168 /* convert and dither the image to XImage */
169 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
170 if (y
<image
->height
-1) {
172 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
183 for (x
=0; x
<image
->width
; x
++) {
185 if (rerr
[x
]>0xff) rerr
[x
]=0xff; else if (rerr
[x
]<0) rerr
[x
]=0;
186 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
187 if (berr
[x
]>0xff) berr
[x
]=0xff; else if (berr
[x
]<0) berr
[x
]=0;
193 *(dataP
++) = (r
<<roffs
) | (g
<<goffs
) | (b
<<boffs
);
196 rer
= rerr
[x
] - r
*dr
;
197 ger
= gerr
[x
] - g
*dg
;
198 ber
= berr
[x
] - b
*db
;
200 /* distribute error */
218 /*(char*)dataP += line_offset;*/
219 dataP
= (unsigned short *)((char *)dataP
+ line_offset
);
221 /* skip to next line */
240 image2TrueColor(RContext
*ctx
, RImage
*image
)
243 register int x
, y
, r
, g
, b
;
244 unsigned char *red
, *grn
, *blu
;
246 unsigned short rmask
, gmask
, bmask
;
247 unsigned short roffs
, goffs
, boffs
;
248 unsigned short *rtable
, *gtable
, *btable
;
251 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
256 red
= image
->data
[0];
257 grn
= image
->data
[1];
258 blu
= image
->data
[2];
260 roffs
= ctx
->red_offset
;
261 goffs
= ctx
->green_offset
;
262 boffs
= ctx
->blue_offset
;
264 rmask
= ctx
->visual
->red_mask
>> roffs
;
265 gmask
= ctx
->visual
->green_mask
>> goffs
;
266 bmask
= ctx
->visual
->blue_mask
>> boffs
;
269 /* this do not seem to increase speed. Only 0.06 second faster in
270 * rendering a 800x600 image to pixmap. 1.12 sec instead of 1.18.
271 * But does not require a 256*256*256 lookup table.
273 if (ctx
->depth
==24) {
275 puts("true color match for 24bpp");
277 for (y
=0; y
< image
->height
; y
++) {
278 for (x
=0; x
< image
->width
; x
++) {
279 pixel
= (*(red
++)<<roffs
) | (*(grn
++)<<goffs
) | (*(blu
++)<<boffs
);
280 XPutPixel(ximg
->image
, x
, y
, pixel
);
287 rtable
= computeTable(rmask
);
288 gtable
= computeTable(gmask
);
289 btable
= computeTable(bmask
);
291 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
292 RErrorCode
= RERR_NOMEMORY
;
293 RDestroyXImage(ctx
, ximg
);
297 if (ctx
->attribs
->render_mode
==RBestMatchRendering
) {
300 puts("true color match");
302 for (y
=0, ofs
=0; y
< image
->height
; y
++) {
303 for (x
=0; x
< image
->width
; x
++, ofs
++) {
305 r
= rtable
[red
[ofs
]];
306 g
= gtable
[grn
[ofs
]];
307 b
= btable
[blu
[ofs
]];
308 pixel
= (r
<<roffs
) | (g
<<goffs
) | (b
<<boffs
);
309 XPutPixel(ximg
->image
, x
, y
, pixel
);
314 short *rerr
, *gerr
, *berr
;
315 short *nrerr
, *ngerr
, *nberr
;
318 const int dr
=0xff/rmask
;
319 const int dg
=0xff/gmask
;
320 const int db
=0xff/bmask
;
323 puts("true color dither");
325 rerr
= (short*)alloca((image
->width
+2)*sizeof(short));
326 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
327 berr
= (short*)alloca((image
->width
+2)*sizeof(short));
328 nrerr
= (short*)alloca((image
->width
+2)*sizeof(short));
329 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
330 nberr
= (short*)alloca((image
->width
+2)*sizeof(short));
331 if (!rerr
|| !gerr
|| !berr
|| !nrerr
|| !ngerr
|| !nberr
) {
332 RErrorCode
= RERR_NOMEMORY
;
333 RDestroyXImage(ctx
, ximg
);
336 for (x
=0; x
<image
->width
; x
++) {
341 rerr
[x
] = gerr
[x
] = berr
[x
] = 0;
342 /* convert and dither the image to XImage */
343 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
344 if (y
<image
->height
-1) {
346 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
357 for (x
=0; x
<image
->width
; x
++) {
359 if (rerr
[x
]>0xff) rerr
[x
]=0xff; else if (rerr
[x
]<0) rerr
[x
]=0;
360 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
361 if (berr
[x
]>0xff) berr
[x
]=0xff; else if (berr
[x
]<0) berr
[x
]=0;
367 pixel
= (r
<<roffs
) | (g
<<goffs
) | (b
<<boffs
);
368 XPutPixel(ximg
->image
, x
, y
, pixel
);
370 rer
= rerr
[x
] - r
*dr
;
371 ger
= gerr
[x
] - g
*dg
;
372 ber
= berr
[x
] - b
*db
;
374 /* distribute error */
392 /* skip to next line */
413 image2PseudoColor(RContext
*ctx
, RImage
*image
)
416 register int x
, y
, r
, g
, b
;
417 unsigned char *red
, *grn
, *blu
;
419 const int cpc
=ctx
->attribs
->colors_per_channel
;
420 const unsigned short rmask
= cpc
-1; /* different sizes could be used */
421 const unsigned short gmask
= rmask
; /* for r,g,b */
422 const unsigned short bmask
= rmask
;
423 unsigned short *rtable
, *gtable
, *btable
;
424 const int cpccpc
= cpc
*cpc
;
427 /*register unsigned char maxrgb = 0xff;*/
429 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
434 red
= image
->data
[0];
435 grn
= image
->data
[1];
436 blu
= image
->data
[2];
438 data
= (unsigned char *)ximg
->image
->data
;
440 /* Tables are same at the moment because rmask==gmask==bmask. */
441 rtable
= computeTable(rmask
);
442 gtable
= computeTable(gmask
);
443 btable
= computeTable(bmask
);
445 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
446 RErrorCode
= RERR_NOMEMORY
;
447 RDestroyXImage(ctx
, ximg
);
451 if (ctx
->attribs
->render_mode
== RBestMatchRendering
) {
454 printf("pseudo color match with %d colors per channel\n", cpc
);
456 for (y
=0, ofs
= 0; y
<image
->height
; y
++) {
457 for (x
=0; x
<image
->width
; x
++, ofs
++) {
459 r
= rtable
[red
[ofs
]];
460 g
= gtable
[grn
[ofs
]];
461 b
= btable
[blu
[ofs
]];
462 pixel
= r
*cpccpc
+ g
*cpc
+ b
;
463 /*data[ofs] = ctx->colors[pixel].pixel;*/
464 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[pixel
].pixel
);
469 short *rerr
, *gerr
, *berr
;
470 short *nrerr
, *ngerr
, *nberr
;
473 const int dr
=0xff/rmask
;
474 const int dg
=0xff/gmask
;
475 const int db
=0xff/bmask
;
478 printf("pseudo color dithering with %d colors per channel\n", cpc
);
480 rerr
= (short*)alloca((image
->width
+2)*sizeof(short));
481 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
482 berr
= (short*)alloca((image
->width
+2)*sizeof(short));
483 nrerr
= (short*)alloca((image
->width
+2)*sizeof(short));
484 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
485 nberr
= (short*)alloca((image
->width
+2)*sizeof(short));
486 if (!rerr
|| !gerr
|| !berr
|| !nrerr
|| !ngerr
|| !nberr
) {
487 RErrorCode
= RERR_NOMEMORY
;
488 RDestroyXImage(ctx
, ximg
);
491 for (x
=0; x
<image
->width
; x
++) {
496 rerr
[x
] = gerr
[x
] = berr
[x
] = 0;
497 /* convert and dither the image to XImage */
498 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
499 if (y
<image
->height
-1) {
501 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
512 for (x
=0; x
<image
->width
; x
++, ofs
++) {
514 if (rerr
[x
]>0xff) rerr
[x
]=0xff; else if (rerr
[x
]<0) rerr
[x
]=0;
515 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
516 if (berr
[x
]>0xff) berr
[x
]=0xff; else if (berr
[x
]<0) berr
[x
]=0;
522 pixel
= r
*cpccpc
+ g
*cpc
+ b
;
523 /*data[ofs] = ctx->colors[pixel].pixel;*/
524 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[pixel
].pixel
);
527 rer
= rerr
[x
] - r
*dr
;
528 ger
= gerr
[x
] - g
*dg
;
529 ber
= berr
[x
] - b
*db
;
531 /* distribute error */
532 rerr
[x
+1]+=(rer
*7)/16;
533 gerr
[x
+1]+=(ger
*7)/16;
534 berr
[x
+1]+=(ber
*7)/16;
536 nrerr
[x
]+=(rer
*5)/16;
537 ngerr
[x
]+=(ger
*5)/16;
538 nberr
[x
]+=(ber
*5)/16;
541 nrerr
[x
-1]+=(rer
*3)/16;
542 ngerr
[x
-1]+=(ger
*3)/16;
543 nberr
[x
-1]+=(ber
*3)/16;
550 /* distribute error */
568 /* skip to next line */
582 ximg
->image
->data
= (char*)data
;
589 image2GrayScale(RContext
*ctx
, RImage
*image
)
592 register int x
, y
, g
;
593 unsigned char *red
, *grn
, *blu
;
594 const int cpc
=ctx
->attribs
->colors_per_channel
;
595 unsigned short gmask
;
596 unsigned short *table
;
599 /*register unsigned char maxrgb = 0xff;*/
601 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
606 red
= image
->data
[0];
607 grn
= image
->data
[1];
608 blu
= image
->data
[2];
610 data
= (unsigned char *)ximg
->image
->data
;
612 if (ctx
->vclass
== StaticGray
)
613 gmask
= (1<<ctx
->depth
) - 1; /* use all grays */
615 gmask
= cpc
*cpc
*cpc
-1;
617 table
= computeTable(gmask
);
620 RErrorCode
= RERR_NOMEMORY
;
621 RDestroyXImage(ctx
, ximg
);
625 if (ctx
->attribs
->render_mode
== RBestMatchRendering
) {
628 printf("grayscale match with %d colors per channel\n", cpc
);
630 for (y
=0, ofs
= 0; y
<image
->height
; y
++) {
631 for (x
=0; x
<image
->width
; x
++, ofs
++) {
633 g
= table
[(red
[ofs
]*30+grn
[ofs
]*59+blu
[ofs
]*11)/100];
635 /*data[ofs] = ctx->colors[g].pixel;*/
636 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[g
].pixel
);
645 const int dg
=0xff/gmask
;
648 printf("grayscale dither with %d colors per channel\n", cpc
);
650 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
651 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
652 if (!gerr
|| !ngerr
) {
653 RErrorCode
= RERR_NOMEMORY
;
654 RDestroyXImage(ctx
, ximg
);
657 for (x
=0; x
<image
->width
; x
++) {
658 gerr
[x
] = (red
[x
]*30 + grn
[x
]*59 + blu
[x
]*11)/100;
661 /* convert and dither the image to XImage */
662 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
663 if (y
<image
->height
-1) {
665 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
666 ngerr
[x
] = (red
[x1
]*30 + grn
[x1
]*59 + blu
[x1
]*11)/100;
670 ngerr
[x
] = (red
[x1
]*30 + grn
[x1
]*59 + blu
[x1
]*11)/100;
672 for (x
=0; x
<image
->width
; x
++, ofs
++) {
674 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
678 /*data[ofs] = ctx->colors[g].pixel;*/
679 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[g
].pixel
);
681 ger
= gerr
[x
] - g
*dg
;
683 /* distribute error */
692 /* skip to next line */
698 ximg
->image
->data
= (char*)data
;
705 image2Bitmap(RContext
*ctx
, RImage
*image
, int threshold
)
708 unsigned char *alpha
;
711 ximg
= RCreateXImage(ctx
, 1, image
->width
, image
->height
);
715 alpha
= image
->data
[3];
717 for (y
= 0; y
< image
->height
; y
++) {
718 for (x
= 0; x
< image
->width
; x
++) {
719 XPutPixel(ximg
->image
, x
, y
, (*alpha
<= threshold
? 0 : 1));
730 RConvertImage(RContext
*context
, RImage
*image
, Pixmap
*pixmap
)
737 assert(context
!=NULL
);
739 assert(pixmap
!=NULL
);
741 /* clear error message */
742 if (context
->vclass
== TrueColor
) {
744 if (context
->attribs
->render_mode
== RDitheredRendering
745 && (context
->depth
== 15 || context
->depth
== 16))
746 ximg
= image2TrueColorD16(context
, image
);
748 ximg
= image2TrueColor(context
, image
);
750 } else if (context
->vclass
== PseudoColor
|| context
->vclass
== StaticColor
)
751 ximg
= image2PseudoColor(context
, image
);
752 else if (context
->vclass
== GrayScale
|| context
->vclass
== StaticGray
)
753 ximg
= image2GrayScale(context
, image
);
763 *pixmap
= XCreatePixmap(context
->dpy
, context
->drawable
, image
->width
,
764 image
->height
, context
->depth
);
767 if (context
->flags
.use_shared_pixmap
&& ximg
->is_shared
)
768 tmp
= R_CreateXImageMappedPixmap(context
, ximg
);
773 * We have to copy the shm Pixmap into a normal Pixmap because
774 * otherwise, we would have to control when Pixmaps are freed so
775 * that we can detach their shm segments. This is a problem if the
776 * program crash, leaving stale shared memory segments in the
777 * system (lots of them). But with some work, we can optimize
778 * things and remove this XCopyArea. This will require
779 * explicitly freeing all pixmaps when exiting or restarting
782 XCopyArea(context
->dpy
, tmp
, *pixmap
, context
->copy_gc
, 0, 0,
783 image
->width
, image
->height
, 0, 0);
784 XFreePixmap(context
->dpy
, tmp
);
786 RPutXImage(context
, *pixmap
, context
->copy_gc
, ximg
, 0, 0, 0, 0,
787 image
->width
, image
->height
);
790 RPutXImage(context
, *pixmap
, context
->copy_gc
, ximg
, 0, 0, 0, 0,
791 image
->width
, image
->height
);
794 RDestroyXImage(context
, ximg
);
804 RConvertImageMask(RContext
*context
, RImage
*image
, Pixmap
*pixmap
,
805 Pixmap
*mask
, int threshold
)
811 assert(context
!=NULL
);
813 assert(pixmap
!=NULL
);
816 if (!RConvertImage(context
, image
, pixmap
))
819 if (image
->data
[3]==NULL
) {
824 ximg
= image2Bitmap(context
, image
, threshold
);
832 *mask
= XCreatePixmap(context
->dpy
, context
->drawable
, image
->width
,
834 gcv
.foreground
= context
->black
;
835 gcv
.background
= context
->white
;
836 gcv
.graphics_exposures
= False
;
837 gc
= XCreateGC(context
->dpy
, *mask
, GCForeground
|GCBackground
838 |GCGraphicsExposures
, &gcv
);
839 RPutXImage(context
, *mask
, gc
, ximg
, 0, 0, 0, 0,
840 image
->width
, image
->height
);
841 RDestroyXImage(context
, ximg
);
851 RGetClosestXColor(RContext
*context
, RColor
*color
, XColor
*retColor
)
853 if (context
->vclass
== TrueColor
) {
854 unsigned short rmask
, gmask
, bmask
;
855 unsigned short roffs
, goffs
, boffs
;
856 unsigned short *rtable
, *gtable
, *btable
;
858 roffs
= context
->red_offset
;
859 goffs
= context
->green_offset
;
860 boffs
= context
->blue_offset
;
862 rmask
= context
->visual
->red_mask
>> roffs
;
863 gmask
= context
->visual
->green_mask
>> goffs
;
864 bmask
= context
->visual
->blue_mask
>> boffs
;
866 rtable
= computeTable(rmask
);
867 gtable
= computeTable(gmask
);
868 btable
= computeTable(bmask
);
870 retColor
->pixel
= (rtable
[color
->red
]<<roffs
) |
871 (gtable
[color
->green
]<<goffs
) | (btable
[color
->blue
]<<boffs
);
873 retColor
->red
= color
->red
<< 8;
874 retColor
->green
= color
->green
<< 8;
875 retColor
->blue
= color
->blue
<< 8;
876 retColor
->flags
= DoRed
|DoGreen
|DoBlue
;
878 } else if (context
->vclass
== PseudoColor
|| context
->vclass
== StaticColor
) {
879 const int cpc
=context
->attribs
->colors_per_channel
;
880 const unsigned short rmask
= cpc
-1; /* different sizes could be used */
881 const unsigned short gmask
= rmask
; /* for r,g,b */
882 const unsigned short bmask
= rmask
;
883 unsigned short *rtable
, *gtable
, *btable
;
884 const int cpccpc
= cpc
*cpc
;
887 rtable
= computeTable(rmask
);
888 gtable
= computeTable(gmask
);
889 btable
= computeTable(bmask
);
891 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
892 RErrorCode
= RERR_NOMEMORY
;
895 index
= rtable
[color
->red
]*cpccpc
+ gtable
[color
->green
]*cpc
896 + btable
[color
->blue
];
897 *retColor
= context
->colors
[index
];
898 } else if (context
->vclass
== GrayScale
|| context
->vclass
== StaticGray
) {
900 const int cpc
= context
->attribs
->colors_per_channel
;
901 unsigned short gmask
;
902 unsigned short *table
;
905 if (context
->vclass
== StaticGray
)
906 gmask
= (1<<context
->depth
) - 1; /* use all grays */
908 gmask
= cpc
*cpc
*cpc
-1;
910 table
= computeTable(gmask
);
914 index
= table
[(color
->red
*30 + color
->green
*59 + color
->blue
*11)/100];
916 *retColor
= context
->colors
[index
];
918 RErrorCode
= RERR_INTERNAL
;