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