X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/211b54b109f623310b6a7558a5f1b0ea44f5bdd8..6e348b12dcc7f994da8c2552b80d60140578a745:/src/msw/bitmap.cpp diff --git a/src/msw/bitmap.cpp b/src/msw/bitmap.cpp index 170c5b7897..b34424a5fe 100644 --- a/src/msw/bitmap.cpp +++ b/src/msw/bitmap.cpp @@ -100,10 +100,18 @@ public: wxDC *m_selectedInto; #endif // __WXDEBUG__ + // when GetRawData() is called for a DDB we need to convert it to a DIB + // first to be able to provide direct access to it and we cache that DIB + // here and convert it back to DDB when UngetRawData() is called + wxDIB *m_dib; + // true if we have alpha transparency info and can be drawn using // AlphaBlend() bool m_hasAlpha; + // true if our HBITMAP is a DIB section, false if it is a DDB + bool m_isDIB; + private: // optional mask for transparent drawing wxMask *m_bitmapMask; @@ -162,7 +170,11 @@ wxBitmapRefData::wxBitmapRefData() m_selectedInto = NULL; #endif m_bitmapMask = NULL; + m_hBitmap = (WXHBITMAP) NULL; + m_dib = NULL; + + m_isDIB = m_hasAlpha = FALSE; } @@ -171,6 +183,8 @@ void wxBitmapRefData::Free() wxASSERT_MSG( !m_selectedInto, wxT("deleting bitmap still selected into wxMemoryDC") ); + wxASSERT_MSG( !m_dib, _T("forgot to call wxBitmap::UngetRawData()!") ); + if ( m_hBitmap) { if ( !::DeleteObject((HBITMAP)m_hBitmap) ) @@ -306,6 +320,38 @@ bool wxBitmap::CopyFromIcon(const wxIcon& icon) #endif // Win16/Win32 } +bool wxBitmap::CopyFromDIB(const wxDIB& dib) +{ + wxCHECK_MSG( dib.IsOk(), FALSE, _T("invalid DIB in CopyFromDIB") ); + + HBITMAP hbitmap = dib.CreateDDB(); + if ( !hbitmap ) + return FALSE; + + UnRef(); + + wxBitmapRefData *refData = new wxBitmapRefData; + m_refData = refData; + + refData->m_width = dib.GetWidth(); + refData->m_height = dib.GetHeight(); + refData->m_depth = dib.GetDepth(); + + refData->m_hBitmap = (WXHBITMAP)hbitmap; + +#if wxUSE_PALETTE + wxPalette *palette = dib.CreatePalette(); + if ( palette ) + { + refData->m_bitmapPalette = *palette; + } + + delete palette; +#endif // wxUSE_PALETTE + + return TRUE; +} + wxBitmap::~wxBitmap() { } @@ -402,6 +448,13 @@ wxBitmap::wxBitmap(int w, int h, int d) (void)Create(w, h, d); } +wxBitmap::wxBitmap(int w, int h, const wxDC& dc) +{ + Init(); + + (void)Create(w, h, dc); +} + wxBitmap::wxBitmap(void *data, long type, int width, int height, int depth) { Init(); @@ -454,8 +507,8 @@ bool wxBitmap::DoCreate(int w, int h, int d, WXHDC hdc) // don't delete the DIB section in dib object dtor hbmp = dib.Detach(); + GetBitmapData()->m_isDIB = TRUE; GetBitmapData()->m_depth = d; - GetBitmapData()->m_hasAlpha = d == 32; // 32bpp DIBs have alpha channel } else // create a DDB { @@ -740,85 +793,12 @@ bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc ) // don't delete the DIB section in dib object dtor hbitmap = dib.Detach(); + refData->m_isDIB = TRUE; refData->m_depth = dib.GetDepth(); } else // we need to convert DIB to DDB { - // create and set the device-dependent bitmap - // - // VZ: why don't we just use SetDIBits() instead? because of the - // palette or is there some other reason? - hbitmap = ::CreateCompatibleBitmap(hdc ? (HDC)hdc : ScreenHDC(), w, h); - if ( !hbitmap ) - { - wxLogLastError(_T("CreateCompatibleBitmap()")); - - return FALSE; - } - - MemoryHDC hdcMem; - SelectInHDC select(hdcMem, hbitmap); - if ( !select ) - { - wxLogLastError(_T("SelectObjct(hBitmap)")); - } - -#if wxUSE_PALETTE - const wxPalette& palette = image.GetPalette(); - - HPALETTE hOldPalette; - if ( palette.Ok() ) - { - SetPalette(palette); - - hOldPalette = ::SelectPalette - ( - hdcMem, - GetHpaletteOf(palette), - FALSE // ignored for hdcMem - ); - - if ( !hOldPalette ) - { - wxLogLastError(_T("SelectPalette()")); - } - - if ( ::RealizePalette(hdcMem) == GDI_ERROR ) - { - wxLogLastError(_T("RealizePalette()")); - } - } - else // no valid palette - { - hOldPalette = 0; - } -#endif // wxUSE_PALETTE - - DIBSECTION ds; - if ( !::GetObject(dib.GetHandle(), sizeof(ds), &ds) ) - { - wxLogLastError(_T("GetObject(hDIB)")); - } - - if ( ::StretchDIBits(hdcMem, - 0, 0, w, h, - 0, 0, w, h, - dib.GetData(), - (BITMAPINFO *)&ds.dsBmih, - DIB_RGB_COLORS, - SRCCOPY) == GDI_ERROR ) - { - wxLogLastError(_T("StretchDIBits()")); - - return FALSE; - } - -#if wxUSE_PALETTE - if ( hOldPalette ) - { - ::SelectPalette(hdcMem, hOldPalette, FALSE); - } -#endif // wxUSE_PALETTE + hbitmap = dib.CreateDDB((HDC)hdc); refData->m_depth = depth == -1 ? wxDisplayDepth() : depth; } @@ -1139,6 +1119,12 @@ int wxBitmap::GetQuality() const #endif // WXWIN_COMPATIBILITY_2_4 +void wxBitmap::UseAlpha() +{ + if ( GetBitmapData() ) + GetBitmapData()->m_hasAlpha = true; +} + bool wxBitmap::HasAlpha() const { return GetBitmapData() && GetBitmapData()->m_hasAlpha; @@ -1209,10 +1195,38 @@ bool wxBitmap::GetRawData(wxRawBitmapData *data) return FALSE; } - // we only support raw access to the DIBs, so check if we have one + // if we're already a DIB we can access our data directly, but if not we + // need to convert this DDB to a DIB section and use it for raw access and + // then convert it back + HBITMAP hDIB; + if ( !GetBitmapData()->m_isDIB ) + { + wxCHECK_MSG( !GetBitmapData()->m_dib, FALSE, + _T("GetRawData() may be called only once") ); + + wxDIB *dib = new wxDIB(*this); + if ( !dib->IsOk() ) + { + delete dib; + + return FALSE; + } + + // we'll free it in UngetRawData() + GetBitmapData()->m_dib = dib; + + hDIB = dib->GetHandle(); + } + else // we're a DIB + { + hDIB = GetHbitmap(); + } + DIBSECTION ds; - if ( !::GetObject(GetHbitmap(), sizeof(ds), &ds) ) + if ( ::GetObject(hDIB, sizeof(ds), &ds) != sizeof(DIBSECTION) ) { + wxFAIL_MSG( _T("failed to get DIBSECTION from a DIB?") ); + return FALSE; } @@ -1235,68 +1249,58 @@ bool wxBitmap::GetRawData(wxRawBitmapData *data) return TRUE; } -// ---------------------------------------------------------------------------- -// TODO: to be replaced by something better -// ---------------------------------------------------------------------------- - -// 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 +void wxBitmap::UngetRawData(wxRawBitmapData *data) { -#ifdef __WXMICROWIN__ - return *this; -#else - wxMemoryDC memDC; - wxBitmap tmpBitmap(GetWidth(), GetHeight(), dc.GetDepth()); - HPALETTE hPal = (HPALETTE) NULL; - LPBITMAPINFO lpDib; - void *lpBits = (void*) NULL; + wxCHECK_RET( data, _T("NULL pointer in wxBitmap::UngetRawData()") ); -#if wxUSE_PALETTE - if( GetPalette() && GetPalette()->Ok() ) - { - tmpBitmap.SetPalette(*GetPalette()); - memDC.SelectObject(tmpBitmap); - memDC.SetPalette(*GetPalette()); - hPal = (HPALETTE)GetPalette()->GetHPALETTE(); - } - else + if ( !Ok() ) + return; + + if ( !*data ) { - hPal = (HPALETTE) ::GetStockObject(DEFAULT_PALETTE); - wxPalette palette; - palette.SetHPALETTE( (WXHPALETTE)hPal ); - tmpBitmap.SetPalette( palette ); - memDC.SelectObject(tmpBitmap); - memDC.SetPalette( palette ); + // invalid data, don't crash -- but don't assert neither as we're + // called automatically from wxRawBitmapData dtor and so there is no + // way to prevent this from happening + return; } -#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) ) + // AlphaBlend() wants to have premultiplied source alpha but wxRawBitmap + // API uses normal, not premultiplied, colours, so adjust them here now + wxRawBitmapIterator p(*data); + + const int w = data->GetWidth(); + const int h = data->GetHeight(); + + for ( int y = 0; y < h; y++ ) { - return wxNullBitmap; - } + wxRawBitmapIterator rowStart = p; - lpBits = malloc(lpDib->bmiHeader.biSizeImage); + for ( int x = 0; x < w; x++ ) + { + const unsigned alpha = p.Alpha(); - ::GetBitmapBits(GetHbitmap(), lpDib->bmiHeader.biSizeImage, lpBits); + p.Red() = (p.Red() * alpha + 127) / 255; + p.Blue() = (p.Blue() * alpha + 127) / 255; + p.Green() = (p.Green() * alpha + 127) / 255; - ::SetDIBitsToDevice(GetHdcOf(memDC), 0, 0, - GetWidth(), GetHeight(), - 0, 0, 0, GetHeight(), - lpBits, lpDib, DIB_RGB_COLORS); + ++p; + } - free(lpBits); + p = rowStart; + p.OffsetY(1); + } + + // if we're a DDB we need to convert DIB back to DDB now to make the + // changes made via wxRawBitmapData effective + if ( !GetBitmapData()->m_isDIB ) + { + wxDIB *dib = GetBitmapData()->m_dib; + GetBitmapData()->m_dib = NULL; - wxFreeDIB(lpDib); + // TODO: convert - return tmpBitmap; -#endif + delete dib; + } } // ----------------------------------------------------------------------------