1 //
2 // "$Id: Fl_Bitmap.cxx 8360 2011-02-02 12:42:47Z manolo $"
3 //
4 // Bitmap drawing routines for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
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.
12 //
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.
17 //
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
21 // USA.
22 //
23 // Please report all bugs and problems on the following page:
24 //
25 //     http://www.fltk.org/str.php
26 //
27 
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.*/
30 
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.*/
33 
34 #include <FL/Fl.H>
35 #include <FL/x.H>
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>
41 #include "flstring.h"
42 
43 #if defined(__APPLE_QUARTZ__)
44 
45 
fl_create_bitmask(int w,int h,const uchar * array)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;
55   }
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_;
60 }
fl_delete_bitmask(Fl_Bitmask bm)61 void fl_delete_bitmask(Fl_Bitmask bm) {
62   if (bm) CGImageRelease((CGImageRef)bm);
63 }
64 
65 
66 #elif defined(WIN32) // Windows bitmask functions...
67 
68 
69 // 'fl_create_bitmap()' - Create a 1-bit bitmap for drawing...
fl_create_bitmap(int w,int h,const uchar * data)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
72   // in each byte.
73   int w1 = (w+7)/8;
74   int w2 = ((w+15)/16)*2;
75   uchar* newarray = new uchar[w2*h];
76   const uchar* src = data;
77   uchar* dest = newarray;
78   Fl_Bitmask bm;
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 };
82 
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));
87     dest += w2-w1;
88   }
89 
90   bm = CreateBitmap(w, h, 1, 1, newarray);
91 
92   delete[] newarray;
93 
94   return bm;
95 }
96 
97 // 'fl_create_bitmask()' - Create an N-bit bitmap for masking...
fl_create_bitmask(int w,int h,const uchar * data)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
101   Fl_Bitmask bm;
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;
116 
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--) {
120       uchar b = *src++;
121       if (bpp==1) {
122         *dst++ = (uchar)( hiNibble[b&15] ) | ( loNibble[(b>>4)&15] );
123       } else if (bpp==4) {
124         for (int k=(j==1)?shr:4; k>0; k--) {
125           *dst++ = (uchar)("\377\360\017\000"[b&3]);
126           b = b >> 2;
127         }
128       } else {
129         for (int k=(j==1)?shr:8; k>0; k--) {
130           if (b&1) {
131             *dst++=0;
132 	    if (bpp>8) *dst++=0;
133             if (bpp>16) *dst++=0;
134 	    if (bpp>24) *dst++=0;
135 	  } else {
136 	    *dst++=0xff;
137 	    if (bpp>8) *dst++=0xff;
138 	    if (bpp>16) *dst++=0xff;
139 	    if (bpp>24) *dst++=0xff;
140 	  }
141 
142 	  b = b >> 1;
143         }
144       }
145     }
146 
147     dst += pad;
148   }
149 
150   bm = CreateBitmap(w, h, np, bpp, newarray);
151   delete[] newarray;
152 
153   return bm;
154 }
155 
156 
fl_delete_bitmask(Fl_Bitmask bm)157 void fl_delete_bitmask(Fl_Bitmask bm) {
158   DeleteObject((HGDIOBJ)bm);
159 }
160 
161 
162 #else // X11 bitmask functions
163 
164 
fl_create_bitmask(int w,int h,const uchar * data)165 Fl_Bitmask fl_create_bitmask(int w, int h, const uchar *data) {
166   return XCreateBitmapFromData(fl_display, fl_window, (const char *)data,
167                                (w+7)&-8, h);
168 }
169 
fl_delete_bitmask(Fl_Bitmask bm)170 void fl_delete_bitmask(Fl_Bitmask bm) {
171   fl_delete_offscreen((Fl_Offscreen)bm);
172 }
173 
174 
175 #endif // __APPLE__
176 
177 
178 // Create a 1-bit mask used for alpha blending
fl_create_alphamask(int w,int h,int d,int ld,const uchar * array)179 Fl_Bitmask fl_create_alphamask(int w, int h, int d, int ld, const uchar *array) {
180   Fl_Bitmask bm;
181   int bmw = (w + 7) / 8;
182   uchar *bitmap = new uchar[bmw * h];
183   uchar *bitptr, bit;
184   const uchar *dataptr;
185   int x, y;
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 }
219   };
220 
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:
225   //
226   //     http://www.xfree86.org/~keithp/render/protocol.html
227   //
228   // for more info on XRender...
229   //
230   // MacOS already provides alpha blending support and has its own
231   // fl_create_alphamask() function...
232   memset(bitmap, 0, bmw * h);
233 
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])
237 	*bitptr |= bit;
238       if (bit < 128) bit <<= 1;
239       else {
240 	bit = 1;
241 	bitptr ++;
242       }
243     }
244 
245   bm = fl_create_bitmask(w, h, bitmap);
246   delete[] bitmap;
247 
248   return (bm);
249 }
250 
draw(int XP,int YP,int WP,int HP,int cx,int cy)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);
253 }
254 
start(Fl_Bitmap * bm,int XP,int YP,int WP,int HP,int w,int h,int & cx,int & cy,int & X,int & Y,int & W,int & H)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)
257 {
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;
268   return 0;
269 }
270 
271 #ifdef __APPLE__
draw(Fl_Bitmap * bm,int XP,int YP,int WP,int HP,int cx,int cy)272 void Fl_Quartz_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) {
273   int X, Y, W, H;
274   if (!bm->array) {
275     bm->draw_empty(XP, YP);
276     return;
277   }
278   if (start(bm, XP, YP, WP, HP, bm->w(), bm->h(), cx, cy, X, Y, W, H)) {
279     return;
280   }
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_);
286     Fl_X::q_end_image();
287   }
288 }
289 
290 #elif defined(WIN32)
draw(Fl_Bitmap * bm,int XP,int YP,int WP,int HP,int cx,int cy)291 void Fl_GDI_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) {
292   int X, Y, W, H;
293   if (!bm->array) {
294     bm->draw_empty(XP, YP);
295     return;
296   }
297   if (start(bm, XP, YP, WP, HP, bm->w(), bm->h(), cx, cy, X, Y, W, H)) {
298     return;
299   }
300   if (!bm->id_) bm->id_ = fl_create_bitmap(bm->w(), bm->h(), bm->array);
301 
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;
304   HDC tempdc;
305   int save;
306   BOOL use_print_algo = false;
307   if (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) {
308     static HMODULE hMod = NULL;
309     if (!hMod) {
310       hMod = LoadLibrary("MSIMG32.DLL");
311       if (hMod) fl_TransparentBlt = (fl_transp_func)GetProcAddress(hMod, "TransparentBlt");
312     }
313     if (fl_TransparentBlt) use_print_algo = true;
314   }
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
319     uchar r, g, b;
320     Fl::get_color(save_c, r, g, b);
321     r = 255-r;
322     g = 255-g;
323     b = 255-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);
338   }
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);
346   }
347   RestoreDC(tempdc, save);
348   DeleteDC(tempdc);
349 }
350 
351 #else // Xlib
draw(Fl_Bitmap * bm,int XP,int YP,int WP,int HP,int cx,int cy)352 void Fl_Xlib_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) {
353   int X, Y, W, H;
354   if (!bm->array) {
355     bm->draw_empty(XP, YP);
356     return;
357   }
358   if (start(bm, XP, YP, WP, HP, bm->w(), bm->h(), cx, cy, X, Y, W, H)) {
359     return;
360   }
361   if (!bm->id_) bm->id_ = fl_create_bitmask(bm->w(), bm->h(), bm->array);
362 
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);
370 }
371 #endif
372 
373 /**
374   The destructor free all memory and server resources that are used by
375   the bitmap.
376 */
~Fl_Bitmap()377 Fl_Bitmap::~Fl_Bitmap() {
378   uncache();
379   if (alloc_array) delete[] (uchar *)array;
380 }
381 
uncache()382 void Fl_Bitmap::uncache() {
383   if (id_) {
384 #ifdef __APPLE_QUARTZ__
385     fl_delete_bitmask((Fl_Bitmask)id_);
386 #else
387     fl_delete_bitmask((Fl_Offscreen)id_);
388 #endif
389     id_ = 0;
390   }
391 }
392 
label(Fl_Widget * widget)393 void Fl_Bitmap::label(Fl_Widget* widget) {
394   widget->image(this);
395 }
396 
label(Fl_Menu_Item * m)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);
400 }
401 
copy(int W,int H)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
405 
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));
410 
411     new_image = new Fl_Bitmap(new_array, W, H);
412     new_image->alloc_array = 1;
413 
414     return new_image;
415   }
416   if (W <= 0 || H <= 0) return 0;
417 
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
428 
429 
430   // Figure out Bresenheim step/modulus values...
431   xmod   = w() % W;
432   xstep  = w() / W;
433   ymod   = h() % H;
434   ystep  = h() / H;
435 
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;
440 
441   memset(new_array, 0, H * ((W + 7) / 8));
442 
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;
446 	 dx > 0;
447 	 dx --) {
448       old_bit = (uchar)(1 << (sx & 7));
449       if (old_ptr[sx / 8] & old_bit) *new_ptr |= new_bit;
450 
451       if (new_bit < 128) new_bit <<= 1;
452       else {
453         new_bit = 1;
454 	new_ptr ++;
455       }
456 
457       sx   += xstep;
458       xerr -= xmod;
459 
460       if (xerr <= 0) {
461 	xerr += W;
462 	sx ++;
463       }
464     }
465 
466     if (new_bit > 1) new_ptr ++;
467 
468     sy   += ystep;
469     yerr -= ymod;
470     if (yerr <= 0) {
471       yerr += H;
472       sy ++;
473     }
474   }
475 
476   return new_image;
477 }
478 
479 
480 //
481 // End of "$Id: Fl_Bitmap.cxx 8360 2011-02-02 12:42:47Z manolo $".
482 //
483