For MSW, scan line boundary aligned, and >2MB case enabled

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1401 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Unknown (AN)
1999-01-13 22:31:01 +00:00
parent 0330f713ee
commit bba6f3bd3c

View File

@@ -1096,36 +1096,66 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream )
wxBitmap wxImage::ConvertToBitmap() const wxBitmap wxImage::ConvertToBitmap() const
{ {
// sizeLimit is the MS upper limit for the DIB size
int sizeLimit = 1024*768*3;
// width and height of the device-dependent bitmap
int width = GetWidth();
int bmpHeight = GetHeight();
// calc the number of bytes per scanline and padding
int bytePerLine = width*3;
int sizeDWORD = sizeof( DWORD );
div_t lineBoundary = div( bytePerLine, sizeDWORD );
int padding = 0;
if( lineBoundary.rem > 0 )
{
padding = sizeDWORD - lineBoundary.rem;
bytePerLine += padding;
}
// calc the number of DIBs and heights of DIBs
int numDIB = 1;
int hRemain = 0;
int height = sizeLimit/bytePerLine;
if( height >= bmpHeight )
height = bmpHeight;
else
{
div_t result = div( bmpHeight, height );
numDIB = result.quot;
hRemain = result.rem;
if( hRemain >0 ) numDIB++;
}
// set bitmap parameters
wxBitmap bitmap; wxBitmap bitmap;
wxCHECK_MSG( Ok(), bitmap, "invalid image" ); wxCHECK_MSG( Ok(), bitmap, "invalid image" );
int width = GetWidth();
int height = GetHeight();
bitmap.SetWidth( width ); bitmap.SetWidth( width );
bitmap.SetHeight( height ); bitmap.SetHeight( bmpHeight );
bitmap.SetDepth( wxDisplayDepth() ); bitmap.SetDepth( wxDisplayDepth() );
// create a DIB header
int headersize = sizeof(BITMAPINFOHEADER); int headersize = sizeof(BITMAPINFOHEADER);
LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize ); LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
wxCHECK_MSG( lpDIBh, bitmap, "could not allocate memory for DIB header" ); wxCHECK_MSG( lpDIBh, bitmap, "could not allocate memory for DIB header" );
// Fill in the DIB header // Fill in the DIB header
lpDIBh->bmiHeader.biSize = headersize; lpDIBh->bmiHeader.biSize = headersize;
lpDIBh->bmiHeader.biWidth = width; lpDIBh->bmiHeader.biWidth = (DWORD)width;
lpDIBh->bmiHeader.biHeight = -height; lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
lpDIBh->bmiHeader.biSizeImage = width * height * 3; lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
// the general formula for biSizeImage:
// ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
lpDIBh->bmiHeader.biPlanes = 1; lpDIBh->bmiHeader.biPlanes = 1;
lpDIBh->bmiHeader.biBitCount = 24; lpDIBh->bmiHeader.biBitCount = 24;
lpDIBh->bmiHeader.biCompression = BI_RGB; lpDIBh->bmiHeader.biCompression = BI_RGB;
lpDIBh->bmiHeader.biClrUsed = 0; lpDIBh->bmiHeader.biClrUsed = 0;
// These seem not really needed for our purpose here.
// These seem not needed for our purpose here. lpDIBh->bmiHeader.biClrImportant = 0;
// lpDIBh->bmiHeader.biClrImportant = 0; lpDIBh->bmiHeader.biXPelsPerMeter = 0;
// lpDIBh->bmiHeader.biXPelsPerMeter = 0; lpDIBh->bmiHeader.biYPelsPerMeter = 0;
// lpDIBh->bmiHeader.biYPelsPerMeter = 0; // memory for DIB data
unsigned char *lpBits;
unsigned char *lpBits = (unsigned char *) malloc( width*height*3 ); lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
if( !lpBits ) if( !lpBits )
{ {
wxFAIL_MSG( "could not allocate memory for DIB" ); wxFAIL_MSG( "could not allocate memory for DIB" );
@@ -1133,22 +1163,48 @@ wxBitmap wxImage::ConvertToBitmap() const
return bitmap; return bitmap;
} }
unsigned char *data = GetData(); // create and set the device-dependent bitmap
HDC hdc = ::GetDC(NULL);
HDC memdc = ::CreateCompatibleDC( hdc );
HBITMAP hbitmap;
hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
::SelectObject( memdc, hbitmap);
unsigned char *ptdata = data, *ptbits = lpBits; // copy image data into DIB data and then into DDB (in a loop)
for( int i=0; i<width*height; i++ ) unsigned char *data = GetData();
int i, j, n;
int origin = 0;
unsigned char *ptdata = data;
unsigned char *ptbits;
for( n=0; n<numDIB; n++ )
{
if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
{
// redefine height and size of the (possibly) last smaller DIB
// memory is not reallocated
height = hRemain;
lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
}
ptbits = lpBits;
for( j=0; j<height; j++ )
{
for( i=0; i<width; i++ )
{ {
*(ptbits++) = *(ptdata+2); *(ptbits++) = *(ptdata+2);
*(ptbits++) = *(ptdata+1); *(ptbits++) = *(ptdata+1);
*(ptbits++) = *(ptdata ); *(ptbits++) = *(ptdata );
ptdata += 3; ptdata += 3;
} }
for( i=0; i< padding; i++ ) *(ptbits++) = 0;
HDC hdc = ::GetDC(NULL); }
::StretchDIBits( memdc, 0, origin, width, height,\
HBITMAP hbitmap; 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS ); origin += height;
// if numDIB = 1, lines below can also be used
// hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
// The above line is equivalent to the following two lines. // The above line is equivalent to the following two lines.
// hbitmap = ::CreateCompatibleBitmap( hdc, width, height ); // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
// ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS); // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
@@ -1160,18 +1216,38 @@ wxBitmap wxImage::ConvertToBitmap() const
// 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS); // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
// ::SelectObject( memdc, 0 ); // ::SelectObject( memdc, 0 );
// ::DeleteDC( memdc ); // ::DeleteDC( memdc );
}
bitmap.SetHBITMAP( (WXHBITMAP) hbitmap ); bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
// similarly, created an mono-bitmap for the possible mask
if( HasMask() ) if( HasMask() )
{ {
hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
::SelectObject( memdc, hbitmap);
if( numDIB == 1 ) height = bmpHeight;
else height = sizeLimit/bytePerLine;
lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
origin = 0;
unsigned char r = GetMaskRed(); unsigned char r = GetMaskRed();
unsigned char g = GetMaskGreen(); unsigned char g = GetMaskGreen();
unsigned char b = GetMaskBlue(); unsigned char b = GetMaskBlue();
unsigned char zero = 0, one = 255; unsigned char zero = 0, one = 255;
ptdata = data; ptdata = data;
for( n=0; n<numDIB; n++ )
{
if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
{
// redefine height and size of the (possibly) last smaller DIB
// memory is not reallocated
height = hRemain;
lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
}
ptbits = lpBits; ptbits = lpBits;
for( int i=0; i<width*height; i++ ) for( int j=0; j<height; j++ )
{
for( int i=0; i<width; i++ )
{ {
if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) ) if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
{ {
@@ -1186,12 +1262,17 @@ wxBitmap wxImage::ConvertToBitmap() const
*(ptbits++) = zero; *(ptbits++) = zero;
} }
} }
hbitmap = ::CreateBitmap( (WORD)width, (WORD)height, 1, 1, NULL ); for( i=0; i< padding; i++ ) *(ptbits++) = zero;
::SetDIBits( hdc, hbitmap, 0, (WORD)height, lpBits, lpDIBh, DIB_RGB_COLORS); }
::StretchDIBits( memdc, 0, origin, width, height,\
0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
origin += height;
}
// create a wxMask object
wxMask *mask = new wxMask(); wxMask *mask = new wxMask();
mask->SetMaskBitmap( (WXHBITMAP) hbitmap ); mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
bitmap.SetMask( mask ); bitmap.SetMask( mask );
// It will be deleted when the wxBitmap object is deleted (as of 01/1999)
/* The following can also be used but is slow to run /* The following can also be used but is slow to run
wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue()); wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
wxMask *mask = new wxMask( bitmap, colour ); wxMask *mask = new wxMask( bitmap, colour );
@@ -1199,10 +1280,14 @@ wxBitmap wxImage::ConvertToBitmap() const
*/ */
} }
// free allocated resources
::SelectObject( memdc, 0 );
::DeleteDC( memdc );
::ReleaseDC(NULL, hdc); ::ReleaseDC(NULL, hdc);
free(lpDIBh); free(lpDIBh);
free(lpBits); free(lpBits);
// check the wxBitmap object
if( bitmap.GetHBITMAP() ) if( bitmap.GetHBITMAP() )
bitmap.SetOk( TRUE ); bitmap.SetOk( TRUE );
else else
@@ -1211,15 +1296,16 @@ wxBitmap wxImage::ConvertToBitmap() const
return bitmap; return bitmap;
} }
wxImage::wxImage( const wxBitmap &bitmap ) wxImage::wxImage( const wxBitmap &bitmap )
{ {
// check the bitmap
if( !bitmap.Ok() ) if( !bitmap.Ok() )
{ {
wxFAIL_MSG( "invalid bitmap" ); wxFAIL_MSG( "invalid bitmap" );
return; return;
} }
// create an wxImage object
int width = bitmap.GetWidth(); int width = bitmap.GetWidth();
int height = bitmap.GetHeight(); int height = bitmap.GetHeight();
Create( width, height ); Create( width, height );
@@ -1230,6 +1316,18 @@ wxImage::wxImage( const wxBitmap &bitmap )
return; return;
} }
// calc the number of bytes per scanline and padding in the DIB
int bytePerLine = width*3;
int sizeDWORD = sizeof( DWORD );
div_t lineBoundary = div( bytePerLine, sizeDWORD );
int padding = 0;
if( lineBoundary.rem > 0 )
{
padding = sizeDWORD - lineBoundary.rem;
bytePerLine += padding;
}
// create a DIB header
int headersize = sizeof(BITMAPINFOHEADER); int headersize = sizeof(BITMAPINFOHEADER);
LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize ); LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
if( !lpDIBh ) if( !lpDIBh )
@@ -1238,24 +1336,22 @@ wxImage::wxImage( const wxBitmap &bitmap )
free( data ); free( data );
return; return;
} }
// Fill in the DIB header // Fill in the DIB header
lpDIBh->bmiHeader.biSize = headersize; lpDIBh->bmiHeader.biSize = headersize;
lpDIBh->bmiHeader.biWidth = width; lpDIBh->bmiHeader.biWidth = width;
lpDIBh->bmiHeader.biHeight = -height; lpDIBh->bmiHeader.biHeight = -height;
lpDIBh->bmiHeader.biSizeImage = width * height * 3; lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
lpDIBh->bmiHeader.biPlanes = 1; lpDIBh->bmiHeader.biPlanes = 1;
lpDIBh->bmiHeader.biBitCount = 24; lpDIBh->bmiHeader.biBitCount = 24;
lpDIBh->bmiHeader.biCompression = BI_RGB; lpDIBh->bmiHeader.biCompression = BI_RGB;
lpDIBh->bmiHeader.biClrUsed = 0; lpDIBh->bmiHeader.biClrUsed = 0;
// These seem not really needed for our purpose here.
// These seem not needed for our purpose here. lpDIBh->bmiHeader.biClrImportant = 0;
// lpDIBh->bmiHeader.biClrImportant = 0; lpDIBh->bmiHeader.biXPelsPerMeter = 0;
// lpDIBh->bmiHeader.biXPelsPerMeter = 0; lpDIBh->bmiHeader.biYPelsPerMeter = 0;
// lpDIBh->bmiHeader.biYPelsPerMeter = 0; // memory for DIB data
unsigned char *lpBits;
unsigned char *lpBits = (unsigned char *) malloc( width*height*3 ); lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
if( !lpBits ) if( !lpBits )
{ {
wxFAIL_MSG( "could not allocate data for DIB" ); wxFAIL_MSG( "could not allocate data for DIB" );
@@ -1264,34 +1360,49 @@ wxImage::wxImage( const wxBitmap &bitmap )
return; return;
} }
// copy data from the device-dependent bitmap to the DIB
HDC hdc = ::GetDC(NULL);
HBITMAP hbitmap; HBITMAP hbitmap;
hbitmap = (HBITMAP) bitmap.GetHBITMAP(); hbitmap = (HBITMAP) bitmap.GetHBITMAP();
HDC hdc = ::GetDC(NULL);
::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS ); ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
unsigned char *ptdata = data, *ptbits = lpBits; // copy DIB data into the wxImage object
for( int i=0; i<width*height; i++ ) int i, j;
unsigned char *ptdata = data;
unsigned char *ptbits = lpBits;
for( i=0; i<height; i++ )
{
for( j=0; j<width; j++ )
{ {
*(ptdata++) = *(ptbits+2); *(ptdata++) = *(ptbits+2);
*(ptdata++) = *(ptbits+1); *(ptdata++) = *(ptbits+1);
*(ptdata++) = *(ptbits ); *(ptdata++) = *(ptbits );
ptbits += 3; ptbits += 3;
} }
ptbits += padding;
}
// similarly, set data according to the possible mask bitmap
if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() ) if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
{ {
hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap(); hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
// memory DC created, color set, data copied, and memory DC deleted
HDC memdc = ::CreateCompatibleDC( hdc ); HDC memdc = ::CreateCompatibleDC( hdc );
::SetTextColor( memdc, RGB( 0, 0, 0 ) ); ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
::SetBkColor( memdc, RGB( 255, 255, 255 ) ); ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS ); ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
::DeleteDC( memdc ); ::DeleteDC( memdc );
unsigned char r=16, g=16, b=16; // background set to RGB(16,16,16) // background color set to RGB(16,16,16) in consistent with wxGTK
unsigned char r=16, g=16, b=16;
ptdata = data; ptdata = data;
ptbits = lpBits; ptbits = lpBits;
for( int i=0; i<width*height; i++ ) for( i=0; i<height; i++ )
{
for( j=0; j<width; j++ )
{ {
if( *ptbits != 0 ) if( *ptbits != 0 )
ptdata += 3;
else
{ {
*(ptdata++) = r; *(ptdata++) = r;
*(ptdata++) = g; *(ptdata++) = g;
@@ -1299,9 +1410,16 @@ wxImage::wxImage( const wxBitmap &bitmap )
} }
ptbits += 3; ptbits += 3;
} }
SetMaskColour( r, g, b ); ptbits += padding;
} }
SetMaskColour( r, g, b );
SetMask( TRUE );
}
else
{
SetMask( FALSE );
}
// free allocated resources
::ReleaseDC(NULL, hdc); ::ReleaseDC(NULL, hdc);
free(lpDIBh); free(lpDIBh);
free(lpBits); free(lpBits);