X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ab13160e71d925cd16c561574af5a9cd4af69268..2aa24b607061a398d0876b87e695f4f9dc531cb2:/src/cocoa/bitmap.mm diff --git a/src/cocoa/bitmap.mm b/src/cocoa/bitmap.mm index 1c6b4cb021..97d7712b1e 100644 --- a/src/cocoa/bitmap.mm +++ b/src/cocoa/bitmap.mm @@ -6,23 +6,29 @@ // Created: 2003/07/19 // RCS-ID: $Id$ // Copyright: (c) 2003 David Elliott -// Licence: wxWindows licence +// Licence: wxWidgets licence ///////////////////////////////////////////////////////////////////////////// -#include "wx/setup.h" -#include "wx/utils.h" -#include "wx/palette.h" +#include "wx/wxprec.h" +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/palette.h" + #include "wx/icon.h" + #include "wx/colour.h" +#endif //WX_PRECOMP #include "wx/bitmap.h" -#include "wx/icon.h" -#include "wx/log.h" #include "wx/image.h" #include "wx/xpmdecod.h" +#include "wx/rawbmp.h" #include "wx/cocoa/autorelease.h" #include "wx/cocoa/string.h" #import #import +#import +#import // ======================================================================== // wxBitmapRefData @@ -141,6 +147,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) @@ -270,7 +302,7 @@ bool wxBitmap::Create(int w, int h, int d) bytesPerRow: 0 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; @@ -324,9 +356,28 @@ 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; + 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 @@ -336,9 +387,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); + 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::CreateFromXpm(const char **xpm) @@ -390,10 +458,45 @@ bool wxBitmap::CreateFromImage(const wxImage& image, int depth) M_BITMAPDATA->m_numColors = 0; M_BITMAPDATA->m_quality = 0; M_BITMAPDATA->m_cocoaNSBitmapImageRep = bitmapImage; - M_BITMAPDATA->m_bitmapMask = NULL; + 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()) + return NULL; + + NSBitmapImageRep *bitmapRep = M_BITMAPDATA->m_cocoaNSBitmapImageRep; + if(!bitmapRep) + return NULL; + + if([bitmapRep bitsPerPixel]!=bpp) + { + wxFAIL_MSG( _T("incorrect bitmap type in wxBitmap::GetRawData()") ); + return NULL; + } + data.m_width = [bitmapRep pixelsWide]; + data.m_height = [bitmapRep pixelsHigh]; + data.m_stride = [bitmapRep bytesPerRow]; + return [bitmapRep bitmapData]; + + // NOTE: It is up to the user to make sure they used the proper + // pixel format class that details what is actually inside the pixels + // We can only check to make sure that the total number of bits per + // pixel are being iterated over properly + // NSBitmapImageRep can contain grayscale or CMYK data and + // wxPixelDataBase doesn't really define the color format +} + +void wxBitmap::UngetRawData(wxPixelDataBase& data) +{ // TODO +} + +void wxBitmap::UseAlpha() +{ // TODO +} + // ======================================================================== // wxMask // ======================================================================== @@ -402,18 +505,14 @@ IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject) wxMask::wxMask() { -/* TODO - m_maskBitmap = 0; -*/ + m_cocoaNSBitmapImageRep = nil; } // Construct a mask from a bitmap and a colour indicating // the transparent area wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour) { -/* TODO - m_maskBitmap = 0; -*/ + m_cocoaNSBitmapImageRep = nil; Create(bitmap, colour); } @@ -421,9 +520,7 @@ wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour) // the transparent area wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex) { -/* TODO - m_maskBitmap = 0; -*/ + m_cocoaNSBitmapImageRep = nil; Create(bitmap, paletteIndex); } @@ -431,16 +528,14 @@ wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex) // Construct a mask from a mono bitmap (copies the bitmap). wxMask::wxMask(const wxBitmap& bitmap) { -/* TODO - m_maskBitmap = 0; -*/ + m_cocoaNSBitmapImageRep = nil; Create(bitmap); } wxMask::~wxMask() { -// TODO: delete mask bitmap + [m_cocoaNSBitmapImageRep release]; } // Create a mask from a mono bitmap (copies the bitmap). @@ -458,11 +553,114 @@ bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex) return FALSE; } +template +static bool wxMask_CreateFromBitmapData(PixelData srcData, const wxColour& colour, unsigned char *dstData) +{ + 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 + const int dstRowLength = (nCols+7)/8; + // Number of source columns that fit into a byte in the destination + const int width_aligned = nCols/8*8; + for(int y=0; y0) + *dstByte = 0; + for(int j=0; j<(nCols%8); ++j, ++p) + { + *dstByte += + ( p.Red()!=colour.Red() + || p.Green()!=colour.Green() + || p.Blue()!=colour.Blue() + ) << (7-j); + } + p = rowStart; + p.OffsetY(srcData,1); + } + return true; +} + // Create a mask from a bitmap and a colour indicating // the transparent area bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) { -// TODO - return FALSE; + wxAutoNSAutoreleasePool pool; + if(!bitmap.Ok()) + return false; + int bmpWidth = bitmap.GetWidth(); + int bmpHeight = bitmap.GetHeight(); + int dstRowLength = (bmpWidth+7)/8; + + // Create a bitmap image rep with 1-bit per pixel data representing + // the alpha channel padded such that rows end on byte boundaries + // Since NSBitmapImageRep doesn't have any sort of NSNullColorSpace + // we must have at least one channel of non-alpha data. In order to + // make our life easy, we use planar data which results in two + // separate arrays. We don't need to touch the first because it + // should never be used. The second is the 1-bit "alpha" data. + NSBitmapImageRep *maskRep = [[[NSBitmapImageRep alloc] + initWithBitmapDataPlanes:NULL pixelsWide:bmpWidth + pixelsHigh:bmpHeight bitsPerSample:1 + samplesPerPixel:2 hasAlpha:YES isPlanar:YES + colorSpaceName:NSCalibratedWhiteColorSpace + bytesPerRow:dstRowLength bitsPerPixel:1] autorelease]; + wxCHECK(maskRep,false); + + // We need the source NSBitmapImageRep to detemine its pixel format + 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, 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, 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]; + return true; }