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
This commit is contained in:
Vadim Zeitlin 2003-01-02 23:28:56 +00:00
parent f178ab7e82
commit 0becd47010
5 changed files with 326 additions and 105 deletions

View File

@ -31,6 +31,7 @@ wxGTK:
wxMSW: wxMSW:
- possibility to use DIBs for wxBitmap implementation (Derry Bryson)
- wxStaticBitmap doesn't stretch its bitmap any longer (like other ports) - wxStaticBitmap doesn't stretch its bitmap any longer (like other ports)
- support for accelerator keys in the owner drawn menus (Derry Bryson) - support for accelerator keys in the owner drawn menus (Derry Bryson)
- wxCaret::SetSize() doesn't hide the caret any longer as it used to - wxCaret::SetSize() doesn't hide the caret any longer as it used to

View File

@ -63,6 +63,10 @@ public:
// optional mask for transparent drawing // optional mask for transparent drawing
wxMask *m_bitmapMask; 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); } void SetHBITMAP(WXHBITMAP bmp) { SetHandle((WXHANDLE)bmp); }
WXHBITMAP GetHBITMAP() const { return (WXHBITMAP)GetHandle(); } 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; } void SetSelectedInto(wxDC *dc) { if (GetBitmapData()) GetBitmapData()->m_selectedInto = dc; }
wxDC *GetSelectedInto() const { return (GetBitmapData() ? GetBitmapData()->m_selectedInto : (wxDC*) NULL); } wxDC *GetSelectedInto() const { return (GetBitmapData() ? GetBitmapData()->m_selectedInto : (wxDC*) NULL); }
@ -209,6 +218,11 @@ protected:
bool CreateFromImage(const wxImage& image, int depth); bool CreateFromImage(const wxImage& image, int depth);
#endif // wxUSE_IMAGE #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: private:
#ifdef __WIN32__ #ifdef __WIN32__
// common part of CopyFromIcon/CopyFromCursor for Win32 // common part of CopyFromIcon/CopyFromCursor for Win32

View File

