X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/54a96d029f6864182e5e49e7d5b2e133be6d3d51..4a46a5df879c4f820d0a0a435b34c7d5e4793991:/src/msw/bitmap.cpp diff --git a/src/msw/bitmap.cpp b/src/msw/bitmap.cpp index 97a886aff9..99e6867101 100644 --- a/src/msw/bitmap.cpp +++ b/src/msw/bitmap.cpp @@ -40,6 +40,8 @@ #include "wx/icon.h" #endif +//#include "device.h" + #include "wx/msw/private.h" #include "wx/log.h" @@ -88,11 +90,13 @@ void wxBitmapRefData::Free() if ( m_hBitmap) { - // printf("About to delete bitmap %d\n", (int) (HBITMAP) m_hBitmap); + // printf("About to delete bitmap %d\n", (int) (HBITMAP) m_hBitmap); +#if 1 if ( !::DeleteObject((HBITMAP)m_hBitmap) ) { wxLogLastError(wxT("DeleteObject(hbitmap)")); } +#endif } delete m_bitmapMask; @@ -381,49 +385,112 @@ bool wxBitmap::Create(int w, int h, int d) bool wxBitmap::CreateFromImage( const wxImage& image, int depth ) { #ifdef __WXMICROWIN__ + + // Set this to 1 to experiment with mask code, + // which currently doesn't work +#define USE_MASKS 0 + m_refData = new wxBitmapRefData(); // 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); + // printf("Screen planes = %d, bpp = %d\n", hScreenDC->psd->planes, hScreenDC->psd->bpp); int screenDepth = ::GetDeviceCaps(hScreenDC, BITSPIXEL); HBITMAP hBitmap = ::CreateCompatibleBitmap(hScreenDC, image.GetWidth(), image.GetHeight()); + HBITMAP hMaskBitmap = NULL; + HBITMAP hOldMaskBitmap = NULL; + HDC hMaskDC = NULL; + unsigned char maskR = 0; + unsigned char maskG = 0; + unsigned char maskB = 0; + // printf("Created bitmap %d\n", (int) hBitmap); if (hBitmap == NULL) { ::ReleaseDC(NULL, hScreenDC); - return FALSE; + return FALSE; } HDC hMemDC = ::CreateCompatibleDC(hScreenDC); - ::ReleaseDC(NULL, hScreenDC); HBITMAP hOldBitmap = ::SelectObject(hMemDC, hBitmap); + ::ReleaseDC(NULL, hScreenDC); + + // created an mono-bitmap for the possible mask + bool hasMask = image.HasMask(); + + if ( hasMask ) + { +#if USE_MASKS + // FIXME: we should be able to pass bpp = 1, but + // GdBlit can't handle a different depth +#if 0 + hMaskBitmap = ::CreateBitmap( (WORD)image.GetWidth(), (WORD)image.GetHeight(), 1, 1, NULL ); +#else + hMaskBitmap = ::CreateCompatibleBitmap( hMemDC, (WORD)image.GetWidth(), (WORD)image.GetHeight()); +#endif + maskR = image.GetMaskRed(); + maskG = image.GetMaskGreen(); + maskB = image.GetMaskBlue(); + + if (!hMaskBitmap) + { + hasMask = FALSE; + } + else + { + hScreenDC = ::GetDC(NULL); + hMaskDC = ::CreateCompatibleDC(hScreenDC); + ::ReleaseDC(NULL, hScreenDC); + + hOldMaskBitmap = ::SelectObject( hMaskDC, hMaskBitmap); + } +#else + hasMask = FALSE; +#endif + } 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)); - } + 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)); + + if (hasMask) + { + // scan the bitmap for the transparent colour and set the corresponding + // pixels in the mask to BLACK and the rest to WHITE + if (maskR == red && maskG == green && maskB == blue) + ::SetPixel(hMaskDC, i, j, PALETTERGB(0, 0, 0)); + else + ::SetPixel(hMaskDC, i, j, PALETTERGB(255, 255, 255)); + } + } } ::SelectObject(hMemDC, hOldBitmap); ::DeleteDC(hMemDC); - + if (hasMask) + { + ::SelectObject(hMaskDC, hOldMaskBitmap); + ::DeleteDC(hMaskDC); + + ((wxBitmapRefData*)m_refData)->m_bitmapMask = new wxMask((WXHBITMAP) hMaskBitmap); + } + SetWidth(image.GetWidth()); SetHeight(image.GetHeight()); SetDepth(screenDepth); SetHBITMAP( (WXHBITMAP) hBitmap ); - + #if wxUSE_PALETTE // Copy the palette from the source image SetPalette(image.GetPalette()); @@ -680,7 +747,7 @@ wxImage wxBitmap::ConvertToImage() const if (!Ok()) { wxFAIL_MSG( wxT("bitmap is invalid") ); - return wxNullImage; + return wxNullImage; } wxImage image; @@ -697,33 +764,33 @@ wxImage wxBitmap::ConvertToImage() const 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); - } + 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()) @@ -940,7 +1007,6 @@ bool wxBitmap::SaveFile(const wxString& filename, wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const { -#ifndef __WXMICROWIN__ wxCHECK_MSG( Ok() && (rect.x >= 0) && (rect.y >= 0) && (rect.x+rect.width <= GetWidth()) && @@ -950,35 +1016,41 @@ wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const wxBitmap ret( rect.width, rect.height, GetDepth() ); wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") ); +#ifndef __WXMICROWIN__ // 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); + MemoryHDC dcSrc, dcDst; + + { + SelectInHDC selectSrc(dcSrc, GetHbitmap()), + selectDst(dcDst, GetHbitmapOf(ret)); + + if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height, + dcSrc, rect.x, rect.y, SRCCOPY) ) + { + wxLogLastError(_T("BitBlt")); + } + } // copy mask if there is one - if (GetMask()) + 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); + SelectInHDC selectSrc(dcSrc, (HBITMAP) GetMask()->GetMaskBitmap()), + selectDst(dcDst, hbmpMask); + + if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height, + dcSrc, rect.x, rect.y, SRCCOPY) ) + { + wxLogLastError(_T("BitBlt")); + } wxMask *mask = new wxMask((WXHBITMAP) hbmpMask); ret.SetMask(mask); } - - SelectObject(dcDst, NULL); - SelectObject(dcSrc, NULL); - DeleteDC(dcDst); - DeleteDC(dcSrc); +#endif // !__WXMICROWIN__ return ret; -#else - return wxBitmap(); -#endif } // ---------------------------------------------------------------------------- @@ -1225,32 +1297,13 @@ bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) 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++ ) + if ( ok ) { - 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)); - } - } + // this will create a monochrome bitmap with 0 points for the pixels + // which have the same value as the background colour and 1 for the + // others + ::SetBkColor(srcDC, maskColour); + ::BitBlt(destDC, 0, 0, width, height, srcDC, 0, 0, NOTSRCCOPY); } ::SelectObject(srcDC, hbmpSrcOld); @@ -1259,9 +1312,9 @@ bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) ::DeleteDC(destDC); return ok; -#else +#else // __WXMICROWIN__ return FALSE; -#endif +#endif // __WXMICROWIN__/!__WXMICROWIN__ } // ----------------------------------------------------------------------------