From: Vadim Zeitlin Date: Thu, 2 Jan 2003 23:28:56 +0000 (+0000) Subject: support for using DIBs for wxBitmap implementation (patch 649866) X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/0becd470109886a71b5fb51c60f9842318eaeca9 support for using DIBs for wxBitmap implementation (patch 649866) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@18524 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/docs/changes.txt b/docs/changes.txt index d28dee8508..a7052afe19 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -31,6 +31,7 @@ wxGTK: wxMSW: +- possibility to use DIBs for wxBitmap implementation (Derry Bryson) - wxStaticBitmap doesn't stretch its bitmap any longer (like other ports) - support for accelerator keys in the owner drawn menus (Derry Bryson) - wxCaret::SetSize() doesn't hide the caret any longer as it used to diff --git a/include/wx/msw/bitmap.h b/include/wx/msw/bitmap.h index dff632bbb3..da82b22d7d 100644 --- a/include/wx/msw/bitmap.h +++ b/include/wx/msw/bitmap.h @@ -63,6 +63,10 @@ public: // optional mask for transparent drawing wxMask *m_bitmapMask; + +#if wxUSE_DIB_FOR_BITMAP + WXHANDLE m_hFileMap; // file mapping handle for large DIB's +#endif }; // ---------------------------------------------------------------------------- @@ -177,6 +181,11 @@ public: void SetHBITMAP(WXHBITMAP bmp) { SetHandle((WXHANDLE)bmp); } WXHBITMAP GetHBITMAP() const { return (WXHBITMAP)GetHandle(); } +#if wxUSE_DIB_FOR_BITMAP + void SetHFileMap(WXHANDLE hFileMap) { GetBitmapData()->m_hFileMap = hFileMap; } + WXHANDLE GetHFileMap() const { return GetBitmapData()->m_hFileMap; } +#endif // wxUSE_DIB_FOR_BITMAP + void SetSelectedInto(wxDC *dc) { if (GetBitmapData()) GetBitmapData()->m_selectedInto = dc; } wxDC *GetSelectedInto() const { return (GetBitmapData() ? GetBitmapData()->m_selectedInto : (wxDC*) NULL); } @@ -209,6 +218,11 @@ protected: bool CreateFromImage(const wxImage& image, int depth); #endif // wxUSE_IMAGE +#if wxUSE_DIB_FOR_BITMAP + void *CreateDIB(int width, int height, int depth); + void CopyDIBLine(void* src, void* dest, int count) const; +#endif + private: #ifdef __WIN32__ // common part of CopyFromIcon/CopyFromCursor for Win32 diff --git a/include/wx/msw/setup0.h b/include/wx/msw/setup0.h index 92bfe23367..365de9e7c0 100644 --- a/include/wx/msw/setup0.h +++ b/include/wx/msw/setup0.h @@ -636,6 +636,10 @@ // wxDC cacheing implementation #define wxUSE_DC_CACHEING 1 +// Set this to 1 to enable the use of DIB's for wxBitmap to support +// bitmaps > 16MB on Win95/98/Me. Set to 0 to use DDB's only. +#define wxUSE_DIB_FOR_BITMAP 0 + // ---------------------------------------------------------------------------- // common dialogs // ---------------------------------------------------------------------------- diff --git a/src/msw/bitmap.cpp b/src/msw/bitmap.cpp index 038afaa721..fceabb32c4 100644 --- a/src/msw/bitmap.cpp +++ b/src/msw/bitmap.cpp @@ -1,4 +1,4 @@ -///////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// // Name: bitmap.cpp // Purpose: wxBitmap // Author: Julian Smart @@ -81,6 +81,9 @@ wxBitmapRefData::wxBitmapRefData() m_numColors = 0; m_bitmapMask = NULL; m_hBitmap = (WXHBITMAP) NULL; +#if wxUSE_DIB_FOR_BITMAP + m_hFileMap = 0; +#endif } void wxBitmapRefData::Free() @@ -99,6 +102,14 @@ void wxBitmapRefData::Free() #endif } +#if wxUSE_DIB_FOR_BITMAP + if(m_hFileMap) + { + ::CloseHandle((void*)m_hFileMap); + m_hFileMap = 0; + } +#endif + delete m_bitmapMask; m_bitmapMask = NULL; } @@ -341,41 +352,122 @@ bool wxBitmap::Create(int w, int h, int d) m_refData = new wxBitmapRefData; - GetBitmapData()->m_width = w; - GetBitmapData()->m_height = h; - GetBitmapData()->m_depth = d; - - HBITMAP hbmp; -#ifndef __WXMICROWIN__ - if ( d > 0 ) +#if wxUSE_DIB_FOR_BITMAP + if ( w && h && d >= 16 ) { - hbmp = ::CreateBitmap(w, h, 1, d, NULL); - if ( !hbmp ) - { - wxLogLastError(wxT("CreateBitmap")); - } + if ( !CreateDIB(w, h, d) ) + return FALSE; } else -#endif +#endif // wxUSE_DIB_FOR_BITMAP { - ScreenHDC dc; - hbmp = ::CreateCompatibleBitmap(dc, w, h); - if ( !hbmp ) + GetBitmapData()->m_width = w; + GetBitmapData()->m_height = h; + GetBitmapData()->m_depth = d; + + HBITMAP hbmp; +#ifndef __WXMICROWIN__ + if ( d > 0 ) + { + hbmp = ::CreateBitmap(w, h, 1, d, NULL); + if ( !hbmp ) + { + wxLogLastError(wxT("CreateBitmap")); + } + } + else +#endif // !__WXMICROWIN__ { - wxLogLastError(wxT("CreateCompatibleBitmap")); + ScreenHDC dc; + hbmp = ::CreateCompatibleBitmap(dc, w, h); + if ( !hbmp ) + { + wxLogLastError(wxT("CreateCompatibleBitmap")); + } + + GetBitmapData()->m_depth = wxDisplayDepth(); } - GetBitmapData()->m_depth = wxDisplayDepth(); + SetHBITMAP((WXHBITMAP)hbmp); } - SetHBITMAP((WXHBITMAP)hbmp); - #if WXWIN_COMPATIBILITY_2 GetBitmapData()->m_ok = hbmp != 0; #endif // WXWIN_COMPATIBILITY_2 + return Ok(); } +#if wxUSE_DIB_FOR_BITMAP + +void *wxBitmap::CreateDIB(int width, int height, int depth) +{ + void *dibBits; + const int infosize = sizeof(BITMAPINFOHEADER); + + BITMAPINFO *info = (BITMAPINFO *)malloc(infosize); + if ( info ) + { + memset(info, 0, infosize); + + info->bmiHeader.biSize = infosize; + info->bmiHeader.biWidth = width; + info->bmiHeader.biHeight = height; + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = depth; + info->bmiHeader.biCompression = BI_RGB; + info->bmiHeader.biSizeImage = + (((width * (depth/8)) + sizeof(DWORD) - 1) / + sizeof(DWORD) * sizeof(DWORD)) * height; + info->bmiHeader.biXPelsPerMeter = 0; + info->bmiHeader.biYPelsPerMeter = 0; + info->bmiHeader.biClrUsed = 0; + info->bmiHeader.biClrImportant = 0; + GetBitmapData()->m_hFileMap = + (WXHANDLE)::CreateFileMapping + ( + INVALID_HANDLE_VALUE, + 0, + PAGE_READWRITE | SEC_COMMIT, + 0, + info->bmiHeader.biSizeImage, + 0 + ); + + // No need to report an error here. If it fails, we just won't use a + // file mapping and CreateDIBSection will just allocate memory for us. + GetBitmapData()->m_handle = + (WXHANDLE)::CreateDIBSection + ( + 0, + info, + DIB_RGB_COLORS, + &dibBits, + (HANDLE)GetBitmapData()->m_hFileMap, + 0 + ); + + if ( !GetBitmapData()->m_handle ) + wxLogLastError(wxT("CreateDIBSection")); + + SetWidth(width); + SetHeight(height); + SetDepth(depth); + + free(info); + } + else + { + wxFAIL_MSG( wxT("could not allocate memory for DIB header") ); + + dibBits = NULL; + } + + return dibBits; +} + +#endif // wxUSE_DIB_FOR_BITMAP + // ---------------------------------------------------------------------------- // wxImage to/from conversions // ---------------------------------------------------------------------------- @@ -397,7 +489,6 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth ) // so the 'depth' argument is ignored. 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()); @@ -503,16 +594,56 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth ) return TRUE; -#else +#else // !__WXMICROWIN__ wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") ) m_refData = new wxBitmapRefData(); +#if wxUSE_DIB_FOR_BITMAP + int h = image.GetHeight(); + int w = image.GetWidth(); + unsigned char *dibBits = (unsigned char*)CreateDIB(w, h, 24); + if ( !dibBits ) + return FALSE; + + // DIBs are stored in bottom to top order so we need to copy bits line by + // line and starting from the end + const int srcBytesPerLine = w * 3; + const int dstBytesPerLine = (srcBytesPerLine + sizeof(DWORD) - 1) / + sizeof(DWORD) * sizeof(DWORD); + const unsigned char *src = image.GetData() + ((h - 1) * srcBytesPerLine); + for ( int i = 0; i < h; i++ ) + { + // copy one DIB line + int x = w; + const unsigned char *rgbBits = src; + while ( x-- ) + { + // also, the order of RGB is inversed for DIBs + *dibBits++ = rgbBits[2]; + *dibBits++ = rgbBits[1]; + *dibBits++ = rgbBits[0]; + + rgbBits += 3; + } + + // pass to the next line + src -= srcBytesPerLine; + dibBits += dstBytesPerLine - srcBytesPerLine; + } + + if ( image.HasMask() ) + { + SetMask(new wxMask(*this, wxColour(image.GetMaskRed(), + image.GetMaskGreen(), + image.GetMaskBlue()))); + } +#else // wxUSE_DIB_FOR_BITMAP // sizeLimit is the MS upper limit for the DIB size #ifdef WIN32 int sizeLimit = 1024*768*3; #else - int sizeLimit = 0x7fff ; + int sizeLimit = 0x7fff; #endif // width and height of the device-dependent bitmap @@ -726,6 +857,7 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth ) ::ReleaseDC(NULL, hdc); free(lpDIBh); free(lpBits); +#endif // wxUSE_DIB_FOR_BITMAP #if WXWIN_COMPATIBILITY_2 // check the wxBitmap object @@ -733,7 +865,7 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth ) #endif // WXWIN_COMPATIBILITY_2 return TRUE; -#endif +#endif // __WXMICROWIN__/!__WXMICROWIN__ } wxImage wxBitmap::ConvertToImage() const @@ -799,8 +931,7 @@ wxImage wxBitmap::ConvertToImage() const return image; -#else // __MICROWIN__ - +#else // !__WXMICROWIN__ wxImage image; wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") ); @@ -925,7 +1056,7 @@ wxImage wxBitmap::ConvertToImage() const free(lpBits); return image; -#endif +#endif // __WXMICROWIN__/!__WXMICROWIN__ } #endif // wxUSE_IMAGE diff --git a/src/msw/dcprint.cpp b/src/msw/dcprint.cpp index e04d74c88d..9ae94b59e1 100644 --- a/src/msw/dcprint.cpp +++ b/src/msw/dcprint.cpp @@ -431,45 +431,78 @@ void wxPrinterDC::DoDrawBitmap(const wxBitmap &bmp, if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB ) { - BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) ); - memset( info, 0, sizeof( BITMAPINFOHEADER ) ); +#if wxUSE_DIB_FOR_BITMAP + if(bmp.GetHFileMap()) // we already have a dib + { + DIBSECTION dib; + if ( ::GetObject(GetHbitmapOf(bmp), + sizeof(dib), + &dib) == sizeof(dib) ) + { + if ( ::StretchDIBits + ( + GetHdc(), + x, y, + width, height, + 0, 0, + width, height, + dib.dsBm.bmBits, + (LPBITMAPINFO)&dib.dsBmih, + DIB_RGB_COLORS, + SRCCOPY + ) == GDI_ERROR ) + { + wxLogLastError(wxT("StretchDIBits")); + } + } + else + { + wxLogLastError(wxT("GetObject")); + } + } + else +#endif // wxUSE_DIB_FOR_BITMAP + { + BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) ); + memset( info, 0, sizeof( BITMAPINFOHEADER ) ); #if wxUSE_DRAWBITMAP_24BITS - int iBitsSize = (((width * 3) + 3 ) & ~3 ) * height; + int iBitsSize = (((width * 3) + 3 ) & ~3 ) * height; #else - int iBitsSize = ((width + 3 ) & ~3 ) * height ; + int iBitsSize = ((width + 3 ) & ~3 ) * height ; #endif - void* bits = malloc( iBitsSize ); + void* bits = malloc( iBitsSize ); - info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); - info->bmiHeader.biWidth = width; - info->bmiHeader.biHeight = height; - info->bmiHeader.biPlanes = 1; + info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); + info->bmiHeader.biWidth = width; + info->bmiHeader.biHeight = height; + info->bmiHeader.biPlanes = 1; #if wxUSE_DRAWBITMAP_24BITS - info->bmiHeader.biBitCount = 24; + info->bmiHeader.biBitCount = 24; #else - info->bmiHeader.biBitCount = 8; -#endif - info->bmiHeader.biCompression = BI_RGB; - - ScreenHDC display; - if ( GetDIBits(display, GetHbitmapOf(bmp), 0, - bmp.GetHeight(), bits, info, - DIB_RGB_COLORS) ) - { - if ( ::StretchDIBits(GetHdc(), x, y, - width, height, - 0 , 0, width, height, - bits, info, - DIB_RGB_COLORS, SRCCOPY) == GDI_ERROR ) + info->bmiHeader.biBitCount = 8; +#endif + info->bmiHeader.biCompression = BI_RGB; + + ScreenHDC display; + if ( GetDIBits(display, GetHbitmapOf(bmp), 0, + bmp.GetHeight(), bits, info, + DIB_RGB_COLORS) ) { - wxLogLastError(wxT("StretchDIBits")); + if ( ::StretchDIBits(GetHdc(), x, y, + width, height, + 0 , 0, width, height, + bits, info, + DIB_RGB_COLORS, SRCCOPY) == GDI_ERROR ) + { + wxLogLastError(wxT("StretchDIBits")); + } } - } - free(bits); - free(info); + free(bits); + free(info); + } } else // no support for StretchDIBits() { @@ -493,9 +526,8 @@ bool wxPrinterDC::DoBlit(wxCoord xdest, wxCoord ydest, if ( useMask ) { - // If we are printing source colours are screen colours - // not printer colours and so we need copy the bitmap - // pixel by pixel. + // If we are printing source colours are screen colours not printer + // colours and so we need copy the bitmap pixel by pixel. RECT rect; HDC dc_src = GetHdcOf(*source); HDC dc_mask = ::CreateCompatibleDC(dc_src); @@ -528,58 +560,97 @@ bool wxPrinterDC::DoBlit(wxCoord xdest, wxCoord ydest, wxBitmap& bmp = source->GetSelectedBitmap(); int width = bmp.GetWidth(), height = bmp.GetHeight(); +#if wxUSE_DIB_FOR_BITMAP + if(bmp.GetHFileMap()) // we already have a dib + { + DIBSECTION dib; + if( ::GetObject(GetHbitmapOf(bmp), + sizeof(dib), + &dib) == sizeof(dib) ) + { + if ( ::StretchDIBits + ( + GetHdc(), + xdest, ydest, + width, height, + xsrc, ysrc, + width, height, + dib.dsBm.bmBits, + (LPBITMAPINFO)&dib.dsBmih, + DIB_RGB_COLORS, + SRCCOPY + ) == GDI_ERROR ) + { + wxLogLastError(wxT("StretchDIBits")); + } + } + else + { + wxLogLastError(wxT("GetObject")); + } + } + else +#endif // wxUSE_DIB_FOR_BITMAP + { + BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) ); +#if wxUSE_DRAWBITMAP_24BITS + int iBitsSize = (((width * 3) + 3 ) & ~3 ) * height; +#else + int iBitsSize = ((width + 3 ) & ~3 ) * height ; +#endif - BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) ); - int iBitsSize = ((width + 3 ) & ~3 ) * height; - - void* bits = malloc( iBitsSize ); + void* bits = malloc( iBitsSize ); - memset( info , 0 , sizeof( BITMAPINFOHEADER ) ); + memset( info , 0 , sizeof( BITMAPINFOHEADER ) ); - info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); - info->bmiHeader.biWidth = width; - info->bmiHeader.biHeight = height; - info->bmiHeader.biPlanes = 1; - info->bmiHeader.biBitCount = 8; - info->bmiHeader.biCompression = BI_RGB; + info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); + info->bmiHeader.biWidth = width; + info->bmiHeader.biHeight = height; + info->bmiHeader.biPlanes = 1; +#if wxUSE_DRAWBITMAP_24BITS + info->bmiHeader.biBitCount = 24; +#else + info->bmiHeader.biBitCount = 8; +#endif + info->bmiHeader.biCompression = BI_RGB; - ScreenHDC display; - if ( !::GetDIBits(display, GetHbitmapOf(bmp), 0, - height, bits, info, DIB_RGB_COLORS) ) - { - wxLogLastError(wxT("GetDIBits")); + ScreenHDC display; + if ( !::GetDIBits(display, GetHbitmapOf(bmp), 0, + height, bits, info, DIB_RGB_COLORS) ) + { + wxLogLastError(wxT("GetDIBits")); - success = FALSE; - } + success = FALSE; + } - if ( success ) - { - success = ::StretchDIBits(GetHdc(), xdest, ydest, - width, height, - xsrc, ysrc, - width, height, - bits, info , - DIB_RGB_COLORS, - SRCCOPY) != GDI_ERROR; - if ( !success ) + if ( success ) { - wxLogLastError(wxT("StretchDIBits")); + success = ::StretchDIBits(GetHdc(), xdest, ydest, + width, height, + xsrc, ysrc, + width, height, + bits, info , + DIB_RGB_COLORS, + SRCCOPY) != GDI_ERROR; + if ( !success ) + { + wxLogLastError(wxT("StretchDIBits")); + } } - } - free(bits); - free(info); + free(bits); + free(info); + } } else // no support for StretchDIBits { - // as we are printing, source colours are screen colours not printer - // colours and so we need copy the bitmap pixel by pixel. + // as we are printing, source colours are screen colours not + // printer colours and so we need copy the bitmap pixel by pixel. HDC dc_src = GetHdcOf(*source); RECT rect; for (int y = 0; y < height; y++) { - // This is Stefan Csomor's optimisation, where identical adjacent - // pixels are drawn together. + // optimization: draw identical adjacent pixels together. for (int x = 0; x < width; x++) { COLORREF col = ::GetPixel(dc_src, x, y);