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:
committed by
Vadim Zeitlin
parent
450019dc21
commit
b65a3f5520
@@ -1104,20 +1104,37 @@ wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer* renderer,
|
|||||||
|
|
||||||
wxImage wxGDIPlusBitmapData::ConvertToImage() const
|
wxImage wxGDIPlusBitmapData::ConvertToImage() const
|
||||||
{
|
{
|
||||||
// We could use Bitmap::LockBits() and convert to wxImage directly but
|
// We need to use Bitmap::LockBits() to convert bitmap to wxImage
|
||||||
// passing by wxBitmap is easier. It would be nice to measure performance
|
// because this way we can retrieve also alpha channel data.
|
||||||
// of the two methods but for this the second one would need to be written
|
// Alternative way by retrieving bitmap handle with Bitmap::GetHBITMAP
|
||||||
// first...
|
// (to pass it to wxBitmap) doesn't preserve real alpha channel data.
|
||||||
HBITMAP hbmp;
|
const UINT w = m_bitmap->GetWidth();
|
||||||
if ( m_bitmap->GetHBITMAP(Color(0xffffffff), &hbmp) != Gdiplus::Ok )
|
const UINT h = m_bitmap->GetHeight();
|
||||||
return wxNullImage;
|
|
||||||
|
|
||||||
wxBitmap bmp;
|
wxImage img(w, h);
|
||||||
bmp.SetWidth(m_bitmap->GetWidth());
|
img.InitAlpha();
|
||||||
bmp.SetHeight(m_bitmap->GetHeight());
|
|
||||||
bmp.SetHBITMAP(hbmp);
|
BitmapData bitmapData;
|
||||||
bmp.SetDepth(IsAlphaPixelFormat(m_bitmap->GetPixelFormat()) ? 32 : 24);
|
Rect rect(0, 0, w, h);
|
||||||
return bmp.ConvertToImage();
|
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
|
#endif // wxUSE_IMAGE
|
||||||
|
Reference in New Issue
Block a user