X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/065e208ec09e3d08d51d9604497f92f53c210f93..06a32e049c1bad9249079ad2e91659303424a774:/src/cocoa/bitmap.mm diff --git a/src/cocoa/bitmap.mm b/src/cocoa/bitmap.mm index 2d335f5548..16ca2a7847 100644 --- a/src/cocoa/bitmap.mm +++ b/src/cocoa/bitmap.mm @@ -1,37 +1,45 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: src/cocoa/bitmap.cpp +// Name: src/cocoa/bitmap.mm // Purpose: wxBitmap // Author: David Elliott // Modified by: // Created: 2003/07/19 // RCS-ID: $Id$ // Copyright: (c) 2003 David Elliott -// Licence: wxWidgets licence +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// #include "wx/wxprec.h" + +#include "wx/bitmap.h" + #ifndef WX_PRECOMP #include "wx/log.h" #include "wx/utils.h" #include "wx/palette.h" #include "wx/icon.h" #include "wx/colour.h" + #include "wx/image.h" #endif //WX_PRECOMP -#include "wx/bitmap.h" -#include "wx/image.h" + #include "wx/xpmdecod.h" #include "wx/rawbmp.h" #include "wx/cocoa/autorelease.h" #include "wx/cocoa/string.h" +#include "wx/cocoa/ObjcRef.h" #import <AppKit/NSBitmapImageRep.h> #import <AppKit/NSGraphics.h> #import <AppKit/NSImage.h> +#import <AppKit/NSColor.h> + +IMPLEMENT_ABSTRACT_CLASS(wxBitmapHandler, wxBitmapHandlerBase) // ======================================================================== // wxBitmapRefData // ======================================================================== + class wxBitmapRefData: public wxGDIRefData { friend class wxBitmap; @@ -40,6 +48,8 @@ public: wxBitmapRefData( const wxBitmapRefData& data ); virtual ~wxBitmapRefData(); + virtual bool IsOk() const { return m_ok; } + protected: int m_width; int m_height; @@ -52,8 +62,6 @@ protected: wxMask *m_bitmapMask; // Optional mask }; -#define M_BITMAPDATA ((wxBitmapRefData *)m_refData) - wxBitmapRefData::wxBitmapRefData() { m_ok = FALSE; @@ -68,6 +76,8 @@ wxBitmapRefData::wxBitmapRefData() wxBitmapRefData::wxBitmapRefData( const wxBitmapRefData& data) { + wxAutoNSAutoreleasePool pool; + m_width = data.m_width; m_height = data.m_height; m_depth = data.m_depth; @@ -75,13 +85,13 @@ wxBitmapRefData::wxBitmapRefData( const wxBitmapRefData& data) m_numColors = data.m_numColors; m_bitmapPalette = data.m_bitmapPalette; m_quality = data.m_quality; - m_cocoaNSBitmapImageRep = [data.m_cocoaNSBitmapImageRep copyWithZone:nil]; + m_cocoaNSBitmapImageRep = wxGCSafeRetain([[data.m_cocoaNSBitmapImageRep copyWithZone:nil] autorelease]); m_bitmapMask = data.m_bitmapMask?new wxMask(*data.m_bitmapMask):NULL; } wxBitmapRefData::~wxBitmapRefData() { - [m_cocoaNSBitmapImageRep release]; + wxGCSafeRelease(m_cocoaNSBitmapImageRep); m_cocoaNSBitmapImageRep = NULL; delete m_bitmapMask; @@ -91,6 +101,9 @@ wxBitmapRefData::~wxBitmapRefData() // ======================================================================== // wxBitmap // ======================================================================== + +#define M_BITMAPDATA ((wxBitmapRefData *)m_refData) + IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject) wxBitmap::wxBitmap() @@ -114,12 +127,17 @@ wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits /* TODO: create the bitmap from data */ } -wxBitmap::wxBitmap(int w, int h, int d) +wxBitmap::wxBitmap(NSImage* cocoaNSImage) +{ + (void) Create(cocoaNSImage); +} + +wxBitmap::wxBitmap(NSBitmapImageRep* cocoaNSBitmapImageRep) { - (void)Create(w, h, d); + (void) Create(cocoaNSBitmapImageRep); } -wxBitmap::wxBitmap(void *data, wxBitmapType type, int width, int height, int depth) +wxBitmap::wxBitmap(const void* data, wxBitmapType type, int width, int height, int depth) { (void) Create(data, type, width, height, depth); } @@ -129,12 +147,12 @@ wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type) LoadFile(filename, type); } -wxObjectRefData *wxBitmap::CreateRefData() const +wxGDIRefData *wxBitmap::CreateGDIRefData() const { return new wxBitmapRefData; } -wxObjectRefData *wxBitmap::CloneRefData(const wxObjectRefData *data) const +wxGDIRefData *wxBitmap::CloneGDIRefData(const wxGDIRefData *data) const { return new wxBitmapRefData(*(wxBitmapRefData*)data); } @@ -148,7 +166,7 @@ WX_NSBitmapImageRep wxBitmap::GetNSBitmapImageRep() WX_NSImage wxBitmap::GetNSImage(bool useMask) const { - if(!Ok()) + if(!IsOk()) return nil; NSImage *nsimage = [[[NSImage alloc] initWithSize:NSMakeSize(GetWidth(), GetHeight())] autorelease]; @@ -177,8 +195,8 @@ void wxBitmap::SetNSBitmapImageRep(WX_NSBitmapImageRep bitmapImageRep) if(!M_BITMAPDATA) return; // NOTE: No checking is done to make sure width/height agree - [bitmapImageRep retain]; - [M_BITMAPDATA->m_cocoaNSBitmapImageRep release]; + wxGCSafeRetain(bitmapImageRep); + wxGCSafeRelease(M_BITMAPDATA->m_cocoaNSBitmapImageRep); M_BITMAPDATA->m_cocoaNSBitmapImageRep = bitmapImageRep; } @@ -238,11 +256,6 @@ void wxBitmap::SetMask(wxMask *mask) M_BITMAPDATA->m_bitmapMask = mask ; } -bool wxBitmap::Ok() const -{ - return m_refData && M_BITMAPDATA->m_ok; -} - wxPalette* wxBitmap::GetPalette() const { if(!m_refData) @@ -280,6 +293,8 @@ int wxBitmap::GetHeight() const bool wxBitmap::Create(int w, int h, int d) { + wxAutoNSAutoreleasePool pool; + UnRef(); m_refData = new wxBitmapRefData; @@ -289,7 +304,7 @@ bool wxBitmap::Create(int w, int h, int d) M_BITMAPDATA->m_depth = d; /* TODO: create new bitmap */ - M_BITMAPDATA->m_cocoaNSBitmapImageRep = [[NSBitmapImageRep alloc] + M_BITMAPDATA->m_cocoaNSBitmapImageRep = wxGCSafeRetain([[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL pixelsWide: w pixelsHigh: h @@ -298,8 +313,9 @@ bool wxBitmap::Create(int w, int h, int d) hasAlpha: NO isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace - bytesPerRow: 0 - bitsPerPixel: 0]; + bytesPerRow: 0 // NOTE: Contrary to Apple documentation Mac OS + // 10.4 will add padding bytes when 0 is used here + bitsPerPixel: 0] autorelease]); wxLogTrace(wxTRACE_COCOA,wxT("M_BITMAPDATA=%p NSBitmapImageRep bitmapData=%p"), M_BITMAPDATA, [M_BITMAPDATA->m_cocoaNSBitmapImageRep bitmapData]); M_BITMAPDATA->m_ok = true; @@ -328,20 +344,47 @@ bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type) M_BITMAPDATA->m_ok = true; M_BITMAPDATA->m_numColors = 0; M_BITMAPDATA->m_quality = 0; - M_BITMAPDATA->m_cocoaNSBitmapImageRep = [imageRep retain]; + M_BITMAPDATA->m_cocoaNSBitmapImageRep = wxGCSafeRetain(imageRep); M_BITMAPDATA->m_bitmapMask = NULL; return true; } wxImage image; if(!image.LoadFile(filename,type)) return false; - if(!image.Ok()) + if(!image.IsOk()) return false; *this = wxBitmap(image); return true; } -bool wxBitmap::Create(void *data, wxBitmapType type, int width, int height, int depth) +bool wxBitmap::Create(NSImage* cocoaNSImage) +{ + wxAutoNSAutoreleasePool pool; + NSBitmapImageRep *bitmapImageRep = [NSBitmapImageRep imageRepWithData:[cocoaNSImage TIFFRepresentation]]; + return Create(bitmapImageRep); +} + +bool wxBitmap::Create(NSBitmapImageRep *imageRep) +{ + UnRef(); + m_refData = new wxBitmapRefData; + if(imageRep != nil) + { + M_BITMAPDATA->m_width = [imageRep pixelsWide]; + M_BITMAPDATA->m_height = [imageRep pixelsHigh]; + M_BITMAPDATA->m_depth = [imageRep bitsPerPixel]; + M_BITMAPDATA->m_ok = true; + M_BITMAPDATA->m_numColors = 0; + M_BITMAPDATA->m_quality = 0; + M_BITMAPDATA->m_cocoaNSBitmapImageRep = wxGCSafeRetain(imageRep); + M_BITMAPDATA->m_bitmapMask = NULL; + return true; + } + else + return false; +} + +bool wxBitmap::Create(const void* data, wxBitmapType type, int width, int height, int depth) { UnRef(); @@ -355,53 +398,92 @@ bool wxBitmap::SaveFile(const wxString& filename, wxBitmapType type, const wxPal return false; } -bool wxBitmap::CopyFromIcon(const wxIcon& icno) +bool wxBitmap::CopyFromIcon(const wxIcon& icon) { - return false; -} + // Pool here due to lack of one during wx init phase + wxAutoNSAutoreleasePool pool; -wxBitmap wxBitmap::GetSubBitmap(wxRect const&) const -{ - return wxNullBitmap; + UnRef(); + if(!icon.GetNSImage()); + [icon.GetNSImage() lockFocus]; + NSRect imageRect; + imageRect.origin.x = imageRect.origin.y = 0.0; + imageRect.size = [icon.GetNSImage() size]; + NSBitmapImageRep *newBitmapRep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:imageRect] autorelease]; + [icon.GetNSImage() unlockFocus]; + if(!newBitmapRep) + return false; + m_refData = new wxBitmapRefData; + M_BITMAPDATA->m_cocoaNSBitmapImageRep = wxGCSafeRetain(newBitmapRep); + M_BITMAPDATA->m_width = [newBitmapRep pixelsWide]; + M_BITMAPDATA->m_height = [newBitmapRep pixelsHigh]; + M_BITMAPDATA->m_depth = [newBitmapRep bitsPerSample]*[newBitmapRep samplesPerPixel]; + M_BITMAPDATA->m_ok = true; + M_BITMAPDATA->m_numColors = 0; + M_BITMAPDATA->m_quality = 0; + M_BITMAPDATA->m_bitmapMask = NULL; + return true; } -wxImage wxBitmap::ConvertToImage() const +wxBitmap wxBitmap::GetSubBitmap(const wxRect& rect) const { - if(!Ok()) - return /*wxImage(5,5)*/wxNullImage; - return wxImage(M_BITMAPDATA->m_width,M_BITMAPDATA->m_height); -} + wxAutoNSAutoreleasePool pool; + if(!IsOk()) + return wxNullBitmap; + NSImage *nsimage = GetNSImage(false); -bool wxBitmap::CreateFromXpm(const char **xpm) -{ -#if wxUSE_IMAGE && wxUSE_XPM - UnRef(); + [nsimage lockFocus]; + NSRect imageRect = {{0,0}, [nsimage size]}; + imageRect.origin.x = imageRect.size.width * rect.x / GetWidth(); + imageRect.origin.y = imageRect.size.height * rect.y / GetHeight(); + imageRect.size.width *= static_cast<CGFloat>(rect.width) / GetWidth(); + imageRect.size.height *= static_cast<CGFloat>(rect.height) / GetHeight(); - wxCHECK_MSG( xpm, false, wxT("invalid XPM data") ) + NSBitmapImageRep *newBitmapRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:imageRect]; + [nsimage unlockFocus]; - wxXPMDecoder decoder; - wxImage img = decoder.ReadData(xpm); - wxCHECK_MSG( img.Ok(), false, wxT("invalid XPM data") ) + wxBitmap newBitmap(newBitmapRep); - *this = wxBitmap(img); - return true; -#else - return false; -#endif + return (newBitmap); +} + +wxImage wxBitmap::ConvertToImage() const +{ + wxAutoNSAutoreleasePool pool; + if(!IsOk()) + return /*wxImage(5,5)*/wxNullImage; + NSImage *nsimage = GetNSImage(false /* don't use mask */); + wxImage newImage(M_BITMAPDATA->m_width,M_BITMAPDATA->m_height); + [nsimage lockFocus]; + for(int i=0; i < M_BITMAPDATA->m_width; i++) + { + // Don't let the pool get too big as you'll notice we're creating + // two autoreleased NSColor objects with every iteration. + wxAutoNSAutoreleasePool loopPool; + for(int j=0; j < M_BITMAPDATA->m_height; j++) + { + NSColor *pixelColor = NSReadPixel(NSMakePoint(i,M_BITMAPDATA->m_height - j - 1)); + NSColor *color = [pixelColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; + newImage.SetRGB(i,j,int([color redComponent]*255.0), int([color greenComponent]*255.0), int([color blueComponent]*255.0)); + } + } + [nsimage unlockFocus]; + return newImage; } bool wxBitmap::CreateFromImage(const wxImage& image, int depth) { + wxAutoNSAutoreleasePool pool; UnRef(); - wxCHECK_MSG(image.Ok(), false, wxT("invalid image")); + wxCHECK_MSG(image.IsOk(), false, wxT("invalid image")); wxCHECK_MSG(depth == -1 || depth == 1, false, wxT("invalid bitmap depth")); m_refData = new wxBitmapRefData(); M_BITMAPDATA->m_width = image.GetWidth(); M_BITMAPDATA->m_height = image.GetHeight(); - NSBitmapImageRep *bitmapImage = [[NSBitmapImageRep alloc] + NSBitmapImageRep *bitmapImage = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL pixelsWide: image.GetWidth() pixelsHigh: image.GetHeight() @@ -410,9 +492,11 @@ bool wxBitmap::CreateFromImage(const wxImage& image, int depth) hasAlpha: NO isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace - bytesPerRow: 0 - bitsPerPixel: 0]; + bytesPerRow: image.GetWidth()*3 + bitsPerPixel: 0] autorelease]; + // TODO: Specify bytesPerRow:0 and then use [bitmapImage bytesPerRow] + // so that the rows are aligned suitably for altivec by the OS (Tiger) const int numBytes = image.GetWidth()*image.GetHeight()*3; memcpy([bitmapImage bitmapData], image.GetData(), numBytes); // TODO: Alpha and convert to desired depth @@ -420,14 +504,14 @@ bool wxBitmap::CreateFromImage(const wxImage& image, int depth) M_BITMAPDATA->m_ok = true; M_BITMAPDATA->m_numColors = 0; M_BITMAPDATA->m_quality = 0; - M_BITMAPDATA->m_cocoaNSBitmapImageRep = bitmapImage; + M_BITMAPDATA->m_cocoaNSBitmapImageRep = wxGCSafeRetain(bitmapImage); M_BITMAPDATA->m_bitmapMask = new wxMask(*this,wxColour(image.GetMaskRed(),image.GetMaskGreen(),image.GetMaskBlue())); return true; } void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp) { - if(!Ok()) + if(!IsOk()) return NULL; NSBitmapImageRep *bitmapRep = M_BITMAPDATA->m_cocoaNSBitmapImageRep; @@ -436,7 +520,7 @@ void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp) if([bitmapRep bitsPerPixel]!=bpp) { - wxFAIL_MSG( _T("incorrect bitmap type in wxBitmap::GetRawData()") ); + wxFAIL_MSG( wxT("incorrect bitmap type in wxBitmap::GetRawData()") ); return NULL; } data.m_width = [bitmapRep pixelsWide]; @@ -492,15 +576,23 @@ wxMask::wxMask(const wxBitmap& bitmap) Create(bitmap); } +// Copy constructor +wxMask::wxMask(const wxMask& src) +: wxObject(src) +, m_cocoaNSBitmapImageRep(wxGCSafeRetain(src.m_cocoaNSBitmapImageRep)) +{ +} + wxMask::~wxMask() { - [m_cocoaNSBitmapImageRep release]; + wxGCSafeRelease(m_cocoaNSBitmapImageRep); } // Create a mask from a mono bitmap (copies the bitmap). bool wxMask::Create(const wxBitmap& bitmap) { // TODO + wxLogDebug(wxT("Cannot yet create a mask from a mono bitmap")); return FALSE; } @@ -509,6 +601,7 @@ bool wxMask::Create(const wxBitmap& bitmap) bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex) { // TODO + wxLogDebug(wxT("Cannot yet create a mask from a palette bitmap")); return FALSE; } @@ -564,7 +657,7 @@ static bool wxMask_CreateFromBitmapData(PixelData srcData, const wxColour& colou bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) { wxAutoNSAutoreleasePool pool; - if(!bitmap.Ok()) + if(!bitmap.IsOk()) return false; int bmpWidth = bitmap.GetWidth(); int bmpHeight = bitmap.GetHeight(); @@ -615,11 +708,18 @@ bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) wxCHECK_MSG(wxMask_CreateFromBitmapData(pixelData, colour, dstData), false, wxT("Unable to access raw data")); } + else if([srcBitmapRep bitsPerPixel]==8 && [srcBitmapRep bitsPerSample]==8 && [srcBitmapRep samplesPerPixel]==1 && [srcBitmapRep hasAlpha]==NO) + // 8-bpp Grayscale, no alpha + { // Force all RGB to access the same grayscale component + typedef wxPixelFormat<unsigned char,8,0,0,0> PixelFormat; + wxPixelData<wxBitmap,PixelFormat> pixelData(const_cast<wxBitmap&>(bitmap)); + wxCHECK_MSG(wxMask_CreateFromBitmapData(pixelData, colour, dstData), + false, wxT("Unable to access raw data")); + } else { wxCHECK_MSG(false,false,wxT("Unimplemented pixel format")); } // maskRep was autoreleased in case we had to exit quickly - m_cocoaNSBitmapImageRep = [maskRep retain]; + m_cocoaNSBitmapImageRep = wxGCSafeRetain(maskRep); return true; } -