@ -636,6 +636,10 @@
// wxDC cacheing implementation // wxDC cacheing implementation
#define wxUSE_DC_CACHEING 1 #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 // common dialogs
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Name: bitmap.cpp // Name: bitmap.cpp
// Purpose: wxBitmap // Purpose: wxBitmap
// Author: Julian Smart // Author: Julian Smart
@ -81,6 +81,9 @@ wxBitmapRefData::wxBitmapRefData()
m_numColors = 0; m_numColors = 0;
m_bitmapMask = NULL; m_bitmapMask = NULL;
m_hBitmap = (WXHBITMAP) NULL; m_hBitmap = (WXHBITMAP) NULL;
#if wxUSE_DIB_FOR_BITMAP
m_hFileMap = 0;
#endif
} }
void wxBitmapRefData::Free() void wxBitmapRefData::Free()
@ -99,6 +102,14 @@ void wxBitmapRefData::Free()
#endif #endif
} }
#if wxUSE_DIB_FOR_BITMAP
if(m_hFileMap)
{
::CloseHandle((void*)m_hFileMap);
m_hFileMap = 0;
}
#endif
delete m_bitmapMask; delete m_bitmapMask;
m_bitmapMask = NULL; m_bitmapMask = NULL;
} }
@ -341,41 +352,122 @@ bool wxBitmap::Create(int w, int h, int d)
m_refData = new wxBitmapRefData; m_refData = new wxBitmapRefData;
GetBitmapData()->m_width = w; #if wxUSE_DIB_FOR_BITMAP
GetBitmapData()->m_height = h; if ( w && h && d >= 16 )
GetBitmapData()->m_depth = d;
HBITMAP hbmp;
#ifndef __WXMICROWIN__
if ( d > 0 )
{ {
hbmp = ::CreateBitmap(w, h, 1, d, NULL); if ( !CreateDIB(w, h, d) )
if ( !hbmp ) return FALSE;
{
wxLogLastError(wxT("CreateBitmap"));
}
} }
else else
#endif #endif // wxUSE_DIB_FOR_BITMAP
{ {
ScreenHDC dc; GetBitmapData()->m_width = w;
hbmp = ::CreateCompatibleBitmap(dc, w, h); GetBitmapData()->m_height = h;
if ( !hbmp ) GetBitmapData()->m_depth = d;
HBITMAP hbmp;
#ifndef __WXMICROWIN__
if ( d > 0 )
{ {
wxLogLastError(wxT("CreateCompatibleBitmap")); hbmp = ::CreateBitmap(w, h, 1, d, NULL);
if ( !hbmp )
{
wxLogLastError(wxT("CreateBitmap"));
}
}
else
#endif // !__WXMICROWIN__
{
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 #if WXWIN_COMPATIBILITY_2
GetBitmapData()->m_ok = hbmp != 0; GetBitmapData()->m_ok = hbmp != 0;
#endif // WXWIN_COMPATIBILITY_2 #endif // WXWIN_COMPATIBILITY_2
return Ok(); 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 // wxImage to/from conversions
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -397,7 +489,6 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
// so the 'depth' argument is ignored. // so the 'depth' argument is ignored.
HDC hScreenDC = ::GetDC(NULL); HDC hScreenDC = ::GetDC(NULL);
// printf("Screen planes = %d, bpp = %d\n", hScreenDC->psd->planes, hScreenDC->psd->bpp);
int screenDepth = ::GetDeviceCaps(hScreenDC, BITSPIXEL); int screenDepth = ::GetDeviceCaps(hScreenDC, BITSPIXEL);
HBITMAP hBitmap = ::CreateCompatibleBitmap(hScreenDC, image.GetWidth(), image.GetHeight()); HBITMAP hBitmap = ::CreateCompatibleBitmap(hScreenDC, image.GetWidth(), image.GetHeight());
@ -503,16 +594,56 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
return TRUE; return TRUE;
#else #else // !__WXMICROWIN__
wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") ) wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") )
m_refData = new wxBitmapRefData(); 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 // sizeLimit is the MS upper limit for the DIB size
#ifdef WIN32 #ifdef WIN32
int sizeLimit = 1024*768*3; int sizeLimit = 1024*768*3;
#else #else
int sizeLimit = 0x7fff ; int sizeLimit = 0x7fff;
#endif #endif
// width and height of the device-dependent bitmap // width and height of the device-dependent bitmap
@ -726,6 +857,7 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
::ReleaseDC(NULL, hdc); ::ReleaseDC(NULL, hdc);
free(lpDIBh); free(lpDIBh);
free(lpBits); free(lpBits);
#endif // wxUSE_DIB_FOR_BITMAP
#if WXWIN_COMPATIBILITY_2 #if WXWIN_COMPATIBILITY_2
// check the wxBitmap object // check the wxBitmap object
@ -733,7 +865,7 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
#endif // WXWIN_COMPATIBILITY_2 #endif // WXWIN_COMPATIBILITY_2
return TRUE; return TRUE;
#endif #endif // __WXMICROWIN__/!__WXMICROWIN__
} }
wxImage wxBitmap::ConvertToImage() const wxImage wxBitmap::ConvertToImage() const
@ -799,8 +931,7 @@ wxImage wxBitmap::ConvertToImage() const
return image; return image;
#else // __MICROWIN__ #else // !__WXMICROWIN__
wxImage image; wxImage image;
wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") ); wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
@ -925,7 +1056,7 @@ wxImage wxBitmap::ConvertToImage() const
free(lpBits); free(lpBits);
return image; return image;
#endif #endif // __WXMICROWIN__/!__WXMICROWIN__
} }
#endif // wxUSE_IMAGE #endif // wxUSE_IMAGE

View File

