wxBitmap uses CGImage instead of NSImage internally and the conversion looses NSImage metadata. In particular, it looses the "template" attribute, which is set for files ending with "Template" and loaded trough wxArtProvider. This change makes it easy to use template images with native controls such as the toolbar. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@78016 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
1968 lines
56 KiB
C++
1968 lines
56 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/osx/core/bitmap.cpp
|
|
// Purpose: wxBitmap
|
|
// Author: Stefan Csomor
|
|
// Modified by:
|
|
// Created: 1998-01-01
|
|
// 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"
|
|
|
|
#include "wx/filename.h"
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
|
|
IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
|
|
|
|
#if wxOSX_USE_CARBON
|
|
#include "wx/osx/uma.h"
|
|
#else
|
|
#include "wx/osx/private.h"
|
|
#endif
|
|
|
|
CGColorSpaceRef wxMacGetGenericRGBColorSpace();
|
|
CGDataProviderRef wxMacCGDataProviderCreateWithMemoryBuffer( const wxMemoryBuffer& buf );
|
|
|
|
// 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
|
|
|
|
class WXDLLEXPORT wxBitmapRefData: public wxGDIRefData
|
|
{
|
|
friend class WXDLLIMPEXP_FWD_CORE wxIcon;
|
|
friend class WXDLLIMPEXP_FWD_CORE wxCursor;
|
|
public:
|
|
wxBitmapRefData(int width , int height , int depth, double logicalscale);
|
|
wxBitmapRefData(int width , int height , int depth);
|
|
wxBitmapRefData(CGContextRef context);
|
|
wxBitmapRefData(CGImageRef image, double scale);
|
|
wxBitmapRefData();
|
|
wxBitmapRefData(const wxBitmapRefData &tocopy);
|
|
|
|
virtual ~wxBitmapRefData();
|
|
|
|
virtual bool IsOk() const wxOVERRIDE { return m_ok; }
|
|
|
|
void Free();
|
|
void SetOk( bool isOk) { m_ok = isOk; }
|
|
|
|
void SetWidth( int width ) { m_width = width; }
|
|
void SetHeight( int height ) { m_height = height; }
|
|
void SetDepth( int depth ) { m_depth = depth; }
|
|
|
|
int GetWidth() const { return m_width; }
|
|
int GetHeight() const { return m_height; }
|
|
int GetDepth() const { return m_depth; }
|
|
double GetScaleFactor() const { return m_scaleFactor; }
|
|
void *GetRawAccess() const;
|
|
void *BeginRawAccess();
|
|
void EndRawAccess();
|
|
|
|
bool HasAlpha() const { return m_hasAlpha; }
|
|
void UseAlpha( bool useAlpha );
|
|
|
|
bool IsTemplate() const { return m_isTemplate; }
|
|
void SetTemplate(bool is) { m_isTemplate = is; }
|
|
|
|
public:
|
|
#if wxUSE_PALETTE
|
|
wxPalette m_bitmapPalette;
|
|
#endif // wxUSE_PALETTE
|
|
|
|
wxMask * m_bitmapMask; // Optional mask
|
|
CGImageRef CreateCGImage() const;
|
|
|
|
// returns true if the bitmap has a size that
|
|
// can be natively transferred into a true icon
|
|
// if no is returned GetIconRef will still produce
|
|
// an icon but it will be generated via a PICT and
|
|
// rescaled to 16 x 16
|
|
bool HasNativeSize();
|
|
|
|
#ifndef __WXOSX_IPHONE__
|
|
// caller should increase ref count if needed longer
|
|
// than the bitmap exists
|
|
IconRef GetIconRef();
|
|
#endif
|
|
|
|
CGContextRef GetBitmapContext() const;
|
|
|
|
int GetBytesPerRow() const { return m_bytesPerRow; }
|
|
private :
|
|
bool Create(int width , int height , int depth);
|
|
bool Create(int width , int height , int depth, double logicalScale);
|
|
bool Create( CGImageRef image, double scale );
|
|
bool Create( CGContextRef bitmapcontext);
|
|
void Init();
|
|
|
|
int m_width;
|
|
int m_height;
|
|
int m_bytesPerRow;
|
|
int m_depth;
|
|
bool m_hasAlpha;
|
|
wxMemoryBuffer m_memBuf;
|
|
int m_rawAccessCount;
|
|
bool m_ok;
|
|
mutable CGImageRef m_cgImageRef;
|
|
bool m_isTemplate;
|
|
|
|
#ifndef __WXOSX_IPHONE__
|
|
IconRef m_iconRef;
|
|
#endif
|
|
|
|
CGContextRef m_hBitmap;
|
|
double m_scaleFactor;
|
|
};
|
|
|
|
|
|
#define wxOSX_USE_PREMULTIPLIED_ALPHA 1
|
|
static const int kBestByteAlignement = 16;
|
|
static const int kMaskBytesPerPixel = 1;
|
|
|
|
static int GetBestBytesPerRow( int rawBytes )
|
|
{
|
|
return (((rawBytes)+kBestByteAlignement-1) & ~(kBestByteAlignement-1) );
|
|
}
|
|
|
|
#if wxUSE_GUI && !defined(__WXOSX_IPHONE__)
|
|
|
|
// this is used for more controls than just the wxBitmap button, also for notebooks etc
|
|
|
|
void wxMacCreateBitmapButton( ControlButtonContentInfo*info , const wxBitmap& bitmap , int forceType )
|
|
{
|
|
memset( info , 0 , sizeof(ControlButtonContentInfo) ) ;
|
|
if ( bitmap.IsOk() )
|
|
{
|
|
wxBitmapRefData * bmap = bitmap.GetBitmapData() ;
|
|
if ( bmap == NULL )
|
|
return ;
|
|
|
|
if ( forceType == 0 )
|
|
{
|
|
forceType = kControlContentCGImageRef;
|
|
}
|
|
|
|
if ( 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 ) ;
|
|
}
|
|
else if ( forceType == kControlContentCGImageRef )
|
|
{
|
|
info->contentType = kControlContentCGImageRef ;
|
|
info->u.imageRef = (CGImageRef) bmap->CreateCGImage() ;
|
|
}
|
|
}
|
|
}
|
|
|
|
CGImageRef wxMacCreateCGImageFromBitmap( const wxBitmap& bitmap )
|
|
{
|
|
wxBitmapRefData * bmap = bitmap.GetBitmapData() ;
|
|
if ( bmap == NULL )
|
|
return NULL ;
|
|
return (CGImageRef) bmap->CreateCGImage();
|
|
}
|
|
|
|
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
|
|
}
|
|
else if ( info->contentType == kControlContentCGImageRef )
|
|
{
|
|
CGImageRelease( info->u.imageRef ) ;
|
|
}
|
|
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_bytesPerRow = 0;
|
|
m_ok = false ;
|
|
m_bitmapMask = NULL ;
|
|
m_cgImageRef = NULL ;
|
|
m_isTemplate = false;
|
|
|
|
#ifndef __WXOSX_IPHONE__
|
|
m_iconRef = NULL ;
|
|
#endif
|
|
m_hBitmap = NULL ;
|
|
|
|
m_rawAccessCount = 0 ;
|
|
m_hasAlpha = false;
|
|
m_scaleFactor = 1.0;
|
|
}
|
|
|
|
wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData &tocopy) : wxGDIRefData()
|
|
{
|
|
Init();
|
|
Create(tocopy.m_width, tocopy.m_height, tocopy.m_depth, tocopy.m_scaleFactor);
|
|
|
|
if (tocopy.m_bitmapMask)
|
|
m_bitmapMask = new wxMask(*tocopy.m_bitmapMask);
|
|
else if (tocopy.m_hasAlpha)
|
|
UseAlpha(true);
|
|
|
|
unsigned char* dest = (unsigned char*)GetRawAccess();
|
|
unsigned char* source = (unsigned char*)tocopy.GetRawAccess();
|
|
size_t numbytes = m_bytesPerRow * m_height;
|
|
memcpy( dest, source, numbytes );
|
|
}
|
|
|
|
wxBitmapRefData::wxBitmapRefData()
|
|
{
|
|
Init() ;
|
|
}
|
|
|
|
wxBitmapRefData::wxBitmapRefData( int w , int h , int d )
|
|
{
|
|
Init() ;
|
|
Create( w , h , d ) ;
|
|
}
|
|
|
|
wxBitmapRefData::wxBitmapRefData(int w , int h , int d, double logicalscale)
|
|
{
|
|
Init() ;
|
|
Create( w , h , d, logicalscale ) ;
|
|
}
|
|
|
|
wxBitmapRefData::wxBitmapRefData(CGContextRef context)
|
|
{
|
|
Init();
|
|
Create( context );
|
|
}
|
|
|
|
wxBitmapRefData::wxBitmapRefData(CGImageRef image, double scale)
|
|
{
|
|
Init();
|
|
Create( image, scale );
|
|
}
|
|
// code from Technical Q&A QA1509
|
|
|
|
bool wxBitmapRefData::Create(CGImageRef image, double scale)
|
|
{
|
|
if ( image != NULL )
|
|
{
|
|
m_width = CGImageGetWidth(image);
|
|
m_height = CGImageGetHeight(image);
|
|
m_depth = 32;
|
|
m_hBitmap = NULL;
|
|
m_scaleFactor = scale;
|
|
|
|
m_bytesPerRow = GetBestBytesPerRow( m_width * 4 ) ;
|
|
size_t size = m_bytesPerRow * m_height ;
|
|
void* data = m_memBuf.GetWriteBuf( size ) ;
|
|
if ( data != NULL )
|
|
{
|
|
memset( data , 0 , size ) ;
|
|
m_memBuf.UngetWriteBuf( size ) ;
|
|
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image);
|
|
if ( alpha == kCGImageAlphaNone || alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast )
|
|
{
|
|
m_hBitmap = CGBitmapContextCreate((char*) data, m_width, m_height, 8, m_bytesPerRow, wxMacGetGenericRGBColorSpace(), kCGImageAlphaNoneSkipFirst );
|
|
}
|
|
else
|
|
{
|
|
m_hasAlpha = true;
|
|
m_hBitmap = CGBitmapContextCreate((char*) data, m_width, m_height, 8, m_bytesPerRow, wxMacGetGenericRGBColorSpace(), kCGImageAlphaPremultipliedFirst );
|
|
}
|
|
CGRect rect = CGRectMake(0,0,m_width,m_height);
|
|
CGContextDrawImage(m_hBitmap, rect, image);
|
|
|
|
wxASSERT_MSG( m_hBitmap , wxT("Unable to create CGBitmapContext context") ) ;
|
|
CGContextTranslateCTM( m_hBitmap, 0, m_height );
|
|
CGContextScaleCTM( m_hBitmap, 1*m_scaleFactor, -1*m_scaleFactor );
|
|
} /* data != NULL */
|
|
}
|
|
m_ok = ( m_hBitmap != NULL ) ;
|
|
|
|
return m_ok ;
|
|
|
|
}
|
|
|
|
bool wxBitmapRefData::Create(CGContextRef context)
|
|
{
|
|
if ( context != NULL && CGBitmapContextGetData(context) )
|
|
{
|
|
m_hBitmap = context;
|
|
m_bytesPerRow = CGBitmapContextGetBytesPerRow(context);
|
|
m_width = CGBitmapContextGetWidth(context);
|
|
m_height = CGBitmapContextGetHeight(context);
|
|
m_depth = CGBitmapContextGetBitsPerPixel(context) ;
|
|
|
|
// our own contexts conform to this, always.
|
|
wxASSERT( m_depth == 32 );
|
|
|
|
// determine content scale
|
|
CGRect userrect = CGRectMake(0, 0, 10, 10);
|
|
CGRect devicerect;
|
|
devicerect = CGContextConvertRectToDeviceSpace(context, userrect);
|
|
m_scaleFactor = devicerect.size.height / userrect.size.height;
|
|
|
|
CGImageAlphaInfo alpha = CGBitmapContextGetAlphaInfo(context);
|
|
|
|
if ( alpha == kCGImageAlphaNone || alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast )
|
|
{
|
|
// no alpha
|
|
}
|
|
else
|
|
{
|
|
m_hasAlpha = true;
|
|
}
|
|
}
|
|
m_ok = ( m_hBitmap != NULL ) ;
|
|
|
|
return m_ok ;
|
|
}
|
|
|
|
bool wxBitmapRefData::Create( int w , int h , int d )
|
|
{
|
|
m_width = wxMax(1, w);
|
|
m_height = wxMax(1, h);
|
|
m_depth = d ;
|
|
m_hBitmap = NULL ;
|
|
|
|
m_bytesPerRow = GetBestBytesPerRow( m_width * 4 ) ;
|
|
size_t size = m_bytesPerRow * m_height ;
|
|
void* data = m_memBuf.GetWriteBuf( size ) ;
|
|
if ( data != NULL )
|
|
{
|
|
memset( data , 0 , size ) ;
|
|
m_memBuf.UngetWriteBuf( size ) ;
|
|
|
|
m_hBitmap = CGBitmapContextCreate((char*) data, m_width, m_height, 8, m_bytesPerRow, wxMacGetGenericRGBColorSpace(), kCGImageAlphaNoneSkipFirst );
|
|
wxASSERT_MSG( m_hBitmap , wxT("Unable to create CGBitmapContext context") ) ;
|
|
CGContextTranslateCTM( m_hBitmap, 0, m_height );
|
|
CGContextScaleCTM( m_hBitmap, 1*m_scaleFactor, -1*m_scaleFactor );
|
|
} /* data != NULL */
|
|
m_ok = ( m_hBitmap != NULL ) ;
|
|
|
|
return m_ok ;
|
|
}
|
|
|
|
bool wxBitmapRefData::Create( int w , int h , int d, double logicalScale )
|
|
{
|
|
m_scaleFactor = logicalScale;
|
|
return Create(w*logicalScale,h*logicalScale,d);
|
|
}
|
|
|
|
void wxBitmapRefData::UseAlpha( bool use )
|
|
{
|
|
if ( m_hasAlpha == use )
|
|
return ;
|
|
|
|
m_hasAlpha = use ;
|
|
|
|
CGContextRelease( m_hBitmap );
|
|
m_hBitmap = CGBitmapContextCreate((char*) m_memBuf.GetData(), m_width, m_height, 8, m_bytesPerRow, wxMacGetGenericRGBColorSpace(), m_hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst );
|
|
wxASSERT_MSG( m_hBitmap , wxT("Unable to create CGBitmapContext context") ) ;
|
|
CGContextTranslateCTM( m_hBitmap, 0, m_height );
|
|
CGContextScaleCTM( m_hBitmap, 1*m_scaleFactor, -1*m_scaleFactor );
|
|
}
|
|
|
|
void *wxBitmapRefData::GetRawAccess() const
|
|
{
|
|
wxCHECK_MSG( IsOk(), NULL , wxT("invalid bitmap") ) ;
|
|
return m_memBuf.GetData() ;
|
|
}
|
|
|
|
void *wxBitmapRefData::BeginRawAccess()
|
|
{
|
|
wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") ) ;
|
|
wxASSERT( m_rawAccessCount == 0 ) ;
|
|
#ifndef __WXOSX_IPHONE__
|
|
wxASSERT_MSG( m_iconRef == NULL ,
|
|
wxT("Currently, modifing bitmaps that are used in controls already is not supported") ) ;
|
|
#endif
|
|
++m_rawAccessCount ;
|
|
|
|
// we must destroy an existing cached image, as
|
|
// the bitmap data may change now
|
|
if ( m_cgImageRef )
|
|
{
|
|
CGImageRelease( m_cgImageRef ) ;
|
|
m_cgImageRef = NULL ;
|
|
}
|
|
|
|
return m_memBuf.GetData() ;
|
|
}
|
|
|
|
void wxBitmapRefData::EndRawAccess()
|
|
{
|
|
wxCHECK_RET( IsOk() , wxT("invalid bitmap") ) ;
|
|
wxASSERT( m_rawAccessCount == 1 ) ;
|
|
|
|
--m_rawAccessCount ;
|
|
}
|
|
|
|
bool wxBitmapRefData::HasNativeSize()
|
|
{
|
|
int w = GetWidth() ;
|
|
int h = GetHeight() ;
|
|
int sz = wxMax( w , h ) ;
|
|
|
|
return ( sz == 128 || sz == 48 || sz == 32 || sz == 16 );
|
|
}
|
|
|
|
#ifndef __WXOSX_IPHONE__
|
|
IconRef wxBitmapRefData::GetIconRef()
|
|
{
|
|
if ( m_iconRef == NULL )
|
|
{
|
|
// Create Icon Family Handle
|
|
|
|
IconFamilyHandle iconFamily = (IconFamilyHandle) NewHandle( 0 );
|
|
|
|
int w = GetWidth() ;
|
|
int h = GetHeight() ;
|
|
int sz = wxMax( w , h ) ;
|
|
|
|
OSType dataType = 0 ;
|
|
OSType maskType = 0 ;
|
|
|
|
// since we don't have PICT conversion available, use
|
|
// the next larger standard icon size
|
|
// TODO: Use NSImage
|
|
if (sz <= 16)
|
|
sz = 16;
|
|
else if ( sz <= 32)
|
|
sz = 32;
|
|
else if ( sz <= 48)
|
|
sz = 48;
|
|
else if ( sz <= 128)
|
|
sz = 128;
|
|
else if ( sz <= 256)
|
|
sz = 256;
|
|
else if ( sz <= 512)
|
|
sz = 512;
|
|
else if ( sz <= 1024)
|
|
sz = 1024;
|
|
|
|
switch (sz)
|
|
{
|
|
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
|
|
case 1024:
|
|
dataType = kIconServices1024PixelDataARGB;
|
|
break;
|
|
#endif
|
|
case 512:
|
|
dataType = kIconServices512PixelDataARGB;
|
|
break;
|
|
|
|
case 256:
|
|
dataType = kIconServices256PixelDataARGB;
|
|
break;
|
|
|
|
case 128:
|
|
dataType = kIconServices128PixelDataARGB ;
|
|
break;
|
|
|
|
case 48:
|
|
dataType = kIconServices48PixelDataARGB ;
|
|
break;
|
|
|
|
case 32:
|
|
dataType = kIconServices32PixelDataARGB ;
|
|
break;
|
|
|
|
case 16:
|
|
dataType = kIconServices16PixelDataARGB ;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ( dataType != 0 )
|
|
{
|
|
if ( maskType == 0 )
|
|
{
|
|
size_t datasize = sz * sz * 4 ;
|
|
Handle data = NewHandle( datasize ) ;
|
|
HLock( data ) ;
|
|
unsigned char* ptr = (unsigned char*) *data ;
|
|
memset( ptr, 0, datasize );
|
|
bool hasAlpha = HasAlpha() ;
|
|
wxMask *mask = m_bitmapMask ;
|
|
unsigned char * sourcePtr = (unsigned char*) GetRawAccess() ;
|
|
unsigned char * masksourcePtr = mask ? (unsigned char*) mask->GetRawAccess() : NULL ;
|
|
|
|
for ( int y = 0 ; y < h ; ++y, sourcePtr += m_bytesPerRow , masksourcePtr += mask ? mask->GetBytesPerRow() : 0 )
|
|
{
|
|
unsigned char * source = sourcePtr;
|
|
unsigned char * masksource = masksourcePtr;
|
|
unsigned char * dest = ptr + y * sz * 4 ;
|
|
unsigned char a, r, g, b;
|
|
|
|
for ( int x = 0 ; x < w ; ++x )
|
|
{
|
|
a = *source ++ ;
|
|
r = *source ++ ;
|
|
g = *source ++ ;
|
|
b = *source ++ ;
|
|
|
|
if ( mask )
|
|
{
|
|
a = 0xFF - *masksource++ ;
|
|
}
|
|
else if ( !hasAlpha )
|
|
a = 0xFF ;
|
|
else
|
|
{
|
|
#if wxOSX_USE_PREMULTIPLIED_ALPHA
|
|
// this must be non-premultiplied data
|
|
if ( a != 0xFF && a!= 0 )
|
|
{
|
|
r = r * 255 / a;
|
|
g = g * 255 / a;
|
|
b = b * 255 / a;
|
|
}
|
|
#endif
|
|
}
|
|
*dest++ = a ;
|
|
*dest++ = r ;
|
|
*dest++ = g ;
|
|
*dest++ = b ;
|
|
|
|
}
|
|
}
|
|
HUnlock( data );
|
|
|
|
OSStatus err = SetIconFamilyData( iconFamily, dataType , data );
|
|
if ( err != noErr )
|
|
{
|
|
wxFAIL_MSG("Error when adding bitmap");
|
|
}
|
|
|
|
DisposeHandle( data );
|
|
}
|
|
else
|
|
{
|
|
// 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 * sourcePtr = (unsigned char*) GetRawAccess() ;
|
|
unsigned char * masksourcePtr = mask ? (unsigned char*) mask->GetRawAccess() : NULL ;
|
|
|
|
for ( int y = 0 ; y < h ; ++y, sourcePtr += m_bytesPerRow , masksourcePtr += mask ? mask->GetBytesPerRow() : 0 )
|
|
{
|
|
unsigned char * source = sourcePtr;
|
|
unsigned char * masksource = masksourcePtr;
|
|
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++ ;
|
|
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 ) ;
|
|
}
|
|
}
|
|
// transform into IconRef
|
|
|
|
// cleaner version existing from 10.3 upwards
|
|
HLock((Handle) iconFamily);
|
|
OSStatus err = GetIconRefFromIconFamilyPtr( *iconFamily, GetHandleSize((Handle) iconFamily), &m_iconRef );
|
|
HUnlock((Handle) iconFamily);
|
|
DisposeHandle( (Handle) iconFamily ) ;
|
|
|
|
wxCHECK_MSG( err == noErr, NULL, wxT("Error when constructing icon ref") );
|
|
}
|
|
|
|
return m_iconRef ;
|
|
}
|
|
|
|
#endif
|
|
|
|
CGImageRef wxBitmapRefData::CreateCGImage() const
|
|
{
|
|
wxASSERT( m_ok ) ;
|
|
wxASSERT( m_rawAccessCount >= 0 ) ;
|
|
CGImageRef image ;
|
|
if ( m_rawAccessCount > 0 || m_cgImageRef == NULL )
|
|
{
|
|
if ( m_depth != 1 && m_bitmapMask == NULL )
|
|
{
|
|
#if 0
|
|
// in order for this code to work properly, wxMask would have to invert black and white
|
|
// in the native bitmap
|
|
if ( m_bitmapMask )
|
|
{
|
|
CGImageRef tempImage = CGBitmapContextCreateImage( m_hBitmap );
|
|
CGImageRef tempMask = CGBitmapContextCreateImage((CGContextRef) m_bitmapMask->GetHBITMAP() );
|
|
image = CGImageCreateWithMask( tempImage, tempMask );
|
|
CGImageRelease(tempMask);
|
|
CGImageRelease(tempImage);
|
|
}
|
|
else
|
|
#endif
|
|
image = CGBitmapContextCreateImage( m_hBitmap );
|
|
}
|
|
else
|
|
{
|
|
size_t imageSize = m_height * m_bytesPerRow ;
|
|
void * dataBuffer = m_memBuf.GetData() ;
|
|
int w = m_width ;
|
|
int h = m_height ;
|
|
CGImageAlphaInfo alphaInfo = kCGImageAlphaNoneSkipFirst ;
|
|
wxMemoryBuffer membuf;
|
|
|
|
if ( m_bitmapMask )
|
|
{
|
|
alphaInfo = kCGImageAlphaFirst ;
|
|
unsigned char *destalphastart = (unsigned char*) membuf.GetWriteBuf( imageSize ) ;
|
|
memcpy( destalphastart , dataBuffer , imageSize ) ;
|
|
unsigned char *sourcemaskstart = (unsigned char *) m_bitmapMask->GetRawAccess() ;
|
|
int maskrowbytes = m_bitmapMask->GetBytesPerRow() ;
|
|
for ( int y = 0 ; y < h ; ++y , destalphastart += m_bytesPerRow, sourcemaskstart += maskrowbytes)
|
|
{
|
|
unsigned char *sourcemask = sourcemaskstart ;
|
|
unsigned char *destalpha = destalphastart ;
|
|
for ( int x = 0 ; x < w ; ++x , sourcemask += kMaskBytesPerPixel , destalpha += 4 )
|
|
{
|
|
*destalpha = 0xFF - *sourcemask ;
|
|
}
|
|
}
|
|
membuf.UngetWriteBuf( imageSize );
|
|
}
|
|
else
|
|
{
|
|
if ( m_hasAlpha )
|
|
{
|
|
#if wxOSX_USE_PREMULTIPLIED_ALPHA
|
|
alphaInfo = kCGImageAlphaPremultipliedFirst ;
|
|
#else
|
|
alphaInfo = kCGImageAlphaFirst ;
|
|
#endif
|
|
}
|
|
|
|
membuf = m_memBuf;
|
|
}
|
|
|
|
CGDataProviderRef dataProvider = NULL ;
|
|
if ( m_depth == 1 )
|
|
{
|
|
// TODO CHECK ALIGNMENT
|
|
wxMemoryBuffer maskBuf;
|
|
unsigned char * maskBufData = (unsigned char*) maskBuf.GetWriteBuf( m_width * m_height );
|
|
unsigned char * bufData = (unsigned char *) membuf.GetData() ;
|
|
// copy one color component
|
|
size_t i = 0;
|
|
for( int y = 0 ; y < m_height ; bufData+= m_bytesPerRow, ++y )
|
|
{
|
|
unsigned char *bufDataIter = bufData+3;
|
|
for ( int x = 0 ; x < m_width ; bufDataIter += 4, ++x, ++i )
|
|
{
|
|
maskBufData[i] = *bufDataIter;
|
|
}
|
|
}
|
|
maskBuf.UngetWriteBuf( m_width * m_height );
|
|
|
|
dataProvider =
|
|
wxMacCGDataProviderCreateWithMemoryBuffer( maskBuf );
|
|
|
|
image = ::CGImageMaskCreate( w, h, 8, 8, m_width , dataProvider, NULL, false );
|
|
}
|
|
else
|
|
{
|
|
CGColorSpaceRef colorSpace = wxMacGetGenericRGBColorSpace();
|
|
dataProvider = wxMacCGDataProviderCreateWithMemoryBuffer( membuf );
|
|
image =
|
|
::CGImageCreate(
|
|
w, h, 8 , 32 , m_bytesPerRow , colorSpace, alphaInfo ,
|
|
dataProvider, NULL , false , kCGRenderingIntentDefault );
|
|
}
|
|
CGDataProviderRelease( dataProvider);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
image = m_cgImageRef ;
|
|
CGImageRetain( image ) ;
|
|
}
|
|
|
|
if ( m_rawAccessCount == 0 && m_cgImageRef == NULL)
|
|
{
|
|
// we keep it for later use
|
|
m_cgImageRef = image ;
|
|
CGImageRetain( image ) ;
|
|
}
|
|
|
|
return image ;
|
|
}
|
|
|
|
CGContextRef wxBitmapRefData::GetBitmapContext() const
|
|
{
|
|
return m_hBitmap;
|
|
}
|
|
|
|
void wxBitmapRefData::Free()
|
|
{
|
|
wxASSERT_MSG( m_rawAccessCount == 0 , wxT("Bitmap still selected when destroyed") ) ;
|
|
|
|
if ( m_cgImageRef )
|
|
{
|
|
CGImageRelease( m_cgImageRef ) ;
|
|
m_cgImageRef = NULL ;
|
|
}
|
|
#ifndef __WXOSX_IPHONE__
|
|
if ( m_iconRef )
|
|
{
|
|
ReleaseIconRef( m_iconRef ) ;
|
|
m_iconRef = NULL ;
|
|
}
|
|
#endif
|
|
if ( m_hBitmap )
|
|
{
|
|
CGContextRelease(m_hBitmap);
|
|
m_hBitmap = NULL ;
|
|
}
|
|
|
|
wxDELETE(m_bitmapMask);
|
|
}
|
|
|
|
wxBitmapRefData::~wxBitmapRefData()
|
|
{
|
|
Free() ;
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxBitmap
|
|
// ----------------------------------------------------------------------------
|
|
|
|
bool wxBitmap::CopyFromIcon(const wxIcon& icon)
|
|
{
|
|
bool created = false ;
|
|
int w = icon.GetWidth() ;
|
|
int h = icon.GetHeight() ;
|
|
|
|
Create( w , h ) ;
|
|
#ifdef __WXOSX_CARBON__
|
|
if ( w == h && ( w == 16 || w == 32 || w == 48 || w == 128 ) )
|
|
{
|
|
IconFamilyHandle iconFamily = NULL ;
|
|
Handle imagehandle = NewHandle( 0 ) ;
|
|
Handle maskhandle = NewHandle( 0 ) ;
|
|
|
|
OSType maskType = 0;
|
|
OSType dataType = 0;
|
|
IconSelectorValue selector = 0 ;
|
|
|
|
switch (w)
|
|
{
|
|
case 128:
|
|
dataType = kThumbnail32BitData ;
|
|
maskType = kThumbnail8BitMask ;
|
|
selector = kSelectorAllAvailableData ;
|
|
break;
|
|
|
|
case 48:
|
|
dataType = kHuge32BitData ;
|
|
maskType = kHuge8BitMask ;
|
|
selector = kSelectorHuge32Bit | kSelectorHuge8BitMask ;
|
|
break;
|
|
|
|
case 32:
|
|
dataType = kLarge32BitData ;
|
|
maskType = kLarge8BitMask ;
|
|
selector = kSelectorLarge32Bit | kSelectorLarge8BitMask ;
|
|
break;
|
|
|
|
case 16:
|
|
dataType = kSmall32BitData ;
|
|
maskType = kSmall8BitMask ;
|
|
selector = kSelectorSmall32Bit | kSelectorSmall8BitMask ;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
OSStatus err = IconRefToIconFamily( MAC_WXHICON(icon.GetHICON()) , selector , &iconFamily ) ;
|
|
|
|
err = GetIconFamilyData( iconFamily , dataType , imagehandle ) ;
|
|
err = GetIconFamilyData( iconFamily , maskType , maskhandle ) ;
|
|
size_t imagehandlesize = GetHandleSize( imagehandle ) ;
|
|
size_t maskhandlesize = GetHandleSize( maskhandle ) ;
|
|
|
|
if ( imagehandlesize != 0 && maskhandlesize != 0 )
|
|
{
|
|
wxASSERT( GetHandleSize( imagehandle ) == w * 4 * h ) ;
|
|
wxASSERT( GetHandleSize( maskhandle ) == w * h ) ;
|
|
|
|
UseAlpha() ;
|
|
|
|
unsigned char *source = (unsigned char *) *imagehandle ;
|
|
unsigned char *sourcemask = (unsigned char *) *maskhandle ;
|
|
unsigned char* destination = (unsigned char*) BeginRawAccess() ;
|
|
|
|
for ( int y = 0 ; y < h ; ++y )
|
|
{
|
|
for ( int x = 0 ; x < w ; ++x )
|
|
{
|
|
unsigned char a = *sourcemask++;
|
|
*destination++ = a;
|
|
source++ ;
|
|
#if wxOSX_USE_PREMULTIPLIED_ALPHA
|
|
*destination++ = ( (*source++) * a + 127 ) / 255;
|
|
*destination++ = ( (*source++) * a + 127 ) / 255;
|
|
*destination++ = ( (*source++) * a + 127 ) / 255;
|
|
#else
|
|
*destination++ = *source++ ;
|
|
*destination++ = *source++ ;
|
|
*destination++ = *source++ ;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
EndRawAccess() ;
|
|
DisposeHandle( imagehandle ) ;
|
|
DisposeHandle( maskhandle ) ;
|
|
created = true ;
|
|
}
|
|
|
|
DisposeHandle( (Handle) iconFamily ) ;
|
|
}
|
|
#endif
|
|
if ( !created )
|
|
{
|
|
wxMemoryDC dc ;
|
|
dc.SelectObject( *this ) ;
|
|
dc.DrawIcon( icon , 0 , 0 ) ;
|
|
dc.SelectObject( wxNullBitmap ) ;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits)
|
|
{
|
|
wxBitmapRefData* bitmapRefData;
|
|
|
|
m_refData = bitmapRefData = new wxBitmapRefData( the_width , the_height , no_bits ) ;
|
|
|
|
if (bitmapRefData->IsOk())
|
|
{
|
|
if ( no_bits == 1 )
|
|
{
|
|
int linesize = the_width / 8;
|
|
if ( the_width % 8 )
|
|
linesize++;
|
|
|
|
unsigned char* linestart = (unsigned char*) bits ;
|
|
unsigned char* destptr = (unsigned char*) BeginRawAccess() ;
|
|
|
|
for ( int y = 0 ; y < the_height ; ++y , linestart += linesize, destptr += M_BITMAPDATA->GetBytesPerRow() )
|
|
{
|
|
unsigned char* destination = destptr;
|
|
int index, bit, mask;
|
|
|
|
for ( int x = 0 ; x < the_width ; ++x )
|
|
{
|
|
index = x / 8 ;
|
|
bit = x % 8 ;
|
|
mask = 1 << bit ;
|
|
|
|
if ( linestart[index] & mask )
|
|
{
|
|
*destination++ = 0xFF ;
|
|
*destination++ = 0 ;
|
|
*destination++ = 0 ;
|
|
*destination++ = 0 ;
|
|
}
|
|
else
|
|
{
|
|
*destination++ = 0xFF ;
|
|
*destination++ = 0xFF ;
|
|
*destination++ = 0xFF ;
|
|
*destination++ = 0xFF ;
|
|
}
|
|
}
|
|
}
|
|
|
|
EndRawAccess() ;
|
|
}
|
|
else
|
|
{
|
|
wxFAIL_MSG(wxT("multicolor BITMAPs not yet implemented"));
|
|
}
|
|
} /* bitmapRefData->IsOk() */
|
|
}
|
|
|
|
wxBitmap::wxBitmap(const void* data, wxBitmapType type, int width, int height, int depth)
|
|
{
|
|
(void) Create(data, type, width, height, depth);
|
|
}
|
|
|
|
wxBitmap::wxBitmap(int width, int height, const wxDC& dc)
|
|
{
|
|
(void)Create(width, height, dc);
|
|
}
|
|
|
|
wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type)
|
|
{
|
|
LoadFile(filename, type);
|
|
}
|
|
|
|
wxBitmap::wxBitmap(CGImageRef image, double scale)
|
|
{
|
|
(void) Create(image,scale);
|
|
}
|
|
|
|
wxGDIRefData* wxBitmap::CreateGDIRefData() const
|
|
{
|
|
return new wxBitmapRefData;
|
|
}
|
|
|
|
wxGDIRefData* wxBitmap::CloneGDIRefData(const wxGDIRefData* data) const
|
|
{
|
|
return new wxBitmapRefData(*static_cast<const wxBitmapRefData *>(data));
|
|
}
|
|
|
|
void * wxBitmap::GetRawAccess() const
|
|
{
|
|
wxCHECK_MSG( IsOk() , NULL , wxT("invalid bitmap") ) ;
|
|
|
|
return M_BITMAPDATA->GetRawAccess() ;
|
|
}
|
|
|
|
void * wxBitmap::BeginRawAccess()
|
|
{
|
|
wxCHECK_MSG( IsOk() , NULL , wxT("invalid bitmap") ) ;
|
|
|
|
return M_BITMAPDATA->BeginRawAccess() ;
|
|
}
|
|
|
|
void wxBitmap::EndRawAccess()
|
|
{
|
|
wxCHECK_RET( IsOk() , wxT("invalid bitmap") ) ;
|
|
|
|
M_BITMAPDATA->EndRawAccess() ;
|
|
}
|
|
|
|
CGImageRef wxBitmap::CreateCGImage() const
|
|
{
|
|
wxCHECK_MSG( IsOk(), NULL , wxT("invalid bitmap") ) ;
|
|
|
|
return M_BITMAPDATA->CreateCGImage() ;
|
|
}
|
|
|
|
#ifndef __WXOSX_IPHONE__
|
|
IconRef wxBitmap::GetIconRef() const
|
|
{
|
|
wxCHECK_MSG( IsOk(), NULL , wxT("invalid bitmap") ) ;
|
|
|
|
return M_BITMAPDATA->GetIconRef() ;
|
|
}
|
|
|
|
IconRef wxBitmap::CreateIconRef() const
|
|
{
|
|
IconRef icon = GetIconRef();
|
|
verify_noerr( AcquireIconRef(icon) );
|
|
return icon;
|
|
}
|
|
#endif
|
|
|
|
#if wxOSX_USE_COCOA
|
|
|
|
wxBitmap::wxBitmap(WX_NSImage image)
|
|
{
|
|
(void)Create(image);
|
|
}
|
|
|
|
bool wxBitmap::Create(WX_NSImage image)
|
|
{
|
|
bool isTemplate;
|
|
if (!Create(wxOSXCreateBitmapContextFromNSImage(image, &isTemplate)))
|
|
return false;
|
|
M_BITMAPDATA->SetTemplate(isTemplate);
|
|
return true;
|
|
}
|
|
|
|
wxBitmap::wxBitmap(CGContextRef bitmapcontext)
|
|
{
|
|
(void)Create(bitmapcontext);
|
|
}
|
|
|
|
bool wxBitmap::Create(CGContextRef bitmapcontext)
|
|
{
|
|
UnRef();
|
|
|
|
m_refData = new wxBitmapRefData( bitmapcontext );
|
|
|
|
return M_BITMAPDATA->IsOk() ;
|
|
}
|
|
|
|
WX_NSImage wxBitmap::GetNSImage() const
|
|
{
|
|
wxCFRef< CGImageRef > cgimage(CreateCGImage());
|
|
return wxOSXGetNSImageFromCGImage( cgimage, GetScaleFactor(), M_BITMAPDATA->IsTemplate() );
|
|
}
|
|
|
|
#endif
|
|
|
|
#if wxOSX_USE_IPHONE
|
|
|
|
WX_UIImage wxBitmap::GetUIImage() const
|
|
{
|
|
wxCFRef< CGImageRef > cgimage(CreateCGImage());
|
|
return wxOSXGetUIImageFromCGImage( cgimage );
|
|
}
|
|
|
|
#endif
|
|
wxBitmap wxBitmap::GetSubBitmap(const wxRect &rect) const
|
|
{
|
|
wxCHECK_MSG( IsOk() &&
|
|
(rect.x >= 0) && (rect.y >= 0) &&
|
|
(rect.x+rect.width <= GetWidth()) &&
|
|
(rect.y+rect.height <= GetHeight()),
|
|
wxNullBitmap, wxT("invalid bitmap or bitmap region") );
|
|
|
|
wxBitmap ret;
|
|
double scale = GetScaleFactor();
|
|
ret.CreateScaled( rect.width, rect.height, GetDepth(), scale );
|
|
wxASSERT_MSG( ret.IsOk(), wxT("GetSubBitmap error") );
|
|
|
|
int destwidth = rect.width*scale ;
|
|
int destheight = rect.height*scale ;
|
|
|
|
{
|
|
unsigned char *sourcedata = (unsigned char*) GetRawAccess() ;
|
|
unsigned char *destdata = (unsigned char*) ret.BeginRawAccess() ;
|
|
wxASSERT((sourcedata != NULL) && (destdata != NULL));
|
|
|
|
if ( (sourcedata != NULL) && (destdata != NULL) )
|
|
{
|
|
int sourcelinesize = GetBitmapData()->GetBytesPerRow() ;
|
|
int destlinesize = ret.GetBitmapData()->GetBytesPerRow() ;
|
|
unsigned char *source = sourcedata + int(rect.x * scale * 4 + rect.y *scale * sourcelinesize) ;
|
|
unsigned char *dest = destdata ;
|
|
|
|
for (int yy = 0; yy < destheight; ++yy, source += sourcelinesize , dest += destlinesize)
|
|
{
|
|
memcpy( dest , source , destlinesize ) ;
|
|
}
|
|
}
|
|
ret.EndRawAccess() ;
|
|
}
|
|
|
|
|
|
if ( M_BITMAPDATA->m_bitmapMask )
|
|
{
|
|
wxMemoryBuffer maskbuf ;
|
|
int rowBytes = GetBestBytesPerRow( destwidth * kMaskBytesPerPixel );
|
|
size_t maskbufsize = rowBytes * destheight ;
|
|
|
|
int sourcelinesize = M_BITMAPDATA->m_bitmapMask->GetBytesPerRow() ;
|
|
int destlinesize = rowBytes ;
|
|
|
|
unsigned char *source = (unsigned char *) M_BITMAPDATA->m_bitmapMask->GetRawAccess() ;
|
|
unsigned char *destdata = (unsigned char * ) maskbuf.GetWriteBuf( maskbufsize ) ;
|
|
wxASSERT( (source != NULL) && (destdata != NULL) ) ;
|
|
|
|
if ( (source != NULL) && (destdata != NULL) )
|
|
{
|
|
source += rect.x * kMaskBytesPerPixel + rect.y * sourcelinesize ;
|
|
unsigned char *dest = destdata ;
|
|
|
|
for (int yy = 0; yy < destheight; ++yy, source += sourcelinesize , dest += destlinesize)
|
|
{
|
|
memcpy( dest , source , destlinesize ) ;
|
|
}
|
|
|
|
maskbuf.UngetWriteBuf( maskbufsize ) ;
|
|
}
|
|
ret.SetMask( new wxMask( maskbuf , destwidth , destheight , rowBytes ) ) ;
|
|
}
|
|
else if ( HasAlpha() )
|
|
ret.UseAlpha() ;
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool wxBitmap::Create(int w, int h, int d)
|
|
{
|
|
UnRef();
|
|
|
|
if ( d < 0 )
|
|
d = wxDisplayDepth() ;
|
|
|
|
m_refData = new wxBitmapRefData( w , h , d );
|
|
|
|
return M_BITMAPDATA->IsOk() ;
|
|
}
|
|
|
|
bool wxBitmap::Create(int w, int h, const wxDC& dc)
|
|
{
|
|
double factor = dc.GetContentScaleFactor();
|
|
return CreateScaled(w,h,wxBITMAP_SCREEN_DEPTH, factor);
|
|
}
|
|
|
|
bool wxBitmap::CreateScaled(int w, int h, int d, double logicalScale)
|
|
{
|
|
UnRef();
|
|
|
|
if ( d < 0 )
|
|
d = wxDisplayDepth() ;
|
|
|
|
m_refData = new wxBitmapRefData( w , h , d, logicalScale );
|
|
|
|
return M_BITMAPDATA->IsOk() ;
|
|
}
|
|
|
|
bool wxBitmap::Create(CGImageRef image, double scale)
|
|
{
|
|
UnRef();
|
|
|
|
m_refData = new wxBitmapRefData( image, scale );
|
|
|
|
return M_BITMAPDATA->IsOk() ;
|
|
}
|
|
|
|
bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type)
|
|
{
|
|
UnRef();
|
|
|
|
wxBitmapHandler *handler = FindHandler(type);
|
|
|
|
if ( handler )
|
|
{
|
|
m_refData = new wxBitmapRefData;
|
|
|
|
return handler->LoadFile(this, filename, type, -1, -1);
|
|
}
|
|
else
|
|
{
|
|
#if wxUSE_IMAGE
|
|
double scale = 1.0;
|
|
wxString fname = filename;
|
|
|
|
if ( type == wxBITMAP_TYPE_PNG )
|
|
{
|
|
if ( wxOSXGetMainScreenContentScaleFactor() > 1.9 )
|
|
{
|
|
wxFileName fn(filename);
|
|
fn.MakeAbsolute();
|
|
fn.SetName(fn.GetName()+"@2x");
|
|
|
|
if ( fn.Exists() )
|
|
{
|
|
fname = fn.GetFullPath();
|
|
scale = 2.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
wxImage loadimage(fname, type);
|
|
if (loadimage.IsOk())
|
|
{
|
|
*this = wxBitmap(loadimage,-1,scale);
|
|
|
|
return true;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
wxLogWarning(wxT("no bitmap handler for type %d defined."), type);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wxBitmap::Create(const void* data, wxBitmapType type, int width, int height, int depth)
|
|
{
|
|
UnRef();
|
|
|
|
m_refData = new wxBitmapRefData;
|
|
|
|
wxBitmapHandler *handler = FindHandler(type);
|
|
|
|
if ( handler == NULL )
|
|
{
|
|
wxLogWarning(wxT("no bitmap handler for type %d defined."), type);
|
|
|
|
return false;
|
|
}
|
|
|
|
return handler->Create(this, data, type, width, height, depth);
|
|
}
|
|
|
|
#if wxUSE_IMAGE
|
|
|
|
wxBitmap::wxBitmap(const wxImage& image, int depth, double scale)
|
|
{
|
|
wxCHECK_RET( image.IsOk(), wxT("invalid image") );
|
|
|
|
// width and height of the device-dependent bitmap
|
|
int width = image.GetWidth();
|
|
int height = image.GetHeight();
|
|
|
|
wxBitmapRefData* bitmapRefData;
|
|
|
|
m_refData = bitmapRefData = new wxBitmapRefData( width/scale, height/scale, depth, scale) ;
|
|
|
|
if ( bitmapRefData->IsOk())
|
|
{
|
|
// Create picture
|
|
|
|
bool hasAlpha = false ;
|
|
|
|
if ( image.HasMask() )
|
|
{
|
|
// takes precedence, don't mix with alpha info
|
|
}
|
|
else
|
|
{
|
|
hasAlpha = image.HasAlpha() ;
|
|
}
|
|
|
|
if ( hasAlpha )
|
|
UseAlpha() ;
|
|
|
|
unsigned char* destinationstart = (unsigned char*) BeginRawAccess() ;
|
|
unsigned char* data = image.GetData();
|
|
if ( destinationstart != NULL && data != NULL )
|
|
{
|
|
const unsigned char *alpha = hasAlpha ? image.GetAlpha() : NULL ;
|
|
for (int y = 0; y < height; destinationstart += M_BITMAPDATA->GetBytesPerRow(), y++)
|
|
{
|
|
unsigned char * destination = destinationstart;
|
|
for (int x = 0; x < width; x++)
|
|
{
|
|
if ( hasAlpha )
|
|
{
|
|
const unsigned char a = *alpha++;
|
|
*destination++ = a ;
|
|
|
|
#if wxOSX_USE_PREMULTIPLIED_ALPHA
|
|
*destination++ = ((*data++) * a + 127) / 255 ;
|
|
*destination++ = ((*data++) * a + 127) / 255 ;
|
|
*destination++ = ((*data++) * a + 127) / 255 ;
|
|
#else
|
|
*destination++ = *data++ ;
|
|
*destination++ = *data++ ;
|
|
*destination++ = *data++ ;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
*destination++ = 0xFF ;
|
|
*destination++ = *data++ ;
|
|
*destination++ = *data++ ;
|
|
*destination++ = *data++ ;
|
|
}
|
|
}
|
|
}
|
|
|
|
EndRawAccess() ;
|
|
}
|
|
if ( image.HasMask() )
|
|
SetMask( new wxMask( *this , wxColour( image.GetMaskRed() , image.GetMaskGreen() , image.GetMaskBlue() ) ) ) ;
|
|
} /* bitmapRefData->IsOk() */
|
|
}
|
|
|
|
wxImage wxBitmap::ConvertToImage() const
|
|
{
|
|
wxImage image;
|
|
|
|
wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid bitmap") );
|
|
|
|
// create an wxImage object
|
|
int width = GetWidth();
|
|
int height = GetHeight();
|
|
image.Create( width, height );
|
|
|
|
unsigned char *data = image.GetData();
|
|
wxCHECK_MSG( data, wxNullImage, wxT("Could not allocate data for image") );
|
|
|
|
unsigned char* sourcestart = (unsigned char*) GetRawAccess() ;
|
|
|
|
bool hasAlpha = false ;
|
|
bool hasMask = false ;
|
|
int maskBytesPerRow = 0 ;
|
|
unsigned char *alpha = NULL ;
|
|
unsigned char *mask = NULL ;
|
|
|
|
if ( HasAlpha() )
|
|
hasAlpha = true ;
|
|
|
|
if ( GetMask() )
|
|
{
|
|
hasMask = true ;
|
|
mask = (unsigned char*) GetMask()->GetRawAccess() ;
|
|
maskBytesPerRow = GetMask()->GetBytesPerRow() ;
|
|
}
|
|
|
|
if ( hasAlpha )
|
|
{
|
|
image.SetAlpha() ;
|
|
alpha = image.GetAlpha() ;
|
|
}
|
|
|
|
int index = 0;
|
|
|
|
// The following masking algorithm is the same as well in msw/gtk:
|
|
// the colour used as transparent one in wxImage and the one it is
|
|
// replaced with when it actually occurs in the bitmap
|
|
static const int MASK_RED = 1;
|
|
static const int MASK_GREEN = 2;
|
|
static const int MASK_BLUE = 3;
|
|
static const int MASK_BLUE_REPLACEMENT = 2;
|
|
|
|
for (int yy = 0; yy < height; yy++ , sourcestart += M_BITMAPDATA->GetBytesPerRow() , mask += maskBytesPerRow )
|
|
{
|
|
unsigned char * maskp = mask ;
|
|
unsigned char * source = sourcestart;
|
|
unsigned char a, r, g, b;
|
|
long color;
|
|
|
|
for (int xx = 0; xx < width; xx++)
|
|
{
|
|
color = *((long*) source) ;
|
|
#ifdef WORDS_BIGENDIAN
|
|
a = ((color&0xFF000000) >> 24) ;
|
|
r = ((color&0x00FF0000) >> 16) ;
|
|
g = ((color&0x0000FF00) >> 8) ;
|
|
b = (color&0x000000FF);
|
|
#else
|
|
b = ((color&0xFF000000) >> 24) ;
|
|
g = ((color&0x00FF0000) >> 16) ;
|
|
r = ((color&0x0000FF00) >> 8) ;
|
|
a = (color&0x000000FF);
|
|
#endif
|
|
if ( hasMask )
|
|
{
|
|
if ( *maskp++ == 0xFF )
|
|
{
|
|
r = MASK_RED ;
|
|
g = MASK_GREEN ;
|
|
b = MASK_BLUE ;
|
|
}
|
|
else if ( r == MASK_RED && g == MASK_GREEN && b == MASK_BLUE )
|
|
b = MASK_BLUE_REPLACEMENT ;
|
|
}
|
|
else if ( hasAlpha )
|
|
{
|
|
*alpha++ = a ;
|
|
#if wxOSX_USE_PREMULTIPLIED_ALPHA
|
|
// this must be non-premultiplied data
|
|
if ( a != 0xFF && a!= 0 )
|
|
{
|
|
r = r * 255 / a;
|
|
g = g * 255 / a;
|
|
b = b * 255 / a;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
data[index ] = r ;
|
|
data[index + 1] = g ;
|
|
data[index + 2] = b ;
|
|
|
|
index += 3;
|
|
source += 4 ;
|
|
}
|
|
}
|
|
|
|
if ( hasMask )
|
|
image.SetMaskColour( MASK_RED, MASK_GREEN, MASK_BLUE );
|
|
|
|
return image;
|
|
}
|
|
|
|
#endif //wxUSE_IMAGE
|
|
|
|
bool wxBitmap::SaveFile( const wxString& filename,
|
|
wxBitmapType type, const wxPalette *palette ) const
|
|
{
|
|
bool success = false;
|
|
wxBitmapHandler *handler = FindHandler(type);
|
|
|
|
if ( handler )
|
|
{
|
|
success = handler->SaveFile(this, filename, type, palette);
|
|
}
|
|
else
|
|
{
|
|
#if wxUSE_IMAGE
|
|
wxImage image = ConvertToImage();
|
|
success = image.SaveFile(filename, type);
|
|
#else
|
|
wxLogWarning(wxT("no bitmap handler for type %d defined."), type);
|
|
#endif
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
int wxBitmap::GetHeight() const
|
|
{
|
|
wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
|
|
|
|
return M_BITMAPDATA->GetHeight();
|
|
}
|
|
|
|
int wxBitmap::GetWidth() const
|
|
{
|
|
wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
|
|
|
|
return M_BITMAPDATA->GetWidth() ;
|
|
}
|
|
|
|
double wxBitmap::GetScaleFactor() const
|
|
{
|
|
wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
|
|
|
|
return M_BITMAPDATA->GetScaleFactor() ;
|
|
}
|
|
|
|
int wxBitmap::GetDepth() const
|
|
{
|
|
wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
|
|
|
|
return M_BITMAPDATA->GetDepth();
|
|
}
|
|
|
|
wxMask *wxBitmap::GetMask() const
|
|
{
|
|
wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
|
|
|
|
return M_BITMAPDATA->m_bitmapMask;
|
|
}
|
|
|
|
bool wxBitmap::HasAlpha() const
|
|
{
|
|
wxCHECK_MSG( IsOk(), false , wxT("invalid bitmap") );
|
|
|
|
return M_BITMAPDATA->HasAlpha() ;
|
|
}
|
|
|
|
void wxBitmap::SetWidth(int w)
|
|
{
|
|
AllocExclusive();
|
|
M_BITMAPDATA->SetWidth(w);
|
|
}
|
|
|
|
void wxBitmap::SetHeight(int h)
|
|
{
|
|
AllocExclusive();
|
|
M_BITMAPDATA->SetHeight(h);
|
|
}
|
|
|
|
void wxBitmap::SetDepth(int d)
|
|
{
|
|
AllocExclusive();
|
|
M_BITMAPDATA->SetDepth(d);
|
|
}
|
|
|
|
void wxBitmap::SetOk(bool isOk)
|
|
{
|
|
AllocExclusive();
|
|
M_BITMAPDATA->SetOk(isOk);
|
|
}
|
|
|
|
#if wxUSE_PALETTE
|
|
wxPalette *wxBitmap::GetPalette() const
|
|
{
|
|
wxCHECK_MSG( IsOk(), NULL, wxT("Invalid bitmap GetPalette()") );
|
|
|
|
return &M_BITMAPDATA->m_bitmapPalette;
|
|
}
|
|
|
|
void wxBitmap::SetPalette(const wxPalette& palette)
|
|
{
|
|
AllocExclusive();
|
|
M_BITMAPDATA->m_bitmapPalette = palette ;
|
|
}
|
|
#endif // wxUSE_PALETTE
|
|
|
|
void wxBitmap::SetMask(wxMask *mask)
|
|
{
|
|
AllocExclusive();
|
|
// Remove existing mask if there is one.
|
|
delete M_BITMAPDATA->m_bitmapMask;
|
|
|
|
M_BITMAPDATA->m_bitmapMask = mask ;
|
|
}
|
|
|
|
WXHBITMAP wxBitmap::GetHBITMAP(WXHBITMAP* mask) const
|
|
{
|
|
wxUnusedVar(mask);
|
|
|
|
return WXHBITMAP(M_BITMAPDATA->GetBitmapContext());
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxMask
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxMask::wxMask()
|
|
{
|
|
Init() ;
|
|
}
|
|
|
|
wxMask::wxMask(const wxMask &tocopy) : wxObject()
|
|
{
|
|
Init();
|
|
|
|
m_bytesPerRow = tocopy.m_bytesPerRow;
|
|
m_width = tocopy.m_width;
|
|
m_height = tocopy.m_height;
|
|
|
|
size_t size = m_bytesPerRow * m_height;
|
|
unsigned char* dest = (unsigned char*)m_memBuf.GetWriteBuf( size );
|
|
unsigned char* source = (unsigned char*)tocopy.m_memBuf.GetData();
|
|
memcpy( dest, source, size );
|
|
m_memBuf.UngetWriteBuf( size ) ;
|
|
RealizeNative() ;
|
|
}
|
|
|
|
// Construct a mask from a bitmap and a colour indicating
|
|
// the transparent area
|
|
wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
|
|
{
|
|
Init() ;
|
|
Create( bitmap, colour );
|
|
}
|
|
|
|
// Construct a mask from a mono bitmap (copies the bitmap).
|
|
wxMask::wxMask( const wxBitmap& bitmap )
|
|
{
|
|
Init() ;
|
|
Create( bitmap );
|
|
}
|
|
|
|
// Construct a mask from a mono bitmap (copies the bitmap).
|
|
|
|
wxMask::wxMask( const wxMemoryBuffer& data, int width , int height , int bytesPerRow )
|
|
{
|
|
Init() ;
|
|
Create( data, width , height , bytesPerRow );
|
|
}
|
|
|
|
wxMask::~wxMask()
|
|
{
|
|
if ( m_maskBitmap )
|
|
{
|
|
CGContextRelease( (CGContextRef) m_maskBitmap );
|
|
m_maskBitmap = NULL ;
|
|
}
|
|
}
|
|
|
|
void wxMask::Init()
|
|
{
|
|
m_width = m_height = m_bytesPerRow = 0 ;
|
|
m_maskBitmap = NULL ;
|
|
}
|
|
|
|
void *wxMask::GetRawAccess() const
|
|
{
|
|
return m_memBuf.GetData() ;
|
|
}
|
|
|
|
// The default ColorTable for k8IndexedGrayPixelFormat in Intel appears to be broken, so we'll use an non-indexed
|
|
// bitmap mask instead; in order to keep the code simple, the change applies to PowerPC implementations as well
|
|
|
|
void wxMask::RealizeNative()
|
|
{
|
|
if ( m_maskBitmap )
|
|
{
|
|
CGContextRelease( (CGContextRef) m_maskBitmap );
|
|
m_maskBitmap = NULL ;
|
|
}
|
|
|
|
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();
|
|
// from MouseTracking sample :
|
|
// Ironically, due to a bug in CGImageCreateWithMask, you cannot use
|
|
// CGColorSpaceCreateWithName(kCGColorSpaceGenericGray) at this point!
|
|
|
|
m_maskBitmap = CGBitmapContextCreate((char*) m_memBuf.GetData(), m_width, m_height, 8, m_bytesPerRow, colorspace,
|
|
kCGImageAlphaNone );
|
|
CGColorSpaceRelease( colorspace );
|
|
wxASSERT_MSG( m_maskBitmap , wxT("Unable to create CGBitmapContext context") ) ;
|
|
}
|
|
|
|
// Create a mask from a mono bitmap (copies the bitmap).
|
|
|
|
bool wxMask::Create(const wxMemoryBuffer& data,int width , int height , int bytesPerRow)
|
|
{
|
|
m_memBuf = data ;
|
|
m_width = width ;
|
|
m_height = height ;
|
|
m_bytesPerRow = bytesPerRow ;
|
|
|
|
wxASSERT( data.GetDataLen() == (size_t)(height * bytesPerRow) ) ;
|
|
|
|
RealizeNative() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
// Create a mask from a mono bitmap (copies the bitmap).
|
|
bool wxMask::Create(const wxBitmap& bitmap)
|
|
{
|
|
m_width = bitmap.GetWidth() ;
|
|
m_height = bitmap.GetHeight() ;
|
|
m_bytesPerRow = GetBestBytesPerRow( m_width * kMaskBytesPerPixel ) ;
|
|
|
|
size_t size = m_bytesPerRow * m_height ;
|
|
unsigned char * destdatabase = (unsigned char*) m_memBuf.GetWriteBuf( size ) ;
|
|
wxASSERT( destdatabase != NULL ) ;
|
|
|
|
if ( destdatabase )
|
|
{
|
|
memset( destdatabase , 0 , size ) ;
|
|
unsigned char * srcdata = (unsigned char*) bitmap.GetRawAccess() ;
|
|
|
|
for ( int y = 0 ; y < m_height ; ++y , destdatabase += m_bytesPerRow )
|
|
{
|
|
unsigned char *destdata = destdatabase ;
|
|
unsigned char r, g, b;
|
|
|
|
for ( int x = 0 ; x < m_width ; ++x )
|
|
{
|
|
srcdata++ ;
|
|
r = *srcdata++ ;
|
|
g = *srcdata++ ;
|
|
b = *srcdata++ ;
|
|
|
|
if ( ( r + g + b ) > 0x10 )
|
|
*destdata++ = 0xFF ;
|
|
else
|
|
*destdata++ = 0x00 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_memBuf.UngetWriteBuf( size ) ;
|
|
RealizeNative() ;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Create a mask from a bitmap and a colour indicating
|
|
// the transparent area
|
|
bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
|
|
{
|
|
m_width = bitmap.GetWidth() ;
|
|
m_height = bitmap.GetHeight() ;
|
|
m_bytesPerRow = GetBestBytesPerRow( m_width * kMaskBytesPerPixel ) ;
|
|
|
|
size_t size = m_bytesPerRow * m_height ;
|
|
unsigned char * destdatabase = (unsigned char*) m_memBuf.GetWriteBuf( size ) ;
|
|
wxASSERT( destdatabase != NULL ) ;
|
|
if ( destdatabase != NULL)
|
|
{
|
|
memset( destdatabase , 0 , size ) ;
|
|
unsigned char * srcdatabase = (unsigned char*) bitmap.GetRawAccess() ;
|
|
size_t sourceBytesRow = bitmap.GetBitmapData()->GetBytesPerRow();
|
|
|
|
for ( int y = 0 ; y < m_height ; ++y , srcdatabase+= sourceBytesRow, destdatabase += m_bytesPerRow)
|
|
{
|
|
unsigned char *srcdata = srcdatabase ;
|
|
unsigned char *destdata = destdatabase ;
|
|
unsigned char r, g, b;
|
|
|
|
for ( int x = 0 ; x < m_width ; ++x )
|
|
{
|
|
srcdata++ ;
|
|
r = *srcdata++ ;
|
|
g = *srcdata++ ;
|
|
b = *srcdata++ ;
|
|
|
|
if ( colour == wxColour( r , g , b ) )
|
|
*destdata++ = 0xFF ;
|
|
else
|
|
*destdata++ = 0x00 ;
|
|
}
|
|
}
|
|
}
|
|
m_memBuf.UngetWriteBuf( size ) ;
|
|
RealizeNative() ;
|
|
|
|
return true;
|
|
}
|
|
|
|
wxBitmap wxMask::GetBitmap() const
|
|
{
|
|
wxBitmap bitmap(m_width, m_height, 1);
|
|
unsigned char* dst = static_cast<unsigned char*>(bitmap.BeginRawAccess());
|
|
const int dst_stride = bitmap.GetBitmapData()->GetBytesPerRow();
|
|
const unsigned char* src = static_cast<unsigned char*>(GetRawAccess());
|
|
for (int j = 0; j < m_height; j++, src += m_bytesPerRow, dst += dst_stride)
|
|
{
|
|
unsigned char* d = dst;
|
|
for (int i = 0; i < m_width; i++)
|
|
{
|
|
const unsigned char byte = src[i];
|
|
*d++ = 0xff;
|
|
*d++ = byte;
|
|
*d++ = byte;
|
|
*d++ = byte;
|
|
}
|
|
}
|
|
bitmap.EndRawAccess();
|
|
return bitmap;
|
|
}
|
|
|
|
WXHBITMAP wxMask::GetHBITMAP() const
|
|
{
|
|
return m_maskBitmap ;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Standard Handlers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
class WXDLLEXPORT wxBundleResourceHandler: public wxBitmapHandler
|
|
{
|
|
DECLARE_ABSTRACT_CLASS(wxBundleResourceHandler)
|
|
|
|
public:
|
|
inline wxBundleResourceHandler()
|
|
{
|
|
}
|
|
|
|
virtual bool LoadFile(wxBitmap *bitmap,
|
|
const wxString& name,
|
|
wxBitmapType type,
|
|
int desiredWidth,
|
|
int desiredHeight) wxOVERRIDE;
|
|
};
|
|
|
|
IMPLEMENT_ABSTRACT_CLASS(wxBundleResourceHandler, wxBitmapHandler);
|
|
|
|
class WXDLLEXPORT wxPNGResourceHandler: public wxBundleResourceHandler
|
|
{
|
|
DECLARE_DYNAMIC_CLASS(wxPNGResourceHandler)
|
|
|
|
public:
|
|
inline wxPNGResourceHandler()
|
|
{
|
|
SetName(wxT("PNG resource"));
|
|
SetExtension("PNG");
|
|
SetType(wxBITMAP_TYPE_PNG_RESOURCE);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxPNGResourceHandler, wxBundleResourceHandler)
|
|
|
|
class WXDLLEXPORT wxJPEGResourceHandler: public wxBundleResourceHandler
|
|
{
|
|
DECLARE_DYNAMIC_CLASS(wxJPEGResourceHandler)
|
|
|
|
public:
|
|
inline wxJPEGResourceHandler()
|
|
{
|
|
SetName(wxT("JPEG resource"));
|
|
SetExtension("JPEG");
|
|
SetType(wxBITMAP_TYPE_JPEG_RESOURCE);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxJPEGResourceHandler, wxBundleResourceHandler)
|
|
|
|
bool wxBundleResourceHandler::LoadFile(wxBitmap *bitmap,
|
|
const wxString& name,
|
|
wxBitmapType WXUNUSED(type),
|
|
int WXUNUSED(desiredWidth),
|
|
int WXUNUSED(desiredHeight))
|
|
{
|
|
wxString ext = GetExtension().Lower();
|
|
wxCFStringRef resname(name);
|
|
wxCFStringRef resname2x(name+"@2x");
|
|
wxCFStringRef restype(ext);
|
|
double scale = 1.0;
|
|
|
|
wxCFRef<CFURLRef> imageURL;
|
|
|
|
if ( wxOSXGetMainScreenContentScaleFactor() > 1.9 )
|
|
{
|
|
imageURL.reset(CFBundleCopyResourceURL(CFBundleGetMainBundle(), resname2x, restype, NULL));
|
|
scale = 2.0;
|
|
}
|
|
|
|
if ( imageURL.get() == NULL )
|
|
{
|
|
imageURL.reset(CFBundleCopyResourceURL(CFBundleGetMainBundle(), resname, restype, NULL));
|
|
scale = 1.0;
|
|
}
|
|
|
|
if ( imageURL.get() != NULL )
|
|
{
|
|
// Create the data provider object
|
|
wxCFRef<CGDataProviderRef> provider(CGDataProviderCreateWithURL (imageURL) );
|
|
CGImageRef image = NULL;
|
|
|
|
if ( ext == "jpeg" )
|
|
image = CGImageCreateWithJPEGDataProvider (provider, NULL, true,
|
|
kCGRenderingIntentDefault);
|
|
else if ( ext == "png" )
|
|
image = CGImageCreateWithPNGDataProvider (provider, NULL, true,
|
|
kCGRenderingIntentDefault);
|
|
if ( image != NULL )
|
|
{
|
|
bitmap->Create(image,scale);
|
|
CGImageRelease(image);
|
|
}
|
|
}
|
|
|
|
return false ;
|
|
}
|
|
|
|
/* static */
|
|
wxBitmap wxBitmapHelpers::NewFromPNGData(const void* data, size_t size)
|
|
{
|
|
wxCFRef<CGDataProviderRef>
|
|
provider(CGDataProviderCreateWithData(NULL, data, size, NULL) );
|
|
wxCFRef<CGImageRef>
|
|
image(CGImageCreateWithPNGDataProvider(provider, NULL, true,
|
|
kCGRenderingIntentDefault));
|
|
|
|
return wxBitmap(image);
|
|
}
|
|
|
|
void wxBitmap::InitStandardHandlers()
|
|
{
|
|
#if wxOSX_USE_COCOA_OR_CARBON
|
|
AddHandler( new wxICONResourceHandler ) ;
|
|
#endif
|
|
AddHandler( new wxPNGResourceHandler );
|
|
AddHandler( new wxJPEGResourceHandler );
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// raw bitmap access support
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void *wxBitmap::GetRawData(wxPixelDataBase& data, int WXUNUSED(bpp))
|
|
{
|
|
if ( !IsOk() )
|
|
// no bitmap, no data (raw or otherwise)
|
|
return NULL;
|
|
|
|
data.m_width = GetWidth() ;
|
|
data.m_height = GetHeight() ;
|
|
data.m_stride = GetBitmapData()->GetBytesPerRow() ;
|
|
|
|
return BeginRawAccess() ;
|
|
}
|
|
|
|
void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(dataBase))
|
|
{
|
|
EndRawAccess() ;
|
|
}
|
|
|
|
void wxBitmap::UseAlpha()
|
|
{
|
|
// remember that we are using alpha channel:
|
|
// we'll need to create a proper mask in UngetRawData()
|
|
M_BITMAPDATA->UseAlpha( true );
|
|
}
|