2 // "$Id: Fl_Bitmap.cxx 8360 2011-02-02 12:42:47Z manolo $"
4 // Bitmap 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 /** \fn Fl_Bitmap::Fl_Bitmap(const char *array, int W, int H)
29 The constructors create a new bitmap from the specified bitmap data.*/
31 /** \fn Fl_Bitmap::Fl_Bitmap(const unsigned char *array, int W, int H)
32 The constructors create a new bitmap from the specified bitmap data.*/
36 #include <FL/fl_draw.H>
37 #include <FL/Fl_Widget.H>
38 #include <FL/Fl_Menu_Item.H>
39 #include <FL/Fl_Bitmap.H>
40 #include <FL/Fl_Printer.H>
43 #if defined(__APPLE_QUARTZ__)
46 Fl_Bitmask
fl_create_bitmask(int w
, int h
, const uchar
*array
) {
47 static uchar reverse
[16] = /* Bit reversal lookup table */
48 { 0x00, 0x88, 0x44, 0xcc, 0x22, 0xaa, 0x66, 0xee,
49 0x11, 0x99, 0x55, 0xdd, 0x33, 0xbb, 0x77, 0xff };
50 int rowBytes
= (w
+7)>>3 ;
51 uchar
*bmask
= (uchar
*)malloc(rowBytes
*h
), *dst
= bmask
;
52 const uchar
*src
= array
;
53 for ( int i
=rowBytes
*h
; i
>0; i
--,src
++ ) {
54 *dst
++ = ((reverse
[*src
& 0x0f] & 0xf0) | (reverse
[(*src
>> 4) & 0x0f] & 0x0f))^0xff;
56 CGDataProviderRef srcp
= CGDataProviderCreateWithData( 0L, bmask
, rowBytes
*h
, 0L);
57 CGImageRef id_
= CGImageMaskCreate( w
, h
, 1, 1, rowBytes
, srcp
, 0L, false);
58 CGDataProviderRelease(srcp
);
59 return (Fl_Bitmask
)id_
;
61 void fl_delete_bitmask(Fl_Bitmask bm
) {
62 if (bm
) CGImageRelease((CGImageRef
)bm
);
66 #elif defined(WIN32) // Windows bitmask functions...
69 // 'fl_create_bitmap()' - Create a 1-bit bitmap for drawing...
70 static Fl_Bitmask
fl_create_bitmap(int w
, int h
, const uchar
*data
) {
71 // we need to pad the lines out to words & swap the bits
74 int w2
= ((w
+15)/16)*2;
75 uchar
* newarray
= new uchar
[w2
*h
];
76 const uchar
* src
= data
;
77 uchar
* dest
= newarray
;
79 static uchar reverse
[16] = /* Bit reversal lookup table */
80 { 0x00, 0x88, 0x44, 0xcc, 0x22, 0xaa, 0x66, 0xee,
81 0x11, 0x99, 0x55, 0xdd, 0x33, 0xbb, 0x77, 0xff };
83 for (int y
=0; y
< h
; y
++) {
84 for (int n
= 0; n
< w1
; n
++, src
++)
85 *dest
++ = (uchar
)((reverse
[*src
& 0x0f] & 0xf0) |
86 (reverse
[(*src
>> 4) & 0x0f] & 0x0f));
90 bm
= CreateBitmap(w
, h
, 1, 1, newarray
);
97 // 'fl_create_bitmask()' - Create an N-bit bitmap for masking...
98 Fl_Bitmask
fl_create_bitmask(int w
, int h
, const uchar
*data
) {
99 // this won't work when the user changes display mode during run or
100 // has two screens with differnet depths
102 static uchar hiNibble
[16] =
103 { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
104 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0 };
105 static uchar loNibble
[16] =
106 { 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e,
107 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f };
108 int np
= GetDeviceCaps(fl_gc
, PLANES
); //: was always one on sample machines
109 int bpp
= GetDeviceCaps(fl_gc
, BITSPIXEL
);//: 1,4,8,16,24,32 and more odd stuff?
110 int Bpr
= (bpp
*w
+7)/8; //: bytes per row
111 int pad
= Bpr
&1, w1
= (w
+7)/8, shr
= ((w
-1)&7)+1;
112 if (bpp
==4) shr
= (shr
+1)/2;
113 uchar
*newarray
= new uchar
[(Bpr
+pad
)*h
];
114 uchar
*dst
= newarray
;
115 const uchar
*src
= data
;
117 for (int i
=0; i
<h
; i
++) {
118 // This is slooow, but we do it only once per pixmap
119 for (int j
=w1
; j
>0; j
--) {
122 *dst
++ = (uchar
)( hiNibble
[b
&15] ) | ( loNibble
[(b
>>4)&15] );
124 for (int k
=(j
==1)?shr
:4; k
>0; k
--) {
125 *dst
++ = (uchar
)("\377\360\017\000"[b
&3]);
129 for (int k
=(j
==1)?shr
:8; k
>0; k
--) {
133 if (bpp
>16) *dst
++=0;
134 if (bpp
>24) *dst
++=0;
137 if (bpp
>8) *dst
++=0xff;
138 if (bpp
>16) *dst
++=0xff;
139 if (bpp
>24) *dst
++=0xff;
150 bm
= CreateBitmap(w
, h
, np
, bpp
, newarray
);
157 void fl_delete_bitmask(Fl_Bitmask bm
) {
158 DeleteObject((HGDIOBJ
)bm
);
162 #else // X11 bitmask functions
165 Fl_Bitmask
fl_create_bitmask(int w
, int h
, const uchar
*data
) {
166 return XCreateBitmapFromData(fl_display
, fl_window
, (const char *)data
,
170 void fl_delete_bitmask(Fl_Bitmask bm
) {
171 fl_delete_offscreen((Fl_Offscreen
)bm
);
178 // Create a 1-bit mask used for alpha blending
179 Fl_Bitmask
fl_create_alphamask(int w
, int h
, int d
, int ld
, const uchar
*array
) {
181 int bmw
= (w
+ 7) / 8;
182 uchar
*bitmap
= new uchar
[bmw
* h
];
184 const uchar
*dataptr
;
186 static uchar dither
[16][16] = { // Simple 16x16 Floyd dither
187 { 0, 128, 32, 160, 8, 136, 40, 168,
188 2, 130, 34, 162, 10, 138, 42, 170 },
189 { 192, 64, 224, 96, 200, 72, 232, 104,
190 194, 66, 226, 98, 202, 74, 234, 106 },
191 { 48, 176, 16, 144, 56, 184, 24, 152,
192 50, 178, 18, 146, 58, 186, 26, 154 },
193 { 240, 112, 208, 80, 248, 120, 216, 88,
194 242, 114, 210, 82, 250, 122, 218, 90 },
195 { 12, 140, 44, 172, 4, 132, 36, 164,
196 14, 142, 46, 174, 6, 134, 38, 166 },
197 { 204, 76, 236, 108, 196, 68, 228, 100,
198 206, 78, 238, 110, 198, 70, 230, 102 },
199 { 60, 188, 28, 156, 52, 180, 20, 148,
200 62, 190, 30, 158, 54, 182, 22, 150 },
201 { 252, 124, 220, 92, 244, 116, 212, 84,
202 254, 126, 222, 94, 246, 118, 214, 86 },
203 { 3, 131, 35, 163, 11, 139, 43, 171,
204 1, 129, 33, 161, 9, 137, 41, 169 },
205 { 195, 67, 227, 99, 203, 75, 235, 107,
206 193, 65, 225, 97, 201, 73, 233, 105 },
207 { 51, 179, 19, 147, 59, 187, 27, 155,
208 49, 177, 17, 145, 57, 185, 25, 153 },
209 { 243, 115, 211, 83, 251, 123, 219, 91,
210 241, 113, 209, 81, 249, 121, 217, 89 },
211 { 15, 143, 47, 175, 7, 135, 39, 167,
212 13, 141, 45, 173, 5, 133, 37, 165 },
213 { 207, 79, 239, 111, 199, 71, 231, 103,
214 205, 77, 237, 109, 197, 69, 229, 101 },
215 { 63, 191, 31, 159, 55, 183, 23, 151,
216 61, 189, 29, 157, 53, 181, 21, 149 },
217 { 254, 127, 223, 95, 247, 119, 215, 87,
218 253, 125, 221, 93, 245, 117, 213, 85 }
221 // Generate a 1-bit "screen door" alpha mask; not always pretty, but
222 // definitely fast... In the future we may be able to support things
223 // like the RENDER extension in XFree86, when available, to provide
224 // true RGBA-blended rendering. See:
226 // http://www.xfree86.org/~keithp/render/protocol.html
228 // for more info on XRender...
230 // MacOS already provides alpha blending support and has its own
231 // fl_create_alphamask() function...
232 memset(bitmap
, 0, bmw
* h
);
234 for (dataptr
= array
+ d
- 1, y
= 0; y
< h
; y
++, dataptr
+= ld
)
235 for (bitptr
= bitmap
+ y
* bmw
, bit
= 1, x
= 0; x
< w
; x
++, dataptr
+= d
) {
236 if (*dataptr
> dither
[x
& 15][y
& 15])
238 if (bit
< 128) bit
<<= 1;
245 bm
= fl_create_bitmask(w
, h
, bitmap
);
251 void Fl_Bitmap::draw(int XP
, int YP
, int WP
, int HP
, int cx
, int cy
) {
252 fl_graphics_driver
->draw(this, XP
, YP
, WP
, HP
, cx
, cy
);
255 static int start(Fl_Bitmap
*bm
, int XP
, int YP
, int WP
, int HP
, int w
, int h
, int &cx
, int &cy
,
256 int &X
, int &Y
, int &W
, int &H
)
258 // account for current clip region (faster on Irix):
259 fl_clip_box(XP
,YP
,WP
,HP
,X
,Y
,W
,H
);
260 cx
+= X
-XP
; cy
+= Y
-YP
;
261 // clip the box down to the size of image, quit if empty:
262 if (cx
< 0) {W
+= cx
; X
-= cx
; cx
= 0;}
263 if (cx
+W
> w
) W
= w
-cx
;
264 if (W
<= 0) return 1;
265 if (cy
< 0) {H
+= cy
; Y
-= cy
; cy
= 0;}
266 if (cy
+H
> h
) H
= h
-cy
;
267 if (H
<= 0) return 1;
272 void Fl_Quartz_Graphics_Driver::draw(Fl_Bitmap
*bm
, int XP
, int YP
, int WP
, int HP
, int cx
, int cy
) {
275 bm
->draw_empty(XP
, YP
);
278 if (start(bm
, XP
, YP
, WP
, HP
, bm
->w(), bm
->h(), cx
, cy
, X
, Y
, W
, H
)) {
281 if (!bm
->id_
) bm
->id_
= fl_create_bitmask(bm
->w(), bm
->h(), bm
->array
);
282 if (bm
->id_
&& fl_gc
) {
283 CGRect rect
= { { X
, Y
}, { W
, H
} };
284 Fl_X::q_begin_image(rect
, cx
, cy
, bm
->w(), bm
->h());
285 CGContextDrawImage(fl_gc
, rect
, (CGImageRef
)bm
->id_
);
291 void Fl_GDI_Graphics_Driver::draw(Fl_Bitmap
*bm
, int XP
, int YP
, int WP
, int HP
, int cx
, int cy
) {
294 bm
->draw_empty(XP
, YP
);
297 if (start(bm
, XP
, YP
, WP
, HP
, bm
->w(), bm
->h(), cx
, cy
, X
, Y
, W
, H
)) {
300 if (!bm
->id_
) bm
->id_
= fl_create_bitmap(bm
->w(), bm
->h(), bm
->array
);
302 typedef BOOL (WINAPI
* fl_transp_func
) (HDC
,int,int,int,int,HDC
,int,int,int,int,UINT
);
303 static fl_transp_func fl_TransparentBlt
;
306 BOOL use_print_algo
= false;
307 if (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id
) {
308 static HMODULE hMod
= NULL
;
310 hMod
= LoadLibrary("MSIMG32.DLL");
311 if (hMod
) fl_TransparentBlt
= (fl_transp_func
)GetProcAddress(hMod
, "TransparentBlt");
313 if (fl_TransparentBlt
) use_print_algo
= true;
315 if (use_print_algo
) { // algorithm for bitmap output to Fl_GDI_Printer
316 Fl_Offscreen tmp_id
= fl_create_offscreen(W
, H
);
317 fl_begin_offscreen(tmp_id
);
318 Fl_Color save_c
= fl_color(); // save bitmap's desired color
320 Fl::get_color(save_c
, r
, g
, b
);
324 Fl_Color background
= fl_rgb_color(r
, g
, b
); // a color very different from the bitmap's
325 fl_color(background
);
326 fl_rectf(0,0,W
,H
); // use this color as offscreen background
327 fl_color(save_c
); // back to bitmap's color
328 tempdc
= CreateCompatibleDC(fl_gc
);
329 save
= SaveDC(tempdc
);
330 SelectObject(tempdc
, (HGDIOBJ
)bm
->id_
);
331 SelectObject(fl_gc
, fl_brush()); // use bitmap's desired color
332 BitBlt(fl_gc
, 0, 0, W
, H
, tempdc
, 0, 0, 0xE20746L
); // draw bitmap to offscreen
333 fl_end_offscreen(); // offscreen data is in tmp_id
334 SelectObject(tempdc
, (HGDIOBJ
)tmp_id
); // use offscreen data
335 // draw it to printer context with background color as transparent
336 fl_TransparentBlt(fl_gc
, X
,Y
,W
,H
, tempdc
, cx
, cy
, bm
->w(), bm
->h(), RGB(r
, g
, b
) );
337 fl_delete_offscreen(tmp_id
);
339 else { // algorithm for bitmap output to display
340 tempdc
= CreateCompatibleDC(fl_gc
);
341 save
= SaveDC(tempdc
);
342 SelectObject(tempdc
, (HGDIOBJ
)bm
->id_
);
343 SelectObject(fl_gc
, fl_brush());
344 // secret bitblt code found in old MSWindows reference manual:
345 BitBlt(fl_gc
, X
, Y
, W
, H
, tempdc
, cx
, cy
, 0xE20746L
);
347 RestoreDC(tempdc
, save
);
352 void Fl_Xlib_Graphics_Driver::draw(Fl_Bitmap
*bm
, int XP
, int YP
, int WP
, int HP
, int cx
, int cy
) {
355 bm
->draw_empty(XP
, YP
);
358 if (start(bm
, XP
, YP
, WP
, HP
, bm
->w(), bm
->h(), cx
, cy
, X
, Y
, W
, H
)) {
361 if (!bm
->id_
) bm
->id_
= fl_create_bitmask(bm
->w(), bm
->h(), bm
->array
);
363 XSetStipple(fl_display
, fl_gc
, bm
->id_
);
364 int ox
= X
-cx
; if (ox
< 0) ox
+= bm
->w();
365 int oy
= Y
-cy
; if (oy
< 0) oy
+= bm
->h();
366 XSetTSOrigin(fl_display
, fl_gc
, ox
, oy
);
367 XSetFillStyle(fl_display
, fl_gc
, FillStippled
);
368 XFillRectangle(fl_display
, fl_window
, fl_gc
, X
, Y
, W
, H
);
369 XSetFillStyle(fl_display
, fl_gc
, FillSolid
);
374 The destructor free all memory and server resources that are used by
377 Fl_Bitmap::~Fl_Bitmap() {
379 if (alloc_array
) delete[] (uchar
*)array
;
382 void Fl_Bitmap::uncache() {
384 #ifdef __APPLE_QUARTZ__
385 fl_delete_bitmask((Fl_Bitmask
)id_
);
387 fl_delete_bitmask((Fl_Offscreen
)id_
);
393 void Fl_Bitmap::label(Fl_Widget
* widget
) {
397 void Fl_Bitmap::label(Fl_Menu_Item
* m
) {
398 Fl::set_labeltype(_FL_IMAGE_LABEL
, labeltype
, measure
);
399 m
->label(_FL_IMAGE_LABEL
, (const char*)this);
402 Fl_Image
*Fl_Bitmap::copy(int W
, int H
) {
403 Fl_Bitmap
*new_image
; // New RGB image
404 uchar
*new_array
; // New array for image data
406 // Optimize the simple copy where the width and height are the same...
407 if (W
== w() && H
== h()) {
408 new_array
= new uchar
[H
* ((W
+ 7) / 8)];
409 memcpy(new_array
, array
, H
* ((W
+ 7) / 8));
411 new_image
= new Fl_Bitmap(new_array
, W
, H
);
412 new_image
->alloc_array
= 1;
416 if (W
<= 0 || H
<= 0) return 0;
418 // OK, need to resize the image data; allocate memory and
419 uchar
*new_ptr
, // Pointer into new array
420 new_bit
, // Bit for new array
421 old_bit
; // Bit for old array
422 const uchar
*old_ptr
; // Pointer into old array
423 int sx
, sy
, // Source coordinates
424 dx
, dy
, // Destination coordinates
425 xerr
, yerr
, // X & Y errors
426 xmod
, ymod
, // X & Y moduli
427 xstep
, ystep
; // X & Y step increments
430 // Figure out Bresenheim step/modulus values...
436 // Allocate memory for the new image...
437 new_array
= new uchar
[H
* ((W
+ 7) / 8)];
438 new_image
= new Fl_Bitmap(new_array
, W
, H
);
439 new_image
->alloc_array
= 1;
441 memset(new_array
, 0, H
* ((W
+ 7) / 8));
443 // Scale the image using a nearest-neighbor algorithm...
444 for (dy
= H
, sy
= 0, yerr
= H
, new_ptr
= new_array
; dy
> 0; dy
--) {
445 for (dx
= W
, xerr
= W
, old_ptr
= array
+ sy
* ((w() + 7) / 8), sx
= 0, new_bit
= 1;
448 old_bit
= (uchar
)(1 << (sx
& 7));
449 if (old_ptr
[sx
/ 8] & old_bit
) *new_ptr
|= new_bit
;
451 if (new_bit
< 128) new_bit
<<= 1;
466 if (new_bit
> 1) new_ptr
++;
481 // End of "$Id: Fl_Bitmap.cxx 8360 2011-02-02 12:42:47Z manolo $".