X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5bd3a2da9573f270564cd035e0cfbf6902cf8750..3f8e5072f7391db2158f44c6b9209bbb3db6eb06:/src/msw/bitmap.cpp diff --git a/src/msw/bitmap.cpp b/src/msw/bitmap.cpp index 8eba1311e5..33651b712f 100644 --- a/src/msw/bitmap.cpp +++ b/src/msw/bitmap.cpp @@ -46,14 +46,19 @@ #include "wx/msw/dib.h" #include "wx/image.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(wxBitmap, wxGDIObject) +IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject) - IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject) // ============================================================================ // implementation @@ -131,26 +136,8 @@ bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon) // the mask returned by GetIconInfo() is inversed compared to the usual // wxWin convention - HBITMAP hbmpMask = ::CreateBitmap(w, h, 1, 1, 0); - - // the icons mask is opposite to the usual wxWin convention - HDC dcSrc = ::CreateCompatibleDC(NULL); - HDC dcDst = ::CreateCompatibleDC(NULL); - (void)SelectObject(dcSrc, iconInfo.hbmMask); - (void)SelectObject(dcDst, hbmpMask); - - HBRUSH brush = ::CreateSolidBrush(RGB(255, 255, 255)); - RECT rect = { 0, 0, w, h }; - FillRect(dcDst, &rect, brush); - - BitBlt(dcDst, 0, 0, w, h, dcSrc, 0, 0, SRCINVERT); - - SelectObject(dcDst, NULL); - SelectObject(dcSrc, NULL); - DeleteDC(dcDst); - DeleteDC(dcSrc); - - refData->m_bitmapMask = new wxMask((WXHBITMAP)hbmpMask); + refData->m_bitmapMask = new wxMask((WXHBITMAP) + wxInvertMask(iconInfo.hbmMask, w, h)); #if WXWIN_COMPATIBILITY_2 refData->m_ok = TRUE; @@ -255,16 +242,22 @@ wxBitmap::wxBitmap(const char bits[], int width, int height, int depth) for ( int rows = 0; rows < height; rows++ ) { - // note that offset cannot be size_t due to >= 0 test! - for ( int offset = bytesPerLine - 1; offset >= 0; offset-- ) + for ( size_t cols = 0; cols < bytesPerLine; cols++ ) { - *dst++ = *(src + offset); + 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; - - src += bytesPerLine; } } else @@ -287,52 +280,12 @@ wxBitmap::wxBitmap(const char bits[], int width, int height, int depth) SetHBITMAP((WXHBITMAP)hbmp); } -// GRG, Dic/99 -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") ); - - // 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; -} - // Create from XPM data -wxBitmap::wxBitmap(char **data, wxControl *WXUNUSED(anItem)) +bool wxBitmap::CreateFromXpm(const char **data) { Init(); - (void)Create((void *)data, wxBITMAP_TYPE_XPM_DATA, 0, 0, 0); + return Create((void *)data, wxBITMAP_TYPE_XPM_DATA, 0, 0, 0); } wxBitmap::wxBitmap(int w, int h, int d) @@ -459,6 +412,49 @@ bool wxBitmap::SaveFile(const wxString& filename, int type, const wxPalette *pal } } +// ---------------------------------------------------------------------------- +// sub bitmap extraction +// ---------------------------------------------------------------------------- + +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") ); + + // 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; +} + // ---------------------------------------------------------------------------- // wxBitmap accessors // ---------------------------------------------------------------------------- @@ -500,7 +496,7 @@ void wxBitmap::SetMask(wxMask *mask) wxBitmap wxBitmap::GetBitmapForDC(wxDC& dc) const { wxMemoryDC memDC; - wxBitmap tmpBitmap(this->GetWidth(), this->GetHeight(), dc.GetDepth()); + wxBitmap tmpBitmap(GetWidth(), GetHeight(), dc.GetDepth()); HPALETTE hPal = (HPALETTE) NULL; LPBITMAPINFO lpDib; void *lpBits = (void*) NULL; @@ -586,15 +582,15 @@ wxMask::~wxMask() // Create a mask from a mono bitmap (copies the bitmap). bool wxMask::Create(const wxBitmap& bitmap) { + 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; } - if (!bitmap.Ok() || bitmap.GetDepth() != 1) - { - return FALSE; - } + m_maskBitmap = (WXHBITMAP) CreateBitmap( bitmap.GetWidth(), bitmap.GetHeight(), @@ -637,38 +633,65 @@ bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex) // the transparent area bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) { + wxCHECK_MSG( bitmap.Ok(), FALSE, _T("invalid bitmap in wxMask::Create") ); + if ( m_maskBitmap ) { ::DeleteObject((HBITMAP) m_maskBitmap); m_maskBitmap = 0; } - if (!bitmap.Ok()) + + 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 = wxColourToRGB(colour); + m_maskBitmap = (WXHBITMAP)::CreateBitmap(width, height, 1, 1, 0); + + HDC srcDC = ::CreateCompatibleDC(NULL); + HDC destDC = ::CreateCompatibleDC(NULL); + if ( !srcDC || !destDC ) { - return FALSE; + wxLogLastError("CreateCompatibleDC"); + } + + bool ok = TRUE; + + HGDIOBJ hbmpSrcOld = ::SelectObject(srcDC, GetHbitmapOf(bitmap)); + if ( !hbmpSrcOld ) + { + wxLogLastError("SelectObject"); + + ok = FALSE; } - // 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( - 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); - - // this is not very efficient, but I can't think - // of a better way of doing it - for (int w = 0; w < bitmap.GetWidth(); w++) + HGDIOBJ hbmpDstOld = ::SelectObject(destDC, (HBITMAP)m_maskBitmap); + if ( !hbmpDstOld ) { - for (int h = 0; h < bitmap.GetHeight(); h++) + wxLogLastError("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 == maskColour) + if ( col == CLR_INVALID ) + { + wxLogLastError("GetPixel"); + + // doesn't make sense to continue + ok = FALSE; + + break; + } + + if ( col == maskColour ) { ::SetPixel(destDC, w, h, RGB(0, 0, 0)); } @@ -678,11 +701,13 @@ bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) } } } - ::SelectObject(srcDC, 0); + + ::SelectObject(srcDC, hbmpSrcOld); ::DeleteDC(srcDC); - ::SelectObject(destDC, 0); + ::SelectObject(destDC, hbmpDstOld); ::DeleteDC(destDC); - return TRUE; + + return ok; } // ---------------------------------------------------------------------------- @@ -797,4 +822,47 @@ void wxFreeDIB(LPBITMAPINFO lpDIBHeader) free(lpDIBHeader); } +// ---------------------------------------------------------------------------- +// other helper functions +// ---------------------------------------------------------------------------- +extern HBITMAP wxInvertMask(HBITMAP hbmpMask, int w, int h) +{ + 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("CreateCompatibleDC"); + } + + HBITMAP hbmpInvMask = ::CreateBitmap(w, h, 1, 1, 0); + if ( !hbmpInvMask ) + { + wxLogLastError("CreateBitmap"); + } + + ::SelectObject(hdcSrc, hbmpMask); + ::SelectObject(hdcDst, hbmpInvMask); + if ( !::BitBlt(hdcDst, 0, 0, w, h, + hdcSrc, 0, 0, + NOTSRCCOPY) ) + { + wxLogLastError("BitBlt"); + } + + ::DeleteDC(hdcSrc); + ::DeleteDC(hdcDst); + + return hbmpInvMask; +}