reimplemented wxBitmap::ConvertToImage() using wxDIB

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@28393 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2004-07-22 11:49:45 +00:00
parent e11d2abe46
commit 6faac21b0b

View File

@@ -810,6 +810,7 @@ bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc)
wxImage wxBitmap::ConvertToImage() const wxImage wxBitmap::ConvertToImage() const
{ {
// convert DDB to DIB
wxDIB dib(*this); wxDIB dib(*this);
if ( !dib.IsOk() ) if ( !dib.IsOk() )
@@ -817,122 +818,75 @@ wxImage wxBitmap::ConvertToImage() const
return wxNullImage; return wxNullImage;
} }
// and then DIB to our wxImage
wxImage image = dib.ConvertToImage(); wxImage image = dib.ConvertToImage();
if ( !image.Ok() ) if ( !image.Ok() )
{ {
return wxNullImage; return wxNullImage;
} }
// set mask // now do the same for the mask, if we have any
HBITMAP hbmpMask = GetMask() ? (HBITMAP) GetMask()->GetMaskBitmap() : NULL;
// TODO: WinCE mask-copying support and use wxDIB if ( hbmpMask )
#ifndef __WXWINCE__
if( GetMask() && GetMask()->GetMaskBitmap() )
{ {
static const int MASK_RED = 1; wxDIB dibMask(hbmpMask);
static const int MASK_GREEN = 2; if ( dibMask.IsOk() )
static const int MASK_BLUE = 3;
static const int MASK_BLUE_REPLACEMENT = 2;
HBITMAP hbitmap = (HBITMAP) GetMask()->GetMaskBitmap();
int width = GetWidth();
int height = GetHeight();
int bytesPerLine = width*3;
int sizeDWORD = sizeof( DWORD );
int lineBoundary = bytesPerLine % sizeDWORD;
int padding = 0;
if( lineBoundary > 0 )
{ {
padding = sizeDWORD - lineBoundary; // TODO: use wxRawBitmap to iterate over DIB
bytesPerLine += padding;
}
// create a DIB header // we hard code the mask colour for now but we could also make an
int headersize = sizeof(BITMAPINFOHEADER); // effort (and waste time) to choose a colour not present in the
BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize ); // image already to avoid having to fudge the pixels below --
if( !lpDIBh ) // whether it's worth to do it is unclear however
{ static const int MASK_RED = 1;
wxFAIL_MSG( wxT("could not allocate data for DIB header") ); static const int MASK_GREEN = 2;
//free( data ); static const int MASK_BLUE = 3;
return wxNullImage; static const int MASK_BLUE_REPLACEMENT = 2;
}
// Fill in the DIB header const int h = dibMask.GetHeight();
lpDIBh->bmiHeader.biSize = headersize; const int w = dibMask.GetWidth();
lpDIBh->bmiHeader.biWidth = width; const int bpp = dibMask.GetDepth();
lpDIBh->bmiHeader.biHeight = -height; const int maskBytesPerPixel = bpp >> 3;
lpDIBh->bmiHeader.biSizeImage = bytesPerLine * height; const int maskBytesPerLine = wxDIB::GetLineSize(w, bpp);
lpDIBh->bmiHeader.biPlanes = 1; unsigned char *data = image.GetData();
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 DC created, color set, data copied, and memory DC deleted // remember that DIBs are stored in bottom to top order
unsigned char *
maskLineStart = dibMask.GetData() + ((h - 1) * maskBytesPerLine);
// memory for DIB data for ( int y = 0; y < h; y++, maskLineStart -= maskBytesPerLine )
unsigned char *lpBits
= (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
if( !lpBits )
{
wxFAIL_MSG( wxT("could not allocate data for DIB") );
free( lpDIBh );
return wxNullImage;
}
HDC hdc = ::GetDC(NULL);
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 );
unsigned char *ptdata = image.GetData();//data;
unsigned char *ptbits = lpBits;
int i, j;
for( i=0; i<height; i++ )
{
for( j=0; j<width; j++ )
{ {
// is this pixel transparent? // traverse one mask DIB line
if ( *ptbits != 0 ) unsigned char *mask = maskLineStart;
for ( int x = 0; x < w; x++, mask += maskBytesPerPixel )
{ {
if ( (ptdata[0] == MASK_RED) && // should this pixel be transparent?
(ptdata[1] == MASK_GREEN) && if ( *mask )
(ptdata[2] == MASK_BLUE) )
{ {
// we have to fudge the colour a bit to prevent this // no, check that it isn't transparent by accident
// pixel from appearing transparent if ( (data[0] == MASK_RED) &&
ptdata[2] = MASK_BLUE_REPLACEMENT; (data[1] == MASK_GREEN) &&
(data[2] == MASK_BLUE) )
{
// we have to fudge the colour a bit to prevent
// this pixel from appearing transparent
data[2] = MASK_BLUE_REPLACEMENT;
}
data += 3;
}
else // yes, transparent pixel
{
*data++ = MASK_RED;
*data++ = MASK_GREEN;
*data++ = MASK_BLUE;
} }
ptdata += 3;
} }
else // masked pixel
{
*(ptdata++) = MASK_RED;
*(ptdata++) = MASK_GREEN;
*(ptdata++) = MASK_BLUE;
}
ptbits += 3;
} }
ptbits += padding;
image.SetMaskColour(MASK_RED, MASK_GREEN, MASK_BLUE);
} }
image.SetMaskColour( MASK_RED, MASK_GREEN, MASK_BLUE );
image.SetMask( true );
// free allocated resources
::ReleaseDC(NULL, hdc);
free(lpDIBh);
free(lpBits);
} }
#endif // __WXWINCE__
return image; return image;
} }