利用 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 就可以了。
参考: