2 // "$Id: fl_draw_image.cxx 8731 2011-05-23 21:05:22Z AlbrechtS $"
4 // Image drawing routines for the Fast Light Tool Kit (FLTK).
6 // Copyright 1998-2010 by Bill Spitzak and others.
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
28 // I hope a simple and portable method of drawing color and monochrome
29 // images. To keep this simple, only a single storage type is
30 // supported: 8 bit unsigned data, byte order RGB, and pixels are
31 // stored packed into rows with the origin at the top-left. It is
32 // possible to alter the size of pixels with the "delta" argument, to
33 // add alpha or other information per pixel. It is also possible to
34 // change the origin and direction of the image data by messing with
35 // the "delta" and "linedelta", making them negative, though this may
36 // defeat some of the shortcuts in translating the image for X.
39 # include "fl_draw_image_win32.cxx"
40 #elif defined(__APPLE__)
41 # include "fl_draw_image_mac.cxx"
44 // A list of assumptions made about the X display:
46 // bits_per_pixel must be one of 8, 16, 24, 32.
48 // scanline_pad must be a power of 2 and greater or equal to 8.
50 // PsuedoColor visuals must have 8 bits_per_pixel (although the depth
51 // may be less than 8). This is the only limitation that affects any
52 // modern X displays, you can't use 12 or 16 bit colormaps.
54 // The mask bits in TrueColor visuals for each color are
55 // contiguous and have at least one bit of each color. This
56 // is not checked for.
58 // For 24 and 32 bit visuals there must be at least 8 bits of each color.
60 ////////////////////////////////////////////////////////////////
63 # include <FL/fl_draw.H>
65 # include "Fl_XColor.H"
66 # include "flstring.h"
68 static XImage xi
; // template used to pass info to X
69 static int bytes_per_pixel
;
70 static int scanline_add
;
71 static int scanline_mask
;
73 static void (*converter
)(const uchar
*from
, uchar
*to
, int w
, int delta
);
74 static void (*mono_converter
)(const uchar
*from
, uchar
*to
, int w
, int delta
);
76 static int dir
; // direction-alternator
77 static int ri
,gi
,bi
; // saved error-diffusion value
80 ////////////////////////////////////////////////////////////////
81 // 8-bit converter with error diffusion
83 static void color8_converter(const uchar
*from
, uchar
*to
, int w
, int delta
) {
88 from
= from
+(w
-1)*delta
;
97 for (; w
--; from
+= d
, to
+= td
) {
98 r
+= from
[0]; if (r
< 0) r
= 0; else if (r
>255) r
= 255;
99 g
+= from
[1]; if (g
< 0) g
= 0; else if (g
>255) g
= 255;
100 b
+= from
[2]; if (b
< 0) b
= 0; else if (b
>255) b
= 255;
101 Fl_Color i
= fl_color_cube(r
*FL_NUM_RED
/256,g
*FL_NUM_GREEN
/256,b
*FL_NUM_BLUE
/256);
102 Fl_XColor
& xmap
= fl_xmap
[0][i
];
103 if (!xmap
.mapped
) {if (!fl_redmask
) fl_xpixel(r
,g
,b
); else fl_xpixel(i
);}
107 *to
= uchar(xmap
.pixel
);
109 ri
= r
; gi
= g
; bi
= b
;
112 static void mono8_converter(const uchar
*from
, uchar
*to
, int w
, int delta
) {
113 int r
=ri
, g
=gi
, b
=bi
;
117 from
= from
+(w
-1)*delta
;
126 for (; w
--; from
+= d
, to
+= td
) {
127 r
+= from
[0]; if (r
< 0) r
= 0; else if (r
>255) r
= 255;
128 g
+= from
[0]; if (g
< 0) g
= 0; else if (g
>255) g
= 255;
129 b
+= from
[0]; if (b
< 0) b
= 0; else if (b
>255) b
= 255;
130 Fl_Color i
= fl_color_cube(r
*FL_NUM_RED
/256,g
*FL_NUM_GREEN
/256,b
*FL_NUM_BLUE
/256);
131 Fl_XColor
& xmap
= fl_xmap
[0][i
];
132 if (!xmap
.mapped
) {if (!fl_redmask
) fl_xpixel(r
,g
,b
); else fl_xpixel(i
);}
136 *to
= uchar(xmap
.pixel
);
138 ri
= r
; gi
= g
; bi
= b
;
143 ////////////////////////////////////////////////////////////////
144 // 16 bit TrueColor converters with error diffusion
145 // Cray computers have no 16-bit type, so we use character pointers
146 // (which may be slow)
151 # define OUTASSIGN(v) *t = v
153 # define OUTTYPE uchar
155 # define OUTASSIGN(v) int tt=v; t[0] = uchar(tt>>8); t[1] = uchar(tt)
158 static void color16_converter(const uchar
*from
, uchar
*to
, int w
, int delta
) {
159 OUTTYPE
*t
= (OUTTYPE
*)to
;
163 from
= from
+(w
-1)*delta
;
172 int r
=ri
, g
=gi
, b
=bi
;
173 for (; w
--; from
+= d
, t
+= td
) {
174 r
= (r
&~fl_redmask
) +from
[0]; if (r
>255) r
= 255;
175 g
= (g
&~fl_greenmask
)+from
[1]; if (g
>255) g
= 255;
176 b
= (b
&~fl_bluemask
) +from
[2]; if (b
>255) b
= 255;
178 ((r
&fl_redmask
)<<fl_redshift
)+
179 ((g
&fl_greenmask
)<<fl_greenshift
)+
180 ((b
&fl_bluemask
)<<fl_blueshift
)
183 ri
= r
; gi
= g
; bi
= b
;
186 static void mono16_converter(const uchar
*from
,uchar
*to
,int w
, int delta
) {
187 OUTTYPE
*t
= (OUTTYPE
*)to
;
191 from
= from
+(w
-1)*delta
;
200 uchar mask
= fl_redmask
& fl_greenmask
& fl_bluemask
;
202 for (; w
--; from
+= d
, t
+= td
) {
203 r
= (r
&~mask
) + *from
; if (r
> 255) r
= 255;
214 // special-case the 5r6g5b layout used by XFree86:
216 static void c565_converter(const uchar
*from
, uchar
*to
, int w
, int delta
) {
217 OUTTYPE
*t
= (OUTTYPE
*)to
;
221 from
= from
+(w
-1)*delta
;
230 int r
=ri
, g
=gi
, b
=bi
;
231 for (; w
--; from
+= d
, t
+= td
) {
232 r
= (r
&7)+from
[0]; if (r
>255) r
= 255;
233 g
= (g
&3)+from
[1]; if (g
>255) g
= 255;
234 b
= (b
&7)+from
[2]; if (b
>255) b
= 255;
235 OUTASSIGN(((r
&0xf8)<<8) + ((g
&0xfc)<<3) + (b
>>3));
237 ri
= r
; gi
= g
; bi
= b
;
240 static void m565_converter(const uchar
*from
,uchar
*to
,int w
, int delta
) {
241 OUTTYPE
*t
= (OUTTYPE
*)to
;
245 from
= from
+(w
-1)*delta
;
255 for (; w
--; from
+= d
, t
+= td
) {
256 r
= (r
&7) + *from
; if (r
> 255) r
= 255;
257 OUTASSIGN((r
>>3) * 0x841);
262 ////////////////////////////////////////////////////////////////
263 // 24bit TrueColor converters:
265 static void rgb_converter(const uchar
*from
, uchar
*to
, int w
, int delta
) {
267 for (; w
--; from
+= d
) {
274 static void bgr_converter(const uchar
*from
, uchar
*to
, int w
, int delta
) {
275 for (; w
--; from
+= delta
) {
284 static void rrr_converter(const uchar
*from
, uchar
*to
, int w
, int delta
) {
285 for (; w
--; from
+= delta
) {
292 ////////////////////////////////////////////////////////////////
293 // 32bit TrueColor converters on a 32 or 64-bit machine:
295 # define STORETYPE U32
296 # define INNARDS32(f) \
297 U32 *t = (U32*)to; for (; w--; from += delta) *t++ = f
299 static void rgbx_converter(const uchar
*from
, uchar
*to
, int w
, int delta
) {
300 INNARDS32((unsigned(from
[0])<<24)+(from
[1]<<16)+(from
[2]<<8));
303 static void xbgr_converter(const uchar
*from
, uchar
*to
, int w
, int delta
) {
304 INNARDS32((from
[0])+(from
[1]<<8)+(from
[2]<<16));
307 static void xrgb_converter(const uchar
*from
, uchar
*to
, int w
, int delta
) {
308 INNARDS32((from
[0]<<16)+(from
[1]<<8)+(from
[2]));
311 static void bgrx_converter(const uchar
*from
, uchar
*to
, int w
, int delta
) {
312 INNARDS32((from
[0]<<8)+(from
[1]<<16)+(unsigned(from
[2])<<24));
315 static void rrrx_converter(const uchar
*from
, uchar
*to
, int w
, int delta
) {
316 INNARDS32(unsigned(*from
) * 0x1010100U
);
319 static void xrrr_converter(const uchar
*from
, uchar
*to
, int w
, int delta
) {
320 INNARDS32(*from
* 0x10101U
);
324 color32_converter(const uchar
*from
, uchar
*to
, int w
, int delta
) {
326 (from
[0]<<fl_redshift
)+(from
[1]<<fl_greenshift
)+(from
[2]<<fl_blueshift
));
330 mono32_converter(const uchar
*from
,uchar
*to
,int w
, int delta
) {
332 (*from
<< fl_redshift
)+(*from
<< fl_greenshift
)+(*from
<< fl_blueshift
));
335 ////////////////////////////////////////////////////////////////
337 static void figure_out_visual() {
339 fl_xpixel(FL_BLACK
); // setup fl_redmask, etc, in fl_color.cxx
340 fl_xpixel(FL_WHITE
); // also make sure white is allocated
342 static XPixmapFormatValues
*pfvlist
;
343 static int FL_NUM_pfv
;
344 if (!pfvlist
) pfvlist
= XListPixmapFormats(fl_display
,&FL_NUM_pfv
);
345 XPixmapFormatValues
*pfv
;
346 for (pfv
= pfvlist
; pfv
< pfvlist
+FL_NUM_pfv
; pfv
++)
347 if (pfv
->depth
== fl_visual
->depth
) break;
349 xi
.byte_order
= ImageByteOrder(fl_display
);
351 //i.bitmap_bit_order = MSBFirst;
353 xi
.depth
= fl_visual
->depth
;
354 xi
.bits_per_pixel
= pfv
->bits_per_pixel
;
356 if (xi
.bits_per_pixel
& 7) bytes_per_pixel
= 0; // produce fatal error
357 else bytes_per_pixel
= xi
.bits_per_pixel
/8;
359 unsigned int n
= pfv
->scanline_pad
/8;
360 if (pfv
->scanline_pad
& 7 || (n
&(n
-1)))
361 Fl::fatal("Can't do scanline_pad of %d",pfv
->scanline_pad
);
362 if (n
< sizeof(STORETYPE
)) n
= sizeof(STORETYPE
);
367 if (bytes_per_pixel
== 1) {
368 converter
= color8_converter
;
369 mono_converter
= mono8_converter
;
372 if (!fl_visual
->red_mask
)
373 Fl::fatal("Can't do %d bits_per_pixel colormap",xi
.bits_per_pixel
);
376 // otherwise it is a TrueColor visual:
378 int rs
= fl_redshift
;
379 int gs
= fl_greenshift
;
380 int bs
= fl_blueshift
;
382 switch (bytes_per_pixel
) {
385 // All 16-bit TrueColor visuals are supported on any machine with
386 // 24 or more bits per integer.
388 xi
.byte_order
= WORDS_BIGENDIAN
;
392 if (rs
== 11 && gs
== 6 && bs
== 0 && fl_extrashift
== 3) {
393 converter
= c565_converter
;
394 mono_converter
= m565_converter
;
396 converter
= color16_converter
;
397 mono_converter
= mono16_converter
;
402 if (xi
.byte_order
) {rs
= 16-rs
; gs
= 16-gs
; bs
= 16-bs
;}
403 if (rs
== 0 && gs
== 8 && bs
== 16) {
404 converter
= rgb_converter
;
405 mono_converter
= rrr_converter
;
406 } else if (rs
== 16 && gs
== 8 && bs
== 0) {
407 converter
= bgr_converter
;
408 mono_converter
= rrr_converter
;
410 Fl::fatal("Can't do arbitrary 24bit color");
415 if ((xi
.byte_order
!=0) != WORDS_BIGENDIAN
)
416 {rs
= 24-rs
; gs
= 24-gs
; bs
= 24-bs
;}
417 if (rs
== 0 && gs
== 8 && bs
== 16) {
418 converter
= xbgr_converter
;
419 mono_converter
= xrrr_converter
;
420 } else if (rs
== 24 && gs
== 16 && bs
== 8) {
421 converter
= rgbx_converter
;
422 mono_converter
= rrrx_converter
;
423 } else if (rs
== 8 && gs
== 16 && bs
== 24) {
424 converter
= bgrx_converter
;
425 mono_converter
= rrrx_converter
;
426 } else if (rs
== 16 && gs
== 8 && bs
== 0) {
427 converter
= xrgb_converter
;
428 mono_converter
= xrrr_converter
;
430 xi
.byte_order
= WORDS_BIGENDIAN
;
431 converter
= color32_converter
;
432 mono_converter
= mono32_converter
;
437 Fl::fatal("Can't do %d bits_per_pixel",xi
.bits_per_pixel
);
442 # define MAXBUFFER 0x40000 // 256k
444 static void innards(const uchar
*buf
, int X
, int Y
, int W
, int H
,
445 int delta
, int linedelta
, int mono
,
446 Fl_Draw_Image_Cb cb
, void* userdata
)
448 if (!linedelta
) linedelta
= W
*delta
;
451 fl_clip_box(X
,Y
,W
,H
,dx
,dy
,w
,h
);
452 if (w
<=0 || h
<=0) return;
456 if (!bytes_per_pixel
) figure_out_visual();
460 void (*conv
)(const uchar
*from
, uchar
*to
, int w
, int delta
) = converter
;
461 if (mono
) conv
= mono_converter
;
463 // See if the data is already in the right format. Unfortunately
464 // some 32-bit x servers (XFree86) care about the unknown 8 bits
465 // and they must be zero. I can't confirm this for user-supplied
466 // data, so the 32-bit shortcut is disabled...
467 // This can set bytes_per_line negative if image is bottom-to-top
468 // I tested it on Linux, but it may fail on other Xlib implementations:
470 # if 0 // set this to 1 to allow 32-bit shortcut
473 conv
== rgbx_converter
475 conv
== xbgr_converter
479 conv
== rgb_converter
&& delta
==3
480 ) && !(linedelta
&scanline_add
)) {
481 xi
.data
= (char *)(buf
+delta
*dx
+linedelta
*dy
);
482 xi
.bytes_per_line
= linedelta
;
485 int linesize
= ((w
*bytes_per_pixel
+scanline_add
)&scanline_mask
)/sizeof(STORETYPE
);
487 static STORETYPE
*buffer
; // our storage, always word aligned
488 static long buffer_size
;
489 {int size
= linesize
*h
;
490 if (size
> MAXBUFFER
) {
492 blocking
= MAXBUFFER
/linesize
;
494 if (size
> buffer_size
) {
497 buffer
= new STORETYPE
[size
];
499 xi
.data
= (char *)buffer
;
500 xi
.bytes_per_line
= linesize
*sizeof(STORETYPE
);
502 buf
+= delta
*dx
+linedelta
*dy
;
503 for (int j
=0; j
<h
; ) {
504 STORETYPE
*to
= buffer
;
506 for (k
= 0; j
<h
&& k
<blocking
; k
++, j
++) {
507 conv(buf
, (uchar
*)to
, w
, delta
);
511 XPutImage(fl_display
,fl_window
,fl_gc
, &xi
, 0, 0, X
+dx
, Y
+dy
+j
-k
, w
, k
);
514 STORETYPE
* linebuf
= new STORETYPE
[(W
*delta
+(sizeof(STORETYPE
)-1))/sizeof(STORETYPE
)];
515 for (int j
=0; j
<h
; ) {
516 STORETYPE
*to
= buffer
;
518 for (k
= 0; j
<h
&& k
<blocking
; k
++, j
++) {
519 cb(userdata
, dx
, dy
+j
, w
, (uchar
*)linebuf
);
520 conv((uchar
*)linebuf
, (uchar
*)to
, w
, delta
);
523 XPutImage(fl_display
,fl_window
,fl_gc
, &xi
, 0, 0, X
+dx
, Y
+dy
+j
-k
, w
, k
);
531 void Fl_Xlib_Graphics_Driver::draw_image(const uchar
* buf
, int x
, int y
, int w
, int h
, int d
, int l
){
532 innards(buf
,x
,y
,w
,h
,d
,l
,(d
<3&&d
>-3),0,0);
534 void Fl_Xlib_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb
, void* data
,
535 int x
, int y
, int w
, int h
,int d
) {
536 innards(0,x
,y
,w
,h
,d
,0,(d
<3&&d
>-3),cb
,data
);
538 void Fl_Xlib_Graphics_Driver::draw_image_mono(const uchar
* buf
, int x
, int y
, int w
, int h
, int d
, int l
){
539 innards(buf
,x
,y
,w
,h
,d
,l
,1,0,0);
541 void Fl_Xlib_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb
, void* data
,
542 int x
, int y
, int w
, int h
,int d
) {
543 innards(0,x
,y
,w
,h
,d
,0,1,cb
,data
);
546 void fl_rectf(int x
, int y
, int w
, int h
, uchar r
, uchar g
, uchar b
) {
547 if (fl_visual
->depth
> 16) {
552 c
[0] = r
; c
[1] = g
; c
[2] = b
;
553 innards(c
,x
,y
,w
,h
,0,0,0,0,0);
560 // End of "$Id: fl_draw_image.cxx 8731 2011-05-23 21:05:22Z AlbrechtS $".