利用 GDI+ 从资源文件加载和缩放 PNG
之前实现了右键菜单(shellext context menu)功能,开始用的是 BMP 图标。不支持透明背景,也不支持缩放(高分屏下很小)。今天参考了一下同事实现的其他模块的代码,也从在网上搜了很多文章来看,终于实现了。代码实现如下:
bool LoadImageFromRes(Gdiplus::Bitmap *&hBitmap, HGLOBAL &hResourceBuffer, HMODULE hInstance, UINT resourceID)
{
HRSRC hResource = ::FindResource(hInstance, MAKEINTRESOURCE(resourceID), L"PNG");
if (!hResource)
return false;
DWORD imageSize = ::SizeofResource(hInstance, hResource);
if (!imageSize)
return false;
const void* pResourceData = ::LockResource(::LoadResource(hInstance, hResource));
if (!pResourceData)
return false;
hResourceBuffer = ::GlobalAlloc(GMEM_MOVEABLE, imageSize);
if (hResourceBuffer)
{
void *pBuffer = ::GlobalLock(hResourceBuffer);
if (pBuffer)
{
CopyMemory(pBuffer, pResourceData, imageSize);
IStream *pStream = nullptr;
if (::CreateStreamOnHGlobal(hResourceBuffer, FALSE, &pStream) == S_OK)
{
hBitmap = Gdiplus::Bitmap::FromStream(pStream);
pStream->Release();
if (hBitmap)
{
if ((hBitmap)->GetLastStatus() == Gdiplus::Ok)
return true;
delete hBitmap;
hBitmap = nullptr;
}
}
hBitmap = nullptr;
::GlobalUnlock(hResourceBuffer);
}
::GlobalFree(hResourceBuffer);
hResourceBuffer = nullptr;
}
return false;
}
Gdiplus::Bitmap *ResizeClone(Gdiplus::Bitmap *bitmap, INT width)
{
UINT oldHeight = bitmap->GetHeight();
UINT oldWidth = bitmap->GetWidth();
INT newWidth = width;
INT newHeight = static_cast<INT>(static_cast<double>(oldHeight) / oldWidth * newWidth);
Gdiplus::Bitmap *newBitmap = new Gdiplus::Bitmap(newWidth, newHeight, bitmap->GetPixelFormat());
Gdiplus::Graphics graphics(newBitmap);
graphics.DrawImage(bitmap, 0, 0, newWidth, newHeight);
return newBitmap;
}
HANDLE LoadPNG(HINSTANCE hInst, UINT resourceID, int width)
{
Gdiplus::Bitmap *bitmap = nullptr;
HGLOBAL hResourceBuffer = nullptr;
if (LoadImageFromRes(bitmap, hResourceBuffer, hInst, resourceID))
{
if (bitmap->GetWidth() != width)
{
Gdiplus::Bitmap *newBitmap = Util::ResizeClone(bitmap, width);
delete bitmap;
bitmap = newBitmap;
}
HBITMAP hBmpIcon = nullptr;
bitmap->GetHBITMAP(0, &hBmpIcon);
delete bitmap;
::GlobalUnlock(hResourceBuffer);
::GlobalFree(hResourceBuffer);
return hBmpIcon;
}
return nullptr;
}
第一段代码是从资源文件加载 PNG,如果直接从本地文件载的话,实现会简单很多,直接Gdiplus::Bitmap::FromFile 就可以了。
参考: