X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/016b064360b6018058a1c1cff688a055425956b1..d48687a0719620cc888072db31bb3814dea400ab:/src/cocoa/bitmap.mm diff --git a/src/cocoa/bitmap.mm b/src/cocoa/bitmap.mm index b630916a41..cddc8c192f 100644 --- a/src/cocoa/bitmap.mm +++ b/src/cocoa/bitmap.mm @@ -1,24 +1,27 @@ ///////////////////////////////////////////////////////////////////////////// -// 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: wxWindows licence +// Licence: wxWidgets 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" @@ -27,6 +30,10 @@ #import #import +#import +#import + +IMPLEMENT_ABSTRACT_CLASS(wxBitmapHandler, wxBitmapHandlerBase) // ======================================================================== // wxBitmapRefData @@ -118,7 +125,17 @@ wxBitmap::wxBitmap(int w, int h, int d) (void)Create(w, h, d); } -wxBitmap::wxBitmap(void *data, wxBitmapType type, int width, int height, int depth) +wxBitmap::wxBitmap(NSImage* cocoaNSImage) +{ + (void) Create(cocoaNSImage); +} + +wxBitmap::wxBitmap(NSBitmapImageRep* cocoaNSBitmapImageRep) +{ + (void) Create(cocoaNSBitmapImageRep); +} + +wxBitmap::wxBitmap(const void* data, wxBitmapType type, int width, int height, int depth) { (void) Create(data, type, width, height, depth); } @@ -145,6 +162,32 @@ WX_NSBitmapImageRep wxBitmap::GetNSBitmapImageRep() return M_BITMAPDATA->m_cocoaNSBitmapImageRep; } +WX_NSImage wxBitmap::GetNSImage(bool useMask) const +{ + if(!Ok()) + return nil; + NSImage *nsimage = [[[NSImage alloc] + initWithSize:NSMakeSize(GetWidth(), GetHeight())] autorelease]; + if(!nsimage) + return nil; + [nsimage addRepresentation: M_BITMAPDATA->m_cocoaNSBitmapImageRep]; + if(useMask && GetMask()) + { + // Show before/after to prove that the bitmap itself is not changed + // even though we just composited onto the NSImage + wxLogTrace(wxTRACE_COCOA,wxT("Before: bpp=%d"),[M_BITMAPDATA->m_cocoaNSBitmapImageRep bitsPerPixel]); + NSImage *maskImage = [[NSImage alloc] + initWithSize:NSMakeSize(GetWidth(), GetHeight())]; + [maskImage addRepresentation: GetMask()->GetNSBitmapImageRep()]; + [nsimage lockFocus]; + [maskImage compositeToPoint:NSZeroPoint operation:NSCompositeDestinationIn]; + [nsimage unlockFocus]; + [maskImage release]; + wxLogTrace(wxTRACE_COCOA,wxT("After: bpp=%d"),[M_BITMAPDATA->m_cocoaNSBitmapImageRep bitsPerPixel]); + } + return nsimage; +} + void wxBitmap::SetNSBitmapImageRep(WX_NSBitmapImageRep bitmapImageRep) { if(!M_BITMAPDATA) @@ -211,7 +254,7 @@ void wxBitmap::SetMask(wxMask *mask) M_BITMAPDATA->m_bitmapMask = mask ; } -bool wxBitmap::Ok() const +bool wxBitmap::IsOk() const { return m_refData && M_BITMAPDATA->m_ok; } @@ -271,10 +314,11 @@ bool wxBitmap::Create(int w, int h, int d) hasAlpha: NO isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace - bytesPerRow: 0 + bytesPerRow: 0 // NOTE: Contrary to Apple documentation Mac OS + // 10.4 will add padding bytes when 0 is used here bitsPerPixel: 0]; - wxLogDebug("M_BITMAPDATA=%p NSBitmapImageRep bitmapData=%p", M_BITMAPDATA, [M_BITMAPDATA->m_cocoaNSBitmapImageRep bitmapData]); + wxLogTrace(wxTRACE_COCOA,wxT("M_BITMAPDATA=%p NSBitmapImageRep bitmapData=%p"), M_BITMAPDATA, [M_BITMAPDATA->m_cocoaNSBitmapImageRep bitmapData]); M_BITMAPDATA->m_ok = true; M_BITMAPDATA->m_numColors = 0; M_BITMAPDATA->m_quality = 0; @@ -314,7 +358,34 @@ bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type) 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 = [imageRep retain]; + 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(); @@ -328,9 +399,31 @@ 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; + + 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]; + [icon.GetNSImage() unlockFocus]; + if(!newBitmapRep) + return false; + m_refData = new wxBitmapRefData; + M_BITMAPDATA->m_cocoaNSBitmapImageRep = 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; } wxBitmap wxBitmap::GetSubBitmap(wxRect const&) const @@ -340,27 +433,26 @@ wxBitmap wxBitmap::GetSubBitmap(wxRect const&) const wxImage wxBitmap::ConvertToImage() const { - if(!M_BITMAPDATA->m_ok) - return wxImage(5,5)/*wxNullImage*/; - return wxImage(M_BITMAPDATA->m_width,M_BITMAPDATA->m_height); -} - -bool wxBitmap::CreateFromXpm(const char **xpm) -{ -#if wxUSE_IMAGE && wxUSE_XPM - UnRef(); - - wxCHECK_MSG( xpm, false, wxT("invalid XPM data") ) - - wxXPMDecoder decoder; - wxImage img = decoder.ReadData(xpm); - wxCHECK_MSG( img.Ok(), false, wxT("invalid XPM data") ) - - *this = wxBitmap(img); - return true; -#else - return false; -#endif + wxAutoNSAutoreleasePool pool; + if(!Ok()) + 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) @@ -383,9 +475,11 @@ bool wxBitmap::CreateFromImage(const wxImage& image, int depth) hasAlpha: NO isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace - bytesPerRow: 0 + bytesPerRow: image.GetWidth()*3 bitsPerPixel: 0]; + // 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 @@ -465,6 +559,13 @@ wxMask::wxMask(const wxBitmap& bitmap) Create(bitmap); } +// Copy constructor +wxMask::wxMask(const wxMask& src) +: wxObject(src) +, m_cocoaNSBitmapImageRep([src.m_cocoaNSBitmapImageRep retain]) +{ +} + wxMask::~wxMask() { [m_cocoaNSBitmapImageRep release]; @@ -474,6 +575,7 @@ wxMask::~wxMask() bool wxMask::Create(const wxBitmap& bitmap) { // TODO + wxLogDebug(wxT("Cannot yet create a mask from a mono bitmap")); return FALSE; } @@ -482,14 +584,15 @@ 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; } -template +template static bool wxMask_CreateFromBitmapData(PixelData srcData, const wxColour& colour, unsigned char *dstData) { - wxCHECK_MSG(dstData,false,"Couldn't access mask data"); - class PixelData::Iterator p(srcData); + wxCHECK_MSG(dstData,false,wxT("Couldn't access mask data")); + typename PixelData::Iterator p(srcData); const int nRows = srcData.GetHeight(); const int nCols = srcData.GetWidth(); // Total number of bytes per destination column @@ -498,7 +601,7 @@ static bool wxMask_CreateFromBitmapData(PixelData srcData, const wxColour& colou const int width_aligned = nCols/8*8; for(int y=0; y0) + *dstByte = 0; for(int j=0; j<(nCols%8); ++j, ++p) { *dstByte += @@ -558,30 +662,47 @@ bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) wxCHECK(maskRep,false); // We need the source NSBitmapImageRep to detemine its pixel format - NSBitmapImageRep *srcBitmapRep = ((wxBitmapRefData*)bitmap.GetRefData())->m_cocoaNSBitmapImageRep; - wxCHECK_MSG(srcBitmapRep,false,"Can't create mask for an uninitialized bitmap"); + NSBitmapImageRep *srcBitmapRep = const_cast(bitmap).GetNSBitmapImageRep(); + wxCHECK_MSG(srcBitmapRep,false,wxT("Can't create mask for an uninitialized bitmap")); // Get a pointer to the destination data unsigned char *dstPlanes[5] = {NULL,NULL,NULL,NULL,NULL}; [maskRep getBitmapDataPlanes:dstPlanes]; unsigned char *dstData = dstPlanes[1]; + // The wxImage format (which we use whenever we imported from wxImage) if([srcBitmapRep bitsPerPixel]==24 && [srcBitmapRep bitsPerSample]==8 && [srcBitmapRep samplesPerPixel]==3 && [srcBitmapRep hasAlpha]==NO) { wxPixelData pixelData(const_cast(bitmap)); wxCHECK_MSG(wxMask_CreateFromBitmapData(pixelData, colour, dstData), - false, "Unable to access raw data"); + false, wxT("Unable to access raw data")); } + // 32-bpp RGBx (x=throw away, no alpha) + else if([srcBitmapRep bitsPerPixel]==32 && [srcBitmapRep bitsPerSample]==8 && [srcBitmapRep samplesPerPixel]==3 && [srcBitmapRep hasAlpha]==NO) + { + typedef wxPixelFormat PixelFormat; + wxPixelData pixelData(const_cast(bitmap)); + wxCHECK_MSG(wxMask_CreateFromBitmapData(pixelData, colour, dstData), + false, wxT("Unable to access raw data")); + } + // 32-bpp RGBA else if([srcBitmapRep bitsPerPixel]==32 && [srcBitmapRep bitsPerSample]==8 && [srcBitmapRep samplesPerPixel]==4 && [srcBitmapRep hasAlpha]==YES) { wxPixelData pixelData(const_cast(bitmap)); wxCHECK_MSG(wxMask_CreateFromBitmapData(pixelData, colour, dstData), - false, "Unable to access raw data"); + 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 PixelFormat; + wxPixelData pixelData(const_cast(bitmap)); + wxCHECK_MSG(wxMask_CreateFromBitmapData(pixelData, colour, dstData), + false, wxT("Unable to access raw data")); } else - { wxCHECK_MSG(false,false,"Unimplemented pixel format"); } + { wxCHECK_MSG(false,false,wxT("Unimplemented pixel format")); } // maskRep was autoreleased in case we had to exit quickly m_cocoaNSBitmapImageRep = [maskRep retain]; return true; } -