// Author: Stefan Csomor
// Modified by:
// Created: 1998-01-01
-// RCS-ID: $Id$
// Copyright: (c) Stefan Csomor
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/rawbmp.h"
+#include "wx/filename.h"
+
IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
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(CGImageRef image);
+ wxBitmapRefData(CGContextRef context);
+ wxBitmapRefData(CGImageRef image, double scale);
wxBitmapRefData();
wxBitmapRefData(const wxBitmapRefData &tocopy);
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();
int GetBytesPerRow() const { return m_bytesPerRow; }
private :
bool Create(int width , int height , int depth);
- bool Create( CGImageRef image );
+ 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;
#endif
CGContextRef m_hBitmap;
+ double m_scaleFactor;
};
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);
+ Create(tocopy.m_width, tocopy.m_height, tocopy.m_depth, tocopy.m_scaleFactor);
if (tocopy.m_bitmapMask)
m_bitmapMask = new wxMask(*tocopy.m_bitmapMask);
Create( w , h , d ) ;
}
-wxBitmapRefData::wxBitmapRefData(CGImageRef image)
+wxBitmapRefData::wxBitmapRefData(int w , int h , int d, double logicalscale)
+{
+ Init() ;
+ Create( w , h , d, logicalscale ) ;
+}
+
+wxBitmapRefData::wxBitmapRefData(CGContextRef context)
{
Init();
- Create( image );
+ Create( context );
+}
+
+wxBitmapRefData::wxBitmapRefData(CGImageRef image, double scale)
+{
+ Init();
+ Create( image, scale );
}
// code from Technical Q&A QA1509
-bool wxBitmapRefData::Create(CGImageRef image)
+bool wxBitmapRefData::Create(CGImageRef image, double scale)
{
if ( image != NULL )
{
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 ;
wxASSERT_MSG( m_hBitmap , wxT("Unable to create CGBitmapContext context") ) ;
CGContextTranslateCTM( m_hBitmap, 0, m_height );
- CGContextScaleCTM( m_hBitmap, 1, -1 );
+ CGContextScaleCTM( m_hBitmap, 1*m_scaleFactor, -1*m_scaleFactor );
} /* data != NULL */
}
m_ok = ( m_hBitmap != NULL ) ;
}
+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_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, -1 );
+ 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 )
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, -1 );
+ CGContextScaleCTM( m_hBitmap, 1*m_scaleFactor, -1*m_scaleFactor );
}
void *wxBitmapRefData::GetRawAccess() const
{
if ( no_bits == 1 )
{
- int linesize = ( the_width / (sizeof(unsigned char) * 8)) ;
- if ( the_width % (sizeof(unsigned char) * 8) )
- linesize += sizeof(unsigned char);
+ int linesize = the_width / 8;
+ if ( the_width % 8 )
+ linesize++;
unsigned char* linestart = (unsigned char*) bits ;
unsigned char* destptr = (unsigned char*) BeginRawAccess() ;
(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)
+wxBitmap::wxBitmap(CGImageRef image, double scale)
{
- (void) Create(image);
+ (void) Create(image,scale);
}
wxGDIRefData* wxBitmap::CreateGDIRefData() const
#if wxOSX_USE_COCOA
+wxBitmap::wxBitmap(WX_NSImage image)
+{
+ (void)Create(image);
+}
+
+bool wxBitmap::Create(WX_NSImage image)
+{
+ return Create(wxOSXCreateBitmapContextFromNSImage(image));
+}
+
+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 );
+ return wxOSXGetNSImageFromCGImage( cgimage, GetScaleFactor() );
}
#endif
(rect.y+rect.height <= GetHeight()),
wxNullBitmap, wxT("invalid bitmap or bitmap region") );
- wxBitmap ret( rect.width, rect.height, GetDepth() );
+ wxBitmap ret;
+ double scale = GetScaleFactor();
+ ret.CreateScaled( rect.width, rect.height, GetDepth(), scale );
wxASSERT_MSG( ret.IsOk(), wxT("GetSubBitmap error") );
- int destwidth = rect.width ;
- int destheight = rect.height ;
+ int destwidth = rect.width*scale ;
+ int destheight = rect.height*scale ;
{
unsigned char *sourcedata = (unsigned char*) GetRawAccess() ;
{
int sourcelinesize = GetBitmapData()->GetBytesPerRow() ;
int destlinesize = ret.GetBitmapData()->GetBytesPerRow() ;
- unsigned char *source = sourcedata + rect.x * 4 + rect.y * sourcelinesize ;
+ 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)
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)
+bool wxBitmap::Create(CGImageRef image, double scale)
{
UnRef();
- m_refData = new wxBitmapRefData( image );
+ m_refData = new wxBitmapRefData( image, scale );
return M_BITMAPDATA->IsOk() ;
}
else
{
#if wxUSE_IMAGE
- wxImage loadimage(filename, type);
+ 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 = loadimage;
+ *this = wxBitmap(loadimage,-1,scale);
return true;
}
#if wxUSE_IMAGE
-wxBitmap::wxBitmap(const wxImage& image, int depth)
+wxBitmap::wxBitmap(const wxImage& image, int depth, double scale)
{
wxCHECK_RET( image.IsOk(), wxT("invalid image") );
wxBitmapRefData* bitmapRefData;
- m_refData = bitmapRefData = new wxBitmapRefData( width , height , depth ) ;
+ m_refData = bitmapRefData = new wxBitmapRefData( width/scale, height/scale, depth, scale) ;
if ( bitmapRefData->IsOk())
{
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 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 ;
class WXDLLEXPORT wxJPEGResourceHandler: public wxBundleResourceHandler
{
- DECLARE_DYNAMIC_CLASS(wxPNGResourceHandler)
+ DECLARE_DYNAMIC_CLASS(wxJPEGResourceHandler)
public:
inline wxJPEGResourceHandler()
{
wxString ext = GetExtension().Lower();
wxCFStringRef resname(name);
+ wxCFStringRef resname2x(name+"@2x");
wxCFStringRef restype(ext);
+ double scale = 1.0;
+
+ wxCFRef<CFURLRef> imageURL;
- wxCFRef<CFURLRef> imageURL(CFBundleCopyResourceURL(CFBundleGetMainBundle(), resname, restype, NULL));
+ 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 )
{
kCGRenderingIntentDefault);
if ( image != NULL )
{
- bitmap->Create(image);
+ bitmap->Create(image,scale);
CGImageRelease(image);
}
}