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>
51 #define MIN(a,b) ((a)<(b) ? (a) : (b))
54 typedef struct RConversionTable
{
55 unsigned short table
[256];
57 struct RConversionTable
*next
;
62 * Lookup table for index*3/8
64 static char errorTable1
[]={
65 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5,
66 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11,
67 12, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17,
68 18, 18, 18, 19, 19, 19, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23,
69 24, 24, 24, 25, 25, 25, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29,
70 30, 30, 30, 31, 31, 31, 32, 32, 33, 33, 33, 34, 34, 34, 35, 35,
71 36, 36, 36, 37, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41,
72 42, 42, 42, 43, 43, 43, 44, 44, 45, 45, 45, 46, 46, 46, 47, 47,
73 48, 48, 48, 49, 49, 49, 50, 50, 51, 51, 51, 52, 52, 52, 53, 53,
74 54, 54, 54, 55, 55, 55, 56, 56, 57, 57, 57, 58, 58, 58, 59, 59,
75 60, 60, 60, 61, 61, 61, 62, 62, 63, 63, 63, 64, 64, 64, 65, 65,
76 66, 66, 66, 67, 67, 67, 68, 68, 69, 69, 69, 70, 70, 70, 71, 71,
77 72, 72, 72, 73, 73, 73, 74, 74, 75, 75, 75, 76, 76, 76, 77, 77,
78 78, 78, 78, 79, 79, 79, 80, 80, 81, 81, 81, 82, 82, 82, 83, 83,
79 84, 84, 84, 85, 85, 85, 86, 86, 87, 87, 87, 88, 88, 88, 89, 89,
80 90, 90, 90, 91, 91, 91, 92, 92, 93, 93, 93, 94, 94, 94, 95
83 * Lookup table for index*2/8
85 static char errorTable2
[]={
86 0, 1, 2, 1, 2, 3, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5,
87 4, 5, 6, 5, 6, 7, 6, 7, 6, 7, 8, 7, 8, 9, 8, 9,
88 8, 9, 10, 9, 10, 11, 10, 11, 10, 11, 12, 11, 12, 13, 12, 13,
89 12, 13, 14, 13, 14, 15, 14, 15, 14, 15, 16, 15, 16, 17, 16, 17,
90 16, 17, 18, 17, 18, 19, 18, 19, 18, 19, 20, 19, 20, 21, 20, 21,
91 20, 21, 22, 21, 22, 23, 22, 23, 22, 23, 24, 23, 24, 25, 24, 25,
92 24, 25, 26, 25, 26, 27, 26, 27, 26, 27, 28, 27, 28, 29, 28, 29,
93 28, 29, 30, 29, 30, 31, 30, 31, 30, 31, 32, 31, 32, 33, 32, 33,
94 32, 33, 34, 33, 34, 35, 34, 35, 34, 35, 36, 35, 36, 37, 36, 37,
95 36, 37, 38, 37, 38, 39, 38, 39, 38, 39, 40, 39, 40, 41, 40, 41,
96 40, 41, 42, 41, 42, 43, 42, 43, 42, 43, 44, 43, 44, 45, 44, 45,
97 44, 45, 46, 45, 46, 47, 46, 47, 46, 47, 48, 47, 48, 49, 48, 49,
98 48, 49, 50, 49, 50, 51, 50, 51, 50, 51, 52, 51, 52, 53, 52, 53,
99 52, 53, 54, 53, 54, 55, 54, 55, 54, 55, 56, 55, 56, 57, 56, 57,
100 56, 57, 58, 57, 58, 59, 58, 59, 58, 59, 60, 59, 60, 61, 60, 61,
101 60, 61, 62, 61, 62, 63, 62, 63, 62, 63, 64, 63, 64, 65, 64
106 static RConversionTable
*conversionTable
= NULL
;
109 static unsigned short*
110 computeTable(unsigned short mask
)
112 RConversionTable
*tmp
= conversionTable
;
116 if (tmp
->index
== mask
)
124 tmp
= (RConversionTable
*)malloc(sizeof(RConversionTable
));
129 tmp
->table
[i
] = (i
*mask
+ 0x7f)/0xff;
132 tmp
->next
= conversionTable
;
133 conversionTable
= tmp
;
139 image2TrueColor(RContext
*ctx
, RImage
*image
)
142 register int x
, y
, r
, g
, b
;
143 unsigned char *red
, *grn
, *blu
;
145 unsigned short rmask
, gmask
, bmask
;
146 unsigned short roffs
, goffs
, boffs
;
147 unsigned short *rtable
, *gtable
, *btable
;
149 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
154 red
= image
->data
[0];
155 grn
= image
->data
[1];
156 blu
= image
->data
[2];
158 roffs
= ctx
->red_offset
;
159 goffs
= ctx
->green_offset
;
160 boffs
= ctx
->blue_offset
;
162 rmask
= ctx
->visual
->red_mask
>> roffs
;
163 gmask
= ctx
->visual
->green_mask
>> goffs
;
164 bmask
= ctx
->visual
->blue_mask
>> boffs
;
167 /* this do not seem to increase speed. Only 0.06 second faster in
168 * rendering a 800x600 image to pixmap. 1.12 sec instead of 1.18.
169 * But does not require a 256*256*256 lookup table.
171 if (ctx
->depth
==24) {
173 puts("true color match for 24bpp");
175 for (y
=0; y
< image
->height
; y
++) {
176 for (x
=0; x
< image
->width
; x
++) {
177 pixel
= (*(red
++)<<roffs
) | (*(grn
++)<<goffs
) | (*(blu
++)<<boffs
);
178 XPutPixel(ximg
->image
, x
, y
, pixel
);
185 rtable
= computeTable(rmask
);
186 gtable
= computeTable(gmask
);
187 btable
= computeTable(bmask
);
189 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
190 sprintf(RErrorString
, "out of memory");
191 RDestroyXImage(ctx
, ximg
);
195 if (ctx
->attribs
->render_mode
==RM_MATCH
) {
198 puts("true color match");
200 for (y
=0; y
< image
->height
; y
++) {
201 for (x
=0; x
< image
->width
; x
++) {
206 pixel
= (r
<<roffs
) | (g
<<goffs
) | (b
<<boffs
);
207 XPutPixel(ximg
->image
, x
, y
, pixel
);
212 unsigned char *rerr
, *gerr
, *berr
;
213 unsigned char *nrerr
, *ngerr
, *nberr
;
214 unsigned char *rerr_
, *gerr_
, *berr_
;
215 unsigned char *nrerr_
, *ngerr_
, *nberr_
;
217 register int ac
, err
;
218 int width
= image
->width
;
223 while ((dr
& 1)==0) dr
= dr
>> 1;
224 while ((dg
& 1)==0) dg
= dg
>> 1;
225 while ((db
& 1)==0) db
= db
>> 1;
228 puts("true color dither");
230 rerr_
= rerr
= (unsigned char*)alloca((width
+2)*sizeof(char));
231 gerr_
= gerr
= (unsigned char*)alloca((width
+2)*sizeof(char));
232 berr_
= berr
= (unsigned char*)alloca((width
+2)*sizeof(char));
233 nrerr_
= nrerr
= (unsigned char*)alloca((width
+2)*sizeof(char));
234 ngerr_
= ngerr
= (unsigned char*)alloca((width
+2)*sizeof(char));
235 nberr_
= nberr
= (unsigned char*)alloca((width
+2)*sizeof(char));
236 if (!rerr
|| !gerr
|| !berr
|| !nrerr
|| !ngerr
|| !nberr
) {
237 sprintf(RErrorString
, "out of memory");
238 RDestroyXImage(ctx
, ximg
);
241 for (x
=0; x
<width
; x
++) {
246 rerr
[x
] = gerr
[x
] = berr
[x
] = 0;
247 /* convert and dither the image to XImage */
248 for (y
=0; y
<image
->height
; y
++) {
249 if (y
<image
->height
-1) {
250 memcpy(nrerr
, red
, width
);
251 memcpy(ngerr
, grn
, width
);
252 memcpy(nberr
, blu
, width
);
261 for (x
=0; x
<width
; x
++) {
263 pixel
= (rtable
[*rerr
]<<roffs
) | (gtable
[*gerr
]<<goffs
)
264 | (btable
[*berr
]<<boffs
);
265 XPutPixel(ximg
->image
, x
, y
, pixel
);
269 /* distribute error */
270 ac
= errorTable1
[err
] + *rerr
;
272 ac
= errorTable1
[err
] + *nrerr
;
273 *nrerr
=MIN(ac
, 0xff);
275 ac
= *nrerr
+ errorTable2
[err
];
281 /* distribute error */
282 ac
= errorTable1
[err
] + *gerr
;
284 ac
= errorTable1
[err
] + *ngerr
;
285 *ngerr
=MIN(ac
, 0xff);
287 ac
= *ngerr
+ errorTable2
[err
];
293 /* distribute error */
294 ac
= errorTable1
[err
] + *berr
;
296 ac
= errorTable1
[err
] + *nberr
;
297 *nberr
=MIN(ac
, 0xff);
299 ac
= *nberr
+ errorTable2
[err
];
302 /* skip to next line */
328 image2PseudoColor(RContext
*ctx
, RImage
*image
)
331 register int x
, y
, r
, g
, b
;
332 unsigned char *red
, *grn
, *blu
;
334 const int cpc
=ctx
->attribs
->colors_per_channel
;
335 const unsigned short rmask
= cpc
-1; /* different sizes could be used */
336 const unsigned short gmask
= rmask
; /* for r,g,b */
337 const unsigned short bmask
= rmask
;
338 unsigned short *rtable
, *gtable
, *btable
;
339 const int cpccpc
= cpc
*cpc
;
342 /*register unsigned char maxrgb = 0xff;*/
344 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
349 red
= image
->data
[0];
350 grn
= image
->data
[1];
351 blu
= image
->data
[2];
353 data
= ximg
->image
->data
;
355 /* Tables are same at the moment because rmask==gmask==bmask. */
356 rtable
= computeTable(rmask
);
357 gtable
= computeTable(gmask
);
358 btable
= computeTable(bmask
);
360 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
361 sprintf(RErrorString
, "out of memory");
362 RDestroyXImage(ctx
, ximg
);
366 if (ctx
->attribs
->render_mode
== RM_MATCH
) {
369 printf("pseudo color match with %d colors per channel\n", cpc
);
371 for (y
=0, ofs
= 0; y
<image
->height
; y
++) {
372 for (x
=0; x
<image
->width
; x
++, ofs
++) {
374 r
= rtable
[red
[ofs
]];
375 g
= gtable
[grn
[ofs
]];
376 b
= btable
[blu
[ofs
]];
377 pixel
= r
*cpccpc
+ g
*cpc
+ b
;
378 /*data[ofs] = ctx->colors[pixel].pixel;*/
379 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[pixel
].pixel
);
384 short *rerr
, *gerr
, *berr
;
385 short *nrerr
, *ngerr
, *nberr
;
388 const int dr
=0xff/rmask
;
389 const int dg
=0xff/gmask
;
390 const int db
=0xff/bmask
;
393 printf("pseudo color dithering with %d colors per channel\n", cpc
);
395 rerr
= (short*)alloca((image
->width
+2)*sizeof(short));
396 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
397 berr
= (short*)alloca((image
->width
+2)*sizeof(short));
398 nrerr
= (short*)alloca((image
->width
+2)*sizeof(short));
399 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
400 nberr
= (short*)alloca((image
->width
+2)*sizeof(short));
401 if (!rerr
|| !gerr
|| !berr
|| !nrerr
|| !ngerr
|| !nberr
) {
402 sprintf(RErrorString
, "out of memory");
403 RDestroyXImage(ctx
, ximg
);
406 for (x
=0; x
<image
->width
; x
++) {
411 rerr
[x
] = gerr
[x
] = berr
[x
] = 0;
412 /* convert and dither the image to XImage */
413 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
414 if (y
<image
->height
-1) {
416 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
427 for (x
=0; x
<image
->width
; x
++, ofs
++) {
429 if (rerr
[x
]>0xff) rerr
[x
]=0xff; else if (rerr
[x
]<0) rerr
[x
]=0;
430 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
431 if (berr
[x
]>0xff) berr
[x
]=0xff; else if (berr
[x
]<0) berr
[x
]=0;
437 pixel
= r
*cpccpc
+ g
*cpc
+ b
;
438 /*data[ofs] = ctx->colors[pixel].pixel;*/
439 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[pixel
].pixel
);
441 rer
= rerr
[x
] - r
*dr
;
442 ger
= gerr
[x
] - g
*dg
;
443 ber
= berr
[x
] - b
*db
;
445 /* distribute error */
462 /* skip to next line */
482 image2GrayScale(RContext
*ctx
, RImage
*image
)
485 register int x
, y
, g
;
486 unsigned char *red
, *grn
, *blu
;
487 const int cpc
=ctx
->attribs
->colors_per_channel
;
488 unsigned short gmask
;
489 unsigned short *table
;
492 /*register unsigned char maxrgb = 0xff;*/
494 ximg
= RCreateXImage(ctx
, ctx
->depth
, image
->width
, image
->height
);
499 red
= image
->data
[0];
500 grn
= image
->data
[1];
501 blu
= image
->data
[2];
503 data
= ximg
->image
->data
;
505 if (ctx
->vclass
== StaticGray
)
506 gmask
= (1<<ctx
->depth
) - 1; /* use all grays */
508 gmask
= cpc
*cpc
*cpc
-1;
510 table
= computeTable(gmask
);
513 sprintf(RErrorString
, "out of memory");
514 RDestroyXImage(ctx
, ximg
);
518 if (ctx
->attribs
->render_mode
== RM_MATCH
) {
521 printf("grayscale match with %d colors per channel\n", cpc
);
523 for (y
=0, ofs
= 0; y
<image
->height
; y
++) {
524 for (x
=0; x
<image
->width
; x
++, ofs
++) {
526 g
= table
[(red
[ofs
]*30+grn
[ofs
]*59+blu
[ofs
]*11)/100];
528 /*data[ofs] = ctx->colors[g].pixel;*/
529 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[g
].pixel
);
538 const int dg
=0xff/gmask
;
541 printf("grayscale dither with %d colors per channel\n", cpc
);
543 gerr
= (short*)alloca((image
->width
+2)*sizeof(short));
544 ngerr
= (short*)alloca((image
->width
+2)*sizeof(short));
545 if (!gerr
|| !ngerr
) {
546 sprintf(RErrorString
, "out of memory");
547 RDestroyXImage(ctx
, ximg
);
550 for (x
=0; x
<image
->width
; x
++) {
551 gerr
[x
] = (red
[x
]*30 + grn
[x
]*59 + blu
[x
]*11)/100;
554 /* convert and dither the image to XImage */
555 for (y
=0, ofs
=0; y
<image
->height
; y
++) {
556 if (y
<image
->height
-1) {
558 for (x
=0, x1
=ofs
+image
->width
; x
<image
->width
; x
++, x1
++) {
559 ngerr
[x
] = (red
[x1
]*30 + grn
[x1
]*59 + blu
[x1
]*11)/100;
563 ngerr
[x
] = (red
[x1
]*30 + grn
[x1
]*59 + blu
[x1
]*11)/100;
565 for (x
=0; x
<image
->width
; x
++, ofs
++) {
567 if (gerr
[x
]>0xff) gerr
[x
]=0xff; else if (gerr
[x
]<0) gerr
[x
]=0;
571 /*data[ofs] = ctx->colors[g].pixel;*/
572 XPutPixel(ximg
->image
, x
, y
, ctx
->colors
[g
].pixel
);
574 ger
= gerr
[x
] - g
*dg
;
576 /* distribute error */
585 /* skip to next line */
591 ximg
->image
->data
= (char*)data
;
598 image2Bitmap(RContext
*ctx
, RImage
*image
, int threshold
)
601 unsigned char *alpha
;
604 ximg
= RCreateXImage(ctx
, 1, image
->width
, image
->height
);
608 alpha
= image
->data
[3];
610 for (y
= 0; y
< image
->height
; y
++) {
611 for (x
= 0; x
< image
->width
; x
++) {
612 XPutPixel(ximg
->image
, x
, y
, (*alpha
<= threshold
? 0 : 1));
623 RConvertImage(RContext
*context
, RImage
*image
, Pixmap
*pixmap
)
627 assert(context
!=NULL
);
629 assert(pixmap
!=NULL
);
631 /* clear error message */
634 if (context
->vclass
== TrueColor
)
635 ximg
= image2TrueColor(context
, image
);
636 else if (context
->vclass
== PseudoColor
|| context
->vclass
== StaticColor
)
637 ximg
= image2PseudoColor(context
, image
);
638 else if (context
->vclass
== GrayScale
|| context
->vclass
== StaticGray
)
639 ximg
= image2GrayScale(context
, image
);
642 strcat(RErrorString
, ":could not convert RImage to XImage");
648 *pixmap
= XCreatePixmap(context
->dpy
, context
->drawable
, image
->width
,
649 image
->height
, context
->depth
);
650 RPutXImage(context
, *pixmap
, context
->copy_gc
, ximg
, 0, 0, 0, 0,
651 image
->width
, image
->height
);
653 RDestroyXImage(context
, ximg
);
663 RConvertImageMask(RContext
*context
, RImage
*image
, Pixmap
*pixmap
,
664 Pixmap
*mask
, int threshold
)
670 assert(context
!=NULL
);
672 assert(pixmap
!=NULL
);
675 if (!RConvertImage(context
, image
, pixmap
))
678 if (image
->data
[3]==NULL
) {
683 ximg
= image2Bitmap(context
, image
, threshold
);
686 strcat(RErrorString
, ":could not convert RImage mask to XImage");
692 *mask
= XCreatePixmap(context
->dpy
, context
->drawable
, image
->width
,
694 gcv
.foreground
= context
->black
;
695 gcv
.background
= context
->white
;
696 gcv
.graphics_exposures
= False
;
697 gc
= XCreateGC(context
->dpy
, *mask
, GCForeground
|GCBackground
698 |GCGraphicsExposures
, &gcv
);
699 RPutXImage(context
, *mask
, gc
, ximg
, 0, 0, 0, 0,
700 image
->width
, image
->height
);
701 RDestroyXImage(context
, ximg
);
711 RGetClosestXColor(RContext
*context
, RColor
*color
, XColor
*retColor
)
715 if (context
->vclass
== TrueColor
) {
716 unsigned short rmask
, gmask
, bmask
;
717 unsigned short roffs
, goffs
, boffs
;
718 unsigned short *rtable
, *gtable
, *btable
;
720 roffs
= context
->red_offset
;
721 goffs
= context
->green_offset
;
722 boffs
= context
->blue_offset
;
724 rmask
= context
->visual
->red_mask
>> roffs
;
725 gmask
= context
->visual
->green_mask
>> goffs
;
726 bmask
= context
->visual
->blue_mask
>> boffs
;
728 rtable
= computeTable(rmask
);
729 gtable
= computeTable(gmask
);
730 btable
= computeTable(bmask
);
732 retColor
->pixel
= (rtable
[color
->red
]<<roffs
) |
733 (rtable
[color
->green
]<<goffs
) | (rtable
[color
->blue
]<<boffs
);
735 retColor
->red
= rtable
[color
->red
] << 8;
736 retColor
->green
= rtable
[color
->green
] << 8;
737 retColor
->blue
= rtable
[color
->blue
] << 8;
738 retColor
->flags
= DoRed
|DoGreen
|DoBlue
;
740 } else if (context
->vclass
== PseudoColor
|| context
->vclass
== StaticColor
) {
741 const int cpc
=context
->attribs
->colors_per_channel
;
742 const unsigned short rmask
= cpc
-1; /* different sizes could be used */
743 const unsigned short gmask
= rmask
; /* for r,g,b */
744 const unsigned short bmask
= rmask
;
745 unsigned short *rtable
, *gtable
, *btable
;
746 const int cpccpc
= cpc
*cpc
;
749 rtable
= computeTable(rmask
);
750 gtable
= computeTable(gmask
);
751 btable
= computeTable(bmask
);
753 if (rtable
==NULL
|| gtable
==NULL
|| btable
==NULL
) {
754 sprintf(RErrorString
, "out of memory");
757 index
= rtable
[color
->red
]*cpccpc
+ gtable
[color
->green
]*cpc
758 + btable
[color
->blue
];
759 *retColor
= context
->colors
[index
];
760 } else if (context
->vclass
== GrayScale
|| context
->vclass
== StaticGray
) {
762 const int cpc
= context
->attribs
->colors_per_channel
;
763 unsigned short gmask
;
764 unsigned short *table
;
767 if (context
->vclass
== StaticGray
)
768 gmask
= (1<<context
->depth
) - 1; /* use all grays */
770 gmask
= cpc
*cpc
*cpc
-1;
772 table
= computeTable(gmask
);
776 index
= table
[(color
->red
*30 + color
->green
*59 + color
->blue
*11)/100];
778 *retColor
= context
->colors
[index
];
780 sprintf(RErrorString
, "internal bug:unsupported visual:%i",