C++提取文件图标保存为ICO时,如何保留原始色深?
解决图标保存为灰度/低色深的问题
你的问题出在两个核心环节:一是获取图标的方式拿到的是系统适配的低色深版本,二是用IPicture::SaveAsFile保存时会丢失原始颜色信息。下面是具体的修改方案:
1. 修改图标获取逻辑,拿到原始高色深图标
原来的GetIcon函数通过系统图标列表索引获取图标,这个列表里的图标往往是为兼容旧系统生成的低色深简化版。我们改成直接让SHGetFileInfo返回文件的原始图标句柄:
HICON GetIcon(PCTSTR pszFile) { SHFILEINFO sfi = { 0 }; // 使用SHGFI_ICON直接获取图标,SHGFI_LARGEICON指定取大图标(换成SHGFI_SMALLICON可获取小图标) SHGetFileInfo(pszFile, 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_LARGEICON); if (sfi.hIcon != NULL) { return sfi.hIcon; } else { return NULL; } }
这样拿到的hIcon就是文件原始的图标,包含完整的色深和分辨率信息。
2. 替换保存逻辑,避免IPicture的格式转换
IPicture::SaveAsFile处理图标时会强制转换格式,导致高色深信息丢失。我们改用Windows API的CreateIconResourceFromIcon生成标准ICO格式的资源,再写入文件:
HRESULT SaveIcon(HICON hIcon, PCTSTR path) { // 创建文件句柄 HANDLE hFile = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { return HRESULT_FROM_WIN32(GetLastError()); } // 从图标句柄生成ICO资源 HGLOBAL hResource = NULL; DWORD dwResourceSize = 0; if (!CreateIconResourceFromIcon(hIcon, &hResource, &dwResourceSize)) { CloseHandle(hFile); return HRESULT_FROM_WIN32(GetLastError()); } // 将资源写入文件 DWORD dwWrittenBytes = 0; BOOL writeSuccess = WriteFile(hFile, GlobalLock(hResource), dwResourceSize, &dwWrittenBytes, NULL); // 清理资源 GlobalUnlock(hResource); GlobalFree(hResource); CloseHandle(hFile); if (!writeSuccess || dwWrittenBytes != dwResourceSize) { return HRESULT_FROM_WIN32(GetLastError()); } return S_OK; }
3. 补充内存泄漏修复
别忘了在使用完图标后调用DestroyIcon释放资源,避免内存泄漏:
int main() { string fileBaseName = "appName"; wstring fileBaseNameWSTRING(fileBaseName.begin(), fileBaseName.end()); HICON hIcon = GetIcon((fileBaseNameWSTRING + L".lnk").c_str()); if (hIcon == NULL) { cout << "GetIcon failed" << endl; return 1; } else { HRESULT hr = SaveIcon(hIcon, (L"temp\\" + fileBaseNameWSTRING + L".ico").c_str()); // 释放图标资源 DestroyIcon(hIcon); return hr; } }
这样修改后,保存的图标就会保留原始的色深和颜色信息,不会再变成灰度啦。
内容的提问来源于stack exchange,提问作者Naser AlOqab
相关产品推荐
相关产品推荐

