X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0765adca2b85389443c6dea4b491bb1de7fb34b1..67bd5bad041419c4714d09749737d5ea9876a47d:/src/msw/bitmap.cpp diff --git a/src/msw/bitmap.cpp b/src/msw/bitmap.cpp index 6737631938..d5b37d2cfd 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 @@ -81,7 +86,7 @@ void wxBitmapRefData::Free() { if ( !::DeleteObject((HBITMAP)m_hBitmap) ) { - wxLogLastError("DeleteObject(hbitmap)"); + wxLogLastError(wxT("DeleteObject(hbitmap)")); } } @@ -112,7 +117,7 @@ bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon) ICONINFO iconInfo; if ( !::GetIconInfo(hicon, &iconInfo) ) { - wxLogLastError("GetIconInfo"); + wxLogLastError(wxT("GetIconInfo")); return FALSE; } @@ -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; @@ -282,7 +269,7 @@ wxBitmap::wxBitmap(const char bits[], int width, int height, int depth) HBITMAP hbmp = ::CreateBitmap(width, height, 1, depth, data); if ( !hbmp ) { - wxLogLastError("CreateBitmap"); + wxLogLastError(wxT("CreateBitmap")); } if ( data != bits ) @@ -293,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) @@ -379,7 +326,7 @@ bool wxBitmap::Create(int w, int h, int d) hbmp = ::CreateBitmap(w, h, 1, d, NULL); if ( !hbmp ) { - wxLogLastError("CreateBitmap"); + wxLogLastError(wxT("CreateBitmap")); } } else @@ -388,7 +335,7 @@ bool wxBitmap::Create(int w, int h, int d) hbmp = ::CreateCompatibleBitmap(dc, w, h); if ( !hbmp ) { - wxLogLastError("CreateCompatibleBitmap"); + wxLogLastError(wxT("CreateCompatibleBitmap")); } GetBitmapData()->m_depth = wxDisplayDepth(); @@ -435,8 +382,7 @@ bool wxBitmap::Create(void *data, long type, int width, int height, int depth) if ( !handler ) { - wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for " - "type %d defined."), type); + wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %d defined."), type); return FALSE; } @@ -465,6 +411,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 // ---------------------------------------------------------------------------- @@ -506,7 +495,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; @@ -592,15 +581,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(), @@ -643,38 +632,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(wxT("CreateCompatibleDC")); } - // 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++) + bool ok = TRUE; + + HGDIOBJ hbmpSrcOld = ::SelectObject(srcDC, GetHbitmapOf(bitmap)); + if ( !hbmpSrcOld ) { - for (int h = 0; h < bitmap.GetHeight(); h++) + 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 == maskColour) + 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)); } @@ -684,11 +700,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; } // ---------------------------------------------------------------------------- @@ -702,7 +720,7 @@ bool wxBitmapHandler::Create(wxGDIImage *image, { wxBitmap *bitmap = wxDynamicCast(image, wxBitmap); - return bitmap ? Create(bitmap, data, width, height, depth) : FALSE; + return bitmap ? Create(bitmap, data, flags, width, height, depth) : FALSE; } bool wxBitmapHandler::Load(wxGDIImage *image, @@ -803,4 +821,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(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; +}