Don't lose alpha when converting GDI+ bitmap to wxImage

wxGDIPlusBitmapData::ConvertToImage() lost the alpha channel of the image as
it used the bitmap handle returned Gdiplus::Bitmap::GetHBITMAP() which is a
DDB and doesn't contain real alpha channel values.

In order to retrieve actual alpha channel data there is necessary to get
direct access to Gdiplus::Bitmap bits with Bitmap::LockBits and transfer pixel
data to wxImage pixel by pixel.

Closes #17174.
This commit is contained in:
Artur Wieczorek
2015-12-31 15:58:56 +01:00
committed by Vadim Zeitlin
parent 450019dc21
commit b65a3f5520

View File

@@ -1104,20 +1104,37 @@ wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer* renderer,
wxImage wxGDIPlusBitmapData::ConvertToImage() const
{
// We could use Bitmap::LockBits() and convert to wxImage directly but
// passing by wxBitmap is easier. It would be nice to measure performance
// of the two methods but for this the second one would need to be written
// first...
HBITMAP hbmp;
if ( m_bitmap->GetHBITMAP(Color(0xffffffff), &hbmp) != Gdiplus::Ok )
return wxNullImage;
// We need to use Bitmap::LockBits() to convert bitmap to wxImage
// because this way we can retrieve also alpha channel data.
// Alternative way by retrieving bitmap handle with Bitmap::GetHBITMAP
// (to pass it to wxBitmap) doesn't preserve real alpha channel data.
const UINT w = m_bitmap->GetWidth();
const UINT h = m_bitmap->GetHeight();
wxBitmap bmp;
bmp.SetWidth(m_bitmap->GetWidth());
bmp.SetHeight(m_bitmap->GetHeight());
bmp.SetHBITMAP(hbmp);
bmp.SetDepth(IsAlphaPixelFormat(m_bitmap->GetPixelFormat()) ? 32 : 24);
return bmp.ConvertToImage();
wxImage img(w, h);
img.InitAlpha();
BitmapData bitmapData;
Rect rect(0, 0, w, h);
m_bitmap->LockBits(&rect, ImageLockModeRead, PixelFormat32bppARGB, &bitmapData);
const BYTE* pixels = static_cast<const BYTE*>(bitmapData.Scan0);
for( UINT y = 0; y < h; y++ )
{
for( UINT x = 0; x < w; x++ )
{
ARGB c = reinterpret_cast<const ARGB*>(pixels)[x];
img.SetRGB(x, y, (c >> 16) & 0xFF,
(c >> 8) & 0xFF,
(c >> 0) & 0xFF);
img.SetAlpha(x, y, (c >> 24) & 0xFF);
}
pixels += bitmapData.Stride;
}
m_bitmap->UnlockBits(&bitmapData);
return img;
}
#endif // wxUSE_IMAGE