X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/fa275e864825d4fbd99d6a3ccb911998fce13a02..74d0b78c365fecd7437672dac3efe6ac371823c7:/src/msw/bitmap.cpp diff --git a/src/msw/bitmap.cpp b/src/msw/bitmap.cpp index b34424a5fe..dbb6114bee 100644 --- a/src/msw/bitmap.cpp +++ b/src/msw/bitmap.cpp @@ -43,14 +43,16 @@ #include "wx/msw/private.h" #include "wx/log.h" -#if !defined(__WXMICROWIN__) +#if wxUSE_WXDIB #include "wx/msw/dib.h" #endif #include "wx/image.h" #include "wx/xpmdecod.h" +#ifdef wxHAVE_RAW_BITMAP #include "wx/rawbmp.h" +#endif // missing from mingw32 header #ifndef CLR_INVALID @@ -100,10 +102,12 @@ public: wxDC *m_selectedInto; #endif // __WXDEBUG__ +#if wxUSE_WXDIB // 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; +#endif // true if we have alpha transparency info and can be drawn using // AlphaBlend() @@ -139,6 +143,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject) // decide whether we should create a DIB or a DDB for the given parameters static bool wxShouldCreateDIB(int w, int h, int d, WXHDC hdc) { +#if wxUSE_WXDIB // here is the logic: // // (a) if hdc is specified, the caller explicitly wants DDB @@ -158,6 +163,9 @@ static bool wxShouldCreateDIB(int w, int h, int d, WXHDC hdc) (d >= 24 || (d == -1 && wxDIB::GetLineSize(w, wxDisplayDepth())*h > 16*1024*1024)); +#else + return FALSE; +#endif } // ---------------------------------------------------------------------------- @@ -172,7 +180,9 @@ wxBitmapRefData::wxBitmapRefData() m_bitmapMask = NULL; m_hBitmap = (WXHBITMAP) NULL; +#if wxUSE_WXDIB m_dib = NULL; +#endif m_isDIB = m_hasAlpha = FALSE; @@ -183,7 +193,9 @@ void wxBitmapRefData::Free() wxASSERT_MSG( !m_selectedInto, wxT("deleting bitmap still selected into wxMemoryDC") ); +#if wxUSE_WXDIB wxASSERT_MSG( !m_dib, _T("forgot to call wxBitmap::UngetRawData()!") ); +#endif if ( m_hBitmap) { @@ -216,7 +228,7 @@ wxGDIImageRefData *wxBitmap::CreateData() const bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon) { -#ifndef __WXMICROWIN__ +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) // it may be either HICON or HCURSOR HICON hicon = (HICON)icon.GetHandle(); @@ -320,6 +332,7 @@ bool wxBitmap::CopyFromIcon(const wxIcon& icon) #endif // Win16/Win32 } +#if wxUSE_WXDIB bool wxBitmap::CopyFromDIB(const wxDIB& dib) { wxCHECK_MSG( dib.IsOk(), FALSE, _T("invalid DIB in CopyFromDIB") ); @@ -351,6 +364,7 @@ bool wxBitmap::CopyFromDIB(const wxDIB& dib) return TRUE; } +#endif wxBitmap::~wxBitmap() { @@ -492,6 +506,7 @@ bool wxBitmap::DoCreate(int w, int h, int d, WXHDC hdc) HBITMAP hbmp; +#if wxUSE_WXDIB if ( wxShouldCreateDIB(w, h, d, hdc) ) { if ( d == -1 ) @@ -511,6 +526,7 @@ bool wxBitmap::DoCreate(int w, int h, int d, WXHDC hdc) GetBitmapData()->m_depth = d; } else // create a DDB +#endif { if ( d == -1 ) d = wxDisplayDepth(); @@ -762,6 +778,7 @@ bool wxBitmap::CreateFromImage(const wxImage& image, const wxDC& dc) bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc ) { +#if wxUSE_WXDIB wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") ); UnRef(); @@ -788,7 +805,9 @@ bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc ) HBITMAP hbitmap; // are we going to use DIB? - if ( wxShouldCreateDIB(w, h, depth, hdc) ) + // + // NB: DDBs don't support alpha so if we have alpha channel we must use DIB + if ( image.HasAlpha() || wxShouldCreateDIB(w, h, depth, hdc) ) { // don't delete the DIB section in dib object dtor hbitmap = dib.Detach(); @@ -819,10 +838,213 @@ bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc ) } return TRUE; +#else + // FIXME: wxWinCE doesn't support wxDIB yet + return FALSE; +#endif } wxImage wxBitmap::ConvertToImage() const { + // FIXME: this is untested code for WinCE, and + // the mask is not yet handled. + // For tips, see: + // http://www.codeproject.com/bitmap/dibsection.asp?print=true + +#ifdef __WXWINCE__ + // the colour used as transparent one in wxImage and the one it is replaced + // with when it really occurs in the bitmap + static const int MASK_RED = 1; + static const int MASK_GREEN = 2; + static const int MASK_BLUE = 3; + static const int MASK_BLUE_REPLACEMENT = 2; + + 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 is allocated by CreateDIBSection + void *lpBits = NULL; + + // copy data from the device-dependent bitmap to the DIB + HDC hdc = ::GetDC(NULL); + HBITMAP hBitmap = (HBITMAP) GetHBITMAP(); + + HBITMAP hBitmapSection = ::CreateDIBSection( hdc, lpDIBh, DIB_RGB_COLORS, & lpBits, NULL, 0 ); + if (!hBitmapSection) + { + wxFAIL_MSG( wxT("could not create a DIB section") ); + return wxNullImage; + } + + // Copy the image from the DDB to the DIBSection + // Need to copy the supplied bitmap onto the newly created DIBsection + HDC hMemDC = CreateCompatibleDC(hdc); + HDC hCopyDC = CreateCompatibleDC(hdc); + + if (! hMemDC || ! hCopyDC) + { + wxFAIL_MSG( wxT("unable to create compatible DCs") ); + return wxNullImage; + } + +#if 0 + if (m_hPal) + { + SelectPalette(hMemDC, m_hPal, FALSE); RealizePalette(hMemDC); + SelectPalette(hCopyDC, m_hPal, FALSE); RealizePalette(hCopyDC); + } +#endif + + HBITMAP hOldMemBitmap = (HBITMAP) SelectObject(hMemDC, hBitmap); + HBITMAP hOldCopyBitmap = (HBITMAP) SelectObject(hCopyDC, hBitmapSection); + + BitBlt(hCopyDC, 0, 0, GetWidth(), GetHeight(), hMemDC, 0, 0, SRCCOPY); + + SelectObject(hMemDC, hOldMemBitmap); + SelectObject(hCopyDC, hOldCopyBitmap); + DeleteDC(hMemDC); + DeleteDC(hCopyDC); + +#if 0 + if (m_hPal) + { + HGDIOBJ hObj = ::GetStockObject(DEFAULT_PALETTE); + SelectObject(hMemDC, hObj); + SelectObject(hCopyDC, hObj); + } +#endif + + ReleaseDC(NULL, hdc); + + // copy DIB data into the wxImage object + int i, j; + unsigned char *ptdata = data; + unsigned char *ptbits = (unsigned char*) 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 ); + ptdata = data; + ptbits = lpBits; + for( i=0; im_bitmapPalette : (wxPalette *) NULL; } +#endif wxMask *wxBitmap::GetMask() const { @@ -1185,14 +1420,14 @@ void wxBitmap::SetQuality(int WXUNUSED(quality)) // raw bitmap access support // ---------------------------------------------------------------------------- -bool wxBitmap::GetRawData(wxRawBitmapData *data) +#ifdef wxHAVE_RAW_BITMAP +void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp) { - wxCHECK_MSG( data, FALSE, _T("NULL pointer in wxBitmap::GetRawData") ); - +#if wxUSE_WXDIB if ( !Ok() ) { // no bitmap, no data (raw or otherwise) - return FALSE; + return NULL; } // if we're already a DIB we can access our data directly, but if not we @@ -1209,7 +1444,7 @@ bool wxBitmap::GetRawData(wxRawBitmapData *data) { delete dib; - return FALSE; + return NULL; } // we'll free it in UngetRawData() @@ -1227,81 +1462,102 @@ bool wxBitmap::GetRawData(wxRawBitmapData *data) { wxFAIL_MSG( _T("failed to get DIBSECTION from a DIB?") ); - return FALSE; + return NULL; + } + + // check that the bitmap is in correct format + if ( ds.dsBm.bmBitsPixel != bpp ) + { + wxFAIL_MSG( _T("incorrect bitmap type in wxBitmap::GetRawData()") ); + + return NULL; } - // ok, store the relevant info in wxRawBitmapData + // ok, store the relevant info in wxPixelDataBase const LONG h = ds.dsBm.bmHeight; - data->m_width = ds.dsBm.bmWidth; - data->m_height = h; - data->m_bypp = ds.dsBm.bmBitsPixel / 8; + data.m_width = ds.dsBm.bmWidth; + data.m_height = h; // remember that DIBs are stored in top to bottom order! const LONG bytesPerRow = ds.dsBm.bmWidthBytes; - data->m_stride = -bytesPerRow; - data->m_pixels = (unsigned char *)ds.dsBm.bmBits; + data.m_stride = -bytesPerRow; + + char *bits = (char *)ds.dsBm.bmBits; if ( h > 1 ) { - data->m_pixels += (h - 1)*bytesPerRow; + bits += (h - 1)*bytesPerRow; } - return TRUE; + return bits; +#else + return NULL; +#endif } -void wxBitmap::UngetRawData(wxRawBitmapData *data) +void wxBitmap::UngetRawData(wxPixelDataBase& dataBase) { - wxCHECK_RET( data, _T("NULL pointer in wxBitmap::UngetRawData()") ); - +#if wxUSE_WXDIB if ( !Ok() ) return; - if ( !*data ) + // the cast is ugly but we can't do without it and without making this + // function template (and hence inline) unfortunately + typedef wxPixelData PixelData; + PixelData& data = (PixelData &)dataBase; + + if ( !data ) { // invalid data, don't crash -- but don't assert neither as we're - // called automatically from wxRawBitmapData dtor and so there is no + // called automatically from wxPixelDataBase dtor and so there is no // way to prevent this from happening return; } - // 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++ ) + if ( GetBitmapData()->m_hasAlpha ) { - wxRawBitmapIterator rowStart = p; + // AlphaBlend() wants to have premultiplied source alpha but + // wxRawBitmap API uses normal, not premultiplied, colours, so adjust + // them here now + PixelData::Iterator p(data); + + const int w = data.GetWidth(); + const int h = data.GetHeight(); - for ( int x = 0; x < w; x++ ) + for ( int y = 0; y < h; y++ ) { - const unsigned alpha = p.Alpha(); + PixelData::Iterator rowStart = p; - p.Red() = (p.Red() * alpha + 127) / 255; - p.Blue() = (p.Blue() * alpha + 127) / 255; - p.Green() = (p.Green() * alpha + 127) / 255; + for ( int x = 0; x < w; x++ ) + { + const unsigned alpha = p.Alpha(); - ++p; - } + p.Red() = (p.Red() * alpha + 127) / 255; + p.Blue() = (p.Blue() * alpha + 127) / 255; + p.Green() = (p.Green() * alpha + 127) / 255; - p = rowStart; - p.OffsetY(1); - } + ++p; + } - // 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; + p = rowStart; + p.OffsetY(data, 1); + } - // TODO: convert + // if we're a DDB we need to convert DIB back to DDB now to make the + // changes made via raw bitmap access effective + if ( !GetBitmapData()->m_isDIB ) + { + wxDIB *dib = GetBitmapData()->m_dib; + GetBitmapData()->m_dib = NULL; + + // TODO: convert - delete dib; + delete dib; + } } +#endif } +#endif // #ifdef wxHAVE_RAW_BITMAP // ---------------------------------------------------------------------------- // wxMask