1 /********************************************************************************
2 *                                                                               *
3 *                             B i t m a p    O b j e c t                        *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1998,2005 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or                 *
9 * modify it under the terms of the GNU Lesser General Public                    *
10 * License as published by the Free Software Foundation; either                  *
11 * version 2.1 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 * Lesser General Public License for more details.                               *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser 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  USA.    *
21 *********************************************************************************
22 * $Id: FXBitmap.cpp,v 1.77 2005/01/16 16:06:06 fox Exp $                        *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "FXHash.h"
28 #include "FXThread.h"
29 #include "FXStream.h"
30 #include "FXString.h"
31 #include "FXSize.h"
32 #include "FXPoint.h"
33 #include "FXRectangle.h"
34 #include "FXSettings.h"
35 #include "FXRegistry.h"
36 #include "FXApp.h"
37 #include "FXVisual.h"
38 #include "FXBitmap.h"
39 #include "FXVisual.h"
40 #include "FXDCWindow.h"
41 #include "FXException.h"
42 
43 
44 /*
45   Note:
46   - Try eliminate temp copy:- slap pixels into XImage directly, if possible...
47   - Perhaps enforce system-native padding necessary for the above.
48   - Our bitmap data is 01234567, i.e. LS-BIT first; byte order ditto.
49   - Issue: should FXBitmap return the DC for drawing onto the X-Server resident
50     pixmap, or the client-side image bits?
51 
52     My idea is it should be the latter:
53 
54       - Allows even richer set of drawing primitives, as everything is
55         drawn in software.
56       - Very useful to generate off-screen renderings, e.g. during printing.
57       - Allows for building and running true-color drawing programs on
58         low-end graphics hardware.
59       - The only drawback I can see is it will be a fairly large implementation
60         effort...
61 
62   - The scale, mirror, rotate and crop API's have been contributed by Marc Cartright,
63     <macartright@hotmail.com>.
64   - The XBM format maps 1 to black instead of white; perhaps this should
65     be reversed.
66 */
67 
68 #define DISPLAY(app) ((Display*)((app)->display))
69 
70 // Changable bitmap options
71 #define BITMAP_MASK   (BITMAP_KEEP|BITMAP_SHMI|BITMAP_SHMP)
72 
73 
74 using namespace FX;
75 
76 /*******************************************************************************/
77 
78 namespace FX {
79 
80 
81 // Object implementation
82 FXIMPLEMENT(FXBitmap,FXDrawable,NULL,0)
83 
84 
85 // For deserialization
FXBitmap()86 FXBitmap::FXBitmap(){
87   data=NULL;
88   bytewidth=0;
89   options=0;
90   }
91 
92 
93 // Initialize
FXBitmap(FXApp * a,const void * pix,FXuint opts,FXint w,FXint h)94 FXBitmap::FXBitmap(FXApp* a,const void *pix,FXuint opts,FXint w,FXint h):FXDrawable(a,w,h){
95   FXTRACE((100,"FXBitmap::FXBitmap %p\n",this));
96   FXASSERT((opts&~(BITMAP_OWNED|BITMAP_MASK))==0);
97   visual=getApp()->getMonoVisual();
98   data=(FXuchar*)pix;
99   bytewidth=(width+7)>>3;
100   options=opts;
101   if(!data && (options&BITMAP_OWNED)){
102     if(!FXCALLOC(&data,FXuchar,height*bytewidth)){ throw FXMemoryException("unable to construct bitmap"); }
103     }
104   }
105 
106 
107 // Create bitmap
create()108 void FXBitmap::create(){
109   if(!xid){
110     if(getApp()->isInitialized()){
111       FXTRACE((100,"%s::create %p\n",getClassName(),this));
112 
113 #ifndef WIN32
114 
115       // Initialize visual
116       visual->create();
117 
118       // Make pixmap
119       xid=XCreatePixmap(DISPLAY(getApp()),XDefaultRootWindow(DISPLAY(getApp())),FXMAX(width,1),FXMAX(height,1),1);
120 
121 #else
122 
123       // Initialize visual
124       visual->create();
125 
126       // Create uninitialized shape bitmap
127       xid=CreateBitmap(FXMAX(width,1),FXMAX(height,1),1,1,NULL);
128 
129 #endif
130 
131       // Were we successful?
132       if(!xid){ throw FXImageException("unable to create bitmap"); }
133 
134       // Render pixels
135       render();
136 
137       // If we're not keeping the pixel buffer, release it
138       if(!(options&BITMAP_KEEP)) release();
139       }
140     }
141   }
142 
143 
144 // Release the client-side buffer, free it if it was owned.
release()145 void FXBitmap::release(){
146   if(options&BITMAP_OWNED){
147     options&=~BITMAP_OWNED;
148     FXFREE(&data);
149     }
150   data=NULL;
151   }
152 
153 
154 // Detach bitmap
detach()155 void FXBitmap::detach(){
156   visual->detach();
157   if(xid){
158     FXTRACE((100,"%s::detach %p\n",getClassName(),this));
159     xid=0;
160     }
161   }
162 
163 
164 // Destroy bitmap
destroy()165 void FXBitmap::destroy(){
166   if(xid){
167     if(getApp()->isInitialized()){
168       FXTRACE((100,"%s::destroy %p\n",getClassName(),this));
169 #ifndef WIN32
170 
171       // Delete pixmap
172       XFreePixmap(DISPLAY(getApp()),xid);
173 #else
174 
175       // Delete bitmap
176       DeleteObject(xid);
177 #endif
178       }
179     xid=0;
180     }
181   }
182 
183 
184 #ifndef WIN32
185 
186 
187 // Render into pixmap
render()188 void FXBitmap::render(){
189   if(xid){
190     register XImage *xim=NULL;
191     register Visual *vis;
192     register int size;
193     register FXuchar *pix;
194     register int i;
195     XGCValues values;
196     GC gc;
197 
198     FXTRACE((100,"%s::render bitmap %p\n",getClassName(),this));
199 
200     // Fill with pixels if there is data
201     if(data && 0<width && 0<height){
202 
203       // Make GC
204       values.foreground=0xffffffff;
205       values.background=0;
206       gc=XCreateGC(DISPLAY(getApp()),xid,GCForeground|GCBackground,&values);
207 
208       // Get Visual
209       vis=(Visual*)visual->visual;
210 
211       xim=XCreateImage(DISPLAY(getApp()),vis,1,XYBitmap,0,NULL,width,height,8,(width+7)>>3);
212       if(!xim){ throw FXImageException("unable to render bitmap"); }
213 
214       // Try create temp pixel store
215       if(!FXMALLOC(&xim->data,char,xim->bytes_per_line*height)){ throw FXMemoryException("unable to render bitmap"); }
216 
217       // Render bits into server-formatted bitmap
218       size=xim->bytes_per_line*height;
219       pix=(FXuchar*)xim->data;
220 
221       // Most significant bit first
222       if(xim->bitmap_bit_order==MSBFirst){
223         for(i=0; i<size; i++) pix[i]=FXBITREVERSE(data[i]);
224         }
225 
226       // Least significant bit first
227       else{
228         memcpy(pix,data,size);
229         }
230 
231       // Blast the image
232       XPutImage(DISPLAY(getApp()),xid,gc,xim,0,0,0,0,width,height);
233       FXFREE(&xim->data);
234       XDestroyImage(xim);
235       XFreeGC(DISPLAY(getApp()),gc);
236       }
237     }
238   }
239 
240 
241 #else
242 
243 
244 struct BITMAPINFO2 {
245   BITMAPINFOHEADER bmiHeader;
246   RGBQUAD          bmiColors[2];
247   };
248 
249 
250 // Render into pixmap
render()251 void FXBitmap::render(){
252   if(xid){
253     register FXuchar *p,*q,bits;
254     register FXint i,j,bytes_per_line;
255     FXuchar *widedata;
256 
257     FXTRACE((100,"%s::render bitmap %p\n",getClassName(),this));
258 
259     // Fill with pixels if there is data
260     if(data && 0<width && 0<height){
261 
262       // Set up the bitmap info, with fixed black/white palette
263       BITMAPINFO2 bmi;
264       bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
265       bmi.bmiHeader.biWidth=width;
266       bmi.bmiHeader.biHeight=height;
267       bmi.bmiHeader.biPlanes=1;
268       bmi.bmiHeader.biBitCount=1;
269       bmi.bmiHeader.biCompression=0;
270       bmi.bmiHeader.biSizeImage=0;
271       bmi.bmiHeader.biXPelsPerMeter=0;
272       bmi.bmiHeader.biYPelsPerMeter=0;
273       bmi.bmiHeader.biClrUsed=0;
274       bmi.bmiHeader.biClrImportant=0;
275       bmi.bmiColors[0].rgbBlue=0;
276       bmi.bmiColors[0].rgbGreen=0;
277       bmi.bmiColors[0].rgbRed=0;
278       bmi.bmiColors[0].rgbReserved=0;
279       bmi.bmiColors[1].rgbBlue=255;
280       bmi.bmiColors[1].rgbGreen=255;
281       bmi.bmiColors[1].rgbRed=255;
282       bmi.bmiColors[1].rgbReserved=0;
283 
284       // Fill temp array
285       bytes_per_line=((width+31)&~31)>>3;
286       if(!FXCALLOC(&widedata,FXuchar,height*bytes_per_line)){ throw FXMemoryException("unable to render bitmap"); }
287       p=widedata+(height-1)*bytes_per_line;
288       q=data;
289       for(i=0; i<height; i++){
290         for(j=0; j<bytewidth; j++){
291           bits=~q[j];
292           p[j]=FXBITREVERSE(bits);
293           }
294         q+=bytewidth;
295         p-=bytes_per_line;
296         }
297 
298       // Get memory device context
299       HDC hdcmem=::CreateCompatibleDC(NULL);
300       if(!SetDIBits(hdcmem,(HBITMAP)xid,0,height,widedata,(BITMAPINFO*)&bmi,DIB_RGB_COLORS)){
301         throw FXImageException("unable to render bitmap");
302         }
303       GdiFlush();
304       FXFREE(&widedata);
305       ::DeleteDC(hdcmem);
306       }
307     }
308   }
309 
310 #endif
311 
312 
313 // Resize bitmap to the specified width and height; the contents become undefined
resize(FXint w,FXint h)314 void FXBitmap::resize(FXint w,FXint h){
315   register FXint bw;
316   if(w<1) w=1;
317   if(h<1) h=1;
318   FXTRACE((100,"%s::resize(%d,%d)\n",getClassName(),w,h));
319   bw=(w+7)>>3;
320   if(xid){
321 
322 #ifndef WIN32
323 
324     // Free old pixmap
325     XFreePixmap(DISPLAY(getApp()),xid);
326 
327     // Make new pixmap
328     xid=XCreatePixmap(DISPLAY(getApp()),XDefaultRootWindow(DISPLAY(getApp())),w,h,1);
329     if(!xid){ throw FXImageException("unable to resize bitmap"); }
330 
331 #else
332 
333     // Delete old bitmap
334     DeleteObject(xid);
335 
336     // Create a bitmap compatible with current display
337     xid=CreateBitmap(w,h,1,1,NULL);
338     if(!xid){ throw FXImageException("unable to resize bitmap"); }
339 
340 #endif
341     }
342 
343   // Resize data array; only do the work if the new
344   // array is a different size as measured in bytes!
345   if(data){
346     if(!(options&BITMAP_OWNED)){        // Need to own array
347       if(!FXMALLOC(&data,FXColor,h*bw)){ throw FXMemoryException("unable to resize bitmap"); }
348       options|=BITMAP_OWNED;
349       }
350     else if(h*bw!=height*bytewidth){
351       if(!FXRESIZE(&data,FXColor,h*bw)){ throw FXMemoryException("unable to resize bitmap"); }
352       }
353     }
354 
355   // Remember new size
356   bytewidth=bw;
357   width=w;
358   height=h;
359   }
360 
361 
362 // Fill bitmap with uniform value
fill(FXbool color)363 void FXBitmap::fill(FXbool color){
364   if(data){
365     memset(data,-color,height*bytewidth);
366     }
367   }
368 
369 
370 // Rescale pixels to the specified width and height; just nearest
371 // neighbor; there ain't no such thing as anti-aliasing in bitmaps!
scale(FXint w,FXint h)372 void FXBitmap::scale(FXint w,FXint h){
373   if(w<1) w=1;
374   if(h<1) h=1;
375   FXTRACE((100,"%s::scale(%d,%d)\n",getClassName(),w,h));
376   if(w!=width || h!=height){
377     if(data){
378       register FXuchar *q,*p,bits;
379       register FXint xs=(width<<16)/w;
380       register FXint ys=(height<<16)/h;
381       register FXint bw=bytewidth;
382       register FXint i,j,x,y,xx;
383       FXuchar *interim;
384 
385       // Copy to old buffer
386       if(!FXMEMDUP(&interim,data,FXuchar,height*bytewidth)){ throw FXMemoryException("unable to scale bitmap"); }
387 
388       // Resize the pixmap and target buffer
389       resize(w,h);
390 
391       // Scale the bitmap
392       i=0;
393       y=ys>>1;
394       p=data;
395       do{
396         j=0;
397         x=xs>>1;
398         q=interim+(y>>16)*bw;
399         bits=0;
400         do{
401           xx=x>>16;
402           bits|=((q[xx>>3]>>(xx&7))&1)<<(j&7);
403           if((j&7)==7){ *p++=bits; bits=0; }
404           x+=xs;
405           }
406         while(++j<w);
407         if(j&7){ *p++=bits; }
408         y+=ys;
409         }
410       while(++i<h);
411 
412       // Free interim buffer
413       FXFREE(&interim);
414       render();
415       }
416     else{
417       resize(w,h);
418       }
419     }
420   }
421 
422 
423 
424 // Mirror bitmap horizontally and/or vertically
mirror(FXbool horizontal,FXbool vertical)425 void FXBitmap::mirror(FXbool horizontal,FXbool vertical){
426   FXTRACE((100,"%s::mirror(%d,%d)\n",getClassName(),horizontal,vertical));
427   if(horizontal || vertical){
428     if(data){
429       register FXuchar *paa,*pa,*pbb,*pb;
430       register FXint sa=(8-width)&7;
431       register FXint sb=8-sa;
432       register FXuint t;
433       FXuchar line[4096];               // Maximum width is 32768/8=4096 bytes
434       if(vertical && height>1){         // Mirror vertically
435         paa=data;
436         pbb=data+bytewidth*(height-1);
437         do{
438           pa=paa; paa+=bytewidth;
439           pb=pbb; pbb-=bytewidth;
440           do{
441             t=*pa; *pa++=*pb; *pb++=t;
442             }
443           while(pa<paa);
444           }
445         while(paa<pbb);
446         }
447       if(horizontal && width>1){        // Mirror horizontally
448         paa=data;
449         pbb=data+bytewidth*height;
450         do{
451           pa=paa;
452           pb=line+bytewidth;
453           do{
454             *--pb=*paa++;               // Gnarly!
455             }
456           while(line<pb);
457           do{
458             t=*pb++ << sa;
459             t|=*pb >> sb;
460             *pa++=FXBITREVERSE(t);
461             }
462           while(pa<paa);
463           }
464         while(paa<pbb);
465         }
466       render();
467       }
468     }
469   }
470 
471 
472 // Rotate bitmap by degrees ccw
rotate(FXint degrees)473 void FXBitmap::rotate(FXint degrees){
474   FXTRACE((100,"%s::rotate(%d)\n",getClassName(),degrees));
475   degrees=(degrees+360)%360;
476   if(degrees!=0 && width>1 && height>1){
477     if(data){
478       register FXuchar *p,*q,bits;
479       register FXint bw=bytewidth;
480       register FXint i,j,x;
481       FXuchar *olddata;
482       if(!FXMEMDUP(&olddata,data,FXuchar,bytewidth*height)){ throw FXMemoryException("unable to rotate bitmap"); }
483       switch(degrees){
484         case 90:
485           resize(height,width);
486           i=height-1;
487           p=data;
488           do{
489             j=0;
490             q=olddata+(i>>3);
491             bits=0;
492             do{
493               bits|=((q[0]>>(i&7))&1)<<(j&7);
494               if((j&7)==7){ *p++=bits; bits=0; }
495               q+=bw;
496               }
497             while(++j<width);
498             if(j&7){ *p++=bits; }
499             }
500           while(--i>=0);
501           break;
502         case 180:               // FIXME works but not as fast as it could be
503           i=height-1;
504           p=data;
505           q=olddata+(height-1)*bw;
506           do{
507             j=0;
508             bits=0;
509             x=width-1;
510             do{
511               bits|=((q[x>>3]>>(x&7))&1)<<(j&7);
512               if((j&7)==7){ *p++=bits; bits=0; }
513               x--;
514               }
515             while(++j<width);
516             if(j&7){ *p++=bits; }
517             q-=bw;
518             }
519           while(--i>=0);
520           break;
521         case 270:
522           resize(height,width);
523           i=0;
524           p=data;
525           do{
526             j=0;
527             q=olddata+(i>>3)+(width-1)*bw;
528             bits=0;
529             do{
530               bits|=((q[0]>>(i&7))&1)<<(j&7);
531               if((j&7)==7){ *p++=bits; bits=0; }
532               q-=bw;
533               }
534             while(++j<width);
535             if(j&7){ *p++=bits; }
536             }
537           while(++i<height);
538           break;
539         default:
540           fxwarning("%s::rotate: rotation by %d degrees not implemented.\n",getClassName(),degrees);
541           break;
542         }
543       FXFREE(&olddata);
544       render();
545       }
546     else{
547       switch(degrees){
548         case 90:
549           resize(height,width);
550           break;
551         case 180:
552           resize(width,height);
553           break;
554         case 270:
555           resize(height,width);
556           break;
557         default:
558           fxwarning("%s::rotate: rotation by %d degrees not implemented.\n",getClassName(),degrees);
559           break;
560         }
561       }
562     }
563   }
564 
565 
566 // Crop bitmap to given rectangle
crop(FXint x,FXint y,FXint w,FXint h,FXbool color)567 void FXBitmap::crop(FXint x,FXint y,FXint w,FXint h,FXbool color){
568   if(w<1) w=1;
569   if(h<1) h=1;
570   if(x>=width || y>=height || x+w<=0 || y+h<=0){ fxerror("%s::crop: bad arguments.\n",getClassName()); }
571   FXTRACE((1,"%s::crop(%d,%d,%d,%d)\n",getClassName(),x,y,w,h));
572   if(data){
573     register FXuchar *pnn,*poo,*yyy,*pn,*po,*xx;
574     register FXint oldbw=bytewidth;
575     register FXint newbw=(w+7)>>3;
576     register FXint cpybw;
577     register FXint ow=width;
578     register FXint oh=height;
579     register FXint nw=w;
580     register FXint nh=h;
581     register FXint cw;
582     register FXint ch;
583     register FXint sh;
584     register FXuint t;
585     FXuchar *olddata;
586     if(!FXMALLOC(&olddata,FXuchar,oh*bytewidth+1)){ throw FXMemoryException("unable to crop bitmap"); }
587     memcpy(olddata,data,oh*bytewidth);
588     resize(w,h);
589     pnn=data;
590     yyy=data+newbw*nh;
591     do{
592       *pnn++=-color;            // 1 -> 0xff, 0 -> 0xff
593       }
594     while(pnn<yyy);
595     if(x<0){                    // x < 0
596       cw=FXMIN(ow,x+nw);
597       if(y<0){                  // y < 0
598         pnn=data-newbw*y;
599         poo=olddata;
600         ch=FXMIN(oh,y+nh);
601         }
602       else{                     // y >= 0
603         pnn=data;
604         poo=olddata+oldbw*y;
605         ch=FXMIN(oh,y+nh)-y;
606         }
607       pnn+=(-x)>>3;
608       sh=8-((-x)&7);
609       FXASSERT(cw>0);
610       FXASSERT(ch>0);
611       yyy=pnn+newbw*ch;
612       cpybw=((cw-x+7)>>3)-((-x)>>3);
613       FXTRACE((1,"ow=%d oh=%d nw=%d nh=%d cw=%d ch=%d sh=%d cpybw=%d\n",ow,oh,nw,nh,cw,ch,sh,cpybw));
614       do{
615         pn=pnn;
616         po=poo;
617         xx=pnn+cpybw;
618         t=(-color)&0xff;
619         do{
620           t|=(*po++)<<8;
621           *pn++=t>>sh;
622           t>>=8;
623           }
624         while(pn<xx);
625         if(color){              // A bit ugly but it'll have to do for now...
626           *(pn-1)|=0xff<<((cw-x)&7);
627           }
628         else{
629           *(pn-1)&=~(0xff<<((cw-x)&7));
630           }
631         pnn+=newbw;
632         poo+=oldbw;
633         }
634       while(pnn<yyy);
635       }
636     else{                       // x >= 0
637       cw=FXMIN(ow,x+nw)-x;
638       if(y<0){                  // y < 0
639         pnn=data-newbw*y;
640         poo=olddata;
641         ch=FXMIN(oh,y+nh);
642         }
643       else{                     // y >= 0
644         pnn=data;
645         poo=olddata+oldbw*y;
646         ch=FXMIN(oh,y+nh)-y;
647         }
648       poo+=x>>3;
649       sh=x&7;
650       FXASSERT(cw>0);
651       FXASSERT(ch>0);
652       yyy=pnn+newbw*ch;
653       cpybw=(cw+7)>>3;
654       do{
655         pn=pnn;
656         po=poo;
657         xx=pnn+cpybw;
658         do{
659           t=*po++;
660           t|=*po<<8;
661           *pn++=t>>sh;
662           }
663         while(pn<xx);
664         pnn+=newbw;
665         poo+=oldbw;
666         }
667       while(pnn<yyy);
668       }
669     FXFREE(&olddata);
670     render();
671     }
672   else{
673     resize(w,h);
674     }
675   }
676 
677 
678 
679 #ifdef WIN32
680 
681 // Get the image's device context
GetDC() const682 FXID FXBitmap::GetDC() const {
683   HDC hdc=::CreateCompatibleDC(NULL);
684   SelectObject(hdc,(HBITMAP)xid);
685   return hdc;
686   }
687 
688 
689 // Release it (no-op)
ReleaseDC(FXID hdc) const690 int FXBitmap::ReleaseDC(FXID hdc) const {
691   return ::DeleteDC((HDC)hdc);
692   }
693 
694 #endif
695 
696 
697 // Change options
setOptions(FXuint opts)698 void FXBitmap::setOptions(FXuint opts){
699   options=(options&~BITMAP_MASK) | (opts&BITMAP_MASK);
700   }
701 
702 
703 // Save pixel data only
savePixels(FXStream & store) const704 FXbool FXBitmap::savePixels(FXStream& store) const {
705   FXuint size=height*bytewidth;
706   store.save(data,size);
707   return TRUE;
708   }
709 
710 
711 // Load pixel data only
loadPixels(FXStream & store)712 FXbool FXBitmap::loadPixels(FXStream& store){
713   FXuint size=height*bytewidth;
714   if(options&BITMAP_OWNED){ FXFREE(&data); }
715   if(!FXMALLOC(&data,FXuchar,size)) return FALSE;
716   store.load(data,size);
717   options|=BITMAP_OWNED;
718   return TRUE;
719   }
720 
721 
722 // Save data
save(FXStream & store) const723 void FXBitmap::save(FXStream& store) const {
724   FXuchar haspixels=(data!=NULL);
725   FXDrawable::save(store);
726   store << options;
727   store << haspixels;
728   if(haspixels) savePixels(store);
729   }
730 
731 
732 // Load data
load(FXStream & store)733 void FXBitmap::load(FXStream& store){
734   FXuchar haspixels;
735   FXDrawable::load(store);
736   store >> options;
737   store >> haspixels;
738   if(haspixels) loadPixels(store);
739   }
740 
741 
742 // Clean up
~FXBitmap()743 FXBitmap::~FXBitmap(){
744   FXTRACE((100,"FXBitmap::~FXBitmap %p\n",this));
745   destroy();
746   if(options&BITMAP_OWNED){FXFREE(&data);}
747   data=(FXuchar*)-1L;
748   }
749 
750 }
751