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 /* skip to next line */
238 image2TrueColor(RContext
*ctx
, RImage
*image
)
241 register int x
, y
, r
, g
, b
;
242 unsigned char *red
, *grn
, *blu
;
244 unsigned short rmask
, gmask
, bmask
;
245 unsigned short roffs
, goffs
, boffs
;
246 unsigned short *rtable
, *gtable
, *btable
;
249 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
254 red
= image
->data
[0];
255 grn
= image
->data
[1];
256 blu
= image
->data
[2];
258 roffs
= ctx
->red_offset
;
259 goffs
= ctx
->green_offset
;
260 boffs
= ctx
->blue_offset
;
262 rmask
= ctx
->visual
->red_mask
>> roffs
;
263 gmask
= ctx
->visual
->green_mask
>> goffs
;
264 bmask
= ctx
->visual
->blue_mask
>> boffs
;
267 /* this do not seem to increase speed. Only 0.06 second faster in
268 * rendering a 800x600 image to pixmap. 1.12 sec instead of 1.18.
269 * But does not require a 256*256*256 lookup table.
271 if (ctx
->depth
==24) {
273 puts("true color match for 24bpp");
275 for (y
=0; y
< image
->height
; y
++) {
276 for (x
=0; x
< image
->width
; x
++) {
277 pixel
= (*(red
++)<<roffs
) | (*(grn
++)<<goffs
) | (*(blu
++)<<boffs
);
278 XPutPixel(ximg
->image
, x
, y
, pixel
);
285 rtable
= computeTable(rmask
);
286 gtable
= computeTable(gmask
);
287 btable
= computeTable(bmask
);
289 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
290 RErrorCode
= RERR_NOMEMORY
;
291 RDestroyXImage(ctx
, ximg
);
295 if (ctx
->attribs
->render_mode
==RBestMatchRendering
) {
298 puts("true color match");
300 for (y
=0, ofs
=0; y
< image
->height
; y
++) {
301 for (x
=0; x
< image
->width
; x
++, ofs
++) {
303 r
= rtable
[red
[ofs
]];
304 g
= gtable
[grn
[ofs
]];
305 b
= btable
[blu
[ofs
]];
306 pixel
= (r
<<roffs
) | (g
<<goffs
) | (b
<<boffs
);
307 XPutPixel(ximg
->image
, x
, y
, pixel
);
312 short *rerr
, *gerr
, *berr
;
313 short *nrerr
, *ngerr
, *nberr
;
316 const int dr
=0xff/rmask
;
317 const int dg
=0xff/gmask
;
318 const int db
=0xff/bmask
;
321 puts("true color dither");
323 rerr
= (short*)alloca((image
->width
+2)*sizeof(short));
324 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
325 berr
= (short*)alloca((image
->width
+2)*sizeof(short));
326 nrerr
= (short*)alloca((image
->width
+2)*sizeof(short));
327 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
328 nberr
= (short*)alloca((image
->width
+2)*sizeof(short));
329 if (!rerr
|| !gerr
|| !berr
|| !nrerr
|| !ngerr
|| !nberr
) {
330 RErrorCode
= RERR_NOMEMORY
;
331 RDestroyXImage(ctx
, ximg
);
334 for (x
=0; x
<image
->width
; x
++) {
339 rerr
[x
] = gerr
[x
] = berr
[x
] = 0;
340 /* convert and dither the image to XImage */
341 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
342 if (y
<image
->height
-1) {
344 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
355 for (x
=0; x
<image
->width
; x
++) {
357 if (rerr
[x
]>0xff) rerr
[x
]=0xff; else if (rerr
[x
]<0) rerr
[x
]=0;
358 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
359 if (berr
[x
]>0xff) berr
[x
]=0xff; else if (berr
[x
]<0) berr
[x
]=0;
365 pixel
= (r
<<roffs
) | (g
<<goffs
) | (b
<<boffs
);
366 XPutPixel(ximg
->image
, x
, y
, pixel
);
368 rer
= rerr
[x
] - r
*dr
;
369 ger
= gerr
[x
] - g
*dg
;
370 ber
= berr
[x
] - b
*db
;
372 /* distribute error */
390 /* skip to next line */
411 image2PseudoColor(RContext
*ctx
, RImage
*image
)
414 register int x
, y
, r
, g
, b
;
415 unsigned char *red
, *grn
, *blu
;
417 const int cpc
=ctx
->attribs
->colors_per_channel
;
418 const unsigned short rmask
= cpc
-1; /* different sizes could be used */
419 const unsigned short gmask
= rmask
; /* for r,g,b */
420 const unsigned short bmask
= rmask
;
421 unsigned short *rtable
, *gtable
, *btable
;
422 const int cpccpc
= cpc
*cpc
;
425 /*register unsigned char maxrgb = 0xff;*/
427 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
432 red
= image
->data
[0];
433 grn
= image
->data
[1];
434 blu
= image
->data
[2];
436 data
= ximg
->image
->data
;
438 /* Tables are same at the moment because rmask==gmask==bmask. */
439 rtable
= computeTable(rmask
);
440 gtable
= computeTable(gmask
);
441 btable
= computeTable(bmask
);
443 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
444 RErrorCode
= RERR_NOMEMORY
;
445 RDestroyXImage(ctx
, ximg
);
449 if (ctx
->attribs
->render_mode
== RBestMatchRendering
) {
452 printf("pseudo color match with %d colors per channel\n", cpc
);
454 for (y
=0, ofs
= 0; y
<image
->height
; y
++) {
455 for (x
=0; x
<image
->width
; x
++, ofs
++) {
457 r
= rtable
[red
[ofs
]];
458 g
= gtable
[grn
[ofs
]];
459 b
= btable
[blu
[ofs
]];
460 pixel
= r
*cpccpc
+ g
*cpc
+ b
;
461 /*data[ofs] = ctx->colors[pixel].pixel;*/
462 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[pixel
].pixel
);
467 short *rerr
, *gerr
, *berr
;
468 short *nrerr
, *ngerr
, *nberr
;
471 const int dr
=0xff/rmask
;
472 const int dg
=0xff/gmask
;
473 const int db
=0xff/bmask
;
476 printf("pseudo color dithering with %d colors per channel\n", cpc
);
478 rerr
= (short*)alloca((image
->width
+2)*sizeof(short));
479 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
480 berr
= (short*)alloca((image
->width
+2)*sizeof(short));
481 nrerr
= (short*)alloca((image
->width
+2)*sizeof(short));
482 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
483 nberr
= (short*)alloca((image
->width
+2)*sizeof(short));
484 if (!rerr
|| !gerr
|| !berr
|| !nrerr
|| !ngerr
|| !nberr
) {
485 RErrorCode
= RERR_NOMEMORY
;
486 RDestroyXImage(ctx
, ximg
);
489 for (x
=0; x
<image
->width
; x
++) {
494 rerr
[x
] = gerr
[x
] = berr
[x
] = 0;
495 /* convert and dither the image to XImage */
496 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
497 if (y
<image
->height
-1) {
499 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
510 for (x
=0; x
<image
->width
; x
++, ofs
++) {
512 if (rerr
[x
]>0xff) rerr
[x
]=0xff; else if (rerr
[x
]<0) rerr
[x
]=0;
513 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
514 if (berr
[x
]>0xff) berr
[x
]=0xff; else if (berr
[x
]<0) berr
[x
]=0;
520 pixel
= r
*cpccpc
+ g
*cpc
+ b
;
521 /*data[ofs] = ctx->colors[pixel].pixel;*/
522 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[pixel
].pixel
);
525 rer
= rerr
[x
] - r
*dr
;
526 ger
= gerr
[x
] - g
*dg
;
527 ber
= berr
[x
] - b
*db
;
529 /* distribute error */
530 rerr
[x
+1]+=(rer
*7)/16;
531 gerr
[x
+1]+=(ger
*7)/16;
532 berr
[x
+1]+=(ber
*7)/16;
534 nrerr
[x
]+=(rer
*5)/16;
535 ngerr
[x
]+=(ger
*5)/16;
536 nberr
[x
]+=(ber
*5)/16;
539 nrerr
[x
-1]+=(rer
*3)/16;
540 ngerr
[x
-1]+=(ger
*3)/16;
541 nberr
[x
-1]+=(ber
*3)/16;
548 /* distribute error */
566 /* skip to next line */
580 ximg
->image
->data
= (char*)data
;
587 image2GrayScale(RContext
*ctx
, RImage
*image
)
590 register int x
, y
, g
;
591 unsigned char *red
, *grn
, *blu
;
592 const int cpc
=ctx
->attribs
->colors_per_channel
;
593 unsigned short gmask
;
594 unsigned short *table
;
597 /*register unsigned char maxrgb = 0xff;*/
599 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
604 red
= image
->data
[0];
605 grn
= image
->data
[1];
606 blu
= image
->data
[2];
608 data
= ximg
->image
->data
;
610 if (ctx
->vclass
== StaticGray
)
611 gmask
= (1<<ctx
->depth
) - 1; /* use all grays */
613 gmask
= cpc
*cpc
*cpc
-1;
615 table
= computeTable(gmask
);
618 RErrorCode
= RERR_NOMEMORY
;
619 RDestroyXImage(ctx
, ximg
);
623 if (ctx
->attribs
->render_mode
== RBestMatchRendering
) {
626 printf("grayscale match with %d colors per channel\n", cpc
);
628 for (y
=0, ofs
= 0; y
<image
->height
; y
++) {
629 for (x
=0; x
<image
->width
; x
++, ofs
++) {
631 g
= table
[(red
[ofs
]*30+grn
[ofs
]*59+blu
[ofs
]*11)/100];
633 /*data[ofs] = ctx->colors[g].pixel;*/
634 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[g
].pixel
);
643 const int dg
=0xff/gmask
;
646 printf("grayscale dither with %d colors per channel\n", cpc
);
648 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
649 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
650 if (!gerr
|| !ngerr
) {
651 RErrorCode
= RERR_NOMEMORY
;
652 RDestroyXImage(ctx
, ximg
);
655 for (x
=0; x
<image
->width
; x
++) {
656 gerr
[x
] = (red
[x
]*30 + grn
[x
]*59 + blu
[x
]*11)/100;
659 /* convert and dither the image to XImage */
660 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
661 if (y
<image
->height
-1) {
663 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
664 ngerr
[x
] = (red
[x1
]*30 + grn
[x1
]*59 + blu
[x1
]*11)/100;
668 ngerr
[x
] = (red
[x1
]*30 + grn
[x1
]*59 + blu
[x1
]*11)/100;
670 for (x
=0; x
<image
->width
; x
++, ofs
++) {
672 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
676 /*data[ofs] = ctx->colors[g].pixel;*/
677 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[g
].pixel
);
679 ger
= gerr
[x
] - g
*dg
;
681 /* distribute error */
690 /* skip to next line */
696 ximg
->image
->data
= (char*)data
;
703 image2Bitmap(RContext
*ctx
, RImage
*image
, int threshold
)
706 unsigned char *alpha
;
709 ximg
= RCreateXImage(ctx
, 1, image
->width
, image
->height
);
713 alpha
= image
->data
[3];
715 for (y
= 0; y
< image
->height
; y
++) {
716 for (x
= 0; x
< image
->width
; x
++) {
717 XPutPixel(ximg
->image
, x
, y
, (*alpha
<= threshold
? 0 : 1));
728 RConvertImage(RContext
*context
, RImage
*image
, Pixmap
*pixmap
)
735 assert(context
!=NULL
);
737 assert(pixmap
!=NULL
);
739 /* clear error message */
740 if (context
->vclass
== TrueColor
) {
742 if (context
->attribs
->render_mode
== RDitheredRendering
743 && (context
->depth
== 15 || context
->depth
== 16))
744 ximg
= image2TrueColorD16(context
, image
);
746 ximg
= image2TrueColor(context
, image
);
748 } else if (context
->vclass
== PseudoColor
|| context
->vclass
== StaticColor
)
749 ximg
= image2PseudoColor(context
, image
);
750 else if (context
->vclass
== GrayScale
|| context
->vclass
== StaticGray
)
751 ximg
= image2GrayScale(context
, image
);
761 *pixmap
= XCreatePixmap(context
->dpy
, context
->drawable
, image
->width
,
762 image
->height
, context
->depth
);
765 if (context
->flags
.use_shared_pixmap
&& ximg
->is_shared
)
766 tmp
= R_CreateXImageMappedPixmap(context
, ximg
);
771 * We have to copy the shm Pixmap into a normal Pixmap because
772 * otherwise, we would have to control when Pixmaps are freed so
773 * that we can detach their shm segments. This is a problem if the
774 * program crash, leaving stale shared memory segments in the
775 * system (lots of them). But with some work, we can optimize
776 * things and remove this XCopyArea. This will require
777 * explicitly freeing all pixmaps when exiting or restarting
780 XCopyArea(context
->dpy
, tmp
, *pixmap
, context
->copy_gc
, 0, 0,
781 image
->width
, image
->height
, 0, 0);
782 XFreePixmap(context
->dpy
, tmp
);
784 RPutXImage(context
, *pixmap
, context
->copy_gc
, ximg
, 0, 0, 0, 0,
785 image
->width
, image
->height
);
788 RPutXImage(context
, *pixmap
, context
->copy_gc
, ximg
, 0, 0, 0, 0,
789 image
->width
, image
->height
);
792 RDestroyXImage(context
, ximg
);
802 RConvertImageMask(RContext
*context
, RImage
*image
, Pixmap
*pixmap
,
803 Pixmap
*mask
, int threshold
)
809 assert(context
!=NULL
);
811 assert(pixmap
!=NULL
);
814 if (!RConvertImage(context
, image
, pixmap
))
817 if (image
->data
[3]==NULL
) {
822 ximg
= image2Bitmap(context
, image
, threshold
);
830 *mask
= XCreatePixmap(context
->dpy
, context
->drawable
, image
->width
,
832 gcv
.foreground
= context
->black
;
833 gcv
.background
= context
->white
;
834 gcv
.graphics_exposures
= False
;
835 gc
= XCreateGC(context
->dpy
, *mask
, GCForeground
|GCBackground
836 |GCGraphicsExposures
, &gcv
);
837 RPutXImage(context
, *mask
, gc
, ximg
, 0, 0, 0, 0,
838 image
->width
, image
->height
);
839 RDestroyXImage(context
, ximg
);
849 RGetClosestXColor(RContext
*context
, RColor
*color
, XColor
*retColor
)
851 if (context
->vclass
== TrueColor
) {
852 unsigned short rmask
, gmask
, bmask
;
853 unsigned short roffs
, goffs
, boffs
;
854 unsigned short *rtable
, *gtable
, *btable
;
856 roffs
= context
->red_offset
;
857 goffs
= context
->green_offset
;
858 boffs
= context
->blue_offset
;
860 rmask
= context
->visual
->red_mask
>> roffs
;
861 gmask
= context
->visual
->green_mask
>> goffs
;
862 bmask
= context
->visual
->blue_mask
>> boffs
;
864 rtable
= computeTable(rmask
);
865 gtable
= computeTable(gmask
);
866 btable
= computeTable(bmask
);
868 retColor
->pixel
= (rtable
[color
->red
]<<roffs
) |
869 (gtable
[color
->green
]<<goffs
) | (btable
[color
->blue
]<<boffs
);
871 retColor
->red
= color
->red
<< 8;
872 retColor
->green
= color
->green
<< 8;
873 retColor
->blue
= color
->blue
<< 8;
874 retColor
->flags
= DoRed
|DoGreen
|DoBlue
;
876 } else if (context
->vclass
== PseudoColor
|| context
->vclass
== StaticColor
) {
877 const int cpc
=context
->attribs
->colors_per_channel
;
878 const unsigned short rmask
= cpc
-1; /* different sizes could be used */
879 const unsigned short gmask
= rmask
; /* for r,g,b */
880 const unsigned short bmask
= rmask
;
881 unsigned short *rtable
, *gtable
, *btable
;
882 const int cpccpc
= cpc
*cpc
;
885 rtable
= computeTable(rmask
);
886 gtable
= computeTable(gmask
);
887 btable
= computeTable(bmask
);
889 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
890 RErrorCode
= RERR_NOMEMORY
;
893 index
= rtable
[color
->red
]*cpccpc
+ gtable
[color
->green
]*cpc
894 + btable
[color
->blue
];
895 *retColor
= context
->colors
[index
];
896 } else if (context
->vclass
== GrayScale
|| context
->vclass
== StaticGray
) {
898 const int cpc
= context
->attribs
->colors_per_channel
;
899 unsigned short gmask
;
900 unsigned short *table
;
903 if (context
->vclass
== StaticGray
)
904 gmask
= (1<<context
->depth
) - 1; /* use all grays */
906 gmask
= cpc
*cpc
*cpc
-1;
908 table
= computeTable(gmask
);
912 index
= table
[(color
->red
*30 + color
->green
*59 + color
->blue
*11)/100];
914 *retColor
= context
->colors
[index
];
916 RErrorCode
= RERR_INTERNAL
;