X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e9576ca53db96b462ed4c0b4bdf47d64c40203e4..ad42b67c35ddcf8df2075ab582c9b64525756d09:/src/mac/carbon/bitmap.cpp?ds=sidebyside diff --git a/src/mac/carbon/bitmap.cpp b/src/mac/carbon/bitmap.cpp index 1e6255f551..394ba8c733 100644 --- a/src/mac/carbon/bitmap.cpp +++ b/src/mac/carbon/bitmap.cpp @@ -13,18 +13,333 @@ #pragma implementation "bitmap.h" #endif -#include "wx/setup.h" -#include "wx/utils.h" -#include "wx/palette.h" +#include "wx/defs.h" + #include "wx/bitmap.h" #include "wx/icon.h" #include "wx/log.h" +#include "wx/image.h" +#include "wx/xpmdecod.h" -#if !USE_SHARED_LIBRARIES IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject) IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject ) + +#ifdef __DARWIN__ + #include +#else + #include #endif +#include "wx/mac/uma.h" + +CTabHandle wxMacCreateColorTable( int numColors ) +{ + CTabHandle newColors; /* Handle to the new color table */ + + /* Allocate memory for the color table */ + newColors = (CTabHandle)NewHandleClear( sizeof (ColorTable) + + sizeof (ColorSpec) * (numColors - 1) ); + if (newColors != nil) + { + /* Initialize the fields */ + (**newColors).ctSeed = GetCTSeed(); + (**newColors).ctFlags = 0; + (**newColors).ctSize = numColors - 1; + /* Initialize the table of colors */ + } + return newColors ; +} + +void wxMacDestroyColorTable( CTabHandle colors ) +{ + DisposeHandle( (Handle) colors ) ; +} + +void wxMacSetColorTableEntry( CTabHandle newColors , int index , int red , int green , int blue ) +{ + (**newColors).ctTable[index].value = index; + (**newColors).ctTable[index].rgb.red = 0 ;// someRedValue; + (**newColors).ctTable[index].rgb.green = 0 ; // someGreenValue; + (**newColors).ctTable[index].rgb.blue = 0 ; // someBlueValue; +} + +GWorldPtr wxMacCreateGWorld( int width , int height , int depth ) +{ + OSErr err = noErr ; + GWorldPtr port ; + Rect rect = { 0 , 0 , height , width } ; + + if ( depth < 0 ) + { + depth = wxDisplayDepth() ; + } + + err = NewGWorld( &port , depth , &rect , NULL , NULL , 0 ) ; + if ( err == noErr ) + { + return port ; + } + return NULL ; +} + +void wxMacDestroyGWorld( GWorldPtr gw ) +{ + if ( gw ) + DisposeGWorld( gw ) ; +} + +#define kDefaultRes 0x00480000 /* Default resolution is 72 DPI; Fixed type */ + +OSErr SetupCIconHandlePixMap( CIconHandle icon , short depth , Rect *bounds , CTabHandle colors ) +{ + CTabHandle newColors; /* Color table used for the off-screen PixMap */ + Ptr offBaseAddr; /* Pointer to the off-screen pixel image */ + OSErr error; /* Returns error code */ + short bytesPerRow; /* Number of bytes per row in the PixMap */ + + + error = noErr; + newColors = nil; + offBaseAddr = nil; + + bytesPerRow = ((depth * (bounds->right - bounds->left) + 31) / 32) * 4; + + /* Clone the clut if indexed color; allocate a dummy clut if direct color*/ + if (depth <= 8) + { + newColors = colors; + error = HandToHand((Handle *) &newColors); + } + else + { + newColors = (CTabHandle) NewHandle(sizeof(ColorTable) - + sizeof(CSpecArray)); + error = MemError(); + } + if (error == noErr) + { + /* Allocate pixel image; long integer multiplication avoids overflow */ + (**icon).iconData = NewHandle((unsigned long) bytesPerRow * (bounds->bottom - + bounds->top)); + if ((**icon).iconData != nil) + { + /* Initialize fields common to indexed and direct PixMaps */ + (**icon).iconPMap.baseAddr = 0; /* Point to image */ + (**icon).iconPMap.rowBytes = bytesPerRow | /* MSB set for PixMap */ + 0x8000; + (**icon).iconPMap.bounds = *bounds; /* Use given bounds */ + (**icon).iconPMap.pmVersion = 0; /* No special stuff */ + (**icon).iconPMap.packType = 0; /* Default PICT pack */ + (**icon).iconPMap.packSize = 0; /* Always zero in mem */ + (**icon).iconPMap.hRes = kDefaultRes; /* 72 DPI default res */ + (**icon).iconPMap.vRes = kDefaultRes; /* 72 DPI default res */ + (**icon).iconPMap.pixelSize = depth; /* Set # bits/pixel */ + + /* Initialize fields specific to indexed and direct PixMaps */ + if (depth <= 8) + { + /* PixMap is indexed */ + (**icon).iconPMap.pixelType = 0; /* Indicates indexed */ + (**icon).iconPMap.cmpCount = 1; /* Have 1 component */ + (**icon).iconPMap.cmpSize = depth; /* Component size=depth */ + (**icon).iconPMap.pmTable = newColors; /* Handle to CLUT */ + } + else + { + /* PixMap is direct */ + (**icon).iconPMap.pixelType = RGBDirect; /* Indicates direct */ + (**icon).iconPMap.cmpCount = 3; /* Have 3 components */ + if (depth == 16) + (**icon).iconPMap.cmpSize = 5; /* 5 bits/component */ + else + (**icon).iconPMap.cmpSize = 8; /* 8 bits/component */ + (**newColors).ctSeed = 3 * (**icon).iconPMap.cmpSize; + (**newColors).ctFlags = 0; + (**newColors).ctSize = 0; + (**icon).iconPMap.pmTable = newColors; + } + } + else + error = MemError(); + } + else + newColors = nil; + + /* If no errors occured, return a handle to the new off-screen PixMap */ + if (error != noErr) + { + if (newColors != nil) + DisposeCTable(newColors); + } + + /* Return the error code */ + return error; +} + +CIconHandle wxMacCreateCIcon(GWorldPtr image , GWorldPtr mask , short dstDepth , short iconSize ) +{ + GWorldPtr saveWorld; + GDHandle saveHandle; + + GetGWorld(&saveWorld,&saveHandle); // save Graphics env state + SetGWorld(image,nil); + + Rect frame = { 0 , 0 , iconSize , iconSize } ; + Rect imageBounds = frame ; + GetPortBounds( image , &imageBounds ) ; + + int bwSize = iconSize / 8 * iconSize ; + CIconHandle icon = (CIconHandle) NewHandleClear( sizeof ( CIcon ) + 2 * bwSize) ; + HLock((Handle)icon) ; + SetupCIconHandlePixMap( icon , dstDepth , &frame,GetCTable(dstDepth)) ; + HLock( (**icon).iconData ) ; + (**icon).iconPMap.baseAddr = *(**icon).iconData ; + + LockPixels(GetGWorldPixMap(image)); + + CopyBits(GetPortBitMapForCopyBits(image), + (BitMapPtr)&((**icon).iconPMap), + &imageBounds, + &imageBounds, + srcCopy | ditherCopy, nil); + + + UnlockPixels(GetGWorldPixMap(image)); + HUnlock( (**icon).iconData ) ; + + (**icon).iconMask.rowBytes = iconSize / 8 ; + (**icon).iconMask.bounds = frame ; + + (**icon).iconBMap.rowBytes = iconSize / 8 ; + (**icon).iconBMap.bounds = frame ; + (**icon).iconMask.baseAddr = (char*) &(**icon).iconMaskData ; + (**icon).iconBMap.baseAddr = (char*) &(**icon).iconMaskData + bwSize ; + + if ( mask ) + { + LockPixels(GetGWorldPixMap(mask) ) ; + CopyBits(GetPortBitMapForCopyBits(mask) , + &(**icon).iconBMap , &imageBounds , &imageBounds, srcCopy , nil ) ; + CopyBits(GetPortBitMapForCopyBits(mask) , + &(**icon).iconMask , &imageBounds , &imageBounds, srcCopy , nil ) ; + UnlockPixels(GetGWorldPixMap( mask ) ) ; + } + else + { + LockPixels(GetGWorldPixMap(image)); + CopyBits(GetPortBitMapForCopyBits(image) , + &(**icon).iconBMap , &imageBounds , &imageBounds, srcCopy , nil ) ; + CopyBits(GetPortBitMapForCopyBits(image) , + &(**icon).iconMask , &imageBounds , &imageBounds, srcCopy , nil ) ; + UnlockPixels(GetGWorldPixMap(image)); + } + + (**icon).iconMask.baseAddr = NULL ; + (**icon).iconBMap.baseAddr = NULL ; + (**icon).iconPMap.baseAddr = NULL ; + HUnlock((Handle)icon) ; + SetGWorld(saveWorld,saveHandle); + + return icon; +} + +PicHandle wxMacCreatePict(GWorldPtr wp, GWorldPtr mask) +{ + CGrafPtr origPort ; + GDHandle origDev ; + + PicHandle pict; + + RGBColor white = { 0xffff ,0xffff , 0xffff } ; + RGBColor black = { 0x0000 ,0x0000 , 0x0000 } ; + + GetGWorld( &origPort , &origDev ) ; + + RgnHandle clipRgn = NULL ; + + if ( mask ) + { + clipRgn = NewRgn() ; + LockPixels( GetGWorldPixMap( mask ) ) ; + BitMapToRegion( clipRgn , (BitMap*) *GetGWorldPixMap( mask ) ) ; + UnlockPixels( GetGWorldPixMap( mask ) ) ; + } + + SetGWorld( wp , NULL ) ; + Rect portRect ; + GetPortBounds( wp , &portRect ) ; + + pict = OpenPicture(&portRect); + if(pict) + { + RGBForeColor( &black ) ; + RGBBackColor( &white ) ; + + LockPixels( GetGWorldPixMap( wp ) ) ; + CopyBits(GetPortBitMapForCopyBits(wp), + GetPortBitMapForCopyBits(wp), + &portRect, + &portRect, + srcCopy,clipRgn); + UnlockPixels( GetGWorldPixMap( wp ) ) ; + ClosePicture(); + } + SetGWorld( origPort , origDev ) ; + return pict; +} + +void wxMacCreateBitmapButton( ControlButtonContentInfo*info , const wxBitmap& bitmap ) +{ + memset( info , 0 , sizeof(ControlButtonContentInfo) ) ; + if ( bitmap.Ok() ) + { + wxBitmapRefData * bmap = (wxBitmapRefData*) ( bitmap.GetRefData()) ; + if ( bmap == NULL ) + return ; + + if ( bmap->m_bitmapType == kMacBitmapTypePict ) + { + info->contentType = kControlContentPictHandle ; + info->u.picture = MAC_WXHMETAFILE(bmap->m_hPict) ; + } + else if ( bmap->m_bitmapType == kMacBitmapTypeGrafWorld ) + { + if ( (bmap->m_width == bmap->m_height) && (bmap->m_width & 0x3 == 0) ) + { + info->contentType = kControlContentCIconHandle ; + if ( bitmap.GetMask() ) + { + info->u.cIconHandle = wxMacCreateCIcon( MAC_WXHBITMAP(bmap->m_hBitmap) , MAC_WXHBITMAP(bitmap.GetMask()->GetMaskBitmap()) , + 8 , bmap->m_width ) ; + } + else + { + info->u.cIconHandle = wxMacCreateCIcon( MAC_WXHBITMAP(bmap->m_hBitmap) , NULL , + 8 , bmap->m_width ) ; + } + } + else + { + info->contentType = kControlContentPictHandle ; + if ( bitmap.GetMask() ) + { + info->u.picture = wxMacCreatePict( MAC_WXHBITMAP(bmap->m_hBitmap) , MAC_WXHBITMAP(bitmap.GetMask()->GetMaskBitmap() ) ) ; + } + else + { + info->u.picture = wxMacCreatePict( MAC_WXHBITMAP(bmap->m_hBitmap) , NULL ) ; + } + } + } + else if ( bmap->m_bitmapType == kMacBitmapTypeIcon ) + { + info->contentType = kControlContentCIconHandle ; + info->u.cIconHandle = MAC_WXHICON(bmap->m_hIcon) ; + } + } +} + wxBitmapRefData::wxBitmapRefData() { m_ok = FALSE; @@ -34,33 +349,72 @@ wxBitmapRefData::wxBitmapRefData() m_quality = 0; m_numColors = 0; m_bitmapMask = NULL; + m_hBitmap = NULL ; + m_hPict = NULL ; + m_hIcon = NULL ; + m_bitmapType = kMacBitmapTypeUnknownType ; } -wxBitmapRefData::~wxBitmapRefData() +// TODO move this do a public function of Bitmap Ref +static void DisposeBitmapRefData(wxBitmapRefData *data) { - /* - * TODO: delete the bitmap data here. - */ + switch (data->m_bitmapType) + { + case kMacBitmapTypePict : + { + if ( data->m_hPict ) + { + KillPicture( MAC_WXHMETAFILE( data->m_hPict ) ) ; + data->m_hPict = NULL ; + } + } + break ; + case kMacBitmapTypeGrafWorld : + { + if ( data->m_hBitmap ) + { + wxMacDestroyGWorld( MAC_WXHBITMAP(data->m_hBitmap) ) ; + data->m_hBitmap = NULL ; + } + } + break ; + case kMacBitmapTypeIcon : + if ( data->m_hIcon ) + { + DisposeCIcon( MAC_WXHICON(data->m_hIcon) ) ; + data->m_hIcon = NULL ; + } + + default : + // unkown type ? + break ; + } + + if (data->m_bitmapMask) + { + delete data->m_bitmapMask; + data->m_bitmapMask = NULL; + } +} - if (m_bitmapMask) - delete m_bitmapMask; - m_bitmapMask = NULL; +wxBitmapRefData::~wxBitmapRefData() +{ + DisposeBitmapRefData( this ) ; } -wxList wxBitmap::sm_handlers; +bool wxBitmap::CopyFromIcon(const wxIcon& icon) +{ + Ref(icon) ; + return true; +} 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) @@ -71,44 +425,181 @@ wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits M_BITMAPDATA->m_height = the_height ; M_BITMAPDATA->m_depth = no_bits ; M_BITMAPDATA->m_numColors = 0; - - /* TODO: create the bitmap from data */ - - if ( wxTheBitmapList ) - wxTheBitmapList->AddBitmap(this); + if ( no_bits == 1 ) + { + M_BITMAPDATA->m_bitmapType = kMacBitmapTypeGrafWorld ; + MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap) = wxMacCreateGWorld( the_width , the_height , no_bits ) ; + M_BITMAPDATA->m_ok = (MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap) != NULL ) ; + + CGrafPtr origPort ; + GDHandle origDevice ; + + GetGWorld( &origPort , &origDevice ) ; + SetGWorld( MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap) , NULL ) ; + LockPixels( GetGWorldPixMap( MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap) ) ) ; + + // bits is a char array + + unsigned char* linestart = (unsigned char*) bits ; + int linesize = ( the_width / (sizeof(unsigned char) * 8)) ; + if ( the_width % (sizeof(unsigned char) * 8) ) { + linesize += sizeof(unsigned char); + } + + RGBColor colors[2] = { + { 0xFFFF , 0xFFFF , 0xFFFF } , + { 0, 0 , 0 } + } ; + + for ( int y = 0 ; y < the_height ; ++y , linestart += linesize ) + { + for ( int x = 0 ; x < the_width ; ++x ) + { + int index = x / 8 ; + int bit = x % 8 ; + int mask = 1 << bit ; + if ( linestart[index] & mask ) + { + SetCPixel( x , y , &colors[1] ) ; + } + else + { + SetCPixel( x , y , &colors[0] ) ; + } + } + } + UnlockPixels( GetGWorldPixMap( MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap) ) ) ; + + SetGWorld( origPort , origDevice ) ; + } + else + { + wxFAIL_MSG(wxT("multicolor BITMAPs not yet implemented")); + } } wxBitmap::wxBitmap(int w, int h, int d) { (void)Create(w, h, d); - - if ( wxTheBitmapList ) - wxTheBitmapList->AddBitmap(this); } -wxBitmap::wxBitmap(void *data, long type, int width, int height, int depth) +wxBitmap::wxBitmap(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); } -wxBitmap::wxBitmap(const wxString& filename, long type) +bool wxBitmap::CreateFromXpm(const char **bits) { - LoadFile(filename, (int)type); + wxCHECK_MSG( bits != NULL, FALSE, wxT("invalid bitmap data") ) + wxXPMDecoder decoder; + wxImage img = decoder.ReadData(bits); + wxCHECK_MSG( img.Ok(), FALSE, wxT("invalid bitmap data") ) + *this = wxBitmap(img); + return TRUE; +} - if ( wxTheBitmapList ) - wxTheBitmapList->AddBitmap(this); +wxBitmap::wxBitmap(const char **bits) +{ + (void) CreateFromXpm(bits); } -/* TODO: maybe allow creation from XPM -// Create from data -wxBitmap::wxBitmap(const char **data) +wxBitmap::wxBitmap(char **bits) { - (void) Create((void *)data, wxBITMAP_TYPE_XPM_DATA, 0, 0, 0); + (void) CreateFromXpm((const char **)bits); +} + +wxBitmap wxBitmap::GetSubBitmap(const wxRect &rect) const +{ + wxCHECK_MSG( Ok() && + (rect.x >= 0) && (rect.y >= 0) && + (rect.x+rect.width <= GetWidth()) && + (rect.y+rect.height <= GetHeight()), + wxNullBitmap, wxT("invalid bitmap or bitmap region") ); + + + wxBitmap ret( rect.width, rect.height, GetDepth() ); + wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") ); + + GWorldPtr origPort; + GDHandle origDevice; + + GetGWorld( &origPort, &origDevice ); + + // Update the subbitmaps reference data + wxBitmapRefData *ref = (wxBitmapRefData *)ret.GetRefData(); + + ref->m_numColors = M_BITMAPDATA->m_numColors; + ref->m_bitmapPalette = M_BITMAPDATA->m_bitmapPalette; + ref->m_bitmapType = M_BITMAPDATA->m_bitmapType; + + // Copy sub region of this bitmap + if(M_BITMAPDATA->m_bitmapType == kMacBitmapTypePict) + { + printf("GetSubBitmap: Copy a region of a Pict structure - TODO\n"); + } + else if(M_BITMAPDATA->m_bitmapType == kMacBitmapTypeGrafWorld) + { + // Copy mask + if(GetMask()) + { + GWorldPtr submask, mask; + RGBColor color; + + mask = (GWorldPtr) GetMask()->GetMaskBitmap(); + submask = wxMacCreateGWorld(rect.width, rect.height, 1); + LockPixels(GetGWorldPixMap(mask)); + LockPixels(GetGWorldPixMap(submask)); + + for(int yy = 0; yy < rect.height; yy++) + { + for(int xx = 0; xx < rect.width; xx++) + { + SetGWorld(mask, NULL); + GetCPixel(rect.x + xx, rect.y + yy, &color); + SetGWorld(submask, NULL); + SetCPixel(xx,yy, &color); + } + } + UnlockPixels(GetGWorldPixMap(mask)); + UnlockPixels(GetGWorldPixMap(submask)); + ref->m_bitmapMask = new wxMask; + ref->m_bitmapMask->SetMaskBitmap(submask); + } + + // Copy bitmap + if(GetHBITMAP()) + { + GWorldPtr subbitmap, bitmap; + RGBColor color; + + bitmap = (GWorldPtr) GetHBITMAP(); + subbitmap = (GWorldPtr) ref->m_hBitmap ; + LockPixels(GetGWorldPixMap(bitmap)); + LockPixels(GetGWorldPixMap(subbitmap)); + + for(int yy = 0; yy < rect.height; yy++) + { + for(int xx = 0; xx < rect.width; xx++) + { + SetGWorld(bitmap, NULL); + GetCPixel(rect.x + xx, rect.y + yy, &color); + SetGWorld(subbitmap, NULL); + SetCPixel(xx, yy, &color); + } + } + UnlockPixels(GetGWorldPixMap(bitmap)); + UnlockPixels(GetGWorldPixMap(subbitmap)); + } + } + SetGWorld( origPort, origDevice ); + + return ret; } -*/ bool wxBitmap::Create(int w, int h, int d) { @@ -120,29 +611,53 @@ bool wxBitmap::Create(int w, int h, int d) M_BITMAPDATA->m_height = h; M_BITMAPDATA->m_depth = d; - /* TODO: create new bitmap */ - + M_BITMAPDATA->m_bitmapType = kMacBitmapTypeGrafWorld ; + M_BITMAPDATA->m_hBitmap = wxMacCreateGWorld( w , h , d ) ; + M_BITMAPDATA->m_ok = ( M_BITMAPDATA->m_hBitmap != NULL ) ; return M_BITMAPDATA->m_ok; } -bool wxBitmap::LoadFile(const wxString& filename, long type) +int wxBitmap::GetBitmapType() const { - UnRef(); + wxCHECK_MSG( Ok(), kMacBitmapTypeUnknownType, wxT("invalid bitmap") ); - m_refData = new wxBitmapRefData; + return M_BITMAPDATA->m_bitmapType; +} + +void wxBitmap::SetHBITMAP(WXHBITMAP bmp) +{ + DisposeBitmapRefData( M_BITMAPDATA ) ; + + M_BITMAPDATA->m_bitmapType = kMacBitmapTypeGrafWorld ; + M_BITMAPDATA->m_hBitmap = bmp ; + M_BITMAPDATA->m_ok = ( M_BITMAPDATA->m_hBitmap != NULL ) ; +} + +bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type) +{ + UnRef(); wxBitmapHandler *handler = FindHandler(type); - if ( handler == NULL ) { - wxLogWarning("no bitmap handler for type %d defined.", type); + if ( handler ) + { + m_refData = new wxBitmapRefData; - return FALSE; + return handler->LoadFile(this, filename, type, -1, -1); } - - return handler->LoadFile(this, filename, type, -1, -1); + else + { + wxImage loadimage(filename, type); + if (loadimage.Ok()) { + *this = loadimage; + return true; + } + } + wxLogWarning("no bitmap handler for type %d defined.", type); + return false; } -bool wxBitmap::Create(void *data, long type, int width, int height, int depth) +bool wxBitmap::Create(void *data, wxBitmapType type, int width, int height, int depth) { UnRef(); @@ -159,17 +674,209 @@ bool wxBitmap::Create(void *data, long type, int width, int height, int depth) return handler->Create(this, data, type, width, height, depth); } -bool wxBitmap::SaveFile(const wxString& filename, int type, const wxPalette *palette) +wxBitmap::wxBitmap(const wxImage& image, int depth) +{ + wxCHECK_RET( image.Ok(), wxT("invalid image") ) + wxCHECK_RET( depth == -1, wxT("invalid bitmap depth") ) + + m_refData = new wxBitmapRefData(); + + // width and height of the device-dependent bitmap + int width = image.GetWidth(); + int height = image.GetHeight(); + + // Create picture + + Create( width , height , 32 ) ; + + CGrafPtr origPort ; + GDHandle origDevice ; + + PixMapHandle pixMap = GetGWorldPixMap((GWorldPtr)GetHBITMAP()) ; + LockPixels( pixMap ); + + GetGWorld( &origPort , &origDevice ) ; + SetGWorld( (GWorldPtr) GetHBITMAP() , NULL ) ; + + // Render image + RGBColor colorRGB ; + + register unsigned char* data = image.GetData(); + char* destinationBase = GetPixBaseAddr( pixMap ); + register unsigned char* destination = (unsigned char*) destinationBase ; + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + *destination++ = 0 ; + *destination++ = *data++ ; + *destination++ = *data++ ; + *destination++ = *data++ ; + } + destinationBase += ((**pixMap).rowBytes & 0x7fff); + destination = (unsigned char*) destinationBase ; + } + if ( image.HasMask() ) + { + data = image.GetData(); + + wxColour maskcolor(image.GetMaskRed(), image.GetMaskGreen(), image.GetMaskBlue()); + RGBColor white = { 0xffff, 0xffff, 0xffff }; + RGBColor black = { 0 , 0 , 0 }; + wxBitmap maskBitmap ; + + maskBitmap.Create( width, height, 1); + LockPixels( GetGWorldPixMap( (GWorldPtr) maskBitmap.GetHBITMAP()) ); + SetGWorld( (GWorldPtr) maskBitmap.GetHBITMAP(), NULL); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + if ( data[0] == image.GetMaskRed() && data[1] == image.GetMaskGreen() && data[2] == image.GetMaskBlue() ) + { + SetCPixel(x,y, &white); + } + else { + SetCPixel(x,y, &black); + } + data += 3 ; + } + } // for height + SetGWorld( (GWorldPtr) GetHBITMAP(), NULL); + SetMask(new wxMask( maskBitmap )); + UnlockPixels( GetGWorldPixMap( (GWorldPtr) maskBitmap.GetHBITMAP()) ); + } + + UnlockPixels( GetGWorldPixMap( (GWorldPtr) GetHBITMAP()) ); + SetGWorld( origPort, origDevice ); +} + +wxImage wxBitmap::ConvertToImage() const +{ + wxImage image; + + wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") ); + + // create an wxImage object + int width = GetWidth(); + int height = GetHeight(); + image.Create( width, height ); + + unsigned char *data = image.GetData(); + + wxCHECK_MSG( data, wxNullImage, wxT("Could not allocate data for image") ); + + GWorldPtr origPort; + GDHandle origDevice; + int index; + RGBColor color; + // background color set to RGB(16,16,16) in consistent with wxGTK + unsigned char mask_r=16, mask_g=16, mask_b=16; + SInt16 r,g,b; + wxMask *mask = GetMask(); + + GetGWorld( &origPort, &origDevice ); + LockPixels(GetGWorldPixMap( (GWorldPtr) GetHBITMAP())); + SetGWorld( (GWorldPtr) GetHBITMAP(), NULL); + + // Copy data into image + index = 0; + for (int yy = 0; yy < height; yy++) + { + for (int xx = 0; xx < width; xx++) + { + GetCPixel(xx,yy, &color); + r = ((color.red ) >> 8); + g = ((color.green ) >> 8); + b = ((color.blue ) >> 8); + data[index ] = r; + data[index + 1] = g; + data[index + 2] = b; + if (mask) + { + if (mask->PointMasked(xx,yy)) + { + data[index ] = mask_r; + data[index + 1] = mask_g; + data[index + 2] = mask_b; + } + } + index += 3; + } + } + if (mask) + { + image.SetMaskColour( mask_r, mask_g, mask_b ); + image.SetMask( true ); + } + + // Free resources + UnlockPixels(GetGWorldPixMap( (GWorldPtr) GetHBITMAP())); + SetGWorld(origPort, origDevice); + + return image; +} + + +bool wxBitmap::SaveFile(const wxString& filename, wxBitmapType type, + const wxPalette *palette) const { wxBitmapHandler *handler = FindHandler(type); - if ( handler == NULL ) { - wxLogWarning("no bitmap handler for type %d defined.", type); + if ( handler ) + { + return handler->SaveFile(this, filename, type, palette); + } + else + { + wxImage image = ConvertToImage(); - return FALSE; - } + return image.SaveFile(filename, type); + } + + wxLogWarning("no bitmap handler for type %d defined.", type); + return false; +} + +bool wxBitmap::Ok() const +{ + return (M_BITMAPDATA && M_BITMAPDATA->m_ok); +} + +int wxBitmap::GetHeight() const +{ + wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") ); + + return M_BITMAPDATA->m_height; +} + +int wxBitmap::GetWidth() const +{ + wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") ); + + return M_BITMAPDATA->m_width; +} + +int wxBitmap::GetDepth() const +{ + wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") ); + + return M_BITMAPDATA->m_depth; +} + +int wxBitmap::GetQuality() const +{ + wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") ); + + return M_BITMAPDATA->m_quality; +} + +wxMask *wxBitmap::GetMask() const +{ + wxCHECK_MSG( Ok(), (wxMask *) NULL, wxT("invalid bitmap") ); - return handler->SaveFile(this, filename, type, palette); + return M_BITMAPDATA->m_bitmapMask; } void wxBitmap::SetWidth(int w) @@ -212,6 +919,13 @@ void wxBitmap::SetOk(bool isOk) M_BITMAPDATA->m_ok = isOk; } +wxPalette *wxBitmap::GetPalette() const +{ + wxCHECK_MSG( Ok(), NULL, wxT("Invalid bitmap GetPalette()") ); + + return &M_BITMAPDATA->m_bitmapPalette; +} + void wxBitmap::SetPalette(const wxPalette& palette) { if (!M_BITMAPDATA) @@ -225,69 +939,110 @@ void wxBitmap::SetMask(wxMask *mask) if (!M_BITMAPDATA) m_refData = new wxBitmapRefData; - M_BITMAPDATA->m_bitmapMask = mask ; -} + // Remove existing mask if there is one. + if (M_BITMAPDATA->m_bitmapMask) + delete M_BITMAPDATA->m_bitmapMask; -void wxBitmap::AddHandler(wxBitmapHandler *handler) -{ - sm_handlers.Append(handler); -} - -void wxBitmap::InsertHandler(wxBitmapHandler *handler) -{ - sm_handlers.Insert(handler); -} - -bool wxBitmap::RemoveHandler(const wxString& name) -{ - wxBitmapHandler *handler = FindHandler(name); - if ( handler ) - { - sm_handlers.DeleteObject(handler); - return TRUE; - } - else - return FALSE; + M_BITMAPDATA->m_bitmapMask = mask ; } -wxBitmapHandler *wxBitmap::FindHandler(const wxString& name) +WXHBITMAP wxBitmap::GetHBITMAP() const { - wxNode *node = sm_handlers.First(); - while ( node ) - { - wxBitmapHandler *handler = (wxBitmapHandler *)node->Data(); - if ( handler->GetName() == name ) - return handler; - node = node->Next(); - } - return NULL; -} + wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") ); -wxBitmapHandler *wxBitmap::FindHandler(const wxString& extension, long bitmapType) -{ - wxNode *node = sm_handlers.First(); - while ( node ) - { - wxBitmapHandler *handler = (wxBitmapHandler *)node->Data(); - if ( handler->GetExtension() == extension && - (bitmapType == -1 || handler->GetType() == bitmapType) ) - return handler; - node = node->Next(); - } - return NULL; + return MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap); } -wxBitmapHandler *wxBitmap::FindHandler(long bitmapType) +WXHMETAFILE wxBitmap::GetPict() const { - wxNode *node = sm_handlers.First(); - while ( node ) - { - wxBitmapHandler *handler = (wxBitmapHandler *)node->Data(); - if (handler->GetType() == bitmapType) - return handler; - node = node->Next(); - } - return NULL; + wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") ); + + PicHandle picture; // This is the returned picture + + // If bitmap already in Pict format return pointer + if(M_BITMAPDATA->m_bitmapType == kMacBitmapTypePict) { + return M_BITMAPDATA->m_hPict; + } + else if(M_BITMAPDATA->m_bitmapType != kMacBitmapTypeGrafWorld) { + // Invalid bitmap + return NULL; + } + + RGBColor gray = { 0xCCCC ,0xCCCC , 0xCCCC } ; + RGBColor white = { 0xffff ,0xffff , 0xffff } ; + RGBColor black = { 0x0000 ,0x0000 , 0x0000 } ; + CGrafPtr origPort; + GDHandle origDev ; + wxMask *mask; + Rect portRect ; + + GetPortBounds( (GWorldPtr) GetHBITMAP() , &portRect ) ; + int width = portRect.right - portRect.left ; + int height = portRect.bottom - portRect.top ; + + LockPixels( GetGWorldPixMap( (GWorldPtr) GetHBITMAP() ) ) ; + GetGWorld( &origPort , &origDev ) ; + + mask = GetMask(); + + SetGWorld( (GWorldPtr) GetHBITMAP() , NULL ) ; + + picture = OpenPicture(&portRect); // open a picture, this disables drawing + if(!picture) { + return NULL; + } + + if( mask ) + { +#ifdef __DARWIN__ + RGBColor trans = white; +#else + RGBBackColor( &gray ); + EraseRect( &portRect ); + RGBColor trans = gray; +#endif + RGBForeColor( &black ) ; + RGBBackColor( &white ) ; + PenMode(transparent); + + for ( int y = 0 ; y < height ; ++y ) + { + for( int x = 0 ; x < width ; ++x ) + { + if ( !mask->PointMasked(x,y) ) + { + RGBColor col ; + + GetCPixel( x + portRect.left , y + portRect.top , &col ) ; + SetCPixel( x + portRect.left , y + portRect.top , &col ) ; + } + else { + // With transparency this sets a blank pixel + SetCPixel( x + portRect.left , y + portRect.top , &trans); + } + } + } + } + else + { + RGBBackColor( &gray ) ; + EraseRect(&portRect); + RGBForeColor( &black ) ; + RGBBackColor( &white ) ; + + CopyBits(GetPortBitMapForCopyBits( (GWorldPtr) GetHBITMAP()), + // src PixMap - we copy image over itself - + GetPortBitMapForCopyBits( (GWorldPtr) GetHBITMAP()), + // dst PixMap - no drawing occurs + &portRect, // srcRect - it will be recorded and compressed - + &portRect, // dstRect - into the picture that is open - + srcCopy,NULL); // copyMode and no clip region + } + ClosePicture(); // We are done recording the picture + UnlockPixels( GetGWorldPixMap( (GWorldPtr) GetHBITMAP() ) ) ; + SetGWorld( origPort , origDev ) ; + + return picture; // return our groovy pict handle } /* @@ -296,18 +1051,14 @@ wxBitmapHandler *wxBitmap::FindHandler(long bitmapType) wxMask::wxMask() { -/* TODO m_maskBitmap = 0; -*/ } // 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; -*/ Create(bitmap, colour); } @@ -315,33 +1066,55 @@ wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour) // the transparent area wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex) { -/* TODO m_maskBitmap = 0; -*/ - Create(bitmap, paletteIndex); } // Construct a mask from a mono bitmap (copies the bitmap). wxMask::wxMask(const wxBitmap& bitmap) { -/* TODO m_maskBitmap = 0; -*/ - Create(bitmap); } wxMask::~wxMask() { -// TODO: delete mask bitmap + if ( m_maskBitmap ) + { + wxMacDestroyGWorld( (GWorldPtr) m_maskBitmap ) ; + m_maskBitmap = NULL ; + } } // Create a mask from a mono bitmap (copies the bitmap). bool wxMask::Create(const wxBitmap& bitmap) { -// TODO - return FALSE; + if ( m_maskBitmap ) + { + wxMacDestroyGWorld( (GWorldPtr) m_maskBitmap ) ; + m_maskBitmap = NULL ; + } + wxCHECK_MSG( bitmap.GetBitmapType() == kMacBitmapTypeGrafWorld, false, + wxT("Cannot create mask from this bitmap type (TODO)")); + // other types would require a temporary bitmap. not yet implemented + + wxCHECK_MSG( bitmap.Ok(), false, wxT("Invalid bitmap")); + + wxCHECK_MSG(bitmap.GetDepth() == 1, false, + wxT("Cannot create mask from colour bitmap")); + + m_maskBitmap = wxMacCreateGWorld(bitmap.GetWidth(), bitmap.GetHeight(), 1); + Rect rect = { 0,0, bitmap.GetHeight(), bitmap.GetWidth() }; + + LockPixels( GetGWorldPixMap( (GWorldPtr) m_maskBitmap) ); + LockPixels( GetGWorldPixMap( (GWorldPtr) bitmap.GetHBITMAP()) ); + CopyBits(GetPortBitMapForCopyBits( (GWorldPtr) bitmap.GetHBITMAP()), + GetPortBitMapForCopyBits( (GWorldPtr) m_maskBitmap), + &rect, &rect, srcCopy, 0); + UnlockPixels( GetGWorldPixMap( (GWorldPtr) m_maskBitmap) ); + UnlockPixels( GetGWorldPixMap( (GWorldPtr) bitmap.GetHBITMAP()) ); + + return FALSE; } // Create a mask from a bitmap and a palette index indicating @@ -349,6 +1122,7 @@ bool wxMask::Create(const wxBitmap& bitmap) bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex) { // TODO + wxCHECK_MSG( 0, false, wxT("Not implemented")); return FALSE; } @@ -356,28 +1130,93 @@ bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex) // the transparent area bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) { -// TODO - return FALSE; + if ( m_maskBitmap ) + { + wxMacDestroyGWorld( (GWorldPtr) m_maskBitmap ) ; + m_maskBitmap = NULL ; + } + wxCHECK_MSG( bitmap.GetBitmapType() == kMacBitmapTypeGrafWorld, false, + wxT("Cannot create mask from this bitmap type (TODO)")); + // other types would require a temporary bitmap. not yet implemented + + wxCHECK_MSG( bitmap.Ok(), false, wxT("Illigal bitmap")); + + m_maskBitmap = wxMacCreateGWorld( bitmap.GetWidth() , bitmap.GetHeight() , 1 ); + LockPixels( GetGWorldPixMap( (GWorldPtr) m_maskBitmap ) ); + LockPixels( GetGWorldPixMap( (GWorldPtr) bitmap.GetHBITMAP() ) ); + RGBColor maskColor = MAC_WXCOLORREF(colour.GetPixel()); + + // this is not very efficient, but I can't think + // of a better way of doing it + CGrafPtr origPort ; + GDHandle origDevice ; + RGBColor col; + RGBColor colors[2] = { + { 0xFFFF, 0xFFFF, 0xFFFF }, + { 0, 0, 0 }}; + + GetGWorld( &origPort , &origDevice ) ; + for (int w = 0; w < bitmap.GetWidth(); w++) + { + for (int h = 0; h < bitmap.GetHeight(); h++) + { + SetGWorld( (GWorldPtr) bitmap.GetHBITMAP(), NULL ) ; + GetCPixel( w , h , &col ) ; + SetGWorld( (GWorldPtr) m_maskBitmap , NULL ) ; + if (col.red == maskColor.red && col.green == maskColor.green && col.blue == maskColor.blue) + { + SetCPixel( w , h , &colors[0] ) ; + } + else + { + SetCPixel( w , h , &colors[1] ) ; + } + } + } + UnlockPixels( GetGWorldPixMap( (CGrafPtr) m_maskBitmap ) ) ; + UnlockPixels( GetGWorldPixMap( (GWorldPtr) bitmap.GetHBITMAP() ) ) ; + SetGWorld( origPort , origDevice ) ; + + return TRUE; +} + +bool wxMask::PointMasked(int x, int y) +{ + GWorldPtr origPort; + GDHandle origDevice; + RGBColor color; + bool masked = true; + + GetGWorld( &origPort, &origDevice); + + //Set port to mask and see if it masked (1) or not ( 0 ) + SetGWorld( (GWorldPtr) m_maskBitmap, NULL); + LockPixels(GetGWorldPixMap( (GWorldPtr) m_maskBitmap)); + GetCPixel(x,y, &color); + masked = !(color.red == 0 && color.green == 0 && color.blue == 0); + UnlockPixels(GetGWorldPixMap( (GWorldPtr) m_maskBitmap)); + + SetGWorld( origPort, origDevice); + + return masked; } /* * wxBitmapHandler */ -IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject) - bool wxBitmapHandler::Create(wxBitmap *bitmap, void *data, long type, int width, int height, int depth) { return FALSE; } -bool wxBitmapHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long type, +bool wxBitmapHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long flags, int desiredWidth, int desiredHeight) { return FALSE; } -bool wxBitmapHandler::SaveFile(wxBitmap *bitmap, const wxString& name, int type, const wxPalette *palette) +bool wxBitmapHandler::SaveFile(const wxBitmap *bitmap, const wxString& name, int type, const wxPalette *palette) { return FALSE; } @@ -386,45 +1225,58 @@ bool wxBitmapHandler::SaveFile(wxBitmap *bitmap, const wxString& name, int type, * Standard handlers */ -/* TODO: bitmap handlers, a bit like this: -class WXDLLEXPORT wxBMPResourceHandler: public wxBitmapHandler +class WXDLLEXPORT wxPICTResourceHandler: public wxBitmapHandler { - DECLARE_DYNAMIC_CLASS(wxBMPResourceHandler) + DECLARE_DYNAMIC_CLASS(wxPICTResourceHandler) public: - inline wxBMPResourceHandler() + inline wxPICTResourceHandler() { - m_name = "Windows bitmap resource"; + m_name = "Macintosh Pict resource"; m_extension = ""; - m_type = wxBITMAP_TYPE_BMP_RESOURCE; + m_type = wxBITMAP_TYPE_PICT_RESOURCE; }; virtual bool LoadFile(wxBitmap *bitmap, const wxString& name, long flags, int desiredWidth, int desiredHeight); }; -IMPLEMENT_DYNAMIC_CLASS(wxBMPResourceHandler, wxBitmapHandler) -*/ +IMPLEMENT_DYNAMIC_CLASS(wxPICTResourceHandler, wxBitmapHandler) -void wxBitmap::CleanUpHandlers() +bool wxPICTResourceHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long flags, + int desiredWidth, int desiredHeight) { - wxNode *node = sm_handlers.First(); - while ( node ) + Str255 theName ; + +#if TARGET_CARBON + c2pstrcpy( (StringPtr) theName , name ) ; +#else + strcpy( (char *) theName , name ) ; + c2pstr( (char *)theName ) ; +#endif + + PicHandle thePict = (PicHandle ) GetNamedResource( 'PICT' , theName ) ; + if ( thePict ) { - wxBitmapHandler *handler = (wxBitmapHandler *)node->Data(); - wxNode *next = node->Next(); - delete handler; - delete node; - node = next; + PictInfo theInfo ; + + GetPictInfo( thePict , &theInfo , 0 , 0 , systemMethod , 0 ) ; + DetachResource( (Handle) thePict ) ; + M_BITMAPHANDLERDATA->m_bitmapType = kMacBitmapTypePict ; + M_BITMAPHANDLERDATA->m_hPict = thePict ; + M_BITMAPHANDLERDATA->m_width = theInfo.sourceRect.right - theInfo.sourceRect.left ; + M_BITMAPHANDLERDATA->m_height = theInfo.sourceRect.bottom - theInfo.sourceRect.top ; + + M_BITMAPHANDLERDATA->m_depth = theInfo.depth ; + M_BITMAPHANDLERDATA->m_ok = true ; + M_BITMAPHANDLERDATA->m_numColors = theInfo.uniqueColors ; +// M_BITMAPHANDLERDATA->m_bitmapPalette; +// M_BITMAPHANDLERDATA->m_quality; + return TRUE ; } + return FALSE ; } 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); -*/ + AddHandler(new wxPICTResourceHandler) ; + AddHandler(new wxICONResourceHandler) ; }