X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a24aff654fb10971e82abccc1b56217d556d447b..eea4d01c65f9b29baa1193db762b4c6b8144af24:/src/cocoa/bitmap.mm diff --git a/src/cocoa/bitmap.mm b/src/cocoa/bitmap.mm index ed803d8085..16ca2a7847 100644 --- a/src/cocoa/bitmap.mm +++ b/src/cocoa/bitmap.mm @@ -1,30 +1,66 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: bitmap.cpp +// Name: src/cocoa/bitmap.mm // Purpose: wxBitmap -// Author: AUTHOR +// Author: David Elliott // Modified by: -// Created: ??/??/98 +// Created: 2003/07/19 // RCS-ID: $Id$ -// Copyright: (c) AUTHOR +// Copyright: (c) 2003 David Elliott // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "bitmap.h" -#endif +#include "wx/wxprec.h" -#include "wx/setup.h" -#include "wx/utils.h" -#include "wx/palette.h" #include "wx/bitmap.h" -#include "wx/icon.h" -#include "wx/log.h" -#include "wx/image.h" -#if !USE_SHARED_LIBRARIES -IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject) -IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject) -#endif +#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/xpmdecod.h" +#include "wx/rawbmp.h" + +#include "wx/cocoa/autorelease.h" +#include "wx/cocoa/string.h" +#include "wx/cocoa/ObjcRef.h" + +#import +#import +#import +#import + +IMPLEMENT_ABSTRACT_CLASS(wxBitmapHandler, wxBitmapHandlerBase) + +// ======================================================================== +// wxBitmapRefData +// ======================================================================== + +class wxBitmapRefData: public wxGDIRefData +{ + friend class wxBitmap; +public: + wxBitmapRefData(); + wxBitmapRefData( const wxBitmapRefData& data ); + virtual ~wxBitmapRefData(); + + virtual bool IsOk() const { return m_ok; } + +protected: + int m_width; + int m_height; + int m_depth; + bool m_ok; + int m_numColors; + wxPalette m_bitmapPalette; + int m_quality; + WX_NSBitmapImageRep m_cocoaNSBitmapImageRep; + wxMask *m_bitmapMask; // Optional mask +}; wxBitmapRefData::wxBitmapRefData() { @@ -34,32 +70,49 @@ wxBitmapRefData::wxBitmapRefData() m_depth = 0; m_quality = 0; m_numColors = 0; + m_cocoaNSBitmapImageRep = nil; m_bitmapMask = NULL; } +wxBitmapRefData::wxBitmapRefData( const wxBitmapRefData& data) +{ + wxAutoNSAutoreleasePool pool; + + m_width = data.m_width; + m_height = data.m_height; + m_depth = data.m_depth; + m_ok = data.m_ok; + m_numColors = data.m_numColors; + m_bitmapPalette = data.m_bitmapPalette; + m_quality = data.m_quality; + m_cocoaNSBitmapImageRep = wxGCSafeRetain([[data.m_cocoaNSBitmapImageRep copyWithZone:nil] autorelease]); + m_bitmapMask = data.m_bitmapMask?new wxMask(*data.m_bitmapMask):NULL; +} + wxBitmapRefData::~wxBitmapRefData() { - /* - * TODO: delete the bitmap data here. - */ + wxGCSafeRelease(m_cocoaNSBitmapImageRep); + m_cocoaNSBitmapImageRep = NULL; - if (m_bitmapMask) - delete m_bitmapMask; + delete m_bitmapMask; m_bitmapMask = NULL; } +// ======================================================================== +// wxBitmap +// ======================================================================== + +#define M_BITMAPDATA ((wxBitmapRefData *)m_refData) + +IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject) + wxBitmap::wxBitmap() { m_refData = NULL; - - if ( wxTheBitmapList ) - wxTheBitmapList->AddBitmap(this); } wxBitmap::~wxBitmap() { - if (wxTheBitmapList) - wxTheBitmapList->DeleteObject(this); } wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits) @@ -72,111 +125,79 @@ wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits M_BITMAPDATA->m_numColors = 0; /* TODO: create the bitmap from data */ - - if ( wxTheBitmapList ) - wxTheBitmapList->AddBitmap(this); } -wxBitmap::wxBitmap(int w, int h, int d) +wxBitmap::wxBitmap(NSImage* cocoaNSImage) { - (void)Create(w, h, d); + (void) Create(cocoaNSImage); +} - if ( wxTheBitmapList ) - wxTheBitmapList->AddBitmap(this); +wxBitmap::wxBitmap(NSBitmapImageRep* cocoaNSBitmapImageRep) +{ + (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); - - if ( wxTheBitmapList ) - wxTheBitmapList->AddBitmap(this); } wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type) { LoadFile(filename, type); - - if ( wxTheBitmapList ) - wxTheBitmapList->AddBitmap(this); } -wxBitmap::wxBitmap(const wxImage& image, int depth) +wxGDIRefData *wxBitmap::CreateGDIRefData() const { + return new wxBitmapRefData; } -wxBitmap::wxBitmap(char **bits) +wxGDIRefData *wxBitmap::CloneGDIRefData(const wxGDIRefData *data) const { + return new wxBitmapRefData(*(wxBitmapRefData*)data); } -/* TODO: maybe allow creation from XPM -// Create from data -wxBitmap::wxBitmap(const char **data) +WX_NSBitmapImageRep wxBitmap::GetNSBitmapImageRep() { - (void) Create((void *)data, wxBITMAP_TYPE_XPM_DATA, 0, 0, 0); + if(!M_BITMAPDATA) + return NULL; + return M_BITMAPDATA->m_cocoaNSBitmapImageRep; } -*/ -bool wxBitmap::Create(int w, int h, int d) +WX_NSImage wxBitmap::GetNSImage(bool useMask) const { - UnRef(); - - m_refData = new wxBitmapRefData; - - M_BITMAPDATA->m_width = w; - M_BITMAPDATA->m_height = h; - M_BITMAPDATA->m_depth = d; - - /* TODO: create new bitmap */ - - return M_BITMAPDATA->m_ok; -} - -bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type) -{ - UnRef(); - - m_refData = new wxBitmapRefData; - - wxBitmapHandler *handler = FindHandler(type); - - if ( handler == NULL ) { - wxLogWarning("no bitmap handler for type %d defined.", type); - - return FALSE; - } - - return handler->LoadFile(this, filename, type, -1, -1); -} - -bool wxBitmap::Create(void *data, wxBitmapType type, int width, int height, int depth) -{ - UnRef(); - - m_refData = new wxBitmapRefData; - - wxBitmapHandler *handler = FindHandler(type); - - if ( handler == NULL ) { - wxLogWarning("no bitmap handler for type %d defined.", type); - - return FALSE; + if(!IsOk()) + 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 handler->Create(this, data, type, width, height, depth); + return nsimage; } -bool wxBitmap::SaveFile(const wxString& filename, wxBitmapType type, const wxPalette *palette) const +void wxBitmap::SetNSBitmapImageRep(WX_NSBitmapImageRep bitmapImageRep) { - wxBitmapHandler *handler = FindHandler(type); - - if ( handler == NULL ) { - wxLogWarning("no bitmap handler for type %d defined.", type); - - return FALSE; - } - - return handler->SaveFile(this, filename, type, palette); + if(!M_BITMAPDATA) + return; + // NOTE: No checking is done to make sure width/height agree + wxGCSafeRetain(bitmapImageRep); + wxGCSafeRelease(M_BITMAPDATA->m_cocoaNSBitmapImageRep); + M_BITMAPDATA->m_cocoaNSBitmapImageRep = bitmapImageRep; } void wxBitmap::SetWidth(int w) @@ -235,185 +256,470 @@ void wxBitmap::SetMask(wxMask *mask) M_BITMAPDATA->m_bitmapMask = mask ; } -/* - * wxMask - */ +wxPalette* wxBitmap::GetPalette() const +{ + if(!m_refData) + return NULL; + return &M_BITMAPDATA->m_bitmapPalette; +} -wxMask::wxMask() +wxMask* wxBitmap::GetMask() const { -/* TODO - m_maskBitmap = 0; -*/ + if(!m_refData) + return NULL; + return M_BITMAPDATA->m_bitmapMask; } -// Construct a mask from a bitmap and a colour indicating -// the transparent area -wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour) +int wxBitmap::GetDepth() const { -/* TODO - m_maskBitmap = 0; -*/ - Create(bitmap, colour); + if(!m_refData) + return 0; + return M_BITMAPDATA->m_depth; } -// Construct a mask from a bitmap and a palette index indicating -// the transparent area -wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex) +int wxBitmap::GetWidth() const { -/* TODO - m_maskBitmap = 0; -*/ + if(!m_refData) + return 0; + return M_BITMAPDATA->m_width; +} - Create(bitmap, paletteIndex); +int wxBitmap::GetHeight() const +{ + if(!m_refData) + return 0; + return M_BITMAPDATA->m_height; } -// Construct a mask from a mono bitmap (copies the bitmap). -wxMask::wxMask(const wxBitmap& bitmap) +bool wxBitmap::Create(int w, int h, int d) { -/* TODO - m_maskBitmap = 0; -*/ + wxAutoNSAutoreleasePool pool; - Create(bitmap); + UnRef(); + + m_refData = new wxBitmapRefData; + + M_BITMAPDATA->m_width = w; + M_BITMAPDATA->m_height = h; + M_BITMAPDATA->m_depth = d; + + /* TODO: create new bitmap */ + M_BITMAPDATA->m_cocoaNSBitmapImageRep = wxGCSafeRetain([[[NSBitmapImageRep alloc] + initWithBitmapDataPlanes: NULL + pixelsWide: w + pixelsHigh: h + bitsPerSample: 8 + samplesPerPixel: 3 + hasAlpha: NO + isPlanar: NO + colorSpaceName: NSCalibratedRGBColorSpace + 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; + M_BITMAPDATA->m_numColors = 0; + M_BITMAPDATA->m_quality = 0; + M_BITMAPDATA->m_bitmapMask = NULL; + + return M_BITMAPDATA->m_ok; } -wxMask::~wxMask() +bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type) { -// TODO: delete mask bitmap + wxAutoNSAutoreleasePool pool; + UnRef(); + + m_refData = new wxBitmapRefData; + + NSBitmapImageRep *imageRep = [NSBitmapImageRep + imageRepWithContentsOfFile:wxNSStringWithWxString(filename)]; + + if(imageRep) + { + M_BITMAPDATA->m_width = [imageRep pixelsWide]; + M_BITMAPDATA->m_height = [imageRep pixelsHigh]; + M_BITMAPDATA->m_depth = 24; // FIXME + 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; + } + wxImage image; + if(!image.LoadFile(filename,type)) + return false; + if(!image.IsOk()) + return false; + *this = wxBitmap(image); + return true; } -// Create a mask from a mono bitmap (copies the bitmap). -bool wxMask::Create(const wxBitmap& bitmap) +bool wxBitmap::Create(NSImage* cocoaNSImage) { -// TODO - return FALSE; + wxAutoNSAutoreleasePool pool; + NSBitmapImageRep *bitmapImageRep = [NSBitmapImageRep imageRepWithData:[cocoaNSImage TIFFRepresentation]]; + return Create(bitmapImageRep); } -// Create a mask from a bitmap and a palette index indicating -// the transparent area -bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex) +bool wxBitmap::Create(NSBitmapImageRep *imageRep) { -// TODO - return FALSE; + 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; } -// Create a mask from a bitmap and a colour indicating -// the transparent area -bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) +bool wxBitmap::Create(const void* data, wxBitmapType type, int width, int height, int depth) { -// TODO - return FALSE; -} + UnRef(); -/* - * wxBitmapHandler - */ + m_refData = new wxBitmapRefData; -IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject) + return false; +} -wxBitmapHandler::~wxBitmapHandler() +bool wxBitmap::SaveFile(const wxString& filename, wxBitmapType type, const wxPalette *palette) const { + return false; } -bool wxBitmapHandler::Create(wxBitmap *bitmap, void *data, long type, int width, int height, int depth) +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] 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; } -bool wxBitmapHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long type, - int desiredWidth, int desiredHeight) +wxBitmap wxBitmap::GetSubBitmap(const wxRect& rect) const { - return FALSE; + wxAutoNSAutoreleasePool pool; + if(!IsOk()) + return wxNullBitmap; + NSImage *nsimage = GetNSImage(false); + + [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(rect.width) / GetWidth(); + imageRect.size.height *= static_cast(rect.height) / GetHeight(); + + NSBitmapImageRep *newBitmapRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:imageRect]; + [nsimage unlockFocus]; + + wxBitmap newBitmap(newBitmapRep); + + return (newBitmap); } -bool wxBitmapHandler::SaveFile(const wxBitmap *bitmap, const wxString& name, int type, const wxPalette *palette) +wxImage wxBitmap::ConvertToImage() const { - return FALSE; + 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; } -/* - * Standard handlers - */ +bool wxBitmap::CreateFromImage(const wxImage& image, int depth) +{ + wxAutoNSAutoreleasePool pool; + UnRef(); + + 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] + initWithBitmapDataPlanes: NULL + pixelsWide: image.GetWidth() + pixelsHigh: image.GetHeight() + bitsPerSample: 8 + samplesPerPixel: 3 + hasAlpha: NO + isPlanar: NO + colorSpaceName: NSCalibratedRGBColorSpace + 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 + M_BITMAPDATA->m_depth = 24; + M_BITMAPDATA->m_ok = true; + M_BITMAPDATA->m_numColors = 0; + M_BITMAPDATA->m_quality = 0; + M_BITMAPDATA->m_cocoaNSBitmapImageRep = wxGCSafeRetain(bitmapImage); + M_BITMAPDATA->m_bitmapMask = new wxMask(*this,wxColour(image.GetMaskRed(),image.GetMaskGreen(),image.GetMaskBlue())); + return true; +} -/* TODO: bitmap handlers, a bit like this: -class WXDLLEXPORT wxBMPResourceHandler: public wxBitmapHandler +void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp) { - DECLARE_DYNAMIC_CLASS(wxBMPResourceHandler) -public: - inline wxBMPResourceHandler() + if(!IsOk()) + return NULL; + + NSBitmapImageRep *bitmapRep = M_BITMAPDATA->m_cocoaNSBitmapImageRep; + if(!bitmapRep) + return NULL; + + if([bitmapRep bitsPerPixel]!=bpp) { - m_name = "Windows bitmap resource"; - m_extension = ""; - m_type = wxBITMAP_TYPE_BMP_RESOURCE; - }; + wxFAIL_MSG( wxT("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]; - virtual bool LoadFile(wxBitmap *bitmap, const wxString& name, long flags, - int desiredWidth, int desiredHeight); -}; -IMPLEMENT_DYNAMIC_CLASS(wxBMPResourceHandler, wxBitmapHandler) -*/ + // 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::InitStandardHandlers() -{ -/* TODO: initialize all standard bitmap or derive class handlers here. - AddHandler(new wxBMPResourceHandler); - AddHandler(new wxBMPFileHandler); - AddHandler(new wxXPMFileHandler); - AddHandler(new wxXPMDataHandler); - AddHandler(new wxICOResourceHandler); - AddHandler(new wxICOFileHandler); -*/ +void wxBitmap::UngetRawData(wxPixelDataBase& data) +{ // TODO } -bool wxBitmap::CopyFromIcon(const wxIcon& icno) +// ======================================================================== +// wxMask +// ======================================================================== + +IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject) + +wxMask::wxMask() { - return false; + m_cocoaNSBitmapImageRep = nil; } -wxPalette* wxBitmap::GetPalette() const +// Construct a mask from a bitmap and a colour indicating +// the transparent area +wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour) { - return NULL; + m_cocoaNSBitmapImageRep = nil; + Create(bitmap, colour); } -wxBitmap wxBitmap::GetSubBitmap(wxRect const&) const +// Construct a mask from a bitmap and a palette index indicating +// the transparent area +wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex) { - return wxNullBitmap; + m_cocoaNSBitmapImageRep = nil; + + Create(bitmap, paletteIndex); } -wxImage wxBitmap::ConvertToImage() const +// Construct a mask from a mono bitmap (copies the bitmap). +wxMask::wxMask(const wxBitmap& bitmap) { - return wxNullImage; + m_cocoaNSBitmapImageRep = nil; + + Create(bitmap); } -bool wxBitmap::Ok() const +// Copy constructor +wxMask::wxMask(const wxMask& src) +: wxObject(src) +, m_cocoaNSBitmapImageRep(wxGCSafeRetain(src.m_cocoaNSBitmapImageRep)) { - return FALSE; } -wxMask* wxBitmap::GetMask() const +wxMask::~wxMask() { - return NULL; + wxGCSafeRelease(m_cocoaNSBitmapImageRep); } -int wxBitmap::GetDepth() const +// Create a mask from a mono bitmap (copies the bitmap). +bool wxMask::Create(const wxBitmap& bitmap) { - return 0; +// TODO + wxLogDebug(wxT("Cannot yet create a mask from a mono bitmap")); + return FALSE; } -int wxBitmap::GetWidth() const +// Create a mask from a bitmap and a palette index indicating +// the transparent area +bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex) { - return 0; +// TODO + wxLogDebug(wxT("Cannot yet create a mask from a palette bitmap")); + return FALSE; } -int wxBitmap::GetHeight() const +template +static bool wxMask_CreateFromBitmapData(PixelData srcData, const wxColour& colour, unsigned char *dstData) { - return 0; + 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; } - -bool wxBitmap::CreateFromXpm(const char **) +// Create a mask from a bitmap and a colour indicating +// the transparent area +bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) { - return false; -} + wxAutoNSAutoreleasePool pool; + if(!bitmap.IsOk()) + 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 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,wxT("Unimplemented pixel format")); } -// vim:sts=4:sw=4:syn=cpp:et + // maskRep was autoreleased in case we had to exit quickly + m_cocoaNSBitmapImageRep = wxGCSafeRetain(maskRep); + return true; +}