Files
wxWidgets/src/osx/core/bitmap.cpp
Vadim Zeitlin 24970061fa Add wxBitmap(wxImage, wxDC) ctor to all ports
This ctor was previously present only in wxMSW, make it available in all
ports to allow the same code to compile everywhere.

In most of them wxDC argument is simply ignored, but in wxGTK and wxOSX
it is used to assign the appropriate scale factor for the new bitmap.

Enable previously wxMSW-only unit test checking for this.
2022-04-12 19:08:56 +01:00

2076 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"
#include "wx/math.h"
#endif
#include "wx/metafile.h"
#include "wx/xpmdecod.h"
#include "wx/rawbmp.h"
#include "wx/filename.h"
wxIMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject);
wxIMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject);
#include "wx/osx/private.h"
CGColorSpaceRef wxMacGetGenericRGBColorSpace();
CGDataProviderRef wxMacCGDataProviderCreateWithMemoryBuffer( const wxMemoryBuffer& buf );
// Implementation Notes
// --------------------
//
// A bitmap can be represented using an NSImage or a CGBitmapContextRef
// If raw bitmap data needs to be accessed, then even the NSImage has to be
// rendered into a CGBitmapContextRef
static inline bool IsCGImageAlphaFlag(CGImageAlphaInfo alphaInfo)
{
return !(alphaInfo == kCGImageAlphaNone || alphaInfo == kCGImageAlphaNoneSkipFirst || alphaInfo == kCGImageAlphaNoneSkipLast);
}
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 = 1.0);
wxBitmapRefData(CGContextRef context);
wxBitmapRefData(CGImageRef image, double scale);
wxBitmapRefData(WXImage image);
wxBitmapRefData();
wxBitmapRefData(const wxBitmapRefData &tocopy);
virtual ~wxBitmapRefData();
bool IsOk() const wxOVERRIDE;
void Free();
int GetWidth() const;
int GetHeight() const;
int GetDepth() const;
int GetBytesPerRow() const;
bool HasAlpha() const;
WXImage GetImage() const;
void SetScaleFactor(double scale) { m_scaleFactor = scale; }
double GetScaleFactor() const { return m_scaleFactor; }
const void *GetRawAccess() const;
void *GetRawAccess();
void *BeginRawAccess();
void EndRawAccess();
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();
#if wxOSX_USE_ICONREF
// caller should increase ref count if needed longer
// than the bitmap exists
IconRef GetIconRef() const;
#endif
CGContextRef GetBitmapContext() const;
void SetSelectedInto(wxDC *dc);
wxDC *GetSelectedInto() const;
private :
bool Create(int width , int height , int depth, double logicalscale);
bool Create( CGImageRef image, double scale );
bool Create( CGContextRef bitmapcontext);
bool Create( WXImage image);
void Init();
void EnsureBitmapExists() const;
void FreeDerivedRepresentations();
WXImage m_nsImage;
int m_rawAccessCount;
mutable CGImageRef m_cgImageRef;
bool m_isTemplate;
#if wxOSX_USE_ICONREF
mutable IconRef m_iconRef;
#endif
wxCFRef<CGContextRef> m_hBitmap;
double m_scaleFactor;
wxDC* m_selectedInto;
};
#define wxOSX_USE_PREMULTIPLIED_ALPHA 1
static const int kBestByteAlignement = 16;
static const int kMaskBytesPerPixel = 1;
static size_t GetBestBytesPerRow( size_t rawBytes )
{
return (((rawBytes)+kBestByteAlignement-1) & ~(kBestByteAlignement-1) );
}
void wxBitmapRefData::Init()
{
m_nsImage = NULL;
m_bitmapMask = NULL ;
m_cgImageRef = NULL ;
m_isTemplate = false;
#if wxOSX_USE_ICONREF
m_iconRef = NULL ;
#endif
m_hBitmap = NULL ;
m_rawAccessCount = 0 ;
m_scaleFactor = 1.0;
m_selectedInto = NULL;
}
wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData &tocopy) : wxGDIRefData()
{
Init();
Create(tocopy.GetWidth(), tocopy.GetHeight(), tocopy.GetDepth(), tocopy.GetScaleFactor());
// Bitmap can have both mask and alpha channel so we have to copy both form the source.
if (tocopy.m_bitmapMask)
m_bitmapMask = new wxMask(*tocopy.m_bitmapMask);
if (tocopy.HasAlpha())
UseAlpha(true);
unsigned char* dest = (unsigned char*)GetRawAccess();
const unsigned char* source = static_cast<const unsigned char*>(tocopy.GetRawAccess());
size_t numbytes = GetBytesPerRow() * GetHeight();
memcpy( dest, source, numbytes );
}
wxBitmapRefData::wxBitmapRefData()
{
Init() ;
}
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 );
}
wxBitmapRefData::wxBitmapRefData(WXImage image)
{
Init();
Create( image );
}
void wxBitmapRefData::EnsureBitmapExists() const
{
if ( ! m_hBitmap && m_nsImage)
{
wxBitmapRefData* t = const_cast<wxBitmapRefData*>(this);
t->m_hBitmap = wxOSXCreateBitmapContextFromImage(m_nsImage, &t->m_isTemplate);
}
}
bool wxBitmapRefData::Create( WXImage image )
{
m_nsImage = image;
wxMacCocoaRetain(image);
m_scaleFactor = wxOSXGetImageScaleFactor(image);
return true;
}
// code from Technical Q&A QA1509
bool wxBitmapRefData::Create(CGImageRef image, double scale)
{
if (image != NULL)
{
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
m_hBitmap = NULL;
m_scaleFactor = scale;
size_t bytesPerRow = GetBestBytesPerRow(width * 4);
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image);
bool hasAlpha = IsCGImageAlphaFlag(alpha);
m_hBitmap = CGBitmapContextCreate(NULL, width, height, 8, bytesPerRow, wxMacGetGenericRGBColorSpace(),
hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst);
wxCHECK_MSG(m_hBitmap, false, wxT("Unable to create CGBitmapContext context"));
CGRect rect = CGRectMake(0, 0, width, height);
CGContextDrawImage(m_hBitmap, rect, image);
CGContextTranslateCTM(m_hBitmap, 0, height);
CGContextScaleCTM(m_hBitmap, 1 * m_scaleFactor, -1 * m_scaleFactor);
}
return IsOk();
}
bool wxBitmapRefData::Create(CGContextRef context)
{
if ( context != NULL && CGBitmapContextGetData(context) )
{
m_hBitmap = context;
// our own contexts conform to this, always.
wxASSERT( GetDepth() == 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;
}
return IsOk() ;
}
bool wxBitmapRefData::Create(int w, int h, int WXUNUSED(d), double logicalscale)
{
size_t width = wxMax(1, w);
size_t height = wxMax(1, h);
m_scaleFactor = logicalscale;
m_hBitmap = NULL;
size_t bytesPerRow = GetBestBytesPerRow(width * 4);
m_hBitmap = CGBitmapContextCreate(NULL, width, height, 8, bytesPerRow, wxMacGetGenericRGBColorSpace(), kCGImageAlphaNoneSkipFirst);
wxCHECK_MSG(m_hBitmap, false, wxT("Unable to create CGBitmapContext context"));
CGContextTranslateCTM(m_hBitmap, 0, height);
CGContextScaleCTM(m_hBitmap, 1 * GetScaleFactor(), -1 * GetScaleFactor());
return IsOk();
}
bool wxBitmapRefData::IsOk() const
{
return (m_hBitmap.get() != NULL || m_nsImage != NULL);
}
int wxBitmapRefData::GetWidth() const
{
wxCHECK_MSG( IsOk() , 0 , "Invalid Bitmap");
if ( m_hBitmap )
return (int) CGBitmapContextGetWidth(m_hBitmap);
else
return int(wxOSXGetImageSize(m_nsImage).width * m_scaleFactor);
}
int wxBitmapRefData::GetHeight() const
{
wxCHECK_MSG( IsOk() , 0 , "Invalid Bitmap");
if ( m_hBitmap )
return (int) CGBitmapContextGetHeight(m_hBitmap);
else
return int(wxOSXGetImageSize(m_nsImage).height * m_scaleFactor);
}
int wxBitmapRefData::GetDepth() const
{
wxCHECK_MSG( IsOk() , 0 , "Invalid Bitmap");
if ( m_hBitmap )
return (int) CGBitmapContextGetBitsPerPixel(m_hBitmap);
else
return 32; // a bitmap converted from an nsimage would have this depth
}
int wxBitmapRefData::GetBytesPerRow() const
{
wxCHECK_MSG( IsOk() , 0 , "Invalid Bitmap");
// Row stride length makes sense only for a bitmap representation
EnsureBitmapExists();
return (int) CGBitmapContextGetBytesPerRow(m_hBitmap);
}
bool wxBitmapRefData::HasAlpha() const
{
wxCHECK_MSG( IsOk() , false , "Invalid Bitmap");
if ( m_hBitmap )
{
CGImageAlphaInfo alpha = CGBitmapContextGetAlphaInfo(m_hBitmap);
return IsCGImageAlphaFlag(alpha);
}
else
{
return true; // a bitmap converted from an nsimage would have alpha
}
}
WXImage wxBitmapRefData::GetImage() const
{
wxCHECK_MSG( IsOk() , 0 , "Invalid Bitmap");
if ( !m_nsImage )
{
wxCFRef< CGImageRef > cgimage(CreateCGImage());
return wxOSXGetImageFromCGImage( cgimage, GetScaleFactor(), IsTemplate() );
}
return m_nsImage;
}
void wxBitmapRefData::UseAlpha( bool use )
{
wxCHECK_RET( IsOk() , wxT("invalid bitmap") ) ;
if ( HasAlpha() == use )
return ;
CGContextRef hBitmap = CGBitmapContextCreate(NULL, GetWidth(), GetHeight(), 8, GetBytesPerRow(), wxMacGetGenericRGBColorSpace(), use ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst );
memcpy(CGBitmapContextGetData(hBitmap),CGBitmapContextGetData(m_hBitmap),GetBytesPerRow()*GetHeight());
wxCHECK_RET( hBitmap , wxT("Unable to create CGBitmapContext context") ) ;
CGContextTranslateCTM( hBitmap, 0, GetHeight() );
CGContextScaleCTM( hBitmap, GetScaleFactor(), -GetScaleFactor() );
m_hBitmap.reset(hBitmap);
}
const void *wxBitmapRefData::GetRawAccess() const
{
wxCHECK_MSG( IsOk(), NULL , wxT("invalid bitmap") ) ;
EnsureBitmapExists();
return CGBitmapContextGetData(m_hBitmap);
}
void *wxBitmapRefData::GetRawAccess()
{
return const_cast<void*>(const_cast<const wxBitmapRefData*>(this)->GetRawAccess());
}
void *wxBitmapRefData::BeginRawAccess()
{
wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") ) ;
wxASSERT( m_rawAccessCount == 0 ) ;
#if wxOSX_USE_ICONREF
wxASSERT_MSG( m_iconRef == NULL ,
wxT("Currently, modifying 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
FreeDerivedRepresentations();
return GetRawAccess() ;
}
void wxBitmapRefData::EndRawAccess()
{
wxCHECK_RET( IsOk() , wxT("invalid bitmap") ) ;
wxASSERT( m_rawAccessCount == 1 ) ;
--m_rawAccessCount ;
// Update existing NSImage with new bitmap data
if ( m_nsImage )
{
wxCFRef<CGImageRef> image(CGBitmapContextCreateImage(m_hBitmap));
wxMacCocoaRelease(m_nsImage);
m_nsImage = wxOSXGetImageFromCGImage(image, GetScaleFactor(), IsTemplate());
wxMacCocoaRetain(m_nsImage);
}
}
bool wxBitmapRefData::HasNativeSize()
{
int w = GetWidth() ;
int h = GetHeight() ;
int sz = wxMax( w , h ) ;
return ( sz == 128 || sz == 48 || sz == 32 || sz == 16 );
}
#if wxOSX_USE_ICONREF
IconRef wxBitmapRefData::GetIconRef() const
{
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)
{
case 1024:
dataType = kIconServices1024PixelDataARGB;
break;
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 += GetBytesPerRow() , 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 = *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 += GetBytesPerRow() , 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++ = *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 // wxOSX_USE_ICONREF
CGImageRef wxBitmapRefData::CreateCGImage() const
{
wxASSERT( IsOk() ) ;
wxASSERT( m_rawAccessCount >= 0 ) ;
CGImageRef image ;
if ( m_rawAccessCount > 0 || m_cgImageRef == NULL )
{
if ( m_hBitmap )
{
image = CGBitmapContextCreateImage(m_hBitmap);
}
else
{
image = wxOSXCreateCGImageFromImage(m_nsImage);
}
if ( m_bitmapMask )
{
// First apply mask to image
CGImageRef imageMask = CGBitmapContextCreateImage(m_bitmapMask->GetHBITMAP());
CGImageRef imageMasked = CGImageCreateWithMask(image, imageMask);
// Convert masked image to plain ARGB image without mask
int w = GetWidth();
int h = GetHeight();
CGContextRef hBmpAlpha = CGBitmapContextCreate(NULL, w, h, 8, GetBytesPerRow(), wxMacGetGenericRGBColorSpace(), kCGImageAlphaPremultipliedFirst);
CGRect r = CGRectMake(0, 0, w, h);
CGContextDrawImage(hBmpAlpha, r, imageMasked);
CGContextTranslateCTM(hBmpAlpha, 0, h);
CGContextScaleCTM(hBmpAlpha, GetScaleFactor(), -GetScaleFactor());
CGImageRelease(imageMasked);
CGImageRelease(imageMask);
CGImageRelease(image);
image = CGBitmapContextCreateImage(hBmpAlpha);
CGContextRelease(hBmpAlpha);
}
}
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::SetSelectedInto(wxDC *dc)
{
if ( dc == NULL )
{
if ( m_selectedInto != NULL )
EndRawAccess();
}
else
{
wxASSERT_MSG( m_selectedInto == NULL || m_selectedInto == dc, "Bitmap already selected into a different dc");
if ( m_selectedInto == NULL )
(void) BeginRawAccess();
}
m_selectedInto = dc;
}
wxDC *wxBitmapRefData::GetSelectedInto() const
{
return m_selectedInto;
}
void wxBitmapRefData::FreeDerivedRepresentations()
{
if ( m_cgImageRef )
{
CGImageRelease( m_cgImageRef ) ;
m_cgImageRef = NULL ;
}
#if wxOSX_USE_ICONREF
if ( m_iconRef )
{
ReleaseIconRef( m_iconRef ) ;
m_iconRef = NULL ;
}
#endif // wxOSX_USE_ICONREF
}
void wxBitmapRefData::Free()
{
wxASSERT_MSG( m_rawAccessCount == 0 , wxT("Bitmap still selected when destroyed") ) ;
FreeDerivedRepresentations();
wxMacCocoaRelease(m_nsImage);
m_hBitmap.reset();
wxDELETE(m_bitmapMask);
}
wxBitmapRefData::~wxBitmapRefData()
{
Free() ;
}
// ----------------------------------------------------------------------------
// wxBitmap
// ----------------------------------------------------------------------------
wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits)
{
m_refData = new wxBitmapRefData( the_width , the_height , no_bits ) ;
if (GetBitmapData()->IsOk())
{
if ( no_bits == 1 )
{
int linesize = the_width / 8;
if ( the_width % 8 )
linesize++;
const unsigned char* linestart = reinterpret_cast<const unsigned char*>(bits);
unsigned char* destptr = (unsigned char*) GetBitmapData()->BeginRawAccess() ;
for ( int y = 0 ; y < the_height ; ++y , linestart += linesize, destptr += GetBitmapData()->GetBytesPerRow() )
{
unsigned char* destination = destptr;
for ( int x = 0 ; x < the_width ; ++x )
{
int index, bit, mask;
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 ;
}
}
}
GetBitmapData()->EndRawAccess() ;
}
else
{
wxFAIL_MSG(wxT("multicolor BITMAPs not yet implemented"));
}
}
}
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));
}
#if WXWIN_COMPATIBILITY_3_0
const void * wxBitmap::GetRawAccess() const
{
wxCHECK_MSG( IsOk() , NULL , wxT("invalid bitmap") ) ;
return GetBitmapData()->GetRawAccess() ;
}
void * wxBitmap::BeginRawAccess()
{
wxCHECK_MSG( IsOk() , NULL , wxT("invalid bitmap") ) ;
return GetBitmapData()->BeginRawAccess() ;
}
void wxBitmap::EndRawAccess()
{
wxCHECK_RET( IsOk() , wxT("invalid bitmap") ) ;
GetBitmapData()->EndRawAccess() ;
}
#endif
CGImageRef wxBitmap::CreateCGImage() const
{
wxCHECK_MSG( IsOk(), NULL , wxT("invalid bitmap") ) ;
return GetBitmapData()->CreateCGImage() ;
}
#if wxOSX_USE_ICONREF
IconRef wxBitmap::GetIconRef() const
{
wxCHECK_MSG( IsOk(), NULL , wxT("invalid bitmap") ) ;
return GetBitmapData()->GetIconRef() ;
}
IconRef wxBitmap::CreateIconRef() const
{
IconRef icon = GetIconRef();
wxOSX_VERIFY_NOERR(AcquireIconRef(icon));
return icon;
}
#endif
wxBitmap::wxBitmap(WXImage image)
{
(void)Create(image);
}
#if wxOSX_USE_COCOA
wxBitmap::wxBitmap(const wxCursor &cursor)
{
m_refData = new wxBitmapRefData( wxOSXGetNSImageFromNSCursor( cursor.GetHCURSOR() ) );
}
#endif
bool wxBitmap::Create(WXImage image)
{
UnRef();
m_refData = new wxBitmapRefData( image );
return GetBitmapData()->IsOk() ;
}
wxBitmap::wxBitmap(CGContextRef bitmapcontext)
{
(void)Create(bitmapcontext);
}
bool wxBitmap::Create(CGContextRef bitmapcontext)
{
UnRef();
m_refData = new wxBitmapRefData( bitmapcontext );
return GetBitmapData()->IsOk() ;
}
WXImage wxBitmap::OSXGetImage() const
{
return IsOk() ? GetBitmapData()->GetImage() : NULL;
}
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.CreateWithDIPSize( rect.GetSize(), scale, GetDepth() );
wxASSERT_MSG( ret.IsOk(), wxT("GetSubBitmap error") );
if ( HasAlpha() )
ret.UseAlpha() ;
int destwidth = int(rect.width * scale);
int destheight = int(rect.height * scale);
{
const unsigned char* sourcedata = static_cast<const unsigned char*>(GetBitmapData()->GetRawAccess());
unsigned char *destdata = (unsigned char*) ret.GetBitmapData()->BeginRawAccess() ;
wxASSERT((sourcedata != NULL) && (destdata != NULL));
if ( (sourcedata != NULL) && (destdata != NULL) )
{
int sourcelinesize = GetBitmapData()->GetBytesPerRow() ;
int destlinesize = ret.GetBitmapData()->GetBytesPerRow() ;
const unsigned char* source = sourcedata + size_t(rect.x * scale) * 4 + size_t(rect.y * scale) * sourcelinesize;
unsigned char* dest = destdata;
for (int yy = 0; yy < destheight; ++yy, source += sourcelinesize , dest += destlinesize)
{
memcpy( dest , source , destlinesize ) ;
}
}
ret.GetBitmapData()->EndRawAccess() ;
}
if ( GetBitmapData()->m_bitmapMask )
{
wxMemoryBuffer maskbuf ;
int rowBytes = GetBestBytesPerRow( destwidth * kMaskBytesPerPixel );
size_t maskbufsize = rowBytes * destheight ;
int sourcelinesize = GetBitmapData()->m_bitmapMask->GetBytesPerRow() ;
int destlinesize = rowBytes ;
unsigned char *source = (unsigned char *) GetBitmapData()->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 ) ;
}
wxMask* const mask = new wxMask();
mask->OSXCreate( maskbuf , destwidth , destheight , rowBytes );
ret.SetMask(mask) ;
}
return ret;
}
bool wxBitmap::Create(int w, int h, int d)
{
UnRef();
wxCHECK_MSG(w > 0 && h > 0, false, "invalid bitmap size");
if ( d < 0 )
d = wxDisplayDepth() ;
m_refData = new wxBitmapRefData( w , h , d );
return GetBitmapData()->IsOk() ;
}
bool wxBitmap::Create(int w, int h, const wxDC& dc)
{
double factor = dc.GetContentScaleFactor();
return CreateWithDIPSize(w, h, factor);
}
bool wxBitmap::DoCreate(const wxSize& size, double scale, int d)
{
UnRef();
if ( d < 0 )
d = wxDisplayDepth() ;
const wxSize sizePhys = size*scale;
m_refData = new wxBitmapRefData( sizePhys.x, sizePhys.y, d, scale );
return GetBitmapData()->IsOk() ;
}
bool wxBitmap::Create(CGImageRef image, double scale)
{
UnRef();
m_refData = new wxBitmapRefData( image, scale );
return GetBitmapData()->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 )
{
const int contentScaleFactor = wxRound(wxOSXGetMainScreenContentScaleFactor());
if ( contentScaleFactor > 1 )
{
wxFileName fn(filename);
fn.MakeAbsolute();
fn.SetName(fn.GetName()+wxString::Format("@%dx",contentScaleFactor));
if ( fn.Exists() )
{
fname = fn.GetFullPath();
scale = contentScaleFactor;
}
}
}
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
void wxBitmap::InitFromImage(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();
// we always use 32 bit internally here
depth = 32;
wxBitmapRefData* bitmapRefData;
m_refData = bitmapRefData = new wxBitmapRefData( width, height, depth, scale) ;
if ( bitmapRefData->IsOk())
{
bool hasMask = image.HasMask();
bool hasAlpha = image.HasAlpha();
// convert this bitmap to use its alpha channel
if ( hasAlpha )
UseAlpha();
const unsigned char *sourcePixels = image.GetData();
unsigned char* destinationPixels = (unsigned char*) GetBitmapData()->BeginRawAccess() ;
if ( destinationPixels != NULL && sourcePixels != NULL )
{
const unsigned char *sourceAlpha = hasAlpha ? image.GetAlpha() : NULL ;
const unsigned char mr = hasMask ? image.GetMaskRed() : 0;
const unsigned char mg = hasMask ? image.GetMaskGreen() : 0;
const unsigned char mb = hasMask ? image.GetMaskBlue() : 0;
unsigned char* destinationRowStart = destinationPixels;
wxMemoryBuffer maskbuf ;
int maskRowBytes = GetBestBytesPerRow( width * kMaskBytesPerPixel );
size_t maskbufsize = maskRowBytes * height ;
unsigned char *destinationMask = NULL;
if ( hasMask )
destinationMask = (unsigned char * ) maskbuf.GetWriteBuf( maskbufsize ) ;
unsigned char* destinationMaskRowStart = destinationMask;
for (int y = 0; y < height;
destinationRowStart += GetBitmapData()->GetBytesPerRow(),
destinationMaskRowStart += hasMask ? maskRowBytes : 0,
y++)
{
unsigned char * destination = destinationRowStart;
unsigned char * destinationMask = destinationMaskRowStart;
for (int x = 0; x < width; x++)
{
if ( hasMask )
{
bool isMasked = sourcePixels[0] == mr && sourcePixels[1] == mg && sourcePixels[2] == mb;
*destinationMask++ = isMasked ? wxIMAGE_ALPHA_TRANSPARENT : wxIMAGE_ALPHA_OPAQUE ;
}
if ( hasAlpha )
{
unsigned char a = *sourceAlpha++;
*destination++ = a ;
#if wxOSX_USE_PREMULTIPLIED_ALPHA
*destination++ = ((*sourcePixels++) * a + 127) / 255 ;
*destination++ = ((*sourcePixels++) * a + 127) / 255 ;
*destination++ = ((*sourcePixels++) * a + 127) / 255 ;
#else
*destination++ = *sourcePixels++ ;
*destination++ = *sourcePixels++ ;
*destination++ = *sourcePixels++ ;
#endif
}
else
{
*destination++ = wxIMAGE_ALPHA_OPAQUE ;
*destination++ = *sourcePixels++ ;
*destination++ = *sourcePixels++ ;
*destination++ = *sourcePixels++ ;
}
}
}
GetBitmapData()->EndRawAccess() ;
if ( hasMask )
{
maskbuf.UngetWriteBuf( maskbufsize ) ;
wxMask* mask = new wxMask();
mask->OSXCreate(maskbuf, width , height , maskRowBytes ) ;
SetMask( mask );
}
}
}
}
wxBitmap::wxBitmap(const wxImage& image, int depth, double scale)
{
InitFromImage(image, depth, scale);
}
wxBitmap::wxBitmap(const wxImage& image, const wxDC& dc)
{
InitFromImage(image, -1, dc.GetContentScaleFactor());
}
wxImage wxBitmap::ConvertToImage() const
{
wxImage image;
wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid bitmap") );
// this call may trigger a conversion from platform image to bitmap, issue it
// before any measurements are taken, multi-resolution platform images may be
// rendered incorrectly otherwise
const unsigned char* sourcestart = static_cast<const unsigned char*>(GetBitmapData()->GetRawAccess());
// 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") );
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 += GetBitmapData()->GetBytesPerRow() , mask += maskBytesPerRow )
{
unsigned char * maskp = mask ;
const wxUint32* source = reinterpret_cast<const wxUint32*>(sourcestart);
for (int xx = 0; xx < width; xx++)
{
const wxUint32 color = *source++;
unsigned char a, r, g, b;
#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
bool isMasked = false;
if ( hasMask )
{
if ( *maskp++ == 0x00 )
{
r = MASK_RED ;
g = MASK_GREEN ;
b = MASK_BLUE ;
isMasked = true;
}
else if ( r == MASK_RED && g == MASK_GREEN && b == MASK_BLUE )
b = MASK_BLUE_REPLACEMENT ;
}
if ( hasAlpha )
{
*alpha++ = a ;
#if wxOSX_USE_PREMULTIPLIED_ALPHA
// this must be non-premultiplied data
if ( !isMasked && 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;
}
}
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 GetBitmapData()->GetHeight();
}
int wxBitmap::GetWidth() const
{
wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
return GetBitmapData()->GetWidth() ;
}
void wxBitmap::SetScaleFactor(double scale)
{
wxCHECK_RET( IsOk(), wxT("invalid bitmap") );
if ( GetBitmapData()->GetScaleFactor() != scale )
{
AllocExclusive();
GetBitmapData()->SetScaleFactor(scale) ;
}
}
double wxBitmap::GetScaleFactor() const
{
wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
return GetBitmapData()->GetScaleFactor() ;
}
int wxBitmap::GetDepth() const
{
wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
return GetBitmapData()->GetDepth();
}
wxMask *wxBitmap::GetMask() const
{
wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
return GetBitmapData()->m_bitmapMask;
}
bool wxBitmap::HasAlpha() const
{
wxCHECK_MSG( IsOk(), false , wxT("invalid bitmap") );
return GetBitmapData()->HasAlpha() ;
}
#if WXWIN_COMPATIBILITY_3_0
void wxBitmap::SetWidth(int WXUNUSED_UNLESS_DEBUG(w))
{
AllocExclusive();
wxASSERT_MSG( GetWidth() == w, "Changing the bitmap width is not supported");
}
void wxBitmap::SetHeight(int WXUNUSED_UNLESS_DEBUG(h))
{
AllocExclusive();
wxASSERT_MSG( GetHeight() == h, "Changing the bitmap height is not supported");
}
void wxBitmap::SetDepth(int WXUNUSED_UNLESS_DEBUG(d))
{
AllocExclusive();
wxASSERT_MSG( d == -1 || GetDepth() == d, "Changing the bitmap depth is not supported");
}
#endif
#if wxUSE_PALETTE
wxPalette *wxBitmap::GetPalette() const
{
wxCHECK_MSG( IsOk(), NULL, wxT("Invalid bitmap GetPalette()") );
return & const_cast<wxBitmapRefData*>(GetBitmapData())->m_bitmapPalette;
}
void wxBitmap::SetPalette(const wxPalette& palette)
{
AllocExclusive();
GetBitmapData()->m_bitmapPalette = palette ;
}
#endif // wxUSE_PALETTE
void wxBitmap::SetMask(wxMask *mask)
{
AllocExclusive();
// Remove existing mask if there is one.
delete GetBitmapData()->m_bitmapMask;
GetBitmapData()->m_bitmapMask = mask ;
}
WXHBITMAP wxBitmap::GetHBITMAP(WXHBITMAP* mask) const
{
wxUnusedVar(mask);
return WXHBITMAP(GetBitmapData()->GetBitmapContext());
}
// ----------------------------------------------------------------------------
// wxMask
// ----------------------------------------------------------------------------
wxMask::wxMask()
{
Init() ;
}
wxMask::wxMask(const wxMask &tocopy) : wxMaskBase()
{
Init();
DoCreateMaskBitmap( tocopy.GetWidth(), tocopy.GetHeight(), tocopy.GetBytesPerRow());
int size = tocopy.GetHeight() * tocopy.GetBytesPerRow();
memcpy( GetRawAccess(), tocopy.GetRawAccess(), size);
}
// 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 );
}
wxMask::~wxMask()
{
}
void wxMask::Init()
{
}
void *wxMask::GetRawAccess() const
{
wxCHECK_MSG( m_maskBitmap, NULL , wxT("invalid mask") ) ;
return CGBitmapContextGetData(m_maskBitmap);
}
int wxMask::GetBytesPerRow() const
{
return CGBitmapContextGetBytesPerRow(m_maskBitmap);
}
int wxMask::GetWidth() const
{
return CGBitmapContextGetWidth(m_maskBitmap);
}
int wxMask::GetHeight() const
{
return CGBitmapContextGetHeight(m_maskBitmap);
}
// 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::DoCreateMaskBitmap(int width, int height, int bytesPerRow)
{
wxCFRef<CGColorSpaceRef> colorspace = CGColorSpaceCreateDeviceGray();
if ( bytesPerRow < 0 )
bytesPerRow = GetBestBytesPerRow(width * kMaskBytesPerPixel);
m_maskBitmap = CGBitmapContextCreate(NULL, width, height, kMaskBytesPerPixel * 8, bytesPerRow, colorspace,
kCGImageAlphaNone);
wxASSERT_MSG(m_maskBitmap, wxT("Unable to create CGBitmapContext context"));
}
void wxMask::RealizeNative()
{
#if 0
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") ) ;
#endif
}
// Construct a mask from a 8 bpp memory buffer
bool wxMask::OSXCreate(const wxMemoryBuffer& data,int width , int height , int bytesPerRow)
{
size_t dataLen = data.GetDataLen();
wxCHECK( dataLen == (size_t)(height * bytesPerRow), false );
const void* srcdata = data.GetData();
wxCHECK( srcdata, false );
DoCreateMaskBitmap(width, height, bytesPerRow);
void* destdata = GetRawAccess();
wxCHECK( destdata, false );
memcpy(destdata, srcdata, dataLen);
return true;
}
// Create a mask from a mono bitmap (copies the bitmap).
bool wxMask::InitFromMonoBitmap(const wxBitmap& bitmap)
{
int width, height, bytesPerRow;
width = bitmap.GetWidth() ;
height = bitmap.GetHeight() ;
DoCreateMaskBitmap(width, height);
bytesPerRow = GetBytesPerRow();
// pixel access needs a non-const bitmap currently
wxBitmap bmp(bitmap);
wxNativePixelData data(bmp);
wxNativePixelData::Iterator p(data);
unsigned char * destdatabase = (unsigned char*) GetRawAccess();
wxASSERT( destdatabase != NULL ) ;
if ( destdatabase != NULL)
{
for ( int y = 0 ; y < height; ++y, destdatabase += bytesPerRow )
{
wxNativePixelData::Iterator rowStart = p;
unsigned char *destdata = destdatabase ;
for ( int x = 0 ; x < width ; ++x, ++p )
{
int v = p.Red() + p.Green() + p.Blue();
wxASSERT_MSG( v == 0 || v == 3*0xFF, "Non-monochrome bitmap supplied" );
*destdata++ = v < (3 * 0xFF) / 2 ? 0 : 0xFF;
}
p = rowStart;
p.OffsetY(data, 1);
}
}
return true;
}
bool wxMask::InitFromColour(const wxBitmap& bitmap, const wxColour& colour)
{
int width, height, bytesPerRow;
width = bitmap.GetWidth() ;
height = bitmap.GetHeight() ;
DoCreateMaskBitmap(width, height);
bytesPerRow = GetBytesPerRow();
// pixel access needs a non-const bitmap currently
wxBitmap bmp(bitmap);
wxNativePixelData data(bmp);
wxNativePixelData::Iterator p(data);
unsigned char * destdatabase = (unsigned char*) GetRawAccess();
wxASSERT( destdatabase != NULL ) ;
if ( destdatabase != NULL)
{
for ( int y = 0 ; y < height; ++y, destdatabase += bytesPerRow )
{
wxNativePixelData::Iterator rowStart = p;
unsigned char *destdata = destdatabase ;
for ( int x = 0 ; x < width ; ++x, ++p )
{
if ( wxColour( p.Red(), p.Green(), p.Blue() ) == colour )
*destdata++ = 0x0 ;
else
*destdata++ = 0xFF ;
}
p = rowStart;
p.OffsetY(data, 1);
}
}
RealizeNative() ;
return true;
}
wxBitmap wxMask::GetBitmap() const
{
int width, height, bytesPerRow;
width = GetWidth();
height = GetHeight();
bytesPerRow = GetBytesPerRow();
wxBitmap bitmap(width, height, 32);
wxNativePixelData data(bitmap);
wxNativePixelData::Iterator p(data);
const unsigned char* srcbase = static_cast<unsigned char*>(GetRawAccess());
for (int y = 0; y < height; ++y, srcbase += bytesPerRow)
{
wxNativePixelData::Iterator rowStart = p;
const unsigned char* src = srcbase;
for (int x = 0; x < width; ++x, ++p, ++src)
{
const unsigned char byte = *src;
wxASSERT( byte == 0 || byte == 0xFF );
p.Red() = p.Green() = p.Blue() = byte;
}
p = rowStart;
p.OffsetY(data, 1);
}
return bitmap;
}
WXHBITMAP wxMask::GetHBITMAP() const
{
return m_maskBitmap ;
}
void wxMask::FreeData()
{
return m_maskBitmap.reset();
}
// ----------------------------------------------------------------------------
// Standard Handlers
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxBundleResourceHandler: public wxBitmapHandler
{
wxDECLARE_ABSTRACT_CLASS(wxBundleResourceHandler);
public:
inline wxBundleResourceHandler()
{
}
virtual bool LoadFile(wxBitmap *bitmap,
const wxString& name,
wxBitmapType type,
int desiredWidth,
int desiredHeight) wxOVERRIDE;
};
wxIMPLEMENT_ABSTRACT_CLASS(wxBundleResourceHandler, wxBitmapHandler);
class WXDLLEXPORT wxPNGResourceHandler: public wxBundleResourceHandler
{
wxDECLARE_DYNAMIC_CLASS(wxPNGResourceHandler);
public:
inline wxPNGResourceHandler()
{
SetName(wxT("PNG resource"));
SetExtension("PNG");
SetType(wxBITMAP_TYPE_PNG_RESOURCE);
}
};
wxIMPLEMENT_DYNAMIC_CLASS(wxPNGResourceHandler, wxBundleResourceHandler);
class WXDLLEXPORT wxJPEGResourceHandler: public wxBundleResourceHandler
{
wxDECLARE_DYNAMIC_CLASS(wxJPEGResourceHandler);
public:
inline wxJPEGResourceHandler()
{
SetName(wxT("JPEG resource"));
SetExtension("JPEG");
SetType(wxBITMAP_TYPE_JPEG_RESOURCE);
}
};
wxIMPLEMENT_DYNAMIC_CLASS(wxJPEGResourceHandler, wxBundleResourceHandler);
#if wxOSX_USE_COCOA
class WXDLLEXPORT wxICNSHandler: public wxBitmapHandler
{
wxDECLARE_DYNAMIC_CLASS(wxICNSHandler);
public:
inline wxICNSHandler()
{
SetName(wxT("icns file"));
SetExtension("icns");
SetType(wxBITMAP_TYPE_ICON);
}
bool LoadFile(wxBitmap *bitmap,
const wxString& name,
wxBitmapType type,
int desiredWidth,
int desiredHeight) wxOVERRIDE
{
wxCFRef<CFURLRef> iconURL;
wxCFStringRef filePath(name);
iconURL.reset(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, filePath, kCFURLPOSIXPathStyle, false));
WXImage img = wxOSXGetNSImageFromCFURL(iconURL);
if ( img )
{
bitmap->Create(img);
return true;
}
return wxBitmapHandler::LoadFile( bitmap, name, type, desiredWidth, desiredHeight);
}
};
wxIMPLEMENT_DYNAMIC_CLASS(wxICNSHandler, wxBitmapHandler);
class WXDLLEXPORT wxICNSResourceHandler: public wxBundleResourceHandler
{
wxDECLARE_DYNAMIC_CLASS(wxICNSResourceHandler);
public:
inline wxICNSResourceHandler()
{
SetName(wxT("icns resource"));
SetExtension("icns");
SetType(wxBITMAP_TYPE_ICON_RESOURCE);
}
virtual bool LoadFile(wxBitmap *bitmap,
const wxString& name,
wxBitmapType type,
int desiredWidth,
int desiredHeight) wxOVERRIDE;
};
wxIMPLEMENT_DYNAMIC_CLASS(wxICNSResourceHandler, wxBundleResourceHandler);
bool wxICNSResourceHandler::LoadFile(wxBitmap *bitmap,
const wxString& resourceName,
wxBitmapType type,
int desiredWidth,
int desiredHeight)
{
OSType theId = 0 ;
if ( resourceName == wxT("wxICON_INFORMATION") )
{
theId = kAlertNoteIcon ;
}
else if ( resourceName == wxT("wxICON_QUESTION") )
{
theId = kAlertCautionIcon ;
}
else if ( resourceName == wxT("wxICON_WARNING") )
{
theId = kAlertCautionIcon ;
}
else if ( resourceName == wxT("wxICON_ERROR") )
{
theId = kAlertStopIcon ;
}
else if ( resourceName == wxT("wxICON_FOLDER") )
{
theId = kGenericFolderIcon ;
}
else if ( resourceName == wxT("wxICON_FOLDER_OPEN") )
{
theId = kOpenFolderIcon ;
}
else if ( resourceName == wxT("wxICON_NORMAL_FILE") )
{
theId = kGenericDocumentIcon ;
}
else if ( resourceName == wxT("wxICON_EXECUTABLE_FILE") )
{
theId = kGenericApplicationIcon ;
}
else if ( resourceName == wxT("wxICON_CDROM") )
{
theId = kGenericCDROMIcon ;
}
else if ( resourceName == wxT("wxICON_FLOPPY") )
{
theId = kGenericFloppyIcon ;
}
else if ( resourceName == wxT("wxICON_HARDDISK") )
{
theId = kGenericHardDiskIcon ;
}
else if ( resourceName == wxT("wxICON_REMOVABLE") )
{
theId = kGenericRemovableMediaIcon ;
}
else if ( resourceName == wxT("wxICON_DELETE") )
{
theId = kToolbarDeleteIcon ;
}
else if ( resourceName == wxT("wxICON_GO_BACK") )
{
theId = kBackwardArrowIcon ;
}
else if ( resourceName == wxT("wxICON_GO_FORWARD") )
{
theId = kForwardArrowIcon ;
}
else if ( resourceName == wxT("wxICON_GO_HOME") )
{
theId = kToolbarHomeIcon ;
}
else if ( resourceName == wxT("wxICON_HELP_SETTINGS") )
{
theId = kGenericFontIcon ;
}
else if ( resourceName == wxT("wxICON_HELP_PAGE") )
{
theId = kGenericDocumentIcon ;
}
else if ( resourceName == wxT( "wxICON_PRINT" ) )
{
theId = kPrintMonitorFolderIcon;
}
else if ( resourceName == wxT( "wxICON_HELP_FOLDER" ) )
{
theId = kHelpFolderIcon;
}
WXImage img = NULL;
if ( theId != 0 )
{
IconRef iconRef = NULL ;
wxOSX_VERIFY_NOERR(GetIconRef( kOnSystemDisk, kSystemIconsCreator, theId, &iconRef )) ;
img = wxOSXGetNSImageFromIconRef(iconRef);
}
else
{
wxCFRef<CFURLRef> iconURL;
wxCFStringRef resname(resourceName);
wxCFStringRef restype(GetExtension().Lower());
iconURL.reset(CFBundleCopyResourceURL(CFBundleGetMainBundle(), resname, restype, NULL));
img = wxOSXGetNSImageFromCFURL(iconURL);
}
if ( img )
{
bitmap->Create(img);
return true;
}
return wxBundleResourceHandler::LoadFile( bitmap, resourceName, type, desiredWidth, desiredHeight);
}
#endif // wxOSX_USE_COCOA
bool wxBundleResourceHandler::LoadFile(wxBitmap *bitmap,
const wxString& name,
wxBitmapType WXUNUSED(type),
int WXUNUSED(desiredWidth),
int WXUNUSED(desiredHeight))
{
wxString ext = GetExtension().Lower();
wxCFStringRef restype(ext);
double scale = 1.0;
wxCFRef<CFURLRef> imageURL;
const int contentScaleFactor = wxRound(wxOSXGetMainScreenContentScaleFactor());
if ( contentScaleFactor > 1 )
{
wxCFStringRef resname(wxString::Format("%s@%dx", name, contentScaleFactor));
imageURL.reset(CFBundleCopyResourceURL(CFBundleGetMainBundle(), resname, restype, NULL));
scale = contentScaleFactor;
}
if ( imageURL.get() == NULL )
{
wxCFStringRef resname(name);
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 true;
}
}
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
// no icns on iOS
AddHandler( new wxICNSHandler );
AddHandler( new wxICNSResourceHandler ) ;
#endif
AddHandler( new wxPNGResourceHandler );
AddHandler( new wxJPEGResourceHandler );
}
// ----------------------------------------------------------------------------
// raw bitmap access support
// ----------------------------------------------------------------------------
void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
{
if ( !IsOk() )
// no bitmap, no data (raw or otherwise)
return NULL;
if ( bpp != GetDepth() )
return NULL;
data.m_width = GetWidth() ;
data.m_height = GetHeight() ;
data.m_stride = GetBitmapData()->GetBytesPerRow() ;
return GetBitmapData()->BeginRawAccess() ;
}
void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(dataBase))
{
GetBitmapData()->EndRawAccess() ;
}
void wxBitmap::UseAlpha(bool use )
{
// remember that we are using alpha channel:
// we'll need to create a proper mask in UngetRawData()
GetBitmapData()->UseAlpha( use );
}
void wxBitmap::SetSelectedInto(wxDC *dc)
{
GetBitmapData()->SetSelectedInto(dc) ;
}
wxDC* wxBitmap::GetSelectedInto() const
{
return GetBitmapData()->GetSelectedInto() ;
}