如何使用GDI+将带透明通道的位图保存为PNG格式文件
问题根因
你调用Bitmap::FromHBITMAP()方法加载带alpha通道的HBITMAP时,该接口默认会丢弃alpha通道信息,导致透明区域被填充为黑色,哪怕原始位图的alpha数据是正常的也不会被识别。
最简解决方案
无需通过HBITMAP中转,直接用提取到的HICON构造GDI+ Bitmap对象,会自动保留alpha通道信息,省去调色板创建的冗余步骤。
修正后可运行代码
using namespace Gdiplus; SHFILEINFO sfi; IImageList* piml; HICON hicon; // 从目标EXE路径获取最大尺寸图标 SHGetFileInfo(FILEPATH, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX); SHGetImageList(SHIL_JUMBO, IID_IImageList, (void**)&piml); piml->GetIcon(sfi.iIcon, 0x00000001, &hicon); // 初始化GDI+ GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); // 直接用HICON构造Bitmap,自动保留alpha通道 Bitmap* h = new Bitmap(hicon); // 获取PNG编码器CLSID(避免硬编码下标,兼容不同系统版本) CLSID encoderClsid; UINT num, sz; GetImageEncodersSize(&num, &sz); ImageCodecInfo* inf = new ImageCodecInfo[sz]; GetImageEncoders(num, sz, inf); for (UINT i = 0; i < num; i++) { if (wcscmp(inf[i].MimeType, L"image/png") == 0) { encoderClsid = inf[i].Clsid; break; } } h->Save(L"PATH_TO_SAVE.png", &encoderClsid, NULL); // 资源释放,避免内存泄漏 delete h; delete[] inf; DestroyIcon(hicon); GdiplusShutdown(gdiplusToken);
其他注意事项
- 原始代码中硬编码
inf[4]作为PNG编码器的写法兼容性差,不同Windows版本的编码器排序可能不同,通过MIME类型匹配更稳定。 - 用完的
HICON、动态申请的编码器数组都需要主动释放,避免GDI资源泄漏。
内容的提问来源于stack exchange,提问作者Danial
相关产品推荐
相关产品推荐

