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
);
220 /* skip to next line */
239 image2TrueColor(RContext
*ctx
, RImage
*image
)
242 register int x
, y
, r
, g
, b
;
243 unsigned char *red
, *grn
, *blu
;
245 unsigned short rmask
, gmask
, bmask
;
246 unsigned short roffs
, goffs
, boffs
;
247 unsigned short *rtable
, *gtable
, *btable
;
250 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
255 red
= image
->data
[0];
256 grn
= image
->data
[1];
257 blu
= image
->data
[2];
259 roffs
= ctx
->red_offset
;
260 goffs
= ctx
->green_offset
;
261 boffs
= ctx
->blue_offset
;
263 rmask
= ctx
->visual
->red_mask
>> roffs
;
264 gmask
= ctx
->visual
->green_mask
>> goffs
;
265 bmask
= ctx
->visual
->blue_mask
>> boffs
;
268 /* this do not seem to increase speed. Only 0.06 second faster in
269 * rendering a 800x600 image to pixmap. 1.12 sec instead of 1.18.
270 * But does not require a 256*256*256 lookup table.
272 if (ctx
->depth
==24) {
274 puts("true color match for 24bpp");
276 for (y
=0; y
< image
->height
; y
++) {
277 for (x
=0; x
< image
->width
; x
++) {
278 pixel
= (*(red
++)<<roffs
) | (*(grn
++)<<goffs
) | (*(blu
++)<<boffs
);
279 XPutPixel(ximg
->image
, x
, y
, pixel
);
286 rtable
= computeTable(rmask
);
287 gtable
= computeTable(gmask
);
288 btable
= computeTable(bmask
);
290 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
291 RErrorCode
= RERR_NOMEMORY
;
292 RDestroyXImage(ctx
, ximg
);
296 if (ctx
->attribs
->render_mode
==RBestMatchRendering
) {
299 puts("true color match");
301 for (y
=0, ofs
=0; y
< image
->height
; y
++) {
302 for (x
=0; x
< image
->width
; x
++, ofs
++) {
304 r
= rtable
[red
[ofs
]];
305 g
= gtable
[grn
[ofs
]];
306 b
= btable
[blu
[ofs
]];
307 pixel
= (r
<<roffs
) | (g
<<goffs
) | (b
<<boffs
);
308 XPutPixel(ximg
->image
, x
, y
, pixel
);
313 short *rerr
, *gerr
, *berr
;
314 short *nrerr
, *ngerr
, *nberr
;
317 const int dr
=0xff/rmask
;
318 const int dg
=0xff/gmask
;
319 const int db
=0xff/bmask
;
322 puts("true color dither");
324 rerr
= (short*)alloca((image
->width
+2)*sizeof(short));
325 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
326 berr
= (short*)alloca((image
->width
+2)*sizeof(short));
327 nrerr
= (short*)alloca((image
->width
+2)*sizeof(short));
328 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
329 nberr
= (short*)alloca((image
->width
+2)*sizeof(short));
330 if (!rerr
|| !gerr
|| !berr
|| !nrerr
|| !ngerr
|| !nberr
) {
331 RErrorCode
= RERR_NOMEMORY
;
332 RDestroyXImage(ctx
, ximg
);
335 for (x
=0; x
<image
->width
; x
++) {
340 rerr
[x
] = gerr
[x
] = berr
[x
] = 0;
341 /* convert and dither the image to XImage */
342 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
343 if (y
<image
->height
-1) {
345 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
356 for (x
=0; x
<image
->width
; x
++) {
358 if (rerr
[x
]>0xff) rerr
[x
]=0xff; else if (rerr
[x
]<0) rerr
[x
]=0;
359 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
360 if (berr
[x
]>0xff) berr
[x
]=0xff; else if (berr
[x
]<0) berr
[x
]=0;
366 pixel
= (r
<<roffs
) | (g
<<goffs
) | (b
<<boffs
);
367 XPutPixel(ximg
->image
, x
, y
, pixel
);
369 rer
= rerr
[x
] - r
*dr
;
370 ger
= gerr
[x
] - g
*dg
;
371 ber
= berr
[x
] - b
*db
;
373 /* distribute error */
391 /* skip to next line */
412 image2PseudoColor(RContext
*ctx
, RImage
*image
)
415 register int x
, y
, r
, g
, b
;
416 unsigned char *red
, *grn
, *blu
;
418 const int cpc
=ctx
->attribs
->colors_per_channel
;
419 const unsigned short rmask
= cpc
-1; /* different sizes could be used */
420 const unsigned short gmask
= rmask
; /* for r,g,b */
421 const unsigned short bmask
= rmask
;
422 unsigned short *rtable
, *gtable
, *btable
;
423 const int cpccpc
= cpc
*cpc
;
426 /*register unsigned char maxrgb = 0xff;*/
428 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
433 red
= image
->data
[0];
434 grn
= image
->data
[1];
435 blu
= image
->data
[2];
437 data
= (unsigned char *)ximg
->image
->data
;
439 /* Tables are same at the moment because rmask==gmask==bmask. */
440 rtable
= computeTable(rmask
);
441 gtable
= computeTable(gmask
);
442 btable
= computeTable(bmask
);
444 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
445 RErrorCode
= RERR_NOMEMORY
;
446 RDestroyXImage(ctx
, ximg
);
450 if (ctx
->attribs
->render_mode
== RBestMatchRendering
) {
453 printf("pseudo color match with %d colors per channel\n", cpc
);
455 for (y
=0, ofs
= 0; y
<image
->height
; y
++) {
456 for (x
=0; x
<image
->width
; x
++, ofs
++) {
458 r
= rtable
[red
[ofs
]];
459 g
= gtable
[grn
[ofs
]];
460 b
= btable
[blu
[ofs
]];
461 pixel
= r
*cpccpc
+ g
*cpc
+ b
;
462 /*data[ofs] = ctx->colors[pixel].pixel;*/
463 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[pixel
].pixel
);
468 short *rerr
, *gerr
, *berr
;
469 short *nrerr
, *ngerr
, *nberr
;
472 const int dr
=0xff/rmask
;
473 const int dg
=0xff/gmask
;
474 const int db
=0xff/bmask
;
477 printf("pseudo color dithering with %d colors per channel\n", cpc
);
479 rerr
= (short*)alloca((image
->width
+2)*sizeof(short));
480 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
481 berr
= (short*)alloca((image
->width
+2)*sizeof(short));
482 nrerr
= (short*)alloca((image
->width
+2)*sizeof(short));
483 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
484 nberr
= (short*)alloca((image
->width
+2)*sizeof(short));
485 if (!rerr
|| !gerr
|| !berr
|| !nrerr
|| !ngerr
|| !nberr
) {
486 RErrorCode
= RERR_NOMEMORY
;
487 RDestroyXImage(ctx
, ximg
);
490 for (x
=0; x
<image
->width
; x
++) {
495 rerr
[x
] = gerr
[x
] = berr
[x
] = 0;
496 /* convert and dither the image to XImage */
497 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
498 if (y
<image
->height
-1) {
500 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
511 for (x
=0; x
<image
->width
; x
++, ofs
++) {
513 if (rerr
[x
]>0xff) rerr
[x
]=0xff; else if (rerr
[x
]<0) rerr
[x
]=0;
514 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
515 if (berr
[x
]>0xff) berr
[x
]=0xff; else if (berr
[x
]<0) berr
[x
]=0;
521 pixel
= r
*cpccpc
+ g
*cpc
+ b
;
522 /*data[ofs] = ctx->colors[pixel].pixel;*/
523 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[pixel
].pixel
);
526 rer
= rerr
[x
] - r
*dr
;
527 ger
= gerr
[x
] - g
*dg
;
528 ber
= berr
[x
] - b
*db
;
530 /* distribute error */
531 rerr
[x
+1]+=(rer
*7)/16;
532 gerr
[x
+1]+=(ger
*7)/16;
533 berr
[x
+1]+=(ber
*7)/16;
535 nrerr
[x
]+=(rer
*5)/16;
536 ngerr
[x
]+=(ger
*5)/16;
537 nberr
[x
]+=(ber
*5)/16;
540 nrerr
[x
-1]+=(rer
*3)/16;
541 ngerr
[x
-1]+=(ger
*3)/16;
542 nberr
[x
-1]+=(ber
*3)/16;
549 /* distribute error */
567 /* skip to next line */
581 ximg
->image
->data
= (char*)data
;
588 image2GrayScale(RContext
*ctx
, RImage
*image
)
591 register int x
, y
, g
;
592 unsigned char *red
, *grn
, *blu
;
593 const int cpc
=ctx
->attribs
->colors_per_channel
;
594 unsigned short gmask
;
595 unsigned short *table
;
598 /*register unsigned char maxrgb = 0xff;*/
600 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
605 red
= image
->data
[0];
606 grn
= image
->data
[1];
607 blu
= image
->data
[2];
609 data
= (unsigned char *)ximg
->image
->data
;
611 if (ctx
->vclass
== StaticGray
)
612 gmask
= (1<<ctx
->depth
) - 1; /* use all grays */
614 gmask
= cpc
*cpc
*cpc
-1;
616 table
= computeTable(gmask
);
619 RErrorCode
= RERR_NOMEMORY
;
620 RDestroyXImage(ctx
, ximg
);
624 if (ctx
->attribs
->render_mode
== RBestMatchRendering
) {
627 printf("grayscale match with %d colors per channel\n", cpc
);
629 for (y
=0, ofs
= 0; y
<image
->height
; y
++) {
630 for (x
=0; x
<image
->width
; x
++, ofs
++) {
632 g
= table
[(red
[ofs
]*30+grn
[ofs
]*59+blu
[ofs
]*11)/100];
634 /*data[ofs] = ctx->colors[g].pixel;*/
635 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[g
].pixel
);
644 const int dg
=0xff/gmask
;
647 printf("grayscale dither with %d colors per channel\n", cpc
);
649 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
650 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
651 if (!gerr
|| !ngerr
) {
652 RErrorCode
= RERR_NOMEMORY
;
653 RDestroyXImage(ctx
, ximg
);
656 for (x
=0; x
<image
->width
; x
++) {
657 gerr
[x
] = (red
[x
]*30 + grn
[x
]*59 + blu
[x
]*11)/100;
660 /* convert and dither the image to XImage */
661 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
662 if (y
<image
->height
-1) {
664 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
665 ngerr
[x
] = (red
[x1
]*30 + grn
[x1
]*59 + blu
[x1
]*11)/100;
669 ngerr
[x
] = (red
[x1
]*30 + grn
[x1
]*59 + blu
[x1
]*11)/100;
671 for (x
=0; x
<image
->width
; x
++, ofs
++) {
673 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
677 /*data[ofs] = ctx->colors[g].pixel;*/
678 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[g
].pixel
);
680 ger
= gerr
[x
] - g
*dg
;
682 /* distribute error */
691 /* skip to next line */
697 ximg
->image
->data
= (char*)data
;
704 image2Bitmap(RContext
*ctx
, RImage
*image
, int threshold
)
707 unsigned char *alpha
;
710 ximg
= RCreateXImage(ctx
, 1, image
->width
, image
->height
);
714 alpha
= image
->data
[3];
716 for (y
= 0; y
< image
->height
; y
++) {
717 for (x
= 0; x
< image
->width
; x
++) {
718 XPutPixel(ximg
->image
, x
, y
, (*alpha
<= threshold
? 0 : 1));
729 RConvertImage(RContext
*context
, RImage
*image
, Pixmap
*pixmap
)
736 assert(context
!=NULL
);
738 assert(pixmap
!=NULL
);
740 /* clear error message */
741 if (context
->vclass
== TrueColor
) {
743 if (context
->attribs
->render_mode
== RDitheredRendering
744 && (context
->depth
== 15 || context
->depth
== 16))
745 ximg
= image2TrueColorD16(context
, image
);
747 ximg
= image2TrueColor(context
, image
);
749 } else if (context
->vclass
== PseudoColor
|| context
->vclass
== StaticColor
)
750 ximg
= image2PseudoColor(context
, image
);
751 else if (context
->vclass
== GrayScale
|| context
->vclass
== StaticGray
)
752 ximg
= image2GrayScale(context
, image
);
762 *pixmap
= XCreatePixmap(context
->dpy
, context
->drawable
, image
->width
,
763 image
->height
, context
->depth
);
766 if (context
->flags
.use_shared_pixmap
&& ximg
->is_shared
)
767 tmp
= R_CreateXImageMappedPixmap(context
, ximg
);
772 * We have to copy the shm Pixmap into a normal Pixmap because
773 * otherwise, we would have to control when Pixmaps are freed so
774 * that we can detach their shm segments. This is a problem if the
775 * program crash, leaving stale shared memory segments in the
776 * system (lots of them). But with some work, we can optimize
777 * things and remove this XCopyArea. This will require
778 * explicitly freeing all pixmaps when exiting or restarting
781 XCopyArea(context
->dpy
, tmp
, *pixmap
, context
->copy_gc
, 0, 0,
782 image
->width
, image
->height
, 0, 0);
783 XFreePixmap(context
->dpy
, tmp
);
785 RPutXImage(context
, *pixmap
, context
->copy_gc
, ximg
, 0, 0, 0, 0,
786 image
->width
, image
->height
);
789 RPutXImage(context
, *pixmap
, context
->copy_gc
, ximg
, 0, 0, 0, 0,
790 image
->width
, image
->height
);
793 RDestroyXImage(context
, ximg
);
803 RConvertImageMask(RContext
*context
, RImage
*image
, Pixmap
*pixmap
,
804 Pixmap
*mask
, int threshold
)
810 assert(context
!=NULL
);
812 assert(pixmap
!=NULL
);
815 if (!RConvertImage(context
, image
, pixmap
))
818 if (image
->data
[3]==NULL
) {
823 ximg
= image2Bitmap(context
, image
, threshold
);
831 *mask
= XCreatePixmap(context
->dpy
, context
->drawable
, image
->width
,
833 gcv
.foreground
= context
->black
;
834 gcv
.background
= context
->white
;
835 gcv
.graphics_exposures
= False
;
836 gc
= XCreateGC(context
->dpy
, *mask
, GCForeground
|GCBackground
837 |GCGraphicsExposures
, &gcv
);
838 RPutXImage(context
, *mask
, gc
, ximg
, 0, 0, 0, 0,
839 image
->width
, image
->height
);
840 RDestroyXImage(context
, ximg
);
850 RGetClosestXColor(RContext
*context
, RColor
*color
, XColor
*retColor
)
852 if (context
->vclass
== TrueColor
) {
853 unsigned short rmask
, gmask
, bmask
;
854 unsigned short roffs
, goffs
, boffs
;
855 unsigned short *rtable
, *gtable
, *btable
;
857 roffs
= context
->red_offset
;
858 goffs
= context
->green_offset
;
859 boffs
= context
->blue_offset
;
861 rmask
= context
->visual
->red_mask
>> roffs
;
862 gmask
= context
->visual
->green_mask
>> goffs
;
863 bmask
= context
->visual
->blue_mask
>> boffs
;
865 rtable
= computeTable(rmask
);
866 gtable
= computeTable(gmask
);
867 btable
= computeTable(bmask
);
869 retColor
->pixel
= (rtable
[color
->red
]<<roffs
) |
870 (gtable
[color
->green
]<<goffs
) | (btable
[color
->blue
]<<boffs
);
872 retColor
->red
= color
->red
<< 8;
873 retColor
->green
= color
->green
<< 8;
874 retColor
->blue
= color
->blue
<< 8;
875 retColor
->flags
= DoRed
|DoGreen
|DoBlue
;
877 } else if (context
->vclass
== PseudoColor
|| context
->vclass
== StaticColor
) {
878 const int cpc
=context
->attribs
->colors_per_channel
;
879 const unsigned short rmask
= cpc
-1; /* different sizes could be used */
880 const unsigned short gmask
= rmask
; /* for r,g,b */
881 const unsigned short bmask
= rmask
;
882 unsigned short *rtable
, *gtable
, *btable
;
883 const int cpccpc
= cpc
*cpc
;
886 rtable
= computeTable(rmask
);
887 gtable
= computeTable(gmask
);
888 btable
= computeTable(bmask
);
890 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
891 RErrorCode
= RERR_NOMEMORY
;
894 index
= rtable
[color
->red
]*cpccpc
+ gtable
[color
->green
]*cpc
895 + btable
[color
->blue
];
896 *retColor
= context
->colors
[index
];
897 } else if (context
->vclass
== GrayScale
|| context
->vclass
== StaticGray
) {
899 const int cpc
= context
->attribs
->colors_per_channel
;
900 unsigned short gmask
;
901 unsigned short *table
;
904 if (context
->vclass
== StaticGray
)
905 gmask
= (1<<context
->depth
) - 1; /* use all grays */
907 gmask
= cpc
*cpc
*cpc
-1;
909 table
= computeTable(gmask
);
913 index
= table
[(color
->red
*30 + color
->green
*59 + color
->blue
*11)/100];
915 *retColor
= context
->colors
[index
];
917 RErrorCode
= RERR_INTERNAL
;