@ -431,45 +431,78 @@ void wxPrinterDC::DoDrawBitmap(const wxBitmap &bmp,
if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB ) if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB )
{ {
BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) ); #if wxUSE_DIB_FOR_BITMAP
memset( info, 0, sizeof( BITMAPINFOHEADER ) ); if(bmp.GetHFileMap()) // we already have a dib
#if wxUSE_DRAWBITMAP_24BITS
int iBitsSize = (((width * 3) + 3 ) & ~3 ) * height;
#else
int iBitsSize = ((width + 3 ) & ~3 ) * height ;
#endif
void* bits = malloc( iBitsSize );
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,
bmp.GetHeight(), bits, info,
DIB_RGB_COLORS) )
{ {
if ( ::StretchDIBits(GetHdc(), x, y, DIBSECTION dib;
width, height, if ( ::GetObject(GetHbitmapOf(bmp),
0 , 0, width, height, sizeof(dib),
bits, info, &dib) == sizeof(dib) )
DIB_RGB_COLORS, SRCCOPY) == GDI_ERROR )
{ {
wxLogLastError(wxT("StretchDIBits")); 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 ) );
free(bits); #if wxUSE_DRAWBITMAP_24BITS
free(info); int iBitsSize = (((width * 3) + 3 ) & ~3 ) * height;
#else
int iBitsSize = ((width + 3 ) & ~3 ) * height ;
#endif
void* bits = malloc( iBitsSize );
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,
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 )
{
wxLogLastError(wxT("StretchDIBits"));
}
}
free(bits);
free(info);
}
} }
else // no support for StretchDIBits() else // no support for StretchDIBits()
{ {
@ -493,9 +526,8 @@ bool wxPrinterDC::DoBlit(wxCoord xdest, wxCoord ydest,
if ( useMask ) if ( useMask )
{ {
// If we are printing source colours are screen colours // If we are printing source colours are screen colours not printer
// not printer colours and so we need copy the bitmap // colours and so we need copy the bitmap pixel by pixel.
// pixel by pixel.
RECT rect; RECT rect;
HDC dc_src = GetHdcOf(*source); HDC dc_src = GetHdcOf(*source);
HDC dc_mask = ::CreateCompatibleDC(dc_src); HDC dc_mask = ::CreateCompatibleDC(dc_src);
@ -528,58 +560,97 @@ bool wxPrinterDC::DoBlit(wxCoord xdest, wxCoord ydest,
wxBitmap& bmp = source->GetSelectedBitmap(); wxBitmap& bmp = source->GetSelectedBitmap();
int width = bmp.GetWidth(), int width = bmp.GetWidth(),
height = bmp.GetHeight(); height = bmp.GetHeight();
#if wxUSE_DIB_FOR_BITMAP
BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) ); if(bmp.GetHFileMap()) // we already have a dib
int iBitsSize = ((width + 3 ) & ~3 ) * height;
void* bits = malloc( iBitsSize );
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;
ScreenHDC display;
if ( !::GetDIBits(display, GetHbitmapOf(bmp), 0,
height, bits, info, DIB_RGB_COLORS) )
{ {
wxLogLastError(wxT("GetDIBits")); DIBSECTION dib;
if( ::GetObject(GetHbitmapOf(bmp),
success = FALSE; sizeof(dib),
} &dib) == sizeof(dib) )
if ( success )
{
success = ::StretchDIBits(GetHdc(), xdest, ydest,
width, height,
xsrc, ysrc,
width, height,
bits, info ,
DIB_RGB_COLORS,
SRCCOPY) != GDI_ERROR;
if ( !success )
{ {
wxLogLastError(wxT("StretchDIBits")); 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
free(bits); void* bits = malloc( iBitsSize );
free(info);
memset( info , 0 , sizeof( BITMAPINFOHEADER ) );
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"));
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 )
{
wxLogLastError(wxT("StretchDIBits"));
}
}
free(bits);
free(info);
}
} }
else // no support for StretchDIBits else // no support for StretchDIBits
{ {
// as we are printing, source colours are screen colours not printer // as we are printing, source colours are screen colours not
// colours and so we need copy the bitmap pixel by pixel. // printer colours and so we need copy the bitmap pixel by pixel.
HDC dc_src = GetHdcOf(*source); HDC dc_src = GetHdcOf(*source);
RECT rect; RECT rect;
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
// This is Stefan Csomor's optimisation, where identical adjacent // optimization: draw identical adjacent pixels together.
// pixels are drawn together.
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
COLORREF col = ::GetPixel(dc_src, x, y); COLORREF col = ::GetPixel(dc_src, x, y);