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