Add real support for monochrome bitmaps to wxMSW

In order to be able to use monochrome bitmaps as wxMask, improve support
for them in various ways:

1. Implement loading and saving of monochrome BMP files.
2. Add wxMonoPixelData for direct access to monochrome bitmap pixels.
3. Implement conversion from wxImage to monochrome wxBitmap.

Closes https://github.com/wxWidgets/wxWidgets/pull/2032
This commit is contained in:
Bill Su
2020-10-19 20:50:31 -04:00
committed by Vadim Zeitlin
parent c0e3bdaab9
commit 7e9afad53a
5 changed files with 602 additions and 69 deletions

View File

@@ -70,7 +70,7 @@ public:
#if wxUSE_WXDIB
// Creates a new bitmap (DDB or DIB) from the contents of the given DIB.
void CopyFromDIB(const wxDIB& dib);
void CopyFromDIB(const wxDIB& dib, int depth = -1);
// Takes ownership of the given DIB.
bool AssignDIB(wxDIB& dib);
@@ -318,14 +318,15 @@ void wxBitmapRefData::InitFromDIB(const wxDIB& dib, HBITMAP hbitmap)
m_hBitmap = (WXHBITMAP)hbitmap;
}
void wxBitmapRefData::CopyFromDIB(const wxDIB& dib)
void wxBitmapRefData::CopyFromDIB(const wxDIB& dib, int depth /* = -1 */)
{
wxCHECK_RET( !IsOk(), "bitmap already initialized" );
wxCHECK_RET( dib.IsOk(), wxT("invalid DIB in CopyFromDIB") );
HBITMAP hbitmap;
#ifdef SOMETIMES_USE_DIB
hbitmap = dib.CreateDDB();
// MemoryHDC defaults to monochrome
hbitmap = dib.CreateDDB(depth == 1 ? HDC(MemoryHDC()) : NULL);
#else // ALWAYS_USE_DIB
hbitmap = NULL;
#endif // SOMETIMES_USE_DIB/ALWAYS_USE_DIB
@@ -845,7 +846,7 @@ bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc)
const int h = image.GetHeight();
const int w = image.GetWidth();
wxDIB dib(image);
wxDIB dib(image, wxDIB::PixelFormat_PreMultiplied, depth);
if ( !dib.IsOk() )
return false;
@@ -1269,7 +1270,7 @@ void wxBitmap::MSWBlendMaskWithAlpha()
{
wxBitmap bmpMask = GetMask()->GetBitmap();
wxNativePixelData maskData(bmpMask);
wxMonoPixelData maskData(bmpMask);
wxCHECK_RET(maskData, "No access to bitmap mask data");
wxAlphaPixelData bmpData(*this);
@@ -1278,17 +1279,17 @@ void wxBitmap::MSWBlendMaskWithAlpha()
const int w = GetWidth();
const int h = GetHeight();
wxNativePixelData::Iterator maskRowStart(maskData);
wxMonoPixelData::Iterator maskRowStart(maskData);
wxAlphaPixelData::Iterator bmpRowStart(bmpData);
for ( int y = 0; y < h; y++ )
{
wxNativePixelData::Iterator pMask = maskRowStart;
wxMonoPixelData::Iterator pMask = maskRowStart;
wxAlphaPixelData::Iterator pBmp = bmpRowStart;
for ( int x = 0; x < w; x++, ++pBmp, ++pMask )
{
// Masked pixel is not drawn i.e. is transparent,
// non-masked pixel is untouched.
if ( pMask.Red() == 0 )
if ( pMask.Pixel() == 0 )
{
pBmp.Red() = pBmp.Green() = pBmp.Blue() = 0; // pre-multiplied
pBmp.Alpha() = wxALPHA_TRANSPARENT;
@@ -1378,6 +1379,12 @@ void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
// no bitmap, no data (raw or otherwise)
return NULL;
}
if ( bpp == 1 && GetDepth() != 1 )
{
wxFAIL_MSG( wxT("use wxQuantize if you want to convert color wxBitmap to mono") );
return NULL;
}
// if we're already a DIB we can access our data directly, but if not we
// need to convert this DDB to a DIB section and use it for raw access and
@@ -1388,7 +1395,7 @@ void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
wxCHECK_MSG( !GetBitmapData()->m_dib, NULL,
wxT("GetRawData() may be called only once") );
wxDIB *dib = new wxDIB(*this);
wxDIB *dib = new wxDIB(*this, bpp);
if ( !dib->IsOk() )
{
delete dib;
@@ -1462,7 +1469,8 @@ void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(data))
GetBitmapData()->m_dib = NULL;
GetBitmapData()->Free();
GetBitmapData()->CopyFromDIB(*dib);
int depth = GetDepth() == 1 && dib->GetDepth() != GetDepth() ? 1 : -1;
GetBitmapData()->CopyFromDIB(*dib, depth);
delete dib;
}