]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/bitmap.cpp
fixed a memory leak and an initialization problem
[wxWidgets.git] / src / mac / carbon / bitmap.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: bitmap.cpp
3 // Purpose: wxBitmap
4 // Author: AUTHOR
5 // Modified by:
6 // Created: ??/??/98
7 // RCS-ID: $Id$
8 // Copyright: (c) AUTHOR
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "bitmapbase.h"
14 #pragma implementation "bitmap.h"
15 #endif
16
17 #include "wx/defs.h"
18
19 #include "wx/bitmap.h"
20 #include "wx/icon.h"
21 #include "wx/log.h"
22 #include "wx/image.h"
23 #include "wx/xpmdecod.h"
24
25 #if !USE_SHARED_LIBRARIES
26 IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
27 IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
28 IMPLEMENT_ABSTRACT_CLASS(wxBitmapBase , wxGDIObject )
29 IMPLEMENT_ABSTRACT_CLASS(wxBitmapHandlerBase, wxObject )
30 #endif
31
32 #ifdef __DARWIN__
33 #include <ApplicationServices/ApplicationServices.h>
34 #else
35 #include <PictUtils.h>
36 #endif
37
38 #include "wx/mac/uma.h"
39
40 CTabHandle wxMacCreateColorTable( int numColors )
41 {
42 CTabHandle newColors; /* Handle to the new color table */
43
44 /* Allocate memory for the color table */
45 newColors = (CTabHandle)NewHandleClear( sizeof (ColorTable) +
46 sizeof (ColorSpec) * (numColors - 1) );
47 if (newColors != nil)
48 {
49 /* Initialize the fields */
50 (**newColors).ctSeed = GetCTSeed();
51 (**newColors).ctFlags = 0;
52 (**newColors).ctSize = numColors - 1;
53 /* Initialize the table of colors */
54 }
55 return newColors ;
56 }
57
58 void wxMacDestroyColorTable( CTabHandle colors )
59 {
60 DisposeHandle( (Handle) colors ) ;
61 }
62
63 void wxMacSetColorTableEntry( CTabHandle newColors , int index , int red , int green , int blue )
64 {
65 (**newColors).ctTable[index].value = index;
66 (**newColors).ctTable[index].rgb.red = 0 ;// someRedValue;
67 (**newColors).ctTable[index].rgb.green = 0 ; // someGreenValue;
68 (**newColors).ctTable[index].rgb.blue = 0 ; // someBlueValue;
69 }
70
71 GWorldPtr wxMacCreateGWorld( int width , int height , int depth )
72 {
73 OSErr err = noErr ;
74 GWorldPtr port ;
75 Rect rect = { 0 , 0 , height , width } ;
76
77 if ( depth < 0 )
78 {
79 depth = wxDisplayDepth() ;
80 }
81
82 err = NewGWorld( &port , depth , &rect , NULL , NULL , 0 ) ;
83 if ( err == noErr )
84 {
85 return port ;
86 }
87 return NULL ;
88 }
89
90 void wxMacDestroyGWorld( GWorldPtr gw )
91 {
92 if ( gw )
93 DisposeGWorld( gw ) ;
94 }
95
96 #define kDefaultRes 0x00480000 /* Default resolution is 72 DPI; Fixed type */
97
98 OSErr SetupCIconHandlePixMap( CIconHandle icon , short depth , Rect *bounds , CTabHandle colors )
99 {
100 CTabHandle newColors; /* Color table used for the off-screen PixMap */
101 Ptr offBaseAddr; /* Pointer to the off-screen pixel image */
102 OSErr error; /* Returns error code */
103 short bytesPerRow; /* Number of bytes per row in the PixMap */
104
105
106 error = noErr;
107 newColors = nil;
108 offBaseAddr = nil;
109
110 bytesPerRow = ((depth * (bounds->right - bounds->left) + 31) / 32) * 4;
111
112 /* Clone the clut if indexed color; allocate a dummy clut if direct color*/
113 if (depth <= 8)
114 {
115 newColors = colors;
116 error = HandToHand((Handle *) &newColors);
117 }
118 else
119 {
120 newColors = (CTabHandle) NewHandle(sizeof(ColorTable) -
121 sizeof(CSpecArray));
122 error = MemError();
123 }
124 if (error == noErr)
125 {
126 /* Allocate pixel image; long integer multiplication avoids overflow */
127 (**icon).iconData = NewHandle((unsigned long) bytesPerRow * (bounds->bottom -
128 bounds->top));
129 if ((**icon).iconData != nil)
130 {
131 /* Initialize fields common to indexed and direct PixMaps */
132 (**icon).iconPMap.baseAddr = 0; /* Point to image */
133 (**icon).iconPMap.rowBytes = bytesPerRow | /* MSB set for PixMap */
134 0x8000;
135 (**icon).iconPMap.bounds = *bounds; /* Use given bounds */
136 (**icon).iconPMap.pmVersion = 0; /* No special stuff */
137 (**icon).iconPMap.packType = 0; /* Default PICT pack */
138 (**icon).iconPMap.packSize = 0; /* Always zero in mem */
139 (**icon).iconPMap.hRes = kDefaultRes; /* 72 DPI default res */
140 (**icon).iconPMap.vRes = kDefaultRes; /* 72 DPI default res */
141 (**icon).iconPMap.pixelSize = depth; /* Set # bits/pixel */
142
143 /* Initialize fields specific to indexed and direct PixMaps */
144 if (depth <= 8)
145 {
146 /* PixMap is indexed */
147 (**icon).iconPMap.pixelType = 0; /* Indicates indexed */
148 (**icon).iconPMap.cmpCount = 1; /* Have 1 component */
149 (**icon).iconPMap.cmpSize = depth; /* Component size=depth */
150 (**icon).iconPMap.pmTable = newColors; /* Handle to CLUT */
151 }
152 else
153 {
154 /* PixMap is direct */
155 (**icon).iconPMap.pixelType = RGBDirect; /* Indicates direct */
156 (**icon).iconPMap.cmpCount = 3; /* Have 3 components */
157 if (depth == 16)
158 (**icon).iconPMap.cmpSize = 5; /* 5 bits/component */
159 else
160 (**icon).iconPMap.cmpSize = 8; /* 8 bits/component */
161 (**newColors).ctSeed = 3 * (**icon).iconPMap.cmpSize;
162 (**newColors).ctFlags = 0;
163 (**newColors).ctSize = 0;
164 (**icon).iconPMap.pmTable = newColors;
165 }
166 }
167 else
168 error = MemError();
169 }
170 else
171 newColors = nil;
172
173 /* If no errors occured, return a handle to the new off-screen PixMap */
174 if (error != noErr)
175 {
176 if (newColors != nil)
177 DisposeCTable(newColors);
178 }
179
180 /* Return the error code */
181 return error;
182 }
183
184 CIconHandle wxMacCreateCIcon(GWorldPtr image , GWorldPtr mask , short dstDepth , short iconSize )
185 {
186 GWorldPtr saveWorld;
187 GDHandle saveHandle;
188
189 GetGWorld(&saveWorld,&saveHandle); // save Graphics env state
190 SetGWorld(image,nil);
191
192 Rect frame = { 0 , 0 , iconSize , iconSize } ;
193 Rect imageBounds = frame ;
194 GetPortBounds( image , &imageBounds ) ;
195
196 int bwSize = iconSize / 8 * iconSize ;
197 CIconHandle icon = (CIconHandle) NewHandleClear( sizeof ( CIcon ) + 2 * bwSize) ;
198 HLock((Handle)icon) ;
199 SetupCIconHandlePixMap( icon , dstDepth , &frame,GetCTable(dstDepth)) ;
200 HLock( (**icon).iconData ) ;
201 (**icon).iconPMap.baseAddr = *(**icon).iconData ;
202
203 LockPixels(GetGWorldPixMap(image));
204
205 CopyBits(GetPortBitMapForCopyBits(image),
206 (BitMapPtr)&((**icon).iconPMap),
207 &imageBounds,
208 &imageBounds,
209 srcCopy | ditherCopy, nil);
210
211
212 UnlockPixels(GetGWorldPixMap(image));
213 HUnlock( (**icon).iconData ) ;
214
215 (**icon).iconMask.rowBytes = iconSize / 8 ;
216 (**icon).iconMask.bounds = frame ;
217
218 (**icon).iconBMap.rowBytes = iconSize / 8 ;
219 (**icon).iconBMap.bounds = frame ;
220 (**icon).iconMask.baseAddr = (char*) &(**icon).iconMaskData ;
221 (**icon).iconBMap.baseAddr = (char*) &(**icon).iconMaskData + bwSize ;
222
223 if ( mask )
224 {
225 LockPixels(GetGWorldPixMap(mask) ) ;
226 CopyBits(GetPortBitMapForCopyBits(mask) ,
227 &(**icon).iconBMap , &imageBounds , &imageBounds, srcCopy , nil ) ;
228 CopyBits(GetPortBitMapForCopyBits(mask) ,
229 &(**icon).iconMask , &imageBounds , &imageBounds, srcCopy , nil ) ;
230 UnlockPixels(GetGWorldPixMap( mask ) ) ;
231 }
232 else
233 {
234 LockPixels(GetGWorldPixMap(image));
235 CopyBits(GetPortBitMapForCopyBits(image) ,
236 &(**icon).iconBMap , &imageBounds , &imageBounds, srcCopy , nil ) ;
237 CopyBits(GetPortBitMapForCopyBits(image) ,
238 &(**icon).iconMask , &imageBounds , &imageBounds, srcCopy , nil ) ;
239 UnlockPixels(GetGWorldPixMap(image));
240 }
241
242 (**icon).iconMask.baseAddr = NULL ;
243 (**icon).iconBMap.baseAddr = NULL ;
244 (**icon).iconPMap.baseAddr = NULL ;
245 HUnlock((Handle)icon) ;
246 SetGWorld(saveWorld,saveHandle);
247
248 return icon;
249 }
250
251 PicHandle wxMacCreatePict(GWorldPtr wp, GWorldPtr mask)
252 {
253 CGrafPtr origPort ;
254 GDHandle origDev ;
255
256 PicHandle pict;
257
258 RGBColor white = { 0xffff ,0xffff , 0xffff } ;
259 RGBColor black = { 0x0000 ,0x0000 , 0x0000 } ;
260
261 GetGWorld( &origPort , &origDev ) ;
262
263 RgnHandle clipRgn = NULL ;
264
265 if ( mask )
266 {
267 clipRgn = NewRgn() ;
268 LockPixels( GetGWorldPixMap( mask ) ) ;
269 BitMapToRegion( clipRgn , (BitMap*) *GetGWorldPixMap( mask ) ) ;
270 UnlockPixels( GetGWorldPixMap( mask ) ) ;
271 }
272
273 SetGWorld( wp , NULL ) ;
274 Rect portRect ;
275 GetPortBounds( wp , &portRect ) ;
276
277 pict = OpenPicture(&portRect);
278 if(pict)
279 {
280 RGBForeColor( &black ) ;
281 RGBBackColor( &white ) ;
282
283 LockPixels( GetGWorldPixMap( wp ) ) ;
284 CopyBits(GetPortBitMapForCopyBits(wp),
285 GetPortBitMapForCopyBits(wp),
286 &portRect,
287 &portRect,
288 srcCopy,clipRgn);
289 UnlockPixels( GetGWorldPixMap( wp ) ) ;
290 ClosePicture();
291 }
292 SetGWorld( origPort , origDev ) ;
293 return pict;
294 }
295
296 wxBitmapRefData::wxBitmapRefData()
297 {
298 m_ok = FALSE;
299 m_width = 0;
300 m_height = 0;
301 m_depth = 0;
302 m_quality = 0;
303 m_numColors = 0;
304 m_bitmapMask = NULL;
305 m_hBitmap = NULL ;
306 m_hPict = NULL ;
307 m_hIcon = NULL ;
308 m_bitmapType = kMacBitmapTypeUnknownType ;
309 }
310
311 // TODO move this do a public function of Bitmap Ref
312 static void DisposeBitmapRefData(wxBitmapRefData *data)
313 {
314 switch (data->m_bitmapType)
315 {
316 case kMacBitmapTypePict :
317 {
318 if ( data->m_hPict )
319 {
320 KillPicture( data->m_hPict ) ;
321 data->m_hPict = NULL ;
322 }
323 }
324 break ;
325 case kMacBitmapTypeGrafWorld :
326 {
327 if ( data->m_hBitmap )
328 {
329 wxMacDestroyGWorld( data->m_hBitmap ) ;
330 data->m_hBitmap = NULL ;
331 }
332 }
333 break ;
334 case kMacBitmapTypeIcon :
335 if ( data->m_hIcon )
336 {
337 DisposeCIcon( data->m_hIcon ) ;
338 data->m_hIcon = NULL ;
339 }
340
341 default :
342 // unkown type ?
343 break ;
344 }
345
346 if (data->m_bitmapMask)
347 {
348 delete data->m_bitmapMask;
349 data->m_bitmapMask = NULL;
350 }
351 }
352
353 wxBitmapRefData::~wxBitmapRefData()
354 {
355 DisposeBitmapRefData( this ) ;
356 }
357
358 wxList wxBitmapBase::sm_handlers;
359
360
361 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
362 {
363 Ref(icon) ;
364 return true;
365 }
366
367 wxBitmap::wxBitmap()
368 {
369 m_refData = NULL;
370
371 if ( wxTheBitmapList )
372 wxTheBitmapList->AddBitmap(this);
373 }
374
375 wxBitmap::~wxBitmap()
376 {
377 if (wxTheBitmapList)
378 wxTheBitmapList->DeleteObject(this);
379 }
380
381 wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits)
382 {
383 m_refData = new wxBitmapRefData;
384
385 M_BITMAPDATA->m_width = the_width ;
386 M_BITMAPDATA->m_height = the_height ;
387 M_BITMAPDATA->m_depth = no_bits ;
388 M_BITMAPDATA->m_numColors = 0;
389 if ( no_bits == 1 )
390 {
391 M_BITMAPDATA->m_bitmapType = kMacBitmapTypeGrafWorld ;
392 M_BITMAPDATA->m_hBitmap = wxMacCreateGWorld( the_width , the_height , no_bits ) ;
393 M_BITMAPDATA->m_ok = (M_BITMAPDATA->m_hBitmap != NULL ) ;
394
395 CGrafPtr origPort ;
396 GDHandle origDevice ;
397
398 GetGWorld( &origPort , &origDevice ) ;
399 SetGWorld( M_BITMAPDATA->m_hBitmap , NULL ) ;
400 LockPixels( GetGWorldPixMap( M_BITMAPDATA->m_hBitmap ) ) ;
401
402 // bits is a char array
403
404 unsigned char* linestart = (unsigned char*) bits ;
405 int linesize = ( the_width / (sizeof(unsigned char) * 8)) ;
406 if ( the_width % (sizeof(unsigned char) * 8) ) {
407 linesize += sizeof(unsigned char);
408 }
409
410 RGBColor colors[2] = {
411 { 0xFFFF , 0xFFFF , 0xFFFF } ,
412 { 0, 0 , 0 }
413 } ;
414
415 for ( int y = 0 ; y < the_height ; ++y , linestart += linesize )
416 {
417 for ( int x = 0 ; x < the_width ; ++x )
418 {
419 int index = x / 8 ;
420 int bit = x % 8 ;
421 int mask = 1 << bit ;
422 if ( linestart[index] & mask )
423 {
424 SetCPixel( x , y , &colors[1] ) ;
425 }
426 else
427 {
428 SetCPixel( x , y , &colors[0] ) ;
429 }
430 }
431 }
432 UnlockPixels( GetGWorldPixMap( M_BITMAPDATA->m_hBitmap ) ) ;
433
434 SetGWorld( origPort , origDevice ) ;
435 }
436 else
437 {
438 wxFAIL_MSG(wxT("multicolor BITMAPs not yet implemented"));
439 }
440
441 if ( wxTheBitmapList ) {
442 wxTheBitmapList->AddBitmap(this);
443 }
444 }
445
446 wxBitmap::wxBitmap(int w, int h, int d)
447 {
448 (void)Create(w, h, d);
449
450 if ( wxTheBitmapList )
451 wxTheBitmapList->AddBitmap(this);
452 }
453
454 wxBitmap::wxBitmap(void *data, wxBitmapType type, int width, int height, int depth)
455 {
456 (void) Create(data, type, width, height, depth);
457
458 if ( wxTheBitmapList )
459 wxTheBitmapList->AddBitmap(this);
460 }
461
462 wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type)
463 {
464 LoadFile(filename, type);
465
466 if ( wxTheBitmapList )
467 wxTheBitmapList->AddBitmap(this);
468 }
469
470 bool wxBitmap::CreateFromXpm(const char **bits)
471 {
472 wxCHECK_MSG( bits != NULL, FALSE, wxT("invalid bitmap data") )
473 wxXPMDecoder decoder;
474 wxImage img = decoder.ReadData(bits);
475 wxCHECK_MSG( img.Ok(), FALSE, wxT("invalid bitmap data") )
476 *this = wxBitmap(img);
477 if ( wxTheBitmapList ) wxTheBitmapList->AddBitmap(this);
478 return TRUE;
479 }
480
481 wxBitmap::wxBitmap(const char **bits)
482 {
483 (void) CreateFromXpm(bits);
484 }
485
486 wxBitmap::wxBitmap(char **bits)
487 {
488 (void) CreateFromXpm((const char **)bits);
489 }
490
491 wxBitmap wxBitmap::GetSubBitmap(const wxRect &rect) const
492 {
493 wxCHECK_MSG( Ok() &&
494 (rect.x >= 0) && (rect.y >= 0) &&
495 (rect.x+rect.width <= GetWidth()) &&
496 (rect.y+rect.height <= GetHeight()),
497 wxNullBitmap, wxT("invalid bitmap or bitmap region") );
498
499
500 wxBitmap ret( rect.width, rect.height, GetDepth() );
501 wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
502
503 WXHBITMAP origPort;
504 GDHandle origDevice;
505
506 GetGWorld( &origPort, &origDevice );
507
508 // Update the subbitmaps reference data
509 wxBitmapRefData *ref = (wxBitmapRefData *)ret.GetRefData();
510
511 ref->m_numColors = M_BITMAPDATA->m_numColors;
512 ref->m_bitmapPalette = M_BITMAPDATA->m_bitmapPalette;
513 ref->m_bitmapType = M_BITMAPDATA->m_bitmapType;
514
515 // Copy sub region of this bitmap
516 if(M_BITMAPDATA->m_bitmapType == kMacBitmapTypePict)
517 {
518 printf("GetSubBitmap: Copy a region of a Pict structure - TODO\n");
519 }
520 else if(M_BITMAPDATA->m_bitmapType == kMacBitmapTypeGrafWorld)
521 {
522 // Copy mask
523 if(GetMask())
524 {
525 WXHBITMAP submask, mask;
526 RGBColor color;
527
528 mask = GetMask()->GetMaskBitmap();
529 submask = wxMacCreateGWorld(rect.width, rect.height, 1);
530 LockPixels(GetGWorldPixMap(mask));
531 LockPixels(GetGWorldPixMap(submask));
532
533 for(int yy = 0; yy < rect.height; yy++)
534 {
535 for(int xx = 0; xx < rect.width; xx++)
536 {
537 SetGWorld(mask, NULL);
538 GetCPixel(rect.x + xx, rect.y + yy, &color);
539 SetGWorld(submask, NULL);
540 SetCPixel(xx,yy, &color);
541 }
542 }
543 UnlockPixels(GetGWorldPixMap(mask));
544 UnlockPixels(GetGWorldPixMap(submask));
545 ref->m_bitmapMask = new wxMask;
546 ref->m_bitmapMask->SetMaskBitmap(submask);
547 }
548
549 // Copy bitmap
550 if(GetHBITMAP())
551 {
552 WXHBITMAP subbitmap, bitmap;
553 RGBColor color;
554
555 bitmap = GetHBITMAP();
556 subbitmap = ref->m_hBitmap ;
557 LockPixels(GetGWorldPixMap(bitmap));
558 LockPixels(GetGWorldPixMap(subbitmap));
559
560 for(int yy = 0; yy < rect.height; yy++)
561 {
562 for(int xx = 0; xx < rect.width; xx++)
563 {
564 SetGWorld(bitmap, NULL);
565 GetCPixel(rect.x + xx, rect.y + yy, &color);
566 SetGWorld(subbitmap, NULL);
567 SetCPixel(xx, yy, &color);
568 }
569 }
570 UnlockPixels(GetGWorldPixMap(bitmap));
571 UnlockPixels(GetGWorldPixMap(subbitmap));
572 }
573 }
574 SetGWorld( origPort, origDevice );
575
576 return ret;
577 }
578
579 bool wxBitmap::Create(int w, int h, int d)
580 {
581 UnRef();
582
583 m_refData = new wxBitmapRefData;
584
585 M_BITMAPDATA->m_width = w;
586 M_BITMAPDATA->m_height = h;
587 M_BITMAPDATA->m_depth = d;
588
589 M_BITMAPDATA->m_bitmapType = kMacBitmapTypeGrafWorld ;
590 M_BITMAPDATA->m_hBitmap = wxMacCreateGWorld( w , h , d ) ;
591 M_BITMAPDATA->m_ok = (M_BITMAPDATA->m_hBitmap != NULL ) ;
592 return M_BITMAPDATA->m_ok;
593 }
594
595 int wxBitmap::GetBitmapType() const
596 {
597 wxCHECK_MSG( Ok(), kMacBitmapTypeUnknownType, wxT("invalid bitmap") );
598
599 return M_BITMAPDATA->m_bitmapType;
600 }
601
602 void wxBitmap::SetHBITMAP(WXHBITMAP bmp)
603 {
604 DisposeBitmapRefData( M_BITMAPDATA ) ;
605
606 M_BITMAPDATA->m_bitmapType = kMacBitmapTypeGrafWorld ;
607 M_BITMAPDATA->m_hBitmap = bmp ;
608 M_BITMAPDATA->m_ok = (M_BITMAPDATA->m_hBitmap != NULL ) ;
609 }
610
611 bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type)
612 {
613 UnRef();
614
615 wxBitmapHandler *handler = FindHandler(type);
616
617 if ( handler )
618 {
619 m_refData = new wxBitmapRefData;
620
621 return handler->LoadFile(this, filename, type, -1, -1);
622 }
623 else
624 {
625 wxImage loadimage(filename, type);
626 if (loadimage.Ok()) {
627 *this = loadimage;
628 return true;
629 }
630 }
631 wxLogWarning("no bitmap handler for type %d defined.", type);
632 return false;
633 }
634
635 bool wxBitmap::Create(void *data, wxBitmapType type, int width, int height, int depth)
636 {
637 UnRef();
638
639 m_refData = new wxBitmapRefData;
640
641 wxBitmapHandler *handler = FindHandler(type);
642
643 if ( handler == NULL ) {
644 wxLogWarning("no bitmap handler for type %d defined.", type);
645
646 return FALSE;
647 }
648
649 return handler->Create(this, data, type, width, height, depth);
650 }
651
652 wxBitmap::wxBitmap(const wxImage& image, int depth)
653 {
654 wxCHECK_RET( image.Ok(), wxT("invalid image") )
655 wxCHECK_RET( depth == -1, wxT("invalid bitmap depth") )
656
657 m_refData = new wxBitmapRefData();
658
659 if (wxTheBitmapList) wxTheBitmapList->AddBitmap(this);
660
661 // width and height of the device-dependent bitmap
662 int width = image.GetWidth();
663 int height = image.GetHeight();
664
665 // Create picture
666
667 Create( width , height , 32 ) ;
668
669 CGrafPtr origPort ;
670 GDHandle origDevice ;
671
672 PixMapHandle pixMap = GetGWorldPixMap(GetHBITMAP()) ;
673 LockPixels( pixMap );
674
675 GetGWorld( &origPort , &origDevice ) ;
676 SetGWorld( GetHBITMAP() , NULL ) ;
677
678 // Render image
679 RGBColor colorRGB ;
680
681 register unsigned char* data = image.GetData();
682 char* destinationBase = GetPixBaseAddr( pixMap );
683 register unsigned char* destination = (unsigned char*) destinationBase ;
684 for (int y = 0; y < height; y++)
685 {
686 for (int x = 0; x < width; x++)
687 {
688 *destination++ = 0 ;
689 *destination++ = *data++ ;
690 *destination++ = *data++ ;
691 *destination++ = *data++ ;
692 }
693 destinationBase += ((**pixMap).rowBytes & 0x7fff);
694 destination = (unsigned char*) destinationBase ;
695 }
696 if ( image.HasMask() )
697 {
698 data = image.GetData();
699
700 wxColour maskcolor(image.GetMaskRed(), image.GetMaskGreen(), image.GetMaskBlue());
701 RGBColor white = { 0xffff, 0xffff, 0xffff };
702 RGBColor black = { 0 , 0 , 0 };
703 wxBitmap maskBitmap ;
704
705 maskBitmap.Create( width, height, 1);
706 LockPixels( GetGWorldPixMap(maskBitmap.GetHBITMAP()) );
707 SetGWorld(maskBitmap.GetHBITMAP(), NULL);
708
709 for (int y = 0; y < height; y++)
710 {
711 for (int x = 0; x < width; x++)
712 {
713 if ( data[0] == image.GetMaskRed() && data[1] == image.GetMaskGreen() && data[2] == image.GetMaskBlue() )
714 {
715 SetCPixel(x,y, &white);
716 }
717 else {
718 SetCPixel(x,y, &black);
719 }
720 data += 3 ;
721 }
722 } // for height
723 SetGWorld(GetHBITMAP(), NULL);
724 SetMask(new wxMask( maskBitmap ));
725 UnlockPixels( GetGWorldPixMap(maskBitmap.GetHBITMAP()) );
726 }
727
728 UnlockPixels( GetGWorldPixMap(GetHBITMAP()) );
729 SetGWorld( origPort, origDevice );
730 }
731
732 wxImage wxBitmap::ConvertToImage() const
733 {
734 wxImage image;
735
736 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
737
738 // create an wxImage object
739 int width = GetWidth();
740 int height = GetHeight();
741 image.Create( width, height );
742
743 unsigned char *data = image.GetData();
744
745 wxCHECK_MSG( data, wxNullImage, wxT("Could not allocate data for image") );
746
747 WXHBITMAP origPort;
748 GDHandle origDevice;
749 int index;
750 RGBColor color;
751 // background color set to RGB(16,16,16) in consistent with wxGTK
752 unsigned char mask_r=16, mask_g=16, mask_b=16;
753 SInt16 r,g,b;
754 wxMask *mask = GetMask();
755
756 GetGWorld( &origPort, &origDevice );
757 LockPixels(GetGWorldPixMap(GetHBITMAP()));
758 SetGWorld( GetHBITMAP(), NULL);
759
760 // Copy data into image
761 index = 0;
762 for (int yy = 0; yy < height; yy++)
763 {
764 for (int xx = 0; xx < width; xx++)
765 {
766 GetCPixel(xx,yy, &color);
767 r = ((color.red ) >> 8);
768 g = ((color.green ) >> 8);
769 b = ((color.blue ) >> 8);
770 data[index ] = r;
771 data[index + 1] = g;
772 data[index + 2] = b;
773 if (mask)
774 {
775 if (mask->PointMasked(xx,yy))
776 {
777 data[index ] = mask_r;
778 data[index + 1] = mask_g;
779 data[index + 2] = mask_b;
780 }
781 }
782 index += 3;
783 }
784 }
785 if (mask)
786 {
787 image.SetMaskColour( mask_r, mask_g, mask_b );
788 image.SetMask( true );
789 }
790
791 // Free resources
792 UnlockPixels(GetGWorldPixMap(GetHBITMAP()));
793 SetGWorld(origPort, origDevice);
794
795 return image;
796 }
797
798
799 bool wxBitmap::SaveFile(const wxString& filename, wxBitmapType type,
800 const wxPalette *palette) const
801 {
802 wxBitmapHandler *handler = FindHandler(type);
803
804 if ( handler )
805 {
806 return handler->SaveFile(this, filename, type, palette);
807 }
808 else
809 {
810 wxImage image = ConvertToImage();
811
812 return image.SaveFile(filename, type);
813 }
814
815 wxLogWarning("no bitmap handler for type %d defined.", type);
816 return false;
817 }
818
819 bool wxBitmap::Ok() const
820 {
821 return (M_BITMAPDATA && M_BITMAPDATA->m_ok);
822 }
823
824 int wxBitmap::GetHeight() const
825 {
826 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
827
828 return M_BITMAPDATA->m_height;
829 }
830
831 int wxBitmap::GetWidth() const
832 {
833 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
834
835 return M_BITMAPDATA->m_width;
836 }
837
838 int wxBitmap::GetDepth() const
839 {
840 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
841
842 return M_BITMAPDATA->m_depth;
843 }
844
845 int wxBitmap::GetQuality() const
846 {
847 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
848
849 return M_BITMAPDATA->m_quality;
850 }
851
852 wxMask *wxBitmap::GetMask() const
853 {
854 wxCHECK_MSG( Ok(), (wxMask *) NULL, wxT("invalid bitmap") );
855
856 return M_BITMAPDATA->m_bitmapMask;
857 }
858
859 void wxBitmap::SetWidth(int w)
860 {
861 if (!M_BITMAPDATA)
862 m_refData = new wxBitmapRefData;
863
864 M_BITMAPDATA->m_width = w;
865 }
866
867 void wxBitmap::SetHeight(int h)
868 {
869 if (!M_BITMAPDATA)
870 m_refData = new wxBitmapRefData;
871
872 M_BITMAPDATA->m_height = h;
873 }
874
875 void wxBitmap::SetDepth(int d)
876 {
877 if (!M_BITMAPDATA)
878 m_refData = new wxBitmapRefData;
879
880 M_BITMAPDATA->m_depth = d;
881 }
882
883 void wxBitmap::SetQuality(int q)
884 {
885 if (!M_BITMAPDATA)
886 m_refData = new wxBitmapRefData;
887
888 M_BITMAPDATA->m_quality = q;
889 }
890
891 void wxBitmap::SetOk(bool isOk)
892 {
893 if (!M_BITMAPDATA)
894 m_refData = new wxBitmapRefData;
895
896 M_BITMAPDATA->m_ok = isOk;
897 }
898
899 wxPalette *wxBitmap::GetPalette() const
900 {
901 wxCHECK_MSG( Ok(), NULL, wxT("Invalid bitmap GetPalette()") );
902
903 return &M_BITMAPDATA->m_bitmapPalette;
904 }
905
906 void wxBitmap::SetPalette(const wxPalette& palette)
907 {
908 if (!M_BITMAPDATA)
909 m_refData = new wxBitmapRefData;
910
911 M_BITMAPDATA->m_bitmapPalette = palette ;
912 }
913
914 void wxBitmap::SetMask(wxMask *mask)
915 {
916 if (!M_BITMAPDATA)
917 m_refData = new wxBitmapRefData;
918
919 // Remove existing mask if there is one.
920 if (M_BITMAPDATA->m_bitmapMask)
921 delete M_BITMAPDATA->m_bitmapMask;
922
923 M_BITMAPDATA->m_bitmapMask = mask ;
924 }
925
926 WXHBITMAP wxBitmap::GetHBITMAP() const
927 {
928 wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") );
929
930 return M_BITMAPDATA->m_hBitmap;
931 }
932
933 PicHandle wxBitmap::GetPict() const
934 {
935 wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") );
936
937 PicHandle picture; // This is the returned picture
938
939 // If bitmap already in Pict format return pointer
940 if(M_BITMAPDATA->m_bitmapType == kMacBitmapTypePict) {
941 return M_BITMAPDATA->m_hPict;
942 }
943 else if(M_BITMAPDATA->m_bitmapType != kMacBitmapTypeGrafWorld) {
944 // Invalid bitmap
945 return NULL;
946 }
947
948 RGBColor gray = { 0xCCCC ,0xCCCC , 0xCCCC } ;
949 RGBColor white = { 0xffff ,0xffff , 0xffff } ;
950 RGBColor black = { 0x0000 ,0x0000 , 0x0000 } ;
951 CGrafPtr origPort;
952 GDHandle origDev ;
953 wxMask *mask;
954 Rect portRect ;
955
956 GetPortBounds( GetHBITMAP() , &portRect ) ;
957 int width = portRect.right - portRect.left ;
958 int height = portRect.bottom - portRect.top ;
959
960 LockPixels( GetGWorldPixMap( GetHBITMAP() ) ) ;
961 GetGWorld( &origPort , &origDev ) ;
962
963 mask = GetMask();
964
965 SetGWorld( GetHBITMAP() , NULL ) ;
966
967 picture = OpenPicture(&portRect); // open a picture, this disables drawing
968 if(!picture) {
969 return NULL;
970 }
971
972 if( mask )
973 {
974 #ifdef __DARWIN__
975 RGBColor trans = white;
976 #else
977 RGBBackColor( &gray );
978 EraseRect( &portRect );
979 RGBColor trans = gray;
980 #endif
981 RGBForeColor( &black ) ;
982 RGBBackColor( &white ) ;
983 PenMode(transparent);
984
985 for ( int y = 0 ; y < height ; ++y )
986 {
987 for( int x = 0 ; x < width ; ++x )
988 {
989 if ( !mask->PointMasked(x,y) )
990 {
991 RGBColor col ;
992
993 GetCPixel( x + portRect.left , y + portRect.top , &col ) ;
994 SetCPixel( x + portRect.left , y + portRect.top , &col ) ;
995 }
996 else {
997 // With transparency this sets a blank pixel
998 SetCPixel( x + portRect.left , y + portRect.top , &trans);
999 }
1000 }
1001 }
1002 }
1003 else
1004 {
1005 RGBBackColor( &gray ) ;
1006 EraseRect(&portRect);
1007 RGBForeColor( &black ) ;
1008 RGBBackColor( &white ) ;
1009
1010 CopyBits(GetPortBitMapForCopyBits(GetHBITMAP()),
1011 // src PixMap - we copy image over itself -
1012 GetPortBitMapForCopyBits(GetHBITMAP()),
1013 // dst PixMap - no drawing occurs
1014 &portRect, // srcRect - it will be recorded and compressed -
1015 &portRect, // dstRect - into the picture that is open -
1016 srcCopy,NULL); // copyMode and no clip region
1017 }
1018 ClosePicture(); // We are done recording the picture
1019 UnlockPixels( GetGWorldPixMap( GetHBITMAP() ) ) ;
1020 SetGWorld( origPort , origDev ) ;
1021
1022 return picture; // return our groovy pict handle
1023 }
1024
1025 void wxBitmap::AddHandler(wxBitmapHandler *handler)
1026 {
1027 sm_handlers.Append(handler);
1028 }
1029
1030 void wxBitmap::InsertHandler(wxBitmapHandler *handler)
1031 {
1032 sm_handlers.Insert(handler);
1033 }
1034
1035 bool wxBitmap::RemoveHandler(const wxString& name)
1036 {
1037 wxBitmapHandler *handler = FindHandler(name);
1038 if ( handler )
1039 {
1040 sm_handlers.DeleteObject(handler);
1041 return TRUE;
1042 }
1043 else
1044 return FALSE;
1045 }
1046
1047 wxBitmapHandler *wxBitmap::FindHandler(const wxString& name)
1048 {
1049 wxNode *node = sm_handlers.First();
1050 while ( node )
1051 {
1052 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
1053 if ( handler->GetName() == name )
1054 return handler;
1055 node = node->Next();
1056 }
1057 return NULL;
1058 }
1059
1060 wxBitmapHandler *wxBitmap::FindHandler(const wxString& extension, wxBitmapType type)
1061 {
1062 wxNode *node = sm_handlers.First();
1063 while ( node )
1064 {
1065 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
1066 if ( handler->GetExtension() == extension &&
1067 (type == -1 || handler->GetType() == type) )
1068 return handler;
1069 node = node->Next();
1070 }
1071 return NULL;
1072 }
1073
1074 wxBitmapHandler *wxBitmap::FindHandler(wxBitmapType type)
1075 {
1076 wxNode *node = sm_handlers.First();
1077 while ( node )
1078 {
1079 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
1080 if (handler->GetType() == type)
1081 return handler;
1082 node = node->Next();
1083 }
1084 return NULL;
1085 }
1086
1087 /*
1088 * wxMask
1089 */
1090
1091 wxMask::wxMask()
1092 {
1093 m_maskBitmap = 0;
1094 }
1095
1096 // Construct a mask from a bitmap and a colour indicating
1097 // the transparent area
1098 wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour)
1099 {
1100 m_maskBitmap = 0;
1101 Create(bitmap, colour);
1102 }
1103
1104 // Construct a mask from a bitmap and a palette index indicating
1105 // the transparent area
1106 wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex)
1107 {
1108 m_maskBitmap = 0;
1109 Create(bitmap, paletteIndex);
1110 }
1111
1112 // Construct a mask from a mono bitmap (copies the bitmap).
1113 wxMask::wxMask(const wxBitmap& bitmap)
1114 {
1115 m_maskBitmap = 0;
1116 Create(bitmap);
1117 }
1118
1119 wxMask::~wxMask()
1120 {
1121 if ( m_maskBitmap )
1122 {
1123 wxMacDestroyGWorld( m_maskBitmap ) ;
1124 m_maskBitmap = NULL ;
1125 }
1126 }
1127
1128 // Create a mask from a mono bitmap (copies the bitmap).
1129 bool wxMask::Create(const wxBitmap& bitmap)
1130 {
1131 if ( m_maskBitmap )
1132 {
1133 wxMacDestroyGWorld( m_maskBitmap ) ;
1134 m_maskBitmap = NULL ;
1135 }
1136 wxCHECK_MSG( bitmap.GetBitmapType() == kMacBitmapTypeGrafWorld, false,
1137 wxT("Cannot create mask from this bitmap type (TODO)"));
1138 // other types would require a temporary bitmap. not yet implemented
1139
1140 wxCHECK_MSG( bitmap.Ok(), false, wxT("Invalid bitmap"));
1141
1142 wxCHECK_MSG(bitmap.GetDepth() == 1, false,
1143 wxT("Cannot create mask from colour bitmap"));
1144
1145 m_maskBitmap = wxMacCreateGWorld(bitmap.GetWidth(), bitmap.GetHeight(), 1);
1146 Rect rect = { 0,0, bitmap.GetHeight(), bitmap.GetWidth() };
1147
1148 LockPixels( GetGWorldPixMap(m_maskBitmap) );
1149 LockPixels( GetGWorldPixMap(bitmap.GetHBITMAP()) );
1150 CopyBits(GetPortBitMapForCopyBits(bitmap.GetHBITMAP()),
1151 GetPortBitMapForCopyBits(m_maskBitmap),
1152 &rect, &rect, srcCopy, 0);
1153 UnlockPixels( GetGWorldPixMap(m_maskBitmap) );
1154 UnlockPixels( GetGWorldPixMap(bitmap.GetHBITMAP()) );
1155
1156 return FALSE;
1157 }
1158
1159 // Create a mask from a bitmap and a palette index indicating
1160 // the transparent area
1161 bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex)
1162 {
1163 // TODO
1164 wxCHECK_MSG( 0, false, wxT("Not implemented"));
1165 return FALSE;
1166 }
1167
1168 // Create a mask from a bitmap and a colour indicating
1169 // the transparent area
1170 bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
1171 {
1172 if ( m_maskBitmap )
1173 {
1174 wxMacDestroyGWorld( m_maskBitmap ) ;
1175 m_maskBitmap = NULL ;
1176 }
1177 wxCHECK_MSG( bitmap.GetBitmapType() == kMacBitmapTypeGrafWorld, false,
1178 wxT("Cannot create mask from this bitmap type (TODO)"));
1179 // other types would require a temporary bitmap. not yet implemented
1180
1181 wxCHECK_MSG( bitmap.Ok(), false, wxT("Illigal bitmap"));
1182
1183 m_maskBitmap = wxMacCreateGWorld( bitmap.GetWidth() , bitmap.GetHeight() , 1 );
1184 LockPixels( GetGWorldPixMap( m_maskBitmap ) );
1185 LockPixels( GetGWorldPixMap( bitmap.GetHBITMAP() ) );
1186 RGBColor maskColor = colour.GetPixel();
1187
1188 // this is not very efficient, but I can't think
1189 // of a better way of doing it
1190 CGrafPtr origPort ;
1191 GDHandle origDevice ;
1192 RGBColor col;
1193 RGBColor colors[2] = {
1194 { 0xFFFF, 0xFFFF, 0xFFFF },
1195 { 0, 0, 0 }};
1196
1197 GetGWorld( &origPort , &origDevice ) ;
1198 for (int w = 0; w < bitmap.GetWidth(); w++)
1199 {
1200 for (int h = 0; h < bitmap.GetHeight(); h++)
1201 {
1202 SetGWorld( bitmap.GetHBITMAP(), NULL ) ;
1203 GetCPixel( w , h , &col ) ;
1204 SetGWorld( m_maskBitmap , NULL ) ;
1205 if (col.red == maskColor.red && col.green == maskColor.green && col.blue == maskColor.blue)
1206 {
1207 SetCPixel( w , h , &colors[0] ) ;
1208 }
1209 else
1210 {
1211 SetCPixel( w , h , &colors[1] ) ;
1212 }
1213 }
1214 }
1215 UnlockPixels( GetGWorldPixMap( (CGrafPtr) m_maskBitmap ) ) ;
1216 UnlockPixels( GetGWorldPixMap( bitmap.GetHBITMAP() ) ) ;
1217 SetGWorld( origPort , origDevice ) ;
1218
1219 return TRUE;
1220 }
1221
1222 bool wxMask::PointMasked(int x, int y)
1223 {
1224 WXHBITMAP origPort;
1225 GDHandle origDevice;
1226 RGBColor color;
1227 bool masked = true;
1228
1229 GetGWorld( &origPort, &origDevice);
1230
1231 //Set port to mask and see if it masked (1) or not ( 0 )
1232 SetGWorld(m_maskBitmap, NULL);
1233 LockPixels(GetGWorldPixMap(m_maskBitmap));
1234 GetCPixel(x,y, &color);
1235 masked = !(color.red == 0 && color.green == 0 && color.blue == 0);
1236 UnlockPixels(GetGWorldPixMap(m_maskBitmap));
1237
1238 SetGWorld( origPort, origDevice);
1239
1240 return masked;
1241 }
1242
1243 /*
1244 * wxBitmapHandler
1245 */
1246
1247 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject)
1248
1249 bool wxBitmapHandler::Create(wxBitmap *bitmap, void *data, long type, int width, int height, int depth)
1250 {
1251 return FALSE;
1252 }
1253
1254 bool wxBitmapHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long flags,
1255 int desiredWidth, int desiredHeight)
1256 {
1257 return FALSE;
1258 }
1259
1260 bool wxBitmapHandler::SaveFile(const wxBitmap *bitmap, const wxString& name, int type, const wxPalette *palette)
1261 {
1262 return FALSE;
1263 }
1264
1265 /*
1266 * Standard handlers
1267 */
1268
1269 class WXDLLEXPORT wxPICTResourceHandler: public wxBitmapHandler
1270 {
1271 DECLARE_DYNAMIC_CLASS(wxPICTResourceHandler)
1272 public:
1273 inline wxPICTResourceHandler()
1274 {
1275 m_name = "Macintosh Pict resource";
1276 m_extension = "";
1277 m_type = wxBITMAP_TYPE_PICT_RESOURCE;
1278 };
1279
1280 virtual bool LoadFile(wxBitmap *bitmap, const wxString& name, long flags,
1281 int desiredWidth, int desiredHeight);
1282 };
1283 IMPLEMENT_DYNAMIC_CLASS(wxPICTResourceHandler, wxBitmapHandler)
1284
1285 bool wxPICTResourceHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long flags,
1286 int desiredWidth, int desiredHeight)
1287 {
1288 Str255 theName ;
1289
1290 #if TARGET_CARBON
1291 c2pstrcpy( (StringPtr) theName , name ) ;
1292 #else
1293 strcpy( (char *) theName , name ) ;
1294 c2pstr( (char *)theName ) ;
1295 #endif
1296
1297 PicHandle thePict = (PicHandle ) GetNamedResource( 'PICT' , theName ) ;
1298 if ( thePict )
1299 {
1300 PictInfo theInfo ;
1301
1302 GetPictInfo( thePict , &theInfo , 0 , 0 , systemMethod , 0 ) ;
1303 DetachResource( (Handle) thePict ) ;
1304 M_BITMAPHANDLERDATA->m_bitmapType = kMacBitmapTypePict ;
1305 M_BITMAPHANDLERDATA->m_hPict = thePict ;
1306 M_BITMAPHANDLERDATA->m_width = theInfo.sourceRect.right - theInfo.sourceRect.left ;
1307 M_BITMAPHANDLERDATA->m_height = theInfo.sourceRect.bottom - theInfo.sourceRect.top ;
1308
1309 M_BITMAPHANDLERDATA->m_depth = theInfo.depth ;
1310 M_BITMAPHANDLERDATA->m_ok = true ;
1311 M_BITMAPHANDLERDATA->m_numColors = theInfo.uniqueColors ;
1312 // M_BITMAPHANDLERDATA->m_bitmapPalette;
1313 // M_BITMAPHANDLERDATA->m_quality;
1314 return TRUE ;
1315 }
1316 return FALSE ;
1317 }
1318
1319 #if 0 // The following is an example for creating a bitmap handler
1320
1321 // TODO: bitmap handlers, a bit like this:
1322 class WXDLLEXPORT wxBMPResourceHandler: public wxBitmapHandler
1323 {
1324 DECLARE_DYNAMIC_CLASS(wxBMPResourceHandler)
1325 public:
1326 inline wxBMPResourceHandler()
1327 {
1328 m_name = "Windows bitmap resource";
1329 m_extension = "";
1330 m_type = wxBITMAP_TYPE_BMP_RESOURCE;
1331 };
1332
1333 virtual bool LoadFile(wxBitmap *bitmap, const wxString& name, long flags,
1334 int desiredWidth, int desiredHeight);
1335 };
1336 IMPLEMENT_DYNAMIC_CLASS(wxBMPResourceHandler, wxBitmapHandler)
1337
1338 #endif
1339
1340 void wxBitmap::CleanUpHandlers()
1341 {
1342 wxNode *node = sm_handlers.First();
1343 while ( node )
1344 {
1345 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
1346 wxNode *next = node->Next();
1347 delete handler;
1348 delete node;
1349 node = next;
1350 }
1351 }
1352
1353 void wxBitmap::InitStandardHandlers()
1354 {
1355 AddHandler(new wxPICTResourceHandler) ;
1356 AddHandler(new wxICONResourceHandler) ;
1357 }