]> git.saurik.com Git - wxWidgets.git/blob - src/osx/core/bitmap.cpp
6e49503de663781e60e7f44bc4e293be028670df
[wxWidgets.git] / src / osx / core / bitmap.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/core/bitmap.cpp
3 // Purpose: wxBitmap
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #include "wx/bitmap.h"
15
16 #ifndef WX_PRECOMP
17 #include "wx/log.h"
18 #include "wx/dcmemory.h"
19 #include "wx/icon.h"
20 #include "wx/image.h"
21 #endif
22
23 #include "wx/metafile.h"
24 #include "wx/xpmdecod.h"
25
26 #include "wx/rawbmp.h"
27
28 IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
29 IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
30
31 #if wxOSX_USE_CARBON
32 #include "wx/osx/uma.h"
33 #else
34 #include "wx/osx/private.h"
35 #endif
36
37 #ifndef __WXOSX_IPHONE__
38 #include <QuickTime/QuickTime.h>
39 #endif
40
41 CGColorSpaceRef wxMacGetGenericRGBColorSpace();
42 CGDataProviderRef wxMacCGDataProviderCreateWithMemoryBuffer( const wxMemoryBuffer& buf );
43
44 // Implementation Notes
45 // --------------------
46 //
47 // we are always working with a 32 bit deep pixel buffer
48 // under QuickDraw its alpha parts are going to be ignored in the GWorld,
49 // therefore we have a separate GWorld there for blitting the mask in
50
51 // under Quartz then content is transformed into a CGImageRef representing the same data
52 // which can be transferred to the GPU by the OS for fast rendering
53
54 class WXDLLEXPORT wxBitmapRefData: public wxGDIRefData
55 {
56 friend class WXDLLIMPEXP_FWD_CORE wxIcon;
57 friend class WXDLLIMPEXP_FWD_CORE wxCursor;
58 public:
59 wxBitmapRefData(int width , int height , int depth);
60 wxBitmapRefData(CGImageRef image);
61 wxBitmapRefData();
62 wxBitmapRefData(const wxBitmapRefData &tocopy);
63
64 virtual ~wxBitmapRefData();
65
66 virtual bool IsOk() const { return m_ok; }
67
68 void Free();
69 void SetOk( bool isOk) { m_ok = isOk; }
70
71 void SetWidth( int width ) { m_width = width; }
72 void SetHeight( int height ) { m_height = height; }
73 void SetDepth( int depth ) { m_depth = depth; }
74
75 int GetWidth() const { return m_width; }
76 int GetHeight() const { return m_height; }
77 int GetDepth() const { return m_depth; }
78
79 void *GetRawAccess() const;
80 void *BeginRawAccess();
81 void EndRawAccess();
82
83 bool HasAlpha() const { return m_hasAlpha; }
84 void UseAlpha( bool useAlpha );
85
86 public:
87 #if wxUSE_PALETTE
88 wxPalette m_bitmapPalette;
89 #endif // wxUSE_PALETTE
90
91 wxMask * m_bitmapMask; // Optional mask
92 CGImageRef CreateCGImage() const;
93
94 // returns true if the bitmap has a size that
95 // can be natively transferred into a true icon
96 // if no is returned GetIconRef will still produce
97 // an icon but it will be generated via a PICT and
98 // rescaled to 16 x 16
99 bool HasNativeSize();
100
101 // caller should increase ref count if needed longer
102 // than the bitmap exists
103 IconRef GetIconRef();
104
105 #ifndef __WXOSX_IPHONE__
106 // returns a Pict from the bitmap content
107 PicHandle GetPictHandle();
108 #endif
109
110 CGContextRef GetBitmapContext() const;
111
112 int GetBytesPerRow() const { return m_bytesPerRow; }
113 private :
114 bool Create(int width , int height , int depth);
115 bool Create( CGImageRef image );
116 void Init();
117
118 int m_width;
119 int m_height;
120 int m_bytesPerRow;
121 int m_depth;
122 bool m_hasAlpha;
123 wxMemoryBuffer m_memBuf;
124 int m_rawAccessCount;
125 bool m_ok;
126 mutable CGImageRef m_cgImageRef;
127
128 IconRef m_iconRef;
129 #ifndef __WXOSX_IPHONE__
130 PicHandle m_pictHandle;
131 #endif
132 CGContextRef m_hBitmap;
133 };
134
135
136 #define wxOSX_USE_PREMULTIPLIED_ALPHA 1
137 static const int kBestByteAlignement = 16;
138 static const int kMaskBytesPerPixel = 1;
139
140 static int GetBestBytesPerRow( int rawBytes )
141 {
142 return (((rawBytes)+kBestByteAlignement-1) & ~(kBestByteAlignement-1) );
143 }
144
145 #if wxUSE_GUI && !defined(__WXOSX_IPHONE__)
146
147 // this is used for more controls than just the wxBitmap button, also for notebooks etc
148
149 void wxMacCreateBitmapButton( ControlButtonContentInfo*info , const wxBitmap& bitmap , int forceType )
150 {
151 memset( info , 0 , sizeof(ControlButtonContentInfo) ) ;
152 if ( bitmap.IsOk() )
153 {
154 wxBitmapRefData * bmap = bitmap.GetBitmapData() ;
155 if ( bmap == NULL )
156 return ;
157
158 if ( forceType == 0 )
159 {
160 forceType = kControlContentCGImageRef;
161 }
162
163 if ( forceType == kControlContentIconRef )
164 {
165 wxBitmap scaleBmp ;
166 wxBitmapRefData* bmp = bmap ;
167
168 if ( !bmap->HasNativeSize() )
169 {
170 // as PICT conversion will only result in a 16x16 icon, let's attempt
171 // a few scales for better results
172
173 int w = bitmap.GetWidth() ;
174 int h = bitmap.GetHeight() ;
175 int sz = wxMax( w , h ) ;
176 if ( sz == 24 || sz == 64 )
177 {
178 scaleBmp = wxBitmap( bitmap.ConvertToImage().Scale( w * 2 , h * 2 ) ) ;
179 bmp = scaleBmp.GetBitmapData() ;
180 }
181 }
182
183 info->contentType = kControlContentIconRef ;
184 info->u.iconRef = bmp->GetIconRef() ;
185 AcquireIconRef( info->u.iconRef ) ;
186 }
187 else if ( forceType == kControlContentCGImageRef )
188 {
189 info->contentType = kControlContentCGImageRef ;
190 info->u.imageRef = (CGImageRef) bmap->CreateCGImage() ;
191 }
192 else
193 {
194 #ifndef __LP64__
195 info->contentType = kControlContentPictHandle ;
196 info->u.picture = bmap->GetPictHandle() ;
197 #endif
198 }
199 }
200 }
201
202 CGImageRef wxMacCreateCGImageFromBitmap( const wxBitmap& bitmap )
203 {
204 wxBitmapRefData * bmap = bitmap.GetBitmapData() ;
205 if ( bmap == NULL )
206 return NULL ;
207 return (CGImageRef) bmap->CreateCGImage();
208 }
209
210 void wxMacReleaseBitmapButton( ControlButtonContentInfo*info )
211 {
212 if ( info->contentType == kControlContentIconRef )
213 {
214 ReleaseIconRef( info->u.iconRef ) ;
215 }
216 else if ( info->contentType == kControlNoContent )
217 {
218 // there's no bitmap at all, fall through silently
219 }
220 else if ( info->contentType == kControlContentPictHandle )
221 {
222 // owned by the bitmap, no release here
223 }
224 else if ( info->contentType == kControlContentCGImageRef )
225 {
226 CGImageRelease( info->u.imageRef ) ;
227 }
228 else
229 {
230 wxFAIL_MSG(wxT("Unexpected bitmap type") ) ;
231 }
232 }
233
234 #endif //wxUSE_BMPBUTTON
235
236 #define M_BITMAPDATA ((wxBitmapRefData *)m_refData)
237
238 void wxBitmapRefData::Init()
239 {
240 m_width = 0 ;
241 m_height = 0 ;
242 m_depth = 0 ;
243 m_bytesPerRow = 0;
244 m_ok = false ;
245 m_bitmapMask = NULL ;
246 m_cgImageRef = NULL ;
247
248 #ifndef __WXOSX_IPHONE__
249 m_iconRef = NULL ;
250 m_pictHandle = NULL ;
251 #endif
252 m_hBitmap = NULL ;
253
254 m_rawAccessCount = 0 ;
255 m_hasAlpha = false;
256 }
257
258 wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData &tocopy) : wxGDIRefData()
259 {
260 Init();
261 Create(tocopy.m_width, tocopy.m_height, tocopy.m_depth);
262
263 if (tocopy.m_bitmapMask)
264 m_bitmapMask = new wxMask(*tocopy.m_bitmapMask);
265 else if (tocopy.m_hasAlpha)
266 UseAlpha(true);
267
268 unsigned char* dest = (unsigned char*)GetRawAccess();
269 unsigned char* source = (unsigned char*)tocopy.GetRawAccess();
270 size_t numbytes = m_bytesPerRow * m_height;
271 memcpy( dest, source, numbytes );
272 }
273
274 wxBitmapRefData::wxBitmapRefData()
275 {
276 Init() ;
277 }
278
279 wxBitmapRefData::wxBitmapRefData( int w , int h , int d )
280 {
281 Init() ;
282 Create( w , h , d ) ;
283 }
284
285 wxBitmapRefData::wxBitmapRefData(CGImageRef image)
286 {
287 Init();
288 Create( image );
289 }
290 // code from Technical Q&A QA1509
291
292 bool wxBitmapRefData::Create(CGImageRef image)
293 {
294 if ( image != NULL )
295 {
296 m_width = CGImageGetWidth(image);
297 m_height = CGImageGetHeight(image);
298 m_depth = 32;
299 m_hBitmap = NULL;
300
301 m_bytesPerRow = GetBestBytesPerRow( m_width * 4 ) ;
302 size_t size = m_bytesPerRow * m_height ;
303 void* data = m_memBuf.GetWriteBuf( size ) ;
304 if ( data != NULL )
305 {
306 memset( data , 0 , size ) ;
307 m_memBuf.UngetWriteBuf( size ) ;
308 CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image);
309 if ( alpha == kCGImageAlphaNone || alpha == kCGImageAlphaNoneSkipLast || alpha == kCGImageAlphaNoneSkipLast )
310 {
311 m_hBitmap = CGBitmapContextCreate((char*) data, m_width, m_height, 8, m_bytesPerRow, wxMacGetGenericRGBColorSpace(), kCGImageAlphaNoneSkipFirst );
312 }
313 else
314 {
315 m_hasAlpha = true;
316 m_hBitmap = CGBitmapContextCreate((char*) data, m_width, m_height, 8, m_bytesPerRow, wxMacGetGenericRGBColorSpace(), kCGImageAlphaPremultipliedFirst );
317 }
318 CGRect rect = {{0,0},{m_width,m_height}};
319 CGContextDrawImage(m_hBitmap, rect, image);
320
321 wxASSERT_MSG( m_hBitmap , wxT("Unable to create CGBitmapContext context") ) ;
322 CGContextTranslateCTM( m_hBitmap, 0, m_height );
323 CGContextScaleCTM( m_hBitmap, 1, -1 );
324 } /* data != NULL */
325 }
326 m_ok = ( m_hBitmap != NULL ) ;
327
328 return m_ok ;
329
330 }
331
332 bool wxBitmapRefData::Create( int w , int h , int d )
333 {
334 m_width = wxMax(1, w);
335 m_height = wxMax(1, h);
336 m_depth = d ;
337 m_hBitmap = NULL ;
338
339 m_bytesPerRow = GetBestBytesPerRow( m_width * 4 ) ;
340 size_t size = m_bytesPerRow * m_height ;
341 void* data = m_memBuf.GetWriteBuf( size ) ;
342 if ( data != NULL )
343 {
344 memset( data , 0 , size ) ;
345 m_memBuf.UngetWriteBuf( size ) ;
346
347 m_hBitmap = CGBitmapContextCreate((char*) data, m_width, m_height, 8, m_bytesPerRow, wxMacGetGenericRGBColorSpace(), kCGImageAlphaNoneSkipFirst );
348 wxASSERT_MSG( m_hBitmap , wxT("Unable to create CGBitmapContext context") ) ;
349 CGContextTranslateCTM( m_hBitmap, 0, m_height );
350 CGContextScaleCTM( m_hBitmap, 1, -1 );
351 } /* data != NULL */
352 m_ok = ( m_hBitmap != NULL ) ;
353
354 return m_ok ;
355 }
356
357 void wxBitmapRefData::UseAlpha( bool use )
358 {
359 if ( m_hasAlpha == use )
360 return ;
361
362 m_hasAlpha = use ;
363
364 CGContextRelease( m_hBitmap );
365 m_hBitmap = CGBitmapContextCreate((char*) m_memBuf.GetData(), m_width, m_height, 8, m_bytesPerRow, wxMacGetGenericRGBColorSpace(), m_hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst );
366 wxASSERT_MSG( m_hBitmap , wxT("Unable to create CGBitmapContext context") ) ;
367 CGContextTranslateCTM( m_hBitmap, 0, m_height );
368 CGContextScaleCTM( m_hBitmap, 1, -1 );
369 }
370
371 void *wxBitmapRefData::GetRawAccess() const
372 {
373 wxCHECK_MSG( IsOk(), NULL , wxT("invalid bitmap") ) ;
374 return m_memBuf.GetData() ;
375 }
376
377 void *wxBitmapRefData::BeginRawAccess()
378 {
379 wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") ) ;
380 wxASSERT( m_rawAccessCount == 0 ) ;
381 #ifndef __WXOSX_IPHONE__
382 wxASSERT_MSG( m_pictHandle == NULL && m_iconRef == NULL ,
383 wxT("Currently, modifing bitmaps that are used in controls already is not supported") ) ;
384 #endif
385 ++m_rawAccessCount ;
386
387 // we must destroy an existing cached image, as
388 // the bitmap data may change now
389 if ( m_cgImageRef )
390 {
391 CGImageRelease( m_cgImageRef ) ;
392 m_cgImageRef = NULL ;
393 }
394
395 return m_memBuf.GetData() ;
396 }
397
398 void wxBitmapRefData::EndRawAccess()
399 {
400 wxCHECK_RET( IsOk() , wxT("invalid bitmap") ) ;
401 wxASSERT( m_rawAccessCount == 1 ) ;
402
403 --m_rawAccessCount ;
404 }
405
406 bool wxBitmapRefData::HasNativeSize()
407 {
408 int w = GetWidth() ;
409 int h = GetHeight() ;
410 int sz = wxMax( w , h ) ;
411
412 return ( sz == 128 || sz == 48 || sz == 32 || sz == 16 );
413 }
414
415 #ifndef __WXOSX_IPHONE__
416 IconRef wxBitmapRefData::GetIconRef()
417 {
418 if ( m_iconRef == NULL )
419 {
420 // Create Icon Family Handle
421
422 IconFamilyHandle iconFamily = (IconFamilyHandle) NewHandle( 0 );
423
424 int w = GetWidth() ;
425 int h = GetHeight() ;
426 int sz = wxMax( w , h ) ;
427
428 OSType dataType = 0 ;
429 OSType maskType = 0 ;
430
431 switch (sz)
432 {
433 case 128:
434 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
435 if ( UMAGetSystemVersion() >= 0x1050 )
436 {
437 dataType = kIconServices128PixelDataARGB ;
438 }
439 else
440 #endif
441 {
442 dataType = kThumbnail32BitData ;
443 maskType = kThumbnail8BitMask ;
444 }
445 break;
446
447 case 48:
448 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
449 if ( UMAGetSystemVersion() >= 0x1050 )
450 {
451 dataType = kIconServices48PixelDataARGB ;
452 }
453 else
454 #endif
455 {
456 dataType = kHuge32BitData ;
457 maskType = kHuge8BitMask ;
458 }
459 break;
460
461 case 32:
462 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
463 if ( UMAGetSystemVersion() >= 0x1050 )
464 {
465 dataType = kIconServices32PixelDataARGB ;
466 }
467 else
468 #endif
469 {
470 dataType = kLarge32BitData ;
471 maskType = kLarge8BitMask ;
472 }
473 break;
474
475 case 16:
476 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
477 if ( UMAGetSystemVersion() >= 0x1050 )
478 {
479 dataType = kIconServices16PixelDataARGB ;
480 }
481 else
482 #endif
483 {
484 dataType = kSmall32BitData ;
485 maskType = kSmall8BitMask ;
486 }
487 break;
488
489 default:
490 break;
491 }
492
493 if ( dataType != 0 )
494 {
495 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
496 if ( maskType == 0 && UMAGetSystemVersion() >= 0x1050 )
497 {
498 size_t datasize = sz * sz * 4 ;
499 Handle data = NewHandle( datasize ) ;
500 HLock( data ) ;
501 unsigned char* ptr = (unsigned char*) *data ;
502 memset( ptr, 0, datasize );
503 bool hasAlpha = HasAlpha() ;
504 wxMask *mask = m_bitmapMask ;
505 unsigned char * sourcePtr = (unsigned char*) GetRawAccess() ;
506 unsigned char * masksourcePtr = mask ? (unsigned char*) mask->GetRawAccess() : NULL ;
507
508 for ( int y = 0 ; y < h ; ++y, sourcePtr += m_bytesPerRow , masksourcePtr += mask ? mask->GetBytesPerRow() : 0 )
509 {
510 unsigned char * source = sourcePtr;
511 unsigned char * masksource = masksourcePtr;
512 unsigned char * dest = ptr + y * sz * 4 ;
513 unsigned char a, r, g, b;
514
515 for ( int x = 0 ; x < w ; ++x )
516 {
517 a = *source ++ ;
518 r = *source ++ ;
519 g = *source ++ ;
520 b = *source ++ ;
521
522 if ( mask )
523 {
524 a = 0xFF - *masksource++ ;
525 }
526 else if ( !hasAlpha )
527 a = 0xFF ;
528 else
529 {
530 #if wxOSX_USE_PREMULTIPLIED_ALPHA
531 // this must be non-premultiplied data
532 if ( a != 0xFF && a!= 0 )
533 {
534 r = r * 255 / a;
535 g = g * 255 / a;
536 b = b * 255 / a;
537 }
538 #endif
539 }
540 *dest++ = a ;
541 *dest++ = r ;
542 *dest++ = g ;
543 *dest++ = b ;
544
545 }
546 }
547 HUnlock( data );
548
549 OSStatus err = SetIconFamilyData( iconFamily, dataType , data );
550 if ( err != noErr )
551 {
552 wxFAIL_MSG("Error when adding bitmap");
553 }
554
555 DisposeHandle( data );
556 }
557 else
558 #endif
559 {
560 // setup the header properly
561
562 Handle data = NULL ;
563 Handle maskdata = NULL ;
564 unsigned char * maskptr = NULL ;
565 unsigned char * ptr = NULL ;
566 size_t datasize, masksize ;
567
568 datasize = sz * sz * 4 ;
569 data = NewHandle( datasize ) ;
570 HLock( data ) ;
571 ptr = (unsigned char*) *data ;
572 memset( ptr , 0, datasize ) ;
573
574 masksize = sz * sz ;
575 maskdata = NewHandle( masksize ) ;
576 HLock( maskdata ) ;
577 maskptr = (unsigned char*) *maskdata ;
578 memset( maskptr , 0 , masksize ) ;
579
580 bool hasAlpha = HasAlpha() ;
581 wxMask *mask = m_bitmapMask ;
582 unsigned char * sourcePtr = (unsigned char*) GetRawAccess() ;
583 unsigned char * masksourcePtr = mask ? (unsigned char*) mask->GetRawAccess() : NULL ;
584
585 for ( int y = 0 ; y < h ; ++y, sourcePtr += m_bytesPerRow , masksourcePtr += mask ? mask->GetBytesPerRow() : 0 )
586 {
587 unsigned char * source = sourcePtr;
588 unsigned char * masksource = masksourcePtr;
589 unsigned char * dest = ptr + y * sz * 4 ;
590 unsigned char * maskdest = maskptr + y * sz ;
591 unsigned char a, r, g, b;
592
593 for ( int x = 0 ; x < w ; ++x )
594 {
595 a = *source ++ ;
596 r = *source ++ ;
597 g = *source ++ ;
598 b = *source ++ ;
599
600 *dest++ = 0 ;
601 *dest++ = r ;
602 *dest++ = g ;
603 *dest++ = b ;
604
605 if ( mask )
606 *maskdest++ = 0xFF - *masksource++ ;
607 else if ( hasAlpha )
608 *maskdest++ = a ;
609 else
610 *maskdest++ = 0xFF ;
611 }
612 }
613
614 OSStatus err = SetIconFamilyData( iconFamily, dataType , data ) ;
615 wxASSERT_MSG( err == noErr , wxT("Error when adding bitmap") ) ;
616
617 err = SetIconFamilyData( iconFamily, maskType , maskdata ) ;
618 wxASSERT_MSG( err == noErr , wxT("Error when adding mask") ) ;
619
620 HUnlock( data ) ;
621 HUnlock( maskdata ) ;
622 DisposeHandle( data ) ;
623 DisposeHandle( maskdata ) ;
624 }
625 }
626 else
627 {
628 PicHandle pic = GetPictHandle() ;
629 SetIconFamilyData( iconFamily, 'PICT' , (Handle) pic ) ;
630 }
631 // transform into IconRef
632
633 // cleaner version existing from 10.3 upwards
634 HLock((Handle) iconFamily);
635 OSStatus err = GetIconRefFromIconFamilyPtr( *iconFamily, GetHandleSize((Handle) iconFamily), &m_iconRef );
636 HUnlock((Handle) iconFamily);
637 DisposeHandle( (Handle) iconFamily ) ;
638
639 wxCHECK_MSG( err == noErr, NULL, wxT("Error when constructing icon ref") );
640 }
641
642 return m_iconRef ;
643 }
644
645 PicHandle wxBitmapRefData::GetPictHandle()
646 {
647 if ( m_pictHandle == NULL )
648 {
649 #ifndef __LP64__
650 GraphicsExportComponent exporter = 0;
651 OSStatus err = OpenADefaultComponent(GraphicsExporterComponentType, kQTFileTypePicture, &exporter);
652 if (noErr == err)
653 {
654 m_pictHandle = (PicHandle) NewHandle(0);
655 if ( m_pictHandle )
656 {
657 // QT does not correctly export the mask
658 // TODO if we get around to it create a synthetic PICT with the CopyBits and Mask commands
659 CGImageRef imageRef = CreateCGImage();
660 err = GraphicsExportSetInputCGImage( exporter, imageRef );
661 err = GraphicsExportSetOutputHandle(exporter, (Handle)m_pictHandle);
662 err = GraphicsExportDoExport(exporter, NULL);
663 CGImageRelease( imageRef );
664
665 size_t handleSize = GetHandleSize( (Handle) m_pictHandle );
666 // the 512 bytes header is only needed for pict files, but not in memory
667 if ( handleSize >= 512 )
668 {
669 memmove( *m_pictHandle , (char*)(*m_pictHandle)+512, handleSize - 512 );
670 SetHandleSize( (Handle) m_pictHandle, handleSize - 512 );
671 }
672 }
673 CloseComponent( exporter );
674 }
675 #endif
676 }
677
678 return m_pictHandle ;
679 }
680 #endif
681
682 CGImageRef wxBitmapRefData::CreateCGImage() const
683 {
684 wxASSERT( m_ok ) ;
685 wxASSERT( m_rawAccessCount >= 0 ) ;
686 CGImageRef image ;
687 if ( m_rawAccessCount > 0 || m_cgImageRef == NULL )
688 {
689 if ( m_depth != 1 && m_bitmapMask == NULL )
690 {
691 #if 0
692 // in order for this code to work properly, wxMask would have to invert black and white
693 // in the native bitmap
694 if ( m_bitmapMask )
695 {
696 CGImageRef tempImage = CGBitmapContextCreateImage( m_hBitmap );
697 CGImageRef tempMask = CGBitmapContextCreateImage((CGContextRef) m_bitmapMask->GetHBITMAP() );
698 image = CGImageCreateWithMask( tempImage, tempMask );
699 CGImageRelease(tempMask);
700 CGImageRelease(tempImage);
701 }
702 else
703 #endif
704 image = CGBitmapContextCreateImage( m_hBitmap );
705 }
706 else
707 {
708 size_t imageSize = m_height * m_bytesPerRow ;
709 void * dataBuffer = m_memBuf.GetData() ;
710 int w = m_width ;
711 int h = m_height ;
712 CGImageAlphaInfo alphaInfo = kCGImageAlphaNoneSkipFirst ;
713 wxMemoryBuffer membuf;
714
715 if ( m_bitmapMask )
716 {
717 alphaInfo = kCGImageAlphaFirst ;
718 unsigned char *destalphastart = (unsigned char*) membuf.GetWriteBuf( imageSize ) ;
719 memcpy( destalphastart , dataBuffer , imageSize ) ;
720 unsigned char *sourcemaskstart = (unsigned char *) m_bitmapMask->GetRawAccess() ;
721 int maskrowbytes = m_bitmapMask->GetBytesPerRow() ;
722 for ( int y = 0 ; y < h ; ++y , destalphastart += m_bytesPerRow, sourcemaskstart += maskrowbytes)
723 {
724 unsigned char *sourcemask = sourcemaskstart ;
725 unsigned char *destalpha = destalphastart ;
726 for ( int x = 0 ; x < w ; ++x , sourcemask += kMaskBytesPerPixel , destalpha += 4 )
727 {
728 *destalpha = 0xFF - *sourcemask ;
729 }
730 }
731 membuf.UngetWriteBuf( imageSize );
732 }
733 else
734 {
735 if ( m_hasAlpha )
736 {
737 #if wxOSX_USE_PREMULTIPLIED_ALPHA
738 alphaInfo = kCGImageAlphaPremultipliedFirst ;
739 #else
740 alphaInfo = kCGImageAlphaFirst ;
741 #endif
742 }
743
744 membuf = m_memBuf;
745 }
746
747 CGDataProviderRef dataProvider = NULL ;
748 if ( m_depth == 1 )
749 {
750 // TODO CHECK ALIGNMENT
751 wxMemoryBuffer maskBuf;
752 unsigned char * maskBufData = (unsigned char*) maskBuf.GetWriteBuf( m_width * m_height );
753 unsigned char * bufData = (unsigned char *) membuf.GetData() ;
754 // copy one color component
755 size_t i = 0;
756 for( int y = 0 ; y < m_height ; bufData+= m_bytesPerRow, ++y )
757 {
758 unsigned char *bufDataIter = bufData+3;
759 for ( int x = 0 ; x < m_width ; bufDataIter += 4, ++x, ++i )
760 {
761 maskBufData[i] = *bufDataIter;
762 }
763 }
764 maskBuf.UngetWriteBuf( m_width * m_height );
765
766 dataProvider =
767 wxMacCGDataProviderCreateWithMemoryBuffer( maskBuf );
768
769 image = ::CGImageMaskCreate( w, h, 8, 8, m_width , dataProvider, NULL, false );
770 }
771 else
772 {
773 CGColorSpaceRef colorSpace = wxMacGetGenericRGBColorSpace();
774 dataProvider = wxMacCGDataProviderCreateWithMemoryBuffer( membuf );
775 image =
776 ::CGImageCreate(
777 w, h, 8 , 32 , m_bytesPerRow , colorSpace, alphaInfo ,
778 dataProvider, NULL , false , kCGRenderingIntentDefault );
779 }
780 CGDataProviderRelease( dataProvider);
781 }
782 }
783 else
784 {
785 image = m_cgImageRef ;
786 CGImageRetain( image ) ;
787 }
788
789 if ( m_rawAccessCount == 0 && m_cgImageRef == NULL)
790 {
791 // we keep it for later use
792 m_cgImageRef = image ;
793 CGImageRetain( image ) ;
794 }
795
796 return image ;
797 }
798
799 CGContextRef wxBitmapRefData::GetBitmapContext() const
800 {
801 return m_hBitmap;
802 }
803
804 void wxBitmapRefData::Free()
805 {
806 wxASSERT_MSG( m_rawAccessCount == 0 , wxT("Bitmap still selected when destroyed") ) ;
807
808 if ( m_cgImageRef )
809 {
810 CGImageRelease( m_cgImageRef ) ;
811 m_cgImageRef = NULL ;
812 }
813 #ifndef __WXOSX_IPHONE__
814 if ( m_iconRef )
815 {
816 ReleaseIconRef( m_iconRef ) ;
817 m_iconRef = NULL ;
818 }
819
820 #ifndef __LP64__
821 if ( m_pictHandle )
822 {
823 KillPicture( m_pictHandle ) ;
824 m_pictHandle = NULL ;
825 }
826 #endif
827 #endif
828 if ( m_hBitmap )
829 {
830 CGContextRelease(m_hBitmap);
831 m_hBitmap = NULL ;
832 }
833
834 wxDELETE(m_bitmapMask);
835 }
836
837 wxBitmapRefData::~wxBitmapRefData()
838 {
839 Free() ;
840 }
841
842
843
844 // ----------------------------------------------------------------------------
845 // wxBitmap
846 // ----------------------------------------------------------------------------
847
848 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
849 {
850 bool created = false ;
851 int w = icon.GetWidth() ;
852 int h = icon.GetHeight() ;
853
854 Create( w , h ) ;
855 #ifdef __WXOSX_CARBON__
856 if ( w == h && ( w == 16 || w == 32 || w == 48 || w == 128 ) )
857 {
858 IconFamilyHandle iconFamily = NULL ;
859 Handle imagehandle = NewHandle( 0 ) ;
860 Handle maskhandle = NewHandle( 0 ) ;
861
862 OSType maskType = 0;
863 OSType dataType = 0;
864 IconSelectorValue selector = 0 ;
865
866 switch (w)
867 {
868 case 128:
869 dataType = kThumbnail32BitData ;
870 maskType = kThumbnail8BitMask ;
871 selector = kSelectorAllAvailableData ;
872 break;
873
874 case 48:
875 dataType = kHuge32BitData ;
876 maskType = kHuge8BitMask ;
877 selector = kSelectorHuge32Bit | kSelectorHuge8BitMask ;
878 break;
879
880 case 32:
881 dataType = kLarge32BitData ;
882 maskType = kLarge8BitMask ;
883 selector = kSelectorLarge32Bit | kSelectorLarge8BitMask ;
884 break;
885
886 case 16:
887 dataType = kSmall32BitData ;
888 maskType = kSmall8BitMask ;
889 selector = kSelectorSmall32Bit | kSelectorSmall8BitMask ;
890 break;
891
892 default:
893 break;
894 }
895
896 OSStatus err = IconRefToIconFamily( MAC_WXHICON(icon.GetHICON()) , selector , &iconFamily ) ;
897
898 err = GetIconFamilyData( iconFamily , dataType , imagehandle ) ;
899 err = GetIconFamilyData( iconFamily , maskType , maskhandle ) ;
900 size_t imagehandlesize = GetHandleSize( imagehandle ) ;
901 size_t maskhandlesize = GetHandleSize( maskhandle ) ;
902
903 if ( imagehandlesize != 0 && maskhandlesize != 0 )
904 {
905 wxASSERT( GetHandleSize( imagehandle ) == w * 4 * h ) ;
906 wxASSERT( GetHandleSize( maskhandle ) == w * h ) ;
907
908 UseAlpha() ;
909
910 unsigned char *source = (unsigned char *) *imagehandle ;
911 unsigned char *sourcemask = (unsigned char *) *maskhandle ;
912 unsigned char* destination = (unsigned char*) BeginRawAccess() ;
913
914 for ( int y = 0 ; y < h ; ++y )
915 {
916 for ( int x = 0 ; x < w ; ++x )
917 {
918 unsigned char a = *sourcemask++;
919 *destination++ = a;
920 source++ ;
921 #if wxOSX_USE_PREMULTIPLIED_ALPHA
922 *destination++ = ( (*source++) * a + 127 ) / 255;
923 *destination++ = ( (*source++) * a + 127 ) / 255;
924 *destination++ = ( (*source++) * a + 127 ) / 255;
925 #else
926 *destination++ = *source++ ;
927 *destination++ = *source++ ;
928 *destination++ = *source++ ;
929 #endif
930 }
931 }
932
933 EndRawAccess() ;
934 DisposeHandle( imagehandle ) ;
935 DisposeHandle( maskhandle ) ;
936 created = true ;
937 }
938
939 DisposeHandle( (Handle) iconFamily ) ;
940 }
941 #endif
942 if ( !created )
943 {
944 wxMemoryDC dc ;
945 dc.SelectObject( *this ) ;
946 dc.DrawIcon( icon , 0 , 0 ) ;
947 dc.SelectObject( wxNullBitmap ) ;
948 }
949
950 return true;
951 }
952
953 wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits)
954 {
955 wxBitmapRefData* bitmapRefData;
956
957 m_refData = bitmapRefData = new wxBitmapRefData( the_width , the_height , no_bits ) ;
958
959 if (bitmapRefData->IsOk())
960 {
961 if ( no_bits == 1 )
962 {
963 int linesize = ( the_width / (sizeof(unsigned char) * 8)) ;
964 if ( the_width % (sizeof(unsigned char) * 8) )
965 linesize += sizeof(unsigned char);
966
967 unsigned char* linestart = (unsigned char*) bits ;
968 unsigned char* destptr = (unsigned char*) BeginRawAccess() ;
969
970 for ( int y = 0 ; y < the_height ; ++y , linestart += linesize, destptr += M_BITMAPDATA->GetBytesPerRow() )
971 {
972 unsigned char* destination = destptr;
973 int index, bit, mask;
974
975 for ( int x = 0 ; x < the_width ; ++x )
976 {
977 index = x / 8 ;
978 bit = x % 8 ;
979 mask = 1 << bit ;
980
981 if ( linestart[index] & mask )
982 {
983 *destination++ = 0xFF ;
984 *destination++ = 0 ;
985 *destination++ = 0 ;
986 *destination++ = 0 ;
987 }
988 else
989 {
990 *destination++ = 0xFF ;
991 *destination++ = 0xFF ;
992 *destination++ = 0xFF ;
993 *destination++ = 0xFF ;
994 }
995 }
996 }
997
998 EndRawAccess() ;
999 }
1000 else
1001 {
1002 wxFAIL_MSG(wxT("multicolor BITMAPs not yet implemented"));
1003 }
1004 } /* bitmapRefData->IsOk() */
1005 }
1006
1007 wxBitmap::wxBitmap(const void* data, wxBitmapType type, int width, int height, int depth)
1008 {
1009 (void) Create(data, type, width, height, depth);
1010 }
1011
1012 wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type)
1013 {
1014 LoadFile(filename, type);
1015 }
1016
1017 wxBitmap::wxBitmap(CGImageRef image)
1018 {
1019 (void) Create(image);
1020 }
1021
1022 wxGDIRefData* wxBitmap::CreateGDIRefData() const
1023 {
1024 return new wxBitmapRefData;
1025 }
1026
1027 wxGDIRefData* wxBitmap::CloneGDIRefData(const wxGDIRefData* data) const
1028 {
1029 return new wxBitmapRefData(*static_cast<const wxBitmapRefData *>(data));
1030 }
1031
1032 void * wxBitmap::GetRawAccess() const
1033 {
1034 wxCHECK_MSG( IsOk() , NULL , wxT("invalid bitmap") ) ;
1035
1036 return M_BITMAPDATA->GetRawAccess() ;
1037 }
1038
1039 void * wxBitmap::BeginRawAccess()
1040 {
1041 wxCHECK_MSG( IsOk() , NULL , wxT("invalid bitmap") ) ;
1042
1043 return M_BITMAPDATA->BeginRawAccess() ;
1044 }
1045
1046 void wxBitmap::EndRawAccess()
1047 {
1048 wxCHECK_RET( IsOk() , wxT("invalid bitmap") ) ;
1049
1050 M_BITMAPDATA->EndRawAccess() ;
1051 }
1052
1053 CGImageRef wxBitmap::CreateCGImage() const
1054 {
1055 wxCHECK_MSG( IsOk(), NULL , wxT("invalid bitmap") ) ;
1056
1057 return M_BITMAPDATA->CreateCGImage() ;
1058 }
1059
1060 #ifndef __WXOSX_IPHONE__
1061 IconRef wxBitmap::GetIconRef() const
1062 {
1063 wxCHECK_MSG( IsOk(), NULL , wxT("invalid bitmap") ) ;
1064
1065 return M_BITMAPDATA->GetIconRef() ;
1066 }
1067
1068 IconRef wxBitmap::CreateIconRef() const
1069 {
1070 IconRef icon = GetIconRef();
1071 verify_noerr( AcquireIconRef(icon) );
1072 return icon;
1073 }
1074 #endif
1075
1076 #if wxOSX_USE_COCOA
1077
1078 WX_NSImage wxBitmap::GetNSImage() const
1079 {
1080 wxCFRef< CGImageRef > cgimage(CreateCGImage());
1081 return wxOSXGetNSImageFromCGImage( cgimage );
1082 }
1083
1084 #endif
1085
1086 #if wxOSX_USE_IPHONE
1087
1088 WX_UIImage wxBitmap::GetUIImage() const
1089 {
1090 wxCFRef< CGImageRef > cgimage(CreateCGImage());
1091 return wxOSXGetUIImageFromCGImage( cgimage );
1092 }
1093
1094 #endif
1095 wxBitmap wxBitmap::GetSubBitmap(const wxRect &rect) const
1096 {
1097 wxCHECK_MSG( IsOk() &&
1098 (rect.x >= 0) && (rect.y >= 0) &&
1099 (rect.x+rect.width <= GetWidth()) &&
1100 (rect.y+rect.height <= GetHeight()),
1101 wxNullBitmap, wxT("invalid bitmap or bitmap region") );
1102
1103 wxBitmap ret( rect.width, rect.height, GetDepth() );
1104 wxASSERT_MSG( ret.IsOk(), wxT("GetSubBitmap error") );
1105
1106 int destwidth = rect.width ;
1107 int destheight = rect.height ;
1108
1109 {
1110 unsigned char *sourcedata = (unsigned char*) GetRawAccess() ;
1111 unsigned char *destdata = (unsigned char*) ret.BeginRawAccess() ;
1112 wxASSERT( (sourcedata != NULL) && (destdata != NULL) ) ;
1113
1114 int sourcelinesize = GetBitmapData()->GetBytesPerRow() ;
1115 int destlinesize = ret.GetBitmapData()->GetBytesPerRow() ;
1116 unsigned char *source = sourcedata + rect.x * 4 + rect.y * sourcelinesize ;
1117 unsigned char *dest = destdata ;
1118
1119 for (int yy = 0; yy < destheight; ++yy, source += sourcelinesize , dest += destlinesize)
1120 {
1121 memcpy( dest , source , destlinesize ) ;
1122 }
1123 }
1124
1125 ret.EndRawAccess() ;
1126
1127 if ( M_BITMAPDATA->m_bitmapMask )
1128 {
1129 wxMemoryBuffer maskbuf ;
1130 int rowBytes = GetBestBytesPerRow( destwidth * kMaskBytesPerPixel );
1131 size_t maskbufsize = rowBytes * destheight ;
1132
1133 int sourcelinesize = M_BITMAPDATA->m_bitmapMask->GetBytesPerRow() ;
1134 int destlinesize = rowBytes ;
1135
1136 unsigned char *source = (unsigned char *) M_BITMAPDATA->m_bitmapMask->GetRawAccess() ;
1137 unsigned char *destdata = (unsigned char * ) maskbuf.GetWriteBuf( maskbufsize ) ;
1138 wxASSERT( (source != NULL) && (destdata != NULL) ) ;
1139
1140 source += rect.x * kMaskBytesPerPixel + rect.y * sourcelinesize ;
1141 unsigned char *dest = destdata ;
1142
1143 for (int yy = 0; yy < destheight; ++yy, source += sourcelinesize , dest += destlinesize)
1144 {
1145 memcpy( dest , source , destlinesize ) ;
1146 }
1147
1148 maskbuf.UngetWriteBuf( maskbufsize ) ;
1149 ret.SetMask( new wxMask( maskbuf , destwidth , destheight , rowBytes ) ) ;
1150 }
1151 else if ( HasAlpha() )
1152 ret.UseAlpha() ;
1153
1154 return ret;
1155 }
1156
1157 bool wxBitmap::Create(int w, int h, int d)
1158 {
1159 UnRef();
1160
1161 if ( d < 0 )
1162 d = wxDisplayDepth() ;
1163
1164 m_refData = new wxBitmapRefData( w , h , d );
1165
1166 return M_BITMAPDATA->IsOk() ;
1167 }
1168
1169
1170 bool wxBitmap::Create(CGImageRef image)
1171 {
1172 UnRef();
1173
1174 m_refData = new wxBitmapRefData( image );
1175
1176 return M_BITMAPDATA->IsOk() ;
1177 }
1178
1179 bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type)
1180 {
1181 UnRef();
1182
1183 wxBitmapHandler *handler = FindHandler(type);
1184
1185 if ( handler )
1186 {
1187 m_refData = new wxBitmapRefData;
1188
1189 return handler->LoadFile(this, filename, type, -1, -1);
1190 }
1191 else
1192 {
1193 #if wxUSE_IMAGE
1194 wxImage loadimage(filename, type);
1195 if (loadimage.IsOk())
1196 {
1197 *this = loadimage;
1198
1199 return true;
1200 }
1201 #endif
1202 }
1203
1204 wxLogWarning(wxT("no bitmap handler for type %d defined."), type);
1205
1206 return false;
1207 }
1208
1209 bool wxBitmap::Create(const void* data, wxBitmapType type, int width, int height, int depth)
1210 {
1211 UnRef();
1212
1213 m_refData = new wxBitmapRefData;
1214
1215 wxBitmapHandler *handler = FindHandler(type);
1216
1217 if ( handler == NULL )
1218 {
1219 wxLogWarning(wxT("no bitmap handler for type %d defined."), type);
1220
1221 return false;
1222 }
1223
1224 return handler->Create(this, data, type, width, height, depth);
1225 }
1226
1227 #if wxUSE_IMAGE
1228
1229 wxBitmap::wxBitmap(const wxImage& image, int depth)
1230 {
1231 wxCHECK_RET( image.IsOk(), wxT("invalid image") );
1232
1233 // width and height of the device-dependent bitmap
1234 int width = image.GetWidth();
1235 int height = image.GetHeight();
1236
1237 wxBitmapRefData* bitmapRefData;
1238
1239 m_refData = bitmapRefData = new wxBitmapRefData( width , height , depth ) ;
1240
1241 if ( bitmapRefData->IsOk())
1242 {
1243 // Create picture
1244
1245 bool hasAlpha = false ;
1246
1247 if ( image.HasMask() )
1248 {
1249 // takes precedence, don't mix with alpha info
1250 }
1251 else
1252 {
1253 hasAlpha = image.HasAlpha() ;
1254 }
1255
1256 if ( hasAlpha )
1257 UseAlpha() ;
1258
1259 unsigned char* destinationstart = (unsigned char*) BeginRawAccess() ;
1260 register unsigned char* data = image.GetData();
1261 if ( destinationstart != NULL && data != NULL )
1262 {
1263 const unsigned char *alpha = hasAlpha ? image.GetAlpha() : NULL ;
1264 for (int y = 0; y < height; destinationstart += M_BITMAPDATA->GetBytesPerRow(), y++)
1265 {
1266 unsigned char * destination = destinationstart;
1267 for (int x = 0; x < width; x++)
1268 {
1269 if ( hasAlpha )
1270 {
1271 const unsigned char a = *alpha++;
1272 *destination++ = a ;
1273
1274 #if wxOSX_USE_PREMULTIPLIED_ALPHA
1275 *destination++ = ((*data++) * a + 127) / 255 ;
1276 *destination++ = ((*data++) * a + 127) / 255 ;
1277 *destination++ = ((*data++) * a + 127) / 255 ;
1278 #else
1279 *destination++ = *data++ ;
1280 *destination++ = *data++ ;
1281 *destination++ = *data++ ;
1282 #endif
1283 }
1284 else
1285 {
1286 *destination++ = 0xFF ;
1287 *destination++ = *data++ ;
1288 *destination++ = *data++ ;
1289 *destination++ = *data++ ;
1290 }
1291 }
1292 }
1293
1294 EndRawAccess() ;
1295 }
1296 if ( image.HasMask() )
1297 SetMask( new wxMask( *this , wxColour( image.GetMaskRed() , image.GetMaskGreen() , image.GetMaskBlue() ) ) ) ;
1298 } /* bitmapRefData->IsOk() */
1299 }
1300
1301 wxImage wxBitmap::ConvertToImage() const
1302 {
1303 wxImage image;
1304
1305 wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid bitmap") );
1306
1307 // create an wxImage object
1308 int width = GetWidth();
1309 int height = GetHeight();
1310 image.Create( width, height );
1311
1312 unsigned char *data = image.GetData();
1313 wxCHECK_MSG( data, wxNullImage, wxT("Could not allocate data for image") );
1314
1315 unsigned char* sourcestart = (unsigned char*) GetRawAccess() ;
1316
1317 bool hasAlpha = false ;
1318 bool hasMask = false ;
1319 int maskBytesPerRow = 0 ;
1320 unsigned char *alpha = NULL ;
1321 unsigned char *mask = NULL ;
1322
1323 if ( HasAlpha() )
1324 hasAlpha = true ;
1325
1326 if ( GetMask() )
1327 {
1328 hasMask = true ;
1329 mask = (unsigned char*) GetMask()->GetRawAccess() ;
1330 maskBytesPerRow = GetMask()->GetBytesPerRow() ;
1331 }
1332
1333 if ( hasAlpha )
1334 {
1335 image.SetAlpha() ;
1336 alpha = image.GetAlpha() ;
1337 }
1338
1339 int index = 0;
1340
1341 // The following masking algorithm is the same as well in msw/gtk:
1342 // the colour used as transparent one in wxImage and the one it is
1343 // replaced with when it actually occurs in the bitmap
1344 static const int MASK_RED = 1;
1345 static const int MASK_GREEN = 2;
1346 static const int MASK_BLUE = 3;
1347 static const int MASK_BLUE_REPLACEMENT = 2;
1348
1349 for (int yy = 0; yy < height; yy++ , sourcestart += M_BITMAPDATA->GetBytesPerRow() , mask += maskBytesPerRow )
1350 {
1351 unsigned char * maskp = mask ;
1352 unsigned char * source = sourcestart;
1353 unsigned char a, r, g, b;
1354 long color;
1355
1356 for (int xx = 0; xx < width; xx++)
1357 {
1358 color = *((long*) source) ;
1359 #ifdef WORDS_BIGENDIAN
1360 a = ((color&0xFF000000) >> 24) ;
1361 r = ((color&0x00FF0000) >> 16) ;
1362 g = ((color&0x0000FF00) >> 8) ;
1363 b = (color&0x000000FF);
1364 #else
1365 b = ((color&0xFF000000) >> 24) ;
1366 g = ((color&0x00FF0000) >> 16) ;
1367 r = ((color&0x0000FF00) >> 8) ;
1368 a = (color&0x000000FF);
1369 #endif
1370 if ( hasMask )
1371 {
1372 if ( *maskp++ == 0xFF )
1373 {
1374 r = MASK_RED ;
1375 g = MASK_GREEN ;
1376 b = MASK_BLUE ;
1377 }
1378 else if ( r == MASK_RED && g == MASK_GREEN && b == MASK_BLUE )
1379 b = MASK_BLUE_REPLACEMENT ;
1380 }
1381 else if ( hasAlpha )
1382 {
1383 *alpha++ = a ;
1384 #if wxOSX_USE_PREMULTIPLIED_ALPHA
1385 // this must be non-premultiplied data
1386 if ( a != 0xFF && a!= 0 )
1387 {
1388 r = r * 255 / a;
1389 g = g * 255 / a;
1390 b = b * 255 / a;
1391 }
1392 #endif
1393 }
1394
1395 data[index ] = r ;
1396 data[index + 1] = g ;
1397 data[index + 2] = b ;
1398
1399 index += 3;
1400 source += 4 ;
1401 }
1402 }
1403
1404 if ( hasMask )
1405 image.SetMaskColour( MASK_RED, MASK_GREEN, MASK_BLUE );
1406
1407 return image;
1408 }
1409
1410 #endif //wxUSE_IMAGE
1411
1412 bool wxBitmap::SaveFile( const wxString& filename,
1413 wxBitmapType type, const wxPalette *palette ) const
1414 {
1415 bool success = false;
1416 wxBitmapHandler *handler = FindHandler(type);
1417
1418 if ( handler )
1419 {
1420 success = handler->SaveFile(this, filename, type, palette);
1421 }
1422 else
1423 {
1424 #if wxUSE_IMAGE
1425 wxImage image = ConvertToImage();
1426 success = image.SaveFile(filename, type);
1427 #else
1428 wxLogWarning(wxT("no bitmap handler for type %d defined."), type);
1429 #endif
1430 }
1431
1432 return success;
1433 }
1434
1435 int wxBitmap::GetHeight() const
1436 {
1437 wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
1438
1439 return M_BITMAPDATA->GetHeight();
1440 }
1441
1442 int wxBitmap::GetWidth() const
1443 {
1444 wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
1445
1446 return M_BITMAPDATA->GetWidth() ;
1447 }
1448
1449 int wxBitmap::GetDepth() const
1450 {
1451 wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
1452
1453 return M_BITMAPDATA->GetDepth();
1454 }
1455
1456 wxMask *wxBitmap::GetMask() const
1457 {
1458 wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
1459
1460 return M_BITMAPDATA->m_bitmapMask;
1461 }
1462
1463 bool wxBitmap::HasAlpha() const
1464 {
1465 wxCHECK_MSG( IsOk(), false , wxT("invalid bitmap") );
1466
1467 return M_BITMAPDATA->HasAlpha() ;
1468 }
1469
1470 void wxBitmap::SetWidth(int w)
1471 {
1472 AllocExclusive();
1473 M_BITMAPDATA->SetWidth(w);
1474 }
1475
1476 void wxBitmap::SetHeight(int h)
1477 {
1478 AllocExclusive();
1479 M_BITMAPDATA->SetHeight(h);
1480 }
1481
1482 void wxBitmap::SetDepth(int d)
1483 {
1484 AllocExclusive();
1485 M_BITMAPDATA->SetDepth(d);
1486 }
1487
1488 void wxBitmap::SetOk(bool isOk)
1489 {
1490 AllocExclusive();
1491 M_BITMAPDATA->SetOk(isOk);
1492 }
1493
1494 #if wxUSE_PALETTE
1495 wxPalette *wxBitmap::GetPalette() const
1496 {
1497 wxCHECK_MSG( IsOk(), NULL, wxT("Invalid bitmap GetPalette()") );
1498
1499 return &M_BITMAPDATA->m_bitmapPalette;
1500 }
1501
1502 void wxBitmap::SetPalette(const wxPalette& palette)
1503 {
1504 AllocExclusive();
1505 M_BITMAPDATA->m_bitmapPalette = palette ;
1506 }
1507 #endif // wxUSE_PALETTE
1508
1509 void wxBitmap::SetMask(wxMask *mask)
1510 {
1511 AllocExclusive();
1512 // Remove existing mask if there is one.
1513 delete M_BITMAPDATA->m_bitmapMask;
1514
1515 M_BITMAPDATA->m_bitmapMask = mask ;
1516 }
1517
1518 WXHBITMAP wxBitmap::GetHBITMAP(WXHBITMAP* mask) const
1519 {
1520 wxUnusedVar(mask);
1521
1522 return WXHBITMAP(M_BITMAPDATA->GetBitmapContext());
1523 }
1524
1525 // ----------------------------------------------------------------------------
1526 // wxMask
1527 // ----------------------------------------------------------------------------
1528
1529 wxMask::wxMask()
1530 {
1531 Init() ;
1532 }
1533
1534 wxMask::wxMask(const wxMask &tocopy) : wxObject()
1535 {
1536 Init();
1537
1538 m_bytesPerRow = tocopy.m_bytesPerRow;
1539 m_width = tocopy.m_width;
1540 m_height = tocopy.m_height;
1541
1542 size_t size = m_bytesPerRow * m_height;
1543 unsigned char* dest = (unsigned char*)m_memBuf.GetWriteBuf( size );
1544 unsigned char* source = (unsigned char*)tocopy.m_memBuf.GetData();
1545 memcpy( dest, source, size );
1546 m_memBuf.UngetWriteBuf( size ) ;
1547 RealizeNative() ;
1548 }
1549
1550 // Construct a mask from a bitmap and a colour indicating
1551 // the transparent area
1552 wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
1553 {
1554 Init() ;
1555 Create( bitmap, colour );
1556 }
1557
1558 // Construct a mask from a mono bitmap (copies the bitmap).
1559 wxMask::wxMask( const wxBitmap& bitmap )
1560 {
1561 Init() ;
1562 Create( bitmap );
1563 }
1564
1565 // Construct a mask from a mono bitmap (copies the bitmap).
1566
1567 wxMask::wxMask( const wxMemoryBuffer& data, int width , int height , int bytesPerRow )
1568 {
1569 Init() ;
1570 Create( data, width , height , bytesPerRow );
1571 }
1572
1573 wxMask::~wxMask()
1574 {
1575 if ( m_maskBitmap )
1576 {
1577 CGContextRelease( (CGContextRef) m_maskBitmap );
1578 m_maskBitmap = NULL ;
1579 }
1580 }
1581
1582 void wxMask::Init()
1583 {
1584 m_width = m_height = m_bytesPerRow = 0 ;
1585 m_maskBitmap = NULL ;
1586 }
1587
1588 void *wxMask::GetRawAccess() const
1589 {
1590 return m_memBuf.GetData() ;
1591 }
1592
1593 // The default ColorTable for k8IndexedGrayPixelFormat in Intel appears to be broken, so we'll use an non-indexed
1594 // bitmap mask instead; in order to keep the code simple, the change applies to PowerPC implementations as well
1595
1596 void wxMask::RealizeNative()
1597 {
1598 if ( m_maskBitmap )
1599 {
1600 CGContextRelease( (CGContextRef) m_maskBitmap );
1601 m_maskBitmap = NULL ;
1602 }
1603
1604 CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();
1605 // from MouseTracking sample :
1606 // Ironically, due to a bug in CGImageCreateWithMask, you cannot use
1607 // CGColorSpaceCreateWithName(kCGColorSpaceGenericGray) at this point!
1608
1609 m_maskBitmap = CGBitmapContextCreate((char*) m_memBuf.GetData(), m_width, m_height, 8, m_bytesPerRow, colorspace,
1610 kCGImageAlphaNone );
1611 CGColorSpaceRelease( colorspace );
1612 wxASSERT_MSG( m_maskBitmap , wxT("Unable to create CGBitmapContext context") ) ;
1613 }
1614
1615 // Create a mask from a mono bitmap (copies the bitmap).
1616
1617 bool wxMask::Create(const wxMemoryBuffer& data,int width , int height , int bytesPerRow)
1618 {
1619 m_memBuf = data ;
1620 m_width = width ;
1621 m_height = height ;
1622 m_bytesPerRow = bytesPerRow ;
1623
1624 wxASSERT( data.GetDataLen() == (size_t)(height * bytesPerRow) ) ;
1625
1626 RealizeNative() ;
1627
1628 return true ;
1629 }
1630
1631 // Create a mask from a mono bitmap (copies the bitmap).
1632 bool wxMask::Create(const wxBitmap& bitmap)
1633 {
1634 m_width = bitmap.GetWidth() ;
1635 m_height = bitmap.GetHeight() ;
1636 m_bytesPerRow = GetBestBytesPerRow( m_width * kMaskBytesPerPixel ) ;
1637
1638 size_t size = m_bytesPerRow * m_height ;
1639 unsigned char * destdatabase = (unsigned char*) m_memBuf.GetWriteBuf( size ) ;
1640 wxASSERT( destdatabase != NULL ) ;
1641
1642 if ( destdatabase )
1643 {
1644 memset( destdatabase , 0 , size ) ;
1645 unsigned char * srcdata = (unsigned char*) bitmap.GetRawAccess() ;
1646
1647 for ( int y = 0 ; y < m_height ; ++y , destdatabase += m_bytesPerRow )
1648 {
1649 unsigned char *destdata = destdatabase ;
1650 unsigned char r, g, b;
1651
1652 for ( int x = 0 ; x < m_width ; ++x )
1653 {
1654 srcdata++ ;
1655 r = *srcdata++ ;
1656 g = *srcdata++ ;
1657 b = *srcdata++ ;
1658
1659 if ( ( r + g + b ) > 0x10 )
1660 *destdata++ = 0xFF ;
1661 else
1662 *destdata++ = 0x00 ;
1663 }
1664 }
1665 }
1666
1667 m_memBuf.UngetWriteBuf( size ) ;
1668 RealizeNative() ;
1669
1670 return true;
1671 }
1672
1673 // Create a mask from a bitmap and a colour indicating
1674 // the transparent area
1675 bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
1676 {
1677 m_width = bitmap.GetWidth() ;
1678 m_height = bitmap.GetHeight() ;
1679 m_bytesPerRow = GetBestBytesPerRow( m_width * kMaskBytesPerPixel ) ;
1680
1681 size_t size = m_bytesPerRow * m_height ;
1682 unsigned char * destdatabase = (unsigned char*) m_memBuf.GetWriteBuf( size ) ;
1683 wxASSERT( destdatabase != NULL ) ;
1684
1685 memset( destdatabase , 0 , size ) ;
1686 unsigned char * srcdatabase = (unsigned char*) bitmap.GetRawAccess() ;
1687 size_t sourceBytesRow = bitmap.GetBitmapData()->GetBytesPerRow();
1688
1689 for ( int y = 0 ; y < m_height ; ++y , srcdatabase+= sourceBytesRow, destdatabase += m_bytesPerRow)
1690 {
1691 unsigned char *srcdata = srcdatabase ;
1692 unsigned char *destdata = destdatabase ;
1693 unsigned char r, g, b;
1694
1695 for ( int x = 0 ; x < m_width ; ++x )
1696 {
1697 srcdata++ ;
1698 r = *srcdata++ ;
1699 g = *srcdata++ ;
1700 b = *srcdata++ ;
1701
1702 if ( colour == wxColour( r , g , b ) )
1703 *destdata++ = 0xFF ;
1704 else
1705 *destdata++ = 0x00 ;
1706 }
1707 }
1708
1709 m_memBuf.UngetWriteBuf( size ) ;
1710 RealizeNative() ;
1711
1712 return true;
1713 }
1714
1715 WXHBITMAP wxMask::GetHBITMAP() const
1716 {
1717 return m_maskBitmap ;
1718 }
1719
1720 // ----------------------------------------------------------------------------
1721 // Standard Handlers
1722 // ----------------------------------------------------------------------------
1723
1724 class WXDLLEXPORT wxBundleResourceHandler: public wxBitmapHandler
1725 {
1726 DECLARE_ABSTRACT_CLASS(wxBundleResourceHandler)
1727
1728 public:
1729 inline wxBundleResourceHandler()
1730 {
1731 };
1732
1733 virtual bool LoadFile(wxBitmap *bitmap,
1734 const wxString& name,
1735 wxBitmapType type,
1736 int desiredWidth,
1737 int desiredHeight);
1738 };
1739
1740 IMPLEMENT_ABSTRACT_CLASS(wxBundleResourceHandler, wxBitmapHandler);
1741
1742 class WXDLLEXPORT wxPNGResourceHandler: public wxBundleResourceHandler
1743 {
1744 DECLARE_DYNAMIC_CLASS(wxPNGResourceHandler)
1745
1746 public:
1747 inline wxPNGResourceHandler()
1748 {
1749 SetName(wxT("PNG resource"));
1750 SetExtension("PNG");
1751 SetType(wxBITMAP_TYPE_PNG_RESOURCE);
1752 };
1753 };
1754
1755 IMPLEMENT_DYNAMIC_CLASS(wxPNGResourceHandler, wxBundleResourceHandler)
1756
1757 class WXDLLEXPORT wxJPEGResourceHandler: public wxBundleResourceHandler
1758 {
1759 DECLARE_DYNAMIC_CLASS(wxPNGResourceHandler)
1760
1761 public:
1762 inline wxJPEGResourceHandler()
1763 {
1764 SetName(wxT("JPEG resource"));
1765 SetExtension("JPEG");
1766 SetType(wxBITMAP_TYPE_JPEG_RESOURCE);
1767 };
1768 };
1769
1770 IMPLEMENT_DYNAMIC_CLASS(wxJPEGResourceHandler, wxBundleResourceHandler)
1771
1772 bool wxBundleResourceHandler::LoadFile(wxBitmap *bitmap,
1773 const wxString& name,
1774 wxBitmapType WXUNUSED(type),
1775 int WXUNUSED(desiredWidth),
1776 int WXUNUSED(desiredHeight))
1777 {
1778 wxString ext = GetExtension().Lower();
1779 wxCFStringRef resname(name);
1780 wxCFStringRef restype(ext);
1781
1782 wxCFRef<CFURLRef> imageURL(CFBundleCopyResourceURL(CFBundleGetMainBundle(), resname, restype, NULL));
1783
1784 if ( imageURL.get() != NULL )
1785 {
1786 // Create the data provider object
1787 wxCFRef<CGDataProviderRef> provider(CGDataProviderCreateWithURL (imageURL) );
1788 CGImageRef image = NULL;
1789
1790 if ( ext == "jpeg" )
1791 image = CGImageCreateWithJPEGDataProvider (provider, NULL, true,
1792 kCGRenderingIntentDefault);
1793 else if ( ext == "png" )
1794 image = CGImageCreateWithPNGDataProvider (provider, NULL, true,
1795 kCGRenderingIntentDefault);
1796 if ( image != NULL )
1797 {
1798 bitmap->Create(image);
1799 CGImageRelease(image);
1800 }
1801 }
1802
1803 return false ;
1804 }
1805
1806 #if !defined( __LP64__ ) && !defined(__WXOSX_IPHONE__)
1807
1808 class WXDLLEXPORT wxPICTResourceHandler: public wxBitmapHandler
1809 {
1810 DECLARE_DYNAMIC_CLASS(wxPICTResourceHandler)
1811
1812 public:
1813 inline wxPICTResourceHandler()
1814 {
1815 SetName(wxT("Macintosh Pict resource"));
1816 SetExtension(wxEmptyString);
1817 SetType(wxBITMAP_TYPE_PICT_RESOURCE);
1818 };
1819
1820 virtual bool LoadFile(wxBitmap *bitmap,
1821 const wxString& name,
1822 wxBitmapType type,
1823 int desiredWidth,
1824 int desiredHeight);
1825 };
1826
1827 IMPLEMENT_DYNAMIC_CLASS(wxPICTResourceHandler, wxBitmapHandler)
1828
1829
1830 bool wxPICTResourceHandler::LoadFile(wxBitmap *bitmap,
1831 const wxString& name,
1832 wxBitmapType WXUNUSED(type),
1833 int WXUNUSED(desiredWidth),
1834 int WXUNUSED(desiredHeight))
1835 {
1836 #if wxUSE_METAFILE
1837 Str255 theName ;
1838 wxMacStringToPascal( name , theName ) ;
1839
1840 PicHandle thePict = (PicHandle ) GetNamedResource( 'PICT' , theName ) ;
1841 if ( thePict )
1842 {
1843 wxMetafile mf ;
1844
1845 mf.SetPICT( thePict ) ;
1846 bitmap->Create( mf.GetWidth() , mf.GetHeight() ) ;
1847 wxMemoryDC dc ;
1848 dc.SelectObject( *bitmap ) ;
1849 mf.Play( &dc ) ;
1850 dc.SelectObject( wxNullBitmap ) ;
1851
1852 return true ;
1853 }
1854 #endif
1855
1856 return false ;
1857 }
1858 #endif
1859
1860 void wxBitmap::InitStandardHandlers()
1861 {
1862 #if !defined( __LP64__ ) && !defined(__WXOSX_IPHONE__)
1863 AddHandler( new wxPICTResourceHandler ) ;
1864 #endif
1865 #if wxOSX_USE_COCOA_OR_CARBON
1866 AddHandler( new wxICONResourceHandler ) ;
1867 #endif
1868 AddHandler( new wxPNGResourceHandler );
1869 AddHandler( new wxJPEGResourceHandler );
1870 }
1871
1872 // ----------------------------------------------------------------------------
1873 // raw bitmap access support
1874 // ----------------------------------------------------------------------------
1875
1876 void *wxBitmap::GetRawData(wxPixelDataBase& data, int WXUNUSED(bpp))
1877 {
1878 if ( !IsOk() )
1879 // no bitmap, no data (raw or otherwise)
1880 return NULL;
1881
1882 data.m_width = GetWidth() ;
1883 data.m_height = GetHeight() ;
1884 data.m_stride = GetBitmapData()->GetBytesPerRow() ;
1885
1886 return BeginRawAccess() ;
1887 }
1888
1889 void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(dataBase))
1890 {
1891 EndRawAccess() ;
1892 }
1893
1894 void wxBitmap::UseAlpha()
1895 {
1896 // remember that we are using alpha channel:
1897 // we'll need to create a proper mask in UngetRawData()
1898 M_BITMAPDATA->UseAlpha( true );
1899 }