📄 bitmap.cpp
字号:
/////////////////////////////////////////////////////////////////////////////// Name: src/mac/carbon/bitmap.cpp// Purpose: wxBitmap// Author: Stefan Csomor// Modified by:// Created: 1998-01-01// RCS-ID: $Id: bitmap.cpp,v 1.103 2006/11/01 03:23:28 RD Exp $// Copyright: (c) Stefan Csomor// Licence: wxWindows licence/////////////////////////////////////////////////////////////////////////////#include "wx/wxprec.h"#include "wx/bitmap.h"#ifndef WX_PRECOMP #include "wx/log.h" #include "wx/dcmemory.h" #include "wx/icon.h" #include "wx/image.h"#endif#include "wx/metafile.h"#include "wx/xpmdecod.h"#include "wx/rawbmp.h"IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)#ifdef __DARWIN__ #include <ApplicationServices/ApplicationServices.h>#else #include <PictUtils.h>#endif#include "wx/mac/uma.h"// Implementation Notes// --------------------//// we are always working with a 32 bit deep pixel buffer// under QuickDraw its alpha parts are going to be ignored in the GWorld,// therefore we have a separate GWorld there for blitting the mask in// under Quartz then content is transformed into a CGImageRef representing the same data// which can be transferred to the GPU by the OS for fast rendering// we don't dare use premultiplied alpha yet#define wxMAC_USE_PREMULTIPLIED_ALPHA 0#if wxUSE_BMPBUTTONvoid wxMacCreateBitmapButton( ControlButtonContentInfo*info , const wxBitmap& bitmap , int forceType ){ memset( info , 0 , sizeof(ControlButtonContentInfo) ) ; if ( bitmap.Ok() ) { wxBitmapRefData * bmap = bitmap.GetBitmapData() ; if ( bmap == NULL ) return ; if ( ( bmap->HasNativeSize() && forceType == 0 ) || forceType == kControlContentIconRef ) { wxBitmap scaleBmp ; wxBitmapRefData* bmp = bmap ; if ( !bmap->HasNativeSize() ) { // as PICT conversion will only result in a 16x16 icon, let's attempt // a few scales for better results int w = bitmap.GetWidth() ; int h = bitmap.GetHeight() ; int sz = wxMax( w , h ) ; if ( sz == 24 || sz == 64 ) { scaleBmp = wxBitmap( bitmap.ConvertToImage().Scale( w * 2 , h * 2 ) ) ; bmp = scaleBmp.GetBitmapData() ; } } info->contentType = kControlContentIconRef ; info->u.iconRef = bmp->GetIconRef() ; AcquireIconRef( info->u.iconRef ) ; }#if defined( __WXMAC_OSX__ ) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2 else if ( forceType == kControlContentCGImageRef ) { info->contentType = kControlContentCGImageRef ; info->u.imageRef = (CGImageRef) bmap->CGImageCreate() ; }#endif else {#ifndef __LP64__ info->contentType = kControlContentPictHandle ; info->u.picture = bmap->GetPictHandle() ;#endif } }}void wxMacReleaseBitmapButton( ControlButtonContentInfo*info ){ if ( info->contentType == kControlContentIconRef ) { ReleaseIconRef( info->u.iconRef ) ; } else if ( info->contentType == kControlNoContent ) { // there's no bitmap at all, fall through silently } else if ( info->contentType == kControlContentPictHandle ) { // owned by the bitmap, no release here }#if defined( __WXMAC_OSX__ ) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2 else if ( info->contentType == kControlContentCGImageRef ) { CGImageRelease( info->u.imageRef ) ; }#endif else { wxFAIL_MSG(wxT("Unexpected bitmap type") ) ; }}#endif //wxUSE_BMPBUTTON#define M_BITMAPDATA ((wxBitmapRefData *)m_refData)void wxBitmapRefData::Init(){ m_width = 0 ; m_height = 0 ; m_depth = 0 ; m_ok = false ; m_bitmapMask = NULL ;#ifdef __WXMAC_OSX__ m_cgImageRef = NULL ;#endif m_iconRef = NULL ; m_pictHandle = NULL ; m_hBitmap = NULL ; m_hMaskBitmap = NULL; m_maskBytesPerRow = 0 ; m_rawAccessCount = 0 ; m_hasAlpha = false;}wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData &tocopy){ Init(); Create(tocopy.m_width, tocopy.m_height, tocopy.m_depth); if (tocopy.m_bitmapMask) m_bitmapMask = new wxMask(*tocopy.m_bitmapMask); unsigned char* dest = (unsigned char*)GetRawAccess(); unsigned char* source = (unsigned char*)tocopy.GetRawAccess(); size_t numbytes = tocopy.m_width * tocopy.m_height * 4; for (size_t i=0; i<numbytes; i++) { *dest++ = *source++; } UseAlpha(tocopy.m_hasAlpha); // TODO: Copy palette?}wxBitmapRefData::wxBitmapRefData(){ Init() ;}wxBitmapRefData::wxBitmapRefData( int w , int h , int d ){ Init() ; Create( w , h , d ) ;}bool wxBitmapRefData::Create( int w , int h , int d ){ m_width = wxMax(1, w); m_height = wxMax(1, h); m_depth = d ; m_bytesPerRow = w * 4 ; size_t size = m_bytesPerRow * h ; void* data = m_memBuf.GetWriteBuf( size ) ; memset( data , 0 , size ) ; m_memBuf.UngetWriteBuf( size ) ; m_hBitmap = NULL ; Rect rect = { 0 , 0 , m_height , m_width } ;#ifndef __LP64__ verify_noerr( NewGWorldFromPtr( (GWorldPtr*) &m_hBitmap , k32ARGBPixelFormat , &rect , NULL , NULL , 0 , (char*) data , m_bytesPerRow ) ) ; wxASSERT_MSG( m_hBitmap , wxT("Unable to create GWorld context") ) ;#endif m_ok = ( m_hBitmap != NULL ) ; return m_ok ;}void wxBitmapRefData::UseAlpha( bool use ){ if ( m_hasAlpha == use ) return ; m_hasAlpha = use ; if ( m_hasAlpha ) { wxASSERT( m_hMaskBitmap == NULL ) ; int width = GetWidth() ; int height = GetHeight() ; m_maskBytesPerRow = ( width * 4 + 3 ) & 0xFFFFFFC ; size_t size = height * m_maskBytesPerRow ; unsigned char * data = (unsigned char * ) m_maskMemBuf.GetWriteBuf( size ) ; wxASSERT( data != NULL ) ; memset( data , 0 , size ) ; Rect rect = { 0 , 0 , height , width } ;#ifndef __LP64__ verify_noerr( NewGWorldFromPtr( (GWorldPtr*) &m_hMaskBitmap , k32ARGBPixelFormat , &rect , NULL , NULL , 0 , (char*) data , m_maskBytesPerRow ) ) ; wxASSERT_MSG( m_hMaskBitmap , wxT("Unable to create GWorld context for alpha mask") ) ;#endif m_maskMemBuf.UngetWriteBuf(size) ;#if !wxMAC_USE_CORE_GRAPHICS UpdateAlphaMask() ;#endif } else {#ifndef __LP64__ DisposeGWorld( m_hMaskBitmap ) ;#endif m_hMaskBitmap = NULL ; m_maskBytesPerRow = 0 ; }}void *wxBitmapRefData::GetRawAccess() const{ wxCHECK_MSG( Ok(), NULL , wxT("invalid bitmap") ) ; return m_memBuf.GetData() ;}void *wxBitmapRefData::BeginRawAccess(){ wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") ) ; wxASSERT( m_rawAccessCount == 0 ) ; wxASSERT_MSG( m_pictHandle == NULL && m_iconRef == NULL , wxT("Currently, modifing bitmaps that are used in controls already is not supported") ) ; ++m_rawAccessCount ;#ifdef __WXMAC_OSX__ // we must destroy an existing cached image, as // the bitmap data may change now if ( m_cgImageRef ) { CGImageRelease( m_cgImageRef ) ; m_cgImageRef = NULL ; }#endif return m_memBuf.GetData() ;}void wxBitmapRefData::EndRawAccess(){ wxCHECK_RET( Ok() , wxT("invalid bitmap") ) ; wxASSERT( m_rawAccessCount == 1 ) ; --m_rawAccessCount ;#if !wxMAC_USE_CORE_GRAPHICS UpdateAlphaMask() ;#endif}bool wxBitmapRefData::HasNativeSize(){ int w = GetWidth() ; int h = GetHeight() ; int sz = wxMax( w , h ) ; return ( sz == 128 || sz == 48 || sz == 32 || sz == 16 );}IconRef wxBitmapRefData::GetIconRef(){ if ( m_iconRef == NULL ) { // Create Icon Family Handle IconFamilyHandle iconFamily = NULL ;#ifdef WORDS_BIGENDIAN iconFamily = (IconFamilyHandle) NewHandle( 8 ) ; (**iconFamily).resourceType = kIconFamilyType ; (**iconFamily).resourceSize = sizeof(OSType) + sizeof(Size);#else // test this solution on big endian as well iconFamily = (IconFamilyHandle) NewHandle( 0 ) ;#endif int w = GetWidth() ; int h = GetHeight() ; int sz = wxMax( w , h ) ; OSType dataType = 0 ; OSType maskType = 0 ; switch (sz) { case 128: dataType = kThumbnail32BitData ; maskType = kThumbnail8BitMask ; break; case 48: dataType = kHuge32BitData ; maskType = kHuge8BitMask ; break; case 32: dataType = kLarge32BitData ; maskType = kLarge8BitMask ; break; case 16: dataType = kSmall32BitData ; maskType = kSmall8BitMask ; break; default: break; } if ( dataType != 0 ) { // setup the header properly Handle data = NULL ; Handle maskdata = NULL ; unsigned char * maskptr = NULL ; unsigned char * ptr = NULL ; size_t datasize, masksize ; datasize = sz * sz * 4 ; data = NewHandle( datasize ) ; HLock( data ) ; ptr = (unsigned char*) *data ; memset( ptr , 0, datasize ) ; masksize = sz * sz ; maskdata = NewHandle( masksize ) ; HLock( maskdata ) ; maskptr = (unsigned char*) *maskdata ; memset( maskptr , 0 , masksize ) ; bool hasAlpha = HasAlpha() ; wxMask *mask = m_bitmapMask ; unsigned char * source = (unsigned char*) GetRawAccess() ; unsigned char * masksource = mask ? (unsigned char*) mask->GetRawAccess() : NULL ; for ( int y = 0 ; y < h ; ++y ) { unsigned char * dest = ptr + y * sz * 4 ; unsigned char * maskdest = maskptr + y * sz ; unsigned char a, r, g, b; for ( int x = 0 ; x < w ; ++x ) { a = *source ++ ; r = *source ++ ; g = *source ++ ; b = *source ++ ; *dest++ = 0 ; *dest++ = r ; *dest++ = g ; *dest++ = b ; if ( mask ) { *maskdest++ = 0xFF - *masksource++ ; masksource++ ; masksource++ ; masksource++ ; } else if ( hasAlpha ) *maskdest++ = a ; else *maskdest++ = 0xFF ; } } OSStatus err = SetIconFamilyData( iconFamily, dataType , data ) ; wxASSERT_MSG( err == noErr , wxT("Error when adding bitmap") ) ; err = SetIconFamilyData( iconFamily, maskType , maskdata ) ; wxASSERT_MSG( err == noErr , wxT("Error when adding mask") ) ; HUnlock( data ) ; HUnlock( maskdata ) ; DisposeHandle( data ) ; DisposeHandle( maskdata ) ; } else { PicHandle pic = GetPictHandle() ; SetIconFamilyData( iconFamily, 'PICT' , (Handle) pic ) ; } // transform into IconRef#if defined( __WXMAC_OSX__ ) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2 // cleaner version existing from 10.3 upwards HLock((Handle) iconFamily); OSStatus err = GetIconRefFromIconFamilyPtr( *iconFamily, GetHandleSize((Handle) iconFamily), &m_iconRef ); HUnlock((Handle) iconFamily); wxASSERT_MSG( err == noErr , wxT("Error when constructing icon ref") );#else static int iconCounter = 2 ; OSStatus err = RegisterIconRefFromIconFamily( 'WXNG' , (OSType) iconCounter, iconFamily, &m_iconRef ) ; wxASSERT_MSG( err == noErr , wxT("Error when adding bitmap") ) ; // we have to retain a reference, as Unregister will decrement it AcquireIconRef( m_iconRef ) ; UnregisterIconRef( 'WXNG' , (OSType) iconCounter ) ; ++iconCounter ;#endif DisposeHandle( (Handle) iconFamily ) ; } return m_iconRef ;}PicHandle wxBitmapRefData::GetPictHandle(){ if ( m_pictHandle == NULL ) {#ifndef __LP64__ CGrafPtr origPort = NULL ; GDHandle origDev = NULL ; GWorldPtr wp = NULL ; GWorldPtr mask = NULL ; int height = GetHeight() ; int width = GetWidth() ; Rect rect = { 0 , 0 , height , width } ; RgnHandle clipRgn = NULL ; GetGWorld( &origPort , &origDev ) ; wp = GetHBITMAP( &mask ) ; if ( mask ) { GWorldPtr monoworld ; clipRgn = NewRgn() ; OSStatus err = NewGWorld( &monoworld , 1 , &rect , NULL , NULL , 0 ) ; verify_noerr(err) ; LockPixels( GetGWorldPixMap( monoworld ) ) ; LockPixels( GetGWorldPixMap( mask ) ) ; SetGWorld( monoworld , NULL ) ; RGBColor white = { 0xffff , 0xffff , 0xffff } ; RGBColor black = { 0x0000 , 0x0000 , 0x0000 } ; RGBForeColor( &black ) ; RGBBackColor( &white ) ; CopyBits(GetPortBitMapForCopyBits(mask), GetPortBitMapForCopyBits(monoworld), &rect, &rect, srcCopy, NULL); BitMapToRegion( clipRgn , (BitMap*) *GetGWorldPixMap( monoworld ) ) ; UnlockPixels( GetGWorldPixMap( monoworld ) ) ; UnlockPixels( GetGWorldPixMap( mask ) ) ; DisposeGWorld( monoworld ) ; } SetGWorld( wp , NULL ) ; Rect portRect ; GetPortBounds( wp , &portRect ) ; m_pictHandle = OpenPicture(&portRect); if (m_pictHandle) { RGBColor white = { 0xffff , 0xffff , 0xffff } ; RGBColor black = { 0x0000 , 0x0000 , 0x0000 } ; RGBForeColor( &black ) ; RGBBackColor( &white ) ; if ( clipRgn ) SetClip( clipRgn ) ; LockPixels( GetGWorldPixMap( wp ) ) ; CopyBits(GetPortBitMapForCopyBits(wp), GetPortBitMapForCopyBits(wp), &portRect, &portRect, srcCopy,clipRgn); UnlockPixels( GetGWorldPixMap( wp ) ) ; ClosePicture(); } SetGWorld( origPort , origDev ) ; if ( clipRgn ) DisposeRgn( clipRgn ) ;#endif } return m_pictHandle ;}#ifdef __WXMAC_OSX__void wxMacMemoryBufferReleaseProc(void *info, const void *data, size_t size){ wxMemoryBuffer* membuf = (wxMemoryBuffer*) info ; wxASSERT( data == membuf->GetData() ) ; delete membuf ;}CGImageRef wxBitmapRefData::CGImageCreate() const{ wxASSERT( m_ok ) ; wxASSERT( m_rawAccessCount >= 0 ) ; CGImageRef image ; if ( m_rawAccessCount > 0 || m_cgImageRef == NULL ) { size_t imageSize = m_width * m_height * 4 ; void * dataBuffer = m_memBuf.GetData() ; int w = m_width ; int h = m_height ; CGImageAlphaInfo alphaInfo = kCGImageAlphaNoneSkipFirst ; wxMemoryBuffer* membuf = NULL ; if ( m_bitmapMask ) { alphaInfo = kCGImageAlphaFirst ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -