Getting a GDI+ Bitmap from an HICON with proper transparency
February 29, 2008
The GDI+ Bitmap class has a nice constructor that takes in a HICON. The problem is that it doesn’t preserve alpha values– icons such as the Firefox icon that have semi-transparent shadows show up with completely black shadows. This code will get you the icon with proper transparency:
Gdiplus::Bitmap *WindowsSystem::GetIconPixelData(HICON hIcon)
{
ICONINFO iconInfo;
GetIconInfo(hIcon, &iconInfo);
BITMAP iconBmp;
GetObject(iconInfo.hbmColor, sizeof(BITMAP),&iconBmp);
Gdiplus::Bitmap* bitmap = new Gdiplus::Bitmap(iconBmp.bmWidth,iconBmp.bmHeight,PixelFormat32bppARGB);
bool hasAlpha = false;
{
// We have to read the raw pixels of the bitmap to get proper transparency information
// (not sure why, all we're doing is copying one bitmap into another)
Gdiplus::Bitmap colorBitmap(iconInfo.hbmColor, NULL);
Gdiplus::BitmapData bmpData;
Gdiplus::Rect bmBounds(0, 0, colorBitmap.GetWidth(), colorBitmap.GetHeight());
colorBitmap.LockBits(&bmBounds, Gdiplus::ImageLockModeRead, colorBitmap.GetPixelFormat(), &bmpData);
for (int y = 0; y < colorBitmap.GetHeight(); y++)
{
byte *pixelBytes = (byte*)bmpData.Scan0 + y*bmpData.Stride;
for (int x = 0; x SetPixel(x, y, Gdiplus::Color(*pixel));
hasAlpha = hasAlpha || (pixelBytes[3] > 0 && pixelBytes[3] < 255);
}
}
colorBitmap.UnlockBits(&bmpData);
}
if (!hasAlpha)
{
// If there's no alpha transparency information, we need to use the mask
// to turn back on visible pixels
Gdiplus::Bitmap maskBitmap(iconInfo.hbmMask,NULL);
Gdiplus::Color cMask, cBitmap;
for (int y = 0; y < maskBitmap.GetHeight(); y++)
{
for (int x = 0; x GetPixel(x, y, &cBitmap);
cBitmap.SetValue(cBitmap.GetValue() | 0xFF000000); // turn alpha to opaque (i.e. 0xFF)
bitmap->SetPixel(x, y, cBitmap);
}
}
}
}
return bitmap ;
}