///////////////////////////////////////////////////////////////////////////// // Name: bitmap.cpp // Purpose: wxBitmap // Author: Julian Smart // Modified by: // Created: 04/01/98 // RCS-ID: $Id$ // Copyright: (c) Julian Smart and Markus Holzem // Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// // ============================================================================ // declarations // ============================================================================ // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- #ifdef __GNUG__ #pragma implementation "bitmap.h" #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include #include "wx/list.h" #include "wx/utils.h" #include "wx/app.h" #include "wx/palette.h" #include "wx/dcmemory.h" #include "wx/bitmap.h" #include "wx/icon.h" #endif #include "wx/msw/private.h" #include "wx/log.h" #if !defined(__WXMICROWIN__) #include "wx/msw/dib.h" #endif #include "wx/image.h" #include "wx/xpmdecod.h" // missing from mingw32 header #ifndef CLR_INVALID #define CLR_INVALID ((COLORREF)-1) #endif // no CLR_INVALID // ---------------------------------------------------------------------------- // macros // ---------------------------------------------------------------------------- IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject) IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject) IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject) // ============================================================================ // implementation // ============================================================================ // ---------------------------------------------------------------------------- // wxBitmapRefData // ---------------------------------------------------------------------------- wxBitmapRefData::wxBitmapRefData() { m_quality = 0; m_selectedInto = NULL; m_numColors = 0; m_bitmapMask = NULL; m_hBitmap = (WXHBITMAP) NULL; } void wxBitmapRefData::Free() { wxASSERT_MSG( !m_selectedInto, wxT("deleting bitmap still selected into wxMemoryDC") ); if ( m_hBitmap) { if ( !::DeleteObject((HBITMAP)m_hBitmap) ) { wxLogLastError(wxT("DeleteObject(hbitmap)")); } } delete m_bitmapMask; m_bitmapMask = NULL; } // ---------------------------------------------------------------------------- // wxBitmap creation // ---------------------------------------------------------------------------- // this function should be called from all wxBitmap ctors void wxBitmap::Init() { // m_refData = NULL; done in the base class ctor } #ifdef __WIN32__ bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon) { #ifndef __WXMICROWIN__ // it may be either HICON or HCURSOR HICON hicon = (HICON)icon.GetHandle(); ICONINFO iconInfo; if ( !::GetIconInfo(hicon, &iconInfo) ) { wxLogLastError(wxT("GetIconInfo")); return FALSE; } wxBitmapRefData *refData = new wxBitmapRefData; m_refData = refData; int w = icon.GetWidth(), h = icon.GetHeight(); refData->m_width = w; refData->m_height = h; refData->m_depth = wxDisplayDepth(); refData->m_hBitmap = (WXHBITMAP)iconInfo.hbmColor; // the mask returned by GetIconInfo() is inversed compared to the usual // wxWin convention refData->m_bitmapMask = new wxMask((WXHBITMAP) wxInvertMask(iconInfo.hbmMask, w, h)); // delete the old one now as we don't need it any more ::DeleteObject(iconInfo.hbmMask); #if WXWIN_COMPATIBILITY_2 refData->m_ok = TRUE; #endif // WXWIN_COMPATIBILITY_2 return TRUE; #else return FALSE; #endif } #endif // Win32 bool wxBitmap::CopyFromCursor(const wxCursor& cursor) { UnRef(); if ( !cursor.Ok() ) return FALSE; #ifdef __WIN16__ wxFAIL_MSG( _T("don't know how to convert cursor to bitmap") ); return FALSE; #else return CopyFromIconOrCursor(cursor); #endif // Win16 } bool wxBitmap::CopyFromIcon(const wxIcon& icon) { UnRef(); if ( !icon.Ok() ) return FALSE; // GetIconInfo() doesn't exist under Win16 and I don't know any other way // to create a bitmap from icon there - but using this way we won't have // the mask (FIXME) #ifdef __WIN16__ int width = icon.GetWidth(), height = icon.GetHeight(); // copy the icon to the bitmap ScreenHDC hdcScreen; HDC hdc = ::CreateCompatibleDC(hdcScreen); HBITMAP hbitmap = ::CreateCompatibleBitmap(hdcScreen, width, height); HBITMAP hbmpOld = (HBITMAP)::SelectObject(hdc, hbitmap); ::DrawIcon(hdc, 0, 0, GetHiconOf(icon)); ::SelectObject(hdc, hbmpOld); ::DeleteDC(hdc); wxBitmapRefData *refData = new wxBitmapRefData; m_refData = refData; refData->m_width = width; refData->m_height = height; refData->m_depth = wxDisplayDepth(); refData->m_hBitmap = (WXHBITMAP)hbitmap; #if WXWIN_COMPATIBILITY_2 refData->m_ok = TRUE; #endif // WXWIN_COMPATIBILITY_2 return TRUE; #else // Win32 return CopyFromIconOrCursor(icon); #endif // Win16/Win32 } wxBitmap::~wxBitmap() { } wxBitmap::wxBitmap(const char bits[], int width, int height, int depth) { Init(); #ifndef __WXMICROWIN__ wxBitmapRefData *refData = new wxBitmapRefData; m_refData = refData; refData->m_width = width; refData->m_height = height; refData->m_depth = depth; refData->m_numColors = 0; refData->m_selectedInto = NULL; char *data; if ( depth == 1 ) { // we assume that it is in XBM format which is not quite the same as // the format CreateBitmap() wants because the order of bytes in the // line is inversed! const size_t bytesPerLine = (width + 7) / 8; const size_t padding = bytesPerLine % 2; const size_t len = height * ( padding + bytesPerLine ); data = (char *)malloc(len); const char *src = bits; char *dst = data; for ( int rows = 0; rows < height; rows++ ) { for ( size_t cols = 0; cols < bytesPerLine; cols++ ) { unsigned char val = *src++; unsigned char reversed = 0; for ( int bits = 0; bits < 8; bits++) { reversed <<= 1; reversed |= (val & 0x01); val >>= 1; } *dst++ = reversed; } if ( padding ) *dst++ = 0; } } else { // bits should already be in Windows standard format data = (char *)bits; // const_cast is harmless } HBITMAP hbmp = ::CreateBitmap(width, height, 1, depth, data); if ( !hbmp ) { wxLogLastError(wxT("CreateBitmap")); } if ( data != bits ) { free(data); } SetHBITMAP((WXHBITMAP)hbmp); #endif } // Create from XPM data bool wxBitmap::CreateFromXpm(const char **data) { #if wxUSE_IMAGE && wxUSE_XPM Init(); wxCHECK_MSG( data != NULL, FALSE, wxT("invalid bitmap data") ) wxXPMDecoder decoder; wxImage img = decoder.ReadData(data); wxCHECK_MSG( img.Ok(), FALSE, wxT("invalid bitmap data") ) *this = wxBitmap(img); return TRUE; #else return FALSE; #endif } wxBitmap::wxBitmap(int w, int h, int d) { Init(); (void)Create(w, h, d); } wxBitmap::wxBitmap(void *data, long type, int width, int height, int depth) { Init(); (void)Create(data, type, width, height, depth); } wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type) { Init(); LoadFile(filename, (int)type); } bool wxBitmap::Create(int w, int h, int d) { UnRef(); m_refData = new wxBitmapRefData; GetBitmapData()->m_width = w; GetBitmapData()->m_height = h; GetBitmapData()->m_depth = d; HBITMAP hbmp; #ifndef __WXMICROWIN__ if ( d > 0 ) { hbmp = ::CreateBitmap(w, h, 1, d, NULL); if ( !hbmp ) { wxLogLastError(wxT("CreateBitmap")); } } else #endif { ScreenHDC dc; hbmp = ::CreateCompatibleBitmap(dc, w, h); if ( !hbmp ) { wxLogLastError(wxT("CreateCompatibleBitmap")); } GetBitmapData()->m_depth = wxDisplayDepth(); } SetHBITMAP((WXHBITMAP)hbmp); #if WXWIN_COMPATIBILITY_2 GetBitmapData()->m_ok = hbmp != 0; #endif // WXWIN_COMPATIBILITY_2 return Ok(); } // ---------------------------------------------------------------------------- // wxImage to/from conversions // ---------------------------------------------------------------------------- #if wxUSE_IMAGE bool wxBitmap::CreateFromImage( const wxImage& image, int depth ) { #ifdef __WXMICROWIN__ // Initial attempt at a simple-minded implementation. // The bitmap will always be created at the screen depth, // so the 'depth' argument is ignored. // TODO: transparency (create a mask image) HDC hScreenDC = ::GetDC(NULL); int screenDepth = ::GetDeviceCaps(hScreenDC, BITSPIXEL); HBITMAP hBitmap = ::CreateCompatibleBitmap(hScreenDC, image.GetWidth(), image.GetHeight()); if (hBitmap == NULL) { ::ReleaseDC(NULL, hScreenDC); return FALSE; } HDC hMemDC = ::CreateCompatibleDC(hScreenDC); ::ReleaseDC(NULL, hScreenDC); HBITMAP hOldBitmap = ::SelectObject(hMemDC, hBitmap); int i, j; for (i = 0; i < image.GetWidth(); i++) { for (j = 0; j < image.GetHeight(); j++) { unsigned char red = image.GetRed(i, j); unsigned char green = image.GetGreen(i, j); unsigned char blue = image.GetBlue(i, j); ::SetPixel(hMemDC, i, j, PALETTERGB(red, green, blue)); } } ::SelectObject(hMemDC, hOldBitmap); ::DeleteDC(hMemDC); m_refData = new wxBitmapRefData(); SetWidth(image.GetWidth()); SetHeight(image.GetHeight()); SetDepth(screenDepth); SetHBITMAP( (WXHBITMAP) hBitmap ); #if wxUSE_PALETTE // Copy the palette from the source image SetPalette(image.GetPalette()); #endif // wxUSE_PALETTE return TRUE; #else wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") ) m_refData = new wxBitmapRefData(); // sizeLimit is the MS upper limit for the DIB size #ifdef WIN32 int sizeLimit = 1024*768*3; #else int sizeLimit = 0x7fff ; #endif // width and height of the device-dependent bitmap int width = image.GetWidth(); int bmpHeight = image.GetHeight(); // calc the number of bytes per scanline and padding int bytePerLine = width*3; int sizeDWORD = sizeof( DWORD ); int lineBoundary = bytePerLine % sizeDWORD; int padding = 0; if( lineBoundary > 0 ) { padding = sizeDWORD - lineBoundary; bytePerLine += padding; } // calc the number of DIBs and heights of DIBs int numDIB = 1; int hRemain = 0; int height = sizeLimit/bytePerLine; if( height >= bmpHeight ) height = bmpHeight; else { numDIB = bmpHeight / height; hRemain = bmpHeight % height; if( hRemain >0 ) numDIB++; } // set bitmap parameters wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") ); SetWidth( width ); SetHeight( bmpHeight ); if (depth == -1) depth = wxDisplayDepth(); SetDepth( depth ); #if wxUSE_PALETTE // Copy the palette from the source image SetPalette(image.GetPalette()); #endif // wxUSE_PALETTE // create a DIB header int headersize = sizeof(BITMAPINFOHEADER); BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize ); wxCHECK_MSG( lpDIBh, FALSE, wxT("could not allocate memory for DIB header") ); // Fill in the DIB header lpDIBh->bmiHeader.biSize = headersize; lpDIBh->bmiHeader.biWidth = (DWORD)width; lpDIBh->bmiHeader.biHeight = (DWORD)(-height); lpDIBh->bmiHeader.biSizeImage = bytePerLine*height; // the general formula for biSizeImage: // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height; lpDIBh->bmiHeader.biPlanes = 1; lpDIBh->bmiHeader.biBitCount = 24; lpDIBh->bmiHeader.biCompression = BI_RGB; lpDIBh->bmiHeader.biClrUsed = 0; // These seem not really needed for our purpose here. lpDIBh->bmiHeader.biClrImportant = 0; lpDIBh->bmiHeader.biXPelsPerMeter = 0; lpDIBh->bmiHeader.biYPelsPerMeter = 0; // memory for DIB data unsigned char *lpBits; lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage ); if( !lpBits ) { wxFAIL_MSG( wxT("could not allocate memory for DIB") ); free( lpDIBh ); return FALSE; } // create and set the device-dependent bitmap HDC hdc = ::GetDC(NULL); HDC memdc = ::CreateCompatibleDC( hdc ); HBITMAP hbitmap; hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight ); ::SelectObject( memdc, hbitmap); #if wxUSE_PALETTE HPALETTE hOldPalette = 0; if (image.GetPalette().Ok()) { hOldPalette = ::SelectPalette(memdc, (HPALETTE) image.GetPalette().GetHPALETTE(), FALSE); ::RealizePalette(memdc); } #endif // wxUSE_PALETTE // copy image data into DIB data and then into DDB (in a loop) unsigned char *data = image.GetData(); int i, j, n; int origin = 0; unsigned char *ptdata = data; unsigned char *ptbits; for( n=0; n 1 && n == numDIB-1 && hRemain > 0 ) { // redefine height and size of the (possibly) last smaller DIB // memory is not reallocated height = hRemain; lpDIBh->bmiHeader.biHeight = (DWORD)(-height); lpDIBh->bmiHeader.biSizeImage = bytePerLine*height; } ptbits = lpBits; for( j=0; jbmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS ); // The above line is equivalent to the following two lines. // hbitmap = ::CreateCompatibleBitmap( hdc, width, height ); // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS); // or the following lines // hbitmap = ::CreateCompatibleBitmap( hdc, width, height ); // HDC memdc = ::CreateCompatibleDC( hdc ); // ::SelectObject( memdc, hbitmap); // ::SetDIBitsToDevice( memdc, 0, 0, width, height, // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS); // ::SelectObject( memdc, 0 ); // ::DeleteDC( memdc ); } SetHBITMAP( (WXHBITMAP) hbitmap ); #if wxUSE_PALETTE if (hOldPalette) SelectPalette(memdc, hOldPalette, FALSE); #endif // wxUSE_PALETTE // similarly, created an mono-bitmap for the possible mask if( image.HasMask() ) { hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL ); HGDIOBJ hbmpOld = ::SelectObject( memdc, hbitmap); if( numDIB == 1 ) height = bmpHeight; else height = sizeLimit/bytePerLine; lpDIBh->bmiHeader.biHeight = (DWORD)(-height); lpDIBh->bmiHeader.biSizeImage = bytePerLine*height; origin = 0; unsigned char r = image.GetMaskRed(); unsigned char g = image.GetMaskGreen(); unsigned char b = image.GetMaskBlue(); unsigned char zero = 0, one = 255; ptdata = data; for( n=0; n 1 && n == numDIB - 1 && hRemain > 0 ) { // redefine height and size of the (possibly) last smaller DIB // memory is not reallocated height = hRemain; lpDIBh->bmiHeader.biHeight = (DWORD)(-height); lpDIBh->bmiHeader.biSizeImage = bytePerLine*height; } ptbits = lpBits; for( int j=0; jSetMaskBitmap( (WXHBITMAP) hbitmap ); SetMask( mask ); // It will be deleted when the wxBitmap object is deleted (as of 01/1999) /* The following can also be used but is slow to run wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue()); wxMask *mask = new wxMask( *this, colour ); SetMask( mask ); */ ::SelectObject( memdc, hbmpOld ); } // free allocated resources ::DeleteDC( memdc ); ::ReleaseDC(NULL, hdc); free(lpDIBh); free(lpBits); #if WXWIN_COMPATIBILITY_2 // check the wxBitmap object GetBitmapData()->SetOk(); #endif // WXWIN_COMPATIBILITY_2 return TRUE; #endif } wxImage wxBitmap::ConvertToImage() const { #ifdef __WXMICROWIN__ // Initial attempt at a simple-minded implementation. // The bitmap will always be created at the screen depth, // so the 'depth' argument is ignored. // TODO: transparency (create a mask image) if (!Ok()) { wxFAIL_MSG( wxT("bitmap is invalid") ); return wxNullImage; } 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(); if( !data ) { wxFAIL_MSG( wxT("could not allocate data for image") ); return wxNullImage; } HDC hScreenDC = ::GetDC(NULL); HDC hMemDC = ::CreateCompatibleDC(hScreenDC); ::ReleaseDC(NULL, hScreenDC); HBITMAP hBitmap = (HBITMAP) GetHBITMAP(); HBITMAP hOldBitmap = ::SelectObject(hMemDC, hBitmap); int i, j; for (i = 0; i < GetWidth(); i++) { for (j = 0; j < GetHeight(); j++) { COLORREF color = ::GetPixel(hMemDC, i, j); unsigned char red = GetRValue(color); unsigned char green = GetGValue(color); unsigned char blue = GetBValue(color); image.SetRGB(i, j, red, green, blue); } } ::SelectObject(hMemDC, hOldBitmap); ::DeleteDC(hMemDC); #if wxUSE_PALETTE // Copy the palette from the source image if (GetPalette()) image.SetPalette(* GetPalette()); #endif // wxUSE_PALETTE return image; #else // __MICROWIN__ 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(); if( !data ) { wxFAIL_MSG( wxT("could not allocate data for image") ); return wxNullImage; } // calc the number of bytes per scanline and padding in the DIB int bytePerLine = width*3; int sizeDWORD = sizeof( DWORD ); int lineBoundary = bytePerLine % sizeDWORD; int padding = 0; if( lineBoundary > 0 ) { padding = sizeDWORD - lineBoundary; bytePerLine += padding; } // create a DIB header int headersize = sizeof(BITMAPINFOHEADER); BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize ); if( !lpDIBh ) { wxFAIL_MSG( wxT("could not allocate data for DIB header") ); free( data ); return wxNullImage; } // Fill in the DIB header lpDIBh->bmiHeader.biSize = headersize; lpDIBh->bmiHeader.biWidth = width; lpDIBh->bmiHeader.biHeight = -height; lpDIBh->bmiHeader.biSizeImage = bytePerLine * height; lpDIBh->bmiHeader.biPlanes = 1; lpDIBh->bmiHeader.biBitCount = 24; lpDIBh->bmiHeader.biCompression = BI_RGB; lpDIBh->bmiHeader.biClrUsed = 0; // These seem not really needed for our purpose here. lpDIBh->bmiHeader.biClrImportant = 0; lpDIBh->bmiHeader.biXPelsPerMeter = 0; lpDIBh->bmiHeader.biYPelsPerMeter = 0; // memory for DIB data unsigned char *lpBits; lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage ); if( !lpBits ) { wxFAIL_MSG( wxT("could not allocate data for DIB") ); free( data ); free( lpDIBh ); return wxNullImage; } // copy data from the device-dependent bitmap to the DIB HDC hdc = ::GetDC(NULL); HBITMAP hbitmap; hbitmap = (HBITMAP) GetHBITMAP(); ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS ); // copy DIB data into the wxImage object int i, j; unsigned char *ptdata = data; unsigned char *ptbits = lpBits; for( i=0; iGetMaskBitmap() ) { hbitmap = (HBITMAP) GetMask()->GetMaskBitmap(); // memory DC created, color set, data copied, and memory DC deleted HDC memdc = ::CreateCompatibleDC( hdc ); ::SetTextColor( memdc, RGB( 0, 0, 0 ) ); ::SetBkColor( memdc, RGB( 255, 255, 255 ) ); ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS ); ::DeleteDC( memdc ); // background color set to RGB(16,16,16) in consistent with wxGTK unsigned char r=16, g=16, b=16; ptdata = data; ptbits = lpBits; for( i=0; iLoadFile(this, filename, type, -1, -1); } #if wxUSE_IMAGE else { wxImage image; if ( image.LoadFile( filename, type ) && image.Ok() ) { *this = image.ConvertToBitmap(); return TRUE; } } #endif // wxUSE_IMAGE return FALSE; } bool wxBitmap::Create(void *data, long type, int width, int height, int depth) { UnRef(); wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler); if ( !handler ) { wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %d defined."), type); return FALSE; } m_refData = new wxBitmapRefData; return handler->Create(this, data, type, width, height, depth); } bool wxBitmap::SaveFile(const wxString& filename, int type, const wxPalette *palette) { wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler); if ( handler ) { return handler->SaveFile(this, filename, type, palette); } #if wxUSE_IMAGE else { // FIXME what about palette? shouldn't we use it? wxImage image( *this ); if ( image.Ok() ) { return image.SaveFile(filename, type); } } #endif // wxUSE_IMAGE return FALSE; } // ---------------------------------------------------------------------------- // sub bitmap extraction // ---------------------------------------------------------------------------- wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const { #ifndef __WXMICROWIN__ 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") ); // copy bitmap data HDC dcSrc = ::CreateCompatibleDC(NULL); HDC dcDst = ::CreateCompatibleDC(NULL); SelectObject(dcSrc, (HBITMAP) GetHBITMAP()); SelectObject(dcDst, (HBITMAP) ret.GetHBITMAP()); BitBlt(dcDst, 0, 0, rect.width, rect.height, dcSrc, rect.x, rect.y, SRCCOPY); // copy mask if there is one if (GetMask()) { HBITMAP hbmpMask = ::CreateBitmap(rect.width, rect.height, 1, 1, 0); SelectObject(dcSrc, (HBITMAP) GetMask()->GetMaskBitmap()); SelectObject(dcDst, (HBITMAP) hbmpMask); BitBlt(dcDst, 0, 0, rect.width, rect.height, dcSrc, rect.x, rect.y, SRCCOPY); wxMask *mask = new wxMask((WXHBITMAP) hbmpMask); ret.SetMask(mask); } SelectObject(dcDst, NULL); SelectObject(dcSrc, NULL); DeleteDC(dcDst); DeleteDC(dcSrc); return ret; #else return wxBitmap(); #endif } // ---------------------------------------------------------------------------- // wxBitmap accessors // ---------------------------------------------------------------------------- void wxBitmap::SetQuality(int q) { EnsureHasData(); GetBitmapData()->m_quality = q; } #if WXWIN_COMPATIBILITY_2 void wxBitmap::SetOk(bool isOk) { EnsureHasData(); GetBitmapData()->m_ok = isOk; } #endif // WXWIN_COMPATIBILITY_2 #if wxUSE_PALETTE void wxBitmap::SetPalette(const wxPalette& palette) { EnsureHasData(); GetBitmapData()->m_bitmapPalette = palette; } #endif // wxUSE_PALETTE void wxBitmap::SetMask(wxMask *mask) { EnsureHasData(); GetBitmapData()->m_bitmapMask = mask; } // Creates a bitmap that matches the device context, from // an arbitray bitmap. At present, the original bitmap must have an // associated palette. TODO: use a default palette if no palette exists. // Contributed by Frederic Villeneuve wxBitmap wxBitmap::GetBitmapForDC(wxDC& dc) const { #ifdef __WXMICROWIN__ return wxBitmap(); #else wxMemoryDC memDC; wxBitmap tmpBitmap(GetWidth(), GetHeight(), dc.GetDepth()); HPALETTE hPal = (HPALETTE) NULL; LPBITMAPINFO lpDib; void *lpBits = (void*) NULL; #if wxUSE_PALETTE if( GetPalette() && GetPalette()->Ok() ) { tmpBitmap.SetPalette(*GetPalette()); memDC.SelectObject(tmpBitmap); memDC.SetPalette(*GetPalette()); hPal = (HPALETTE)GetPalette()->GetHPALETTE(); } else { hPal = (HPALETTE) ::GetStockObject(DEFAULT_PALETTE); wxPalette palette; palette.SetHPALETTE( (WXHPALETTE)hPal ); tmpBitmap.SetPalette( palette ); memDC.SelectObject(tmpBitmap); memDC.SetPalette( palette ); } #else // !wxUSE_PALETTE hPal = (HPALETTE) ::GetStockObject(DEFAULT_PALETTE); #endif // wxUSE_PALETTE/!wxUSE_PALETTE // set the height negative because in a DIB the order of the lines is // reversed if ( !wxCreateDIB(GetWidth(), -GetHeight(), GetDepth(), hPal, &lpDib) ) { return wxNullBitmap; } lpBits = malloc(lpDib->bmiHeader.biSizeImage); ::GetBitmapBits(GetHbitmap(), lpDib->bmiHeader.biSizeImage, lpBits); ::SetDIBitsToDevice(GetHdcOf(memDC), 0, 0, GetWidth(), GetHeight(), 0, 0, 0, GetHeight(), lpBits, lpDib, DIB_RGB_COLORS); free(lpBits); wxFreeDIB(lpDib); return tmpBitmap; #endif } // ---------------------------------------------------------------------------- // wxMask // ---------------------------------------------------------------------------- wxMask::wxMask() { m_maskBitmap = 0; } // Construct a mask from a bitmap and a colour indicating // the transparent area wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour) { m_maskBitmap = 0; Create(bitmap, colour); } // Construct a mask from a bitmap and a palette index indicating // the transparent area wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex) { m_maskBitmap = 0; Create(bitmap, paletteIndex); } // Construct a mask from a mono bitmap (copies the bitmap). wxMask::wxMask(const wxBitmap& bitmap) { m_maskBitmap = 0; Create(bitmap); } wxMask::~wxMask() { if ( m_maskBitmap ) ::DeleteObject((HBITMAP) m_maskBitmap); } // Create a mask from a mono bitmap (copies the bitmap). bool wxMask::Create(const wxBitmap& bitmap) { #ifndef __WXMICROWIN__ wxCHECK_MSG( bitmap.Ok() && bitmap.GetDepth() == 1, FALSE, _T("can't create mask from invalid or not monochrome bitmap") ); if ( m_maskBitmap ) { ::DeleteObject((HBITMAP) m_maskBitmap); m_maskBitmap = 0; } m_maskBitmap = (WXHBITMAP) CreateBitmap( bitmap.GetWidth(), bitmap.GetHeight(), 1, 1, 0 ); HDC srcDC = CreateCompatibleDC(0); SelectObject(srcDC, (HBITMAP) bitmap.GetHBITMAP()); HDC destDC = CreateCompatibleDC(0); SelectObject(destDC, (HBITMAP) m_maskBitmap); BitBlt(destDC, 0, 0, bitmap.GetWidth(), bitmap.GetHeight(), srcDC, 0, 0, SRCCOPY); SelectObject(srcDC, 0); DeleteDC(srcDC); SelectObject(destDC, 0); DeleteDC(destDC); return TRUE; #else return FALSE; #endif } // Create a mask from a bitmap and a palette index indicating // the transparent area bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex) { if ( m_maskBitmap ) { ::DeleteObject((HBITMAP) m_maskBitmap); m_maskBitmap = 0; } #if wxUSE_PALETTE if (bitmap.Ok() && bitmap.GetPalette()->Ok()) { unsigned char red, green, blue; if (bitmap.GetPalette()->GetRGB(paletteIndex, &red, &green, &blue)) { wxColour transparentColour(red, green, blue); return Create(bitmap, transparentColour); } } #endif // wxUSE_PALETTE return FALSE; } // Create a mask from a bitmap and a colour indicating // the transparent area bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) { #ifndef __WXMICROWIN__ wxCHECK_MSG( bitmap.Ok(), FALSE, _T("invalid bitmap in wxMask::Create") ); if ( m_maskBitmap ) { ::DeleteObject((HBITMAP) m_maskBitmap); m_maskBitmap = 0; } int width = bitmap.GetWidth(), height = bitmap.GetHeight(); // scan the bitmap for the transparent colour and set the corresponding // pixels in the mask to BLACK and the rest to WHITE COLORREF maskColour = RGB(colour.Red(), colour.Green(), colour.Blue()); m_maskBitmap = (WXHBITMAP)::CreateBitmap(width, height, 1, 1, 0); HDC srcDC = ::CreateCompatibleDC(NULL); HDC destDC = ::CreateCompatibleDC(NULL); if ( !srcDC || !destDC ) { wxLogLastError(wxT("CreateCompatibleDC")); } bool ok = TRUE; // SelectObject() will fail wxASSERT_MSG( !bitmap.GetSelectedInto(), _T("bitmap can't be selected in another DC") ); HGDIOBJ hbmpSrcOld = ::SelectObject(srcDC, GetHbitmapOf(bitmap)); if ( !hbmpSrcOld ) { wxLogLastError(wxT("SelectObject")); ok = FALSE; } HGDIOBJ hbmpDstOld = ::SelectObject(destDC, (HBITMAP)m_maskBitmap); if ( !hbmpDstOld ) { wxLogLastError(wxT("SelectObject")); ok = FALSE; } // this is not very efficient, but I can't think of a better way of doing // it for ( int w = 0; ok && (w < width); w++ ) { for ( int h = 0; ok && (h < height); h++ ) { COLORREF col = GetPixel(srcDC, w, h); if ( col == CLR_INVALID ) { wxLogLastError(wxT("GetPixel")); // doesn't make sense to continue ok = FALSE; break; } if ( col == maskColour ) { ::SetPixel(destDC, w, h, RGB(0, 0, 0)); } else { ::SetPixel(destDC, w, h, RGB(255, 255, 255)); } } } ::SelectObject(srcDC, hbmpSrcOld); ::DeleteDC(srcDC); ::SelectObject(destDC, hbmpDstOld); ::DeleteDC(destDC); return ok; #else return FALSE; #endif } // ---------------------------------------------------------------------------- // wxBitmapHandler // ---------------------------------------------------------------------------- bool wxBitmapHandler::Create(wxGDIImage *image, void *data, long flags, int width, int height, int depth) { wxBitmap *bitmap = wxDynamicCast(image, wxBitmap); return bitmap ? Create(bitmap, data, flags, width, height, depth) : FALSE; } bool wxBitmapHandler::Load(wxGDIImage *image, const wxString& name, long flags, int width, int height) { wxBitmap *bitmap = wxDynamicCast(image, wxBitmap); return bitmap ? LoadFile(bitmap, name, flags, width, height) : FALSE; } bool wxBitmapHandler::Save(wxGDIImage *image, const wxString& name, int type) { wxBitmap *bitmap = wxDynamicCast(image, wxBitmap); return bitmap ? SaveFile(bitmap, name, type) : FALSE; } bool wxBitmapHandler::Create(wxBitmap *WXUNUSED(bitmap), void *WXUNUSED(data), long WXUNUSED(type), int WXUNUSED(width), int WXUNUSED(height), int WXUNUSED(depth)) { return FALSE; } bool wxBitmapHandler::LoadFile(wxBitmap *WXUNUSED(bitmap), const wxString& WXUNUSED(name), long WXUNUSED(type), int WXUNUSED(desiredWidth), int WXUNUSED(desiredHeight)) { return FALSE; } bool wxBitmapHandler::SaveFile(wxBitmap *WXUNUSED(bitmap), const wxString& WXUNUSED(name), int WXUNUSED(type), const wxPalette *WXUNUSED(palette)) { return FALSE; } // ---------------------------------------------------------------------------- // DIB functions // ---------------------------------------------------------------------------- #ifndef __WXMICROWIN__ bool wxCreateDIB(long xSize, long ySize, long bitsPerPixel, HPALETTE hPal, LPBITMAPINFO* lpDIBHeader) { unsigned long i, headerSize; LPBITMAPINFO lpDIBheader = NULL; LPPALETTEENTRY lpPe = NULL; // Allocate space for a DIB header headerSize = (sizeof(BITMAPINFOHEADER) + (256 * sizeof(PALETTEENTRY))); lpDIBheader = (BITMAPINFO *) malloc(headerSize); lpPe = (PALETTEENTRY *)((BYTE*)lpDIBheader + sizeof(BITMAPINFOHEADER)); GetPaletteEntries(hPal, 0, 256, lpPe); memset(lpDIBheader, 0x00, sizeof(BITMAPINFOHEADER)); // Fill in the static parts of the DIB header lpDIBheader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); lpDIBheader->bmiHeader.biWidth = xSize; lpDIBheader->bmiHeader.biHeight = ySize; lpDIBheader->bmiHeader.biPlanes = 1; // this value must be 1, 4, 8 or 24 so PixelDepth can only be lpDIBheader->bmiHeader.biBitCount = (WORD)(bitsPerPixel); lpDIBheader->bmiHeader.biCompression = BI_RGB; lpDIBheader->bmiHeader.biSizeImage = xSize * abs(ySize) * bitsPerPixel >> 3; lpDIBheader->bmiHeader.biClrUsed = 256; // Initialize the DIB palette for (i = 0; i < 256; i++) { lpDIBheader->bmiColors[i].rgbReserved = lpPe[i].peFlags; lpDIBheader->bmiColors[i].rgbRed = lpPe[i].peRed; lpDIBheader->bmiColors[i].rgbGreen = lpPe[i].peGreen; lpDIBheader->bmiColors[i].rgbBlue = lpPe[i].peBlue; } *lpDIBHeader = lpDIBheader; return TRUE; } void wxFreeDIB(LPBITMAPINFO lpDIBHeader) { free(lpDIBHeader); } #endif // ---------------------------------------------------------------------------- // other helper functions // ---------------------------------------------------------------------------- extern HBITMAP wxInvertMask(HBITMAP hbmpMask, int w, int h) { #ifndef __WXMICROWIN__ wxCHECK_MSG( hbmpMask, 0, _T("invalid bitmap in wxInvertMask") ); // get width/height from the bitmap if not given if ( !w || !h ) { BITMAP bm; ::GetObject(hbmpMask, sizeof(BITMAP), (LPVOID)&bm); w = bm.bmWidth; h = bm.bmHeight; } HDC hdcSrc = ::CreateCompatibleDC(NULL); HDC hdcDst = ::CreateCompatibleDC(NULL); if ( !hdcSrc || !hdcDst ) { wxLogLastError(wxT("CreateCompatibleDC")); } HBITMAP hbmpInvMask = ::CreateBitmap(w, h, 1, 1, 0); if ( !hbmpInvMask ) { wxLogLastError(wxT("CreateBitmap")); } ::SelectObject(hdcSrc, hbmpMask); ::SelectObject(hdcDst, hbmpInvMask); if ( !::BitBlt(hdcDst, 0, 0, w, h, hdcSrc, 0, 0, NOTSRCCOPY) ) { wxLogLastError(wxT("BitBlt")); } ::DeleteDC(hdcSrc); ::DeleteDC(hdcDst); return hbmpInvMask; #else return 0; #endif }