icon文件解析和生成

icon文件解析和生成文件头 DIRENTRY DIRENTRY DIRENTRY Imgdata ImgdataImgda 如果图片尺寸 128 则保存的 BMP 数据 否则保存的是 png 格式的数据

大家好,欢迎来到IT知识分享网。

ICON 格式

文件头 | DIRENTRY | DIRENTRY|DIRENTRY|… Imgdata|ImgdataImgdataImgdata|…

//文件头 //sizeof = 6 typedef struct ICONHEADER { 
    WORD idReserved;//保留用, WORD idType;//固定值 1 WORD idCount;//包含的图片个数 }; //标记每张图片的具体信息 //sizeof = 16 typedef struct ICONDIRENTRY { 
    BYTE bWidth;//图片大小,如果图片宽度大于等于256则为0 BYTE bHeight;//图片大小,如果图片宽度大于等于256则为0 BYTE bColorCount; BYTE bReserved; WORD wPlanes; WORD wBitCount; //图像大小w*h*4 + 40 header头 + mask //mask (h * ((w + 31) / 32 * 32 / 8)) DWORD dwBytesInRes;//图片资源大小,需要计算mask DWORD dwImageOffset;//在文件中的偏移量 }*LPICONDIRENTRY; 

从ICON提取PNG文件

static DWORD extractIcoPngs(const std::wstring& iconPath, const std::wstring& outpath) { 
    //文件不存在 if (_waccess(iconPath.c_str(), 00) != 00 || _waccess(outpath.c_str(), 00) != 00) return -1; //打开图标文件  HANDLE hIconFile = CreateFileW(iconPath.c_str(), GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hIconFile == INVALID_HANDLE_VALUE) { 
    DWORD dwErrCode = GetLastError(); return dwErrCode; } //读取文件头 ICONHEADER header; DWORD dwRead = 0; memset(&header, 0, sizeof(ICONHEADER)); if (!ReadFile(hIconFile, &header, sizeof(ICONHEADER), &dwRead, NULL)) { 
    DWORD dwErrCode = GetLastError(); CloseHandle(hIconFile); return dwErrCode; } if (header.idCount <= 0) return -2; std::vector<ICONDIRENTRY> vecEntry(header.idCount); //读取像信息块 if (!ReadFile(hIconFile, &vecEntry[0], header.idCount * sizeof(ICONDIRENTRY), &dwRead, NULL)) { 
    DWORD dwErrCode = GetLastError(); CloseHandle(hIconFile); return dwErrCode; } //读取每一帧的数据 CLSID pngClsid; if (!DCUtil::GetEncoderClsid(L"image/png", &pngClsid)) return -3; for (int i = 0; i < vecEntry.size(); i++) { 
    //根据偏移量读取图像数据 SetFilePointer(hIconFile, vecEntry[i].dwImageOffset, 0, FILE_BEGIN); std::wstring wsave_file = L""; //如果图像高度为0,则表示为256尺寸的数据 if (vecEntry[i].bHeight == 0) { 
    std::vector<unsigned char> imgdata(vecEntry[i].dwBytesInRes, 0); ReadFile(hIconFile, &imgdata[0], vecEntry[i].dwBytesInRes, &dwRead, NULL); std::wstring file_name = A2WSTR(fmt::format("{0}_{1}x{2}.png", W2ASTR(jeflib::FileUtil::GetFileBaseNameW(iconPath)), 256, 256)); wsave_file = jeflib::FileUtil::JoinPathW(outpath, file_name); HANDLE hImg = CreateFileW(wsave_file.c_str(), GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hImg) { 
    DWORD dwWrite = 0; WriteFile(hImg, &imgdata[0], vecEntry[i].dwBytesInRes, &dwWrite, NULL); CloseHandle(hImg); } } else { 
    COLORREF* pBits = nullptr; HBITMAP hBitMap = NULL; BITMAPINFO bitmapinfo = { 
    0 }; if (!ReadFile(hIconFile, &bitmapinfo.bmiHeader, sizeof(BITMAPINFOHEADER), &dwRead, NULL)) { 
    continue; } bitmapinfo.bmiHeader.biHeight /= 2; bitmapinfo.bmiHeader.biSizeImage = bitmapinfo.bmiHeader.biHeight * bitmapinfo.bmiHeader.biWidth * 4; hBitMap = CreateDIBSection(nullptr, &bitmapinfo, DIB_RGB_COLORS, (void**)&pBits, NULL, NULL); if (hBitMap == nullptr || !ReadFile(hIconFile, pBits, bitmapinfo.bmiHeader.biSizeImage, &dwRead, NULL)) { 
    continue; } std::wstring file_name = A2WSTR(fmt::format("{0}_{1}x{2}.png", W2ASTR(jeflib::FileUtil::GetFileBaseNameW(iconPath)), bitmapinfo.bmiHeader.biWidth, bitmapinfo.bmiHeader.biHeight)); wsave_file = jeflib::FileUtil::JoinPathW(outpath, file_name); //创建带alpha通道的Bitmap Gdiplus::Bitmap* pimg = DCUtil::CreateAlphaBmpFromHBITMAP(hBitMap); if (pimg) { 
    pimg->Save(wsave_file.c_str(), &pngClsid); delete pimg; } ::DeleteObject(hBitMap); } } CloseHandle(hIconFile); return 0; } 

PNG合成ICO

static DWORD createIcoByPngs(const std::vector<std::wstring>& pngPaths, const std::wstring& iconPath) { 
    if (pngPaths.empty() || iconPath.empty()) return -1; //打开图标文件  HANDLE hIconFile = CreateFileW(iconPath.c_str(), GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hIconFile == INVALID_HANDLE_VALUE) { 
    DWORD dwErrcode = GetLastError(); return dwErrcode; } //检验png有效性,一个尺寸只保存一张图 std::map<int, ENTRYDATA> mapSizePngImages; for (int i = 0; i < pngPaths.size(); i++) { 
    ENTRYDATA endata; endata.nDataSize = FileUtil::GetFileSizeW(pngPaths[i]); if(endata.nDataSize <= 0) continue; endata.vFileContent.resize(endata.nDataSize); { 
    HANDLE hImag = CreateFileW(pngPaths[i].c_str(), GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hImag != INVALID_HANDLE_VALUE) { 
    DWORD dwRead = 0; ReadFile(hImag, &endata.vFileContent[0], endata.vFileContent.size(), &dwRead, NULL); CloseHandle(hImag); } } std::shared_ptr<Gdiplus::Bitmap> pImg = std::shared_ptr<Gdiplus::Bitmap>(Gdiplus::Bitmap::FromFile(pngPaths[i].c_str())); if (pImg == nullptr || pImg->GetWidth() != pImg->GetHeight() || pImg->GetWidth() <= 0) continue; endata.pImg = pImg; endata.strIconPath = pngPaths[i]; //超过128尺寸直接写入png图片数据,否则写入bitmap,并且计算掩码大小 //图像32位像素 + 40 header头 +AND mask  if (pImg->GetWidth() <= 128) { 
    endata.nDataSize = pImg->GetWidth() * pImg->GetHeight() * 4 + 40 + (pImg->GetHeight() * ((pImg->GetWidth() + 31) / 32 * 32 / 8)); endata.vFileContent.resize(0); mapSizePngImages[pImg->GetWidth()] = endata; } else { 
    mapSizePngImages[256] = endata; } } if (mapSizePngImages.empty()) { 
    CloseHandle(hIconFile); return -2; } ICONHEADER header; DWORD dwWrite = 0; //写文件头 memset(&header, 0, sizeof(ICONHEADER)); header.idReserved = 0; header.idCount = mapSizePngImages.size(); header.idType = 1; WriteFile(hIconFile, &header, sizeof(ICONHEADER), &dwWrite, NULL); //建立每一个图标的目录信息存放区域  LPICONDIRENTRY pIconDirEntry = (LPICONDIRENTRY)new BYTE[header.idCount * sizeof(ICONDIRENTRY)]; if (pIconDirEntry == NULL) { 
    CloseHandle(hIconFile); return -3; } memset(pIconDirEntry, 0, header.idCount * sizeof(ICONDIRENTRY)); //第一张图标的起始位置 DWORD offset = header.idCount * sizeof(ICONDIRENTRY) + sizeof(ICONHEADER); int index = 0; for (auto &it:mapSizePngImages) { 
    pIconDirEntry[index].bWidth = it.first == 256 ? 0: it.first; pIconDirEntry[index].bHeight = it.first == 256 ? 0 : it.first; pIconDirEntry[index].wBitCount = 32; pIconDirEntry[index].bReserved = 0; pIconDirEntry[index].wPlanes = 1; pIconDirEntry[index].dwBytesInRes = it.second.nDataSize; pIconDirEntry[index].dwImageOffset = offset; offset += pIconDirEntry[index].dwBytesInRes; ++index; } //写图像信息块 WriteFile(hIconFile, pIconDirEntry, header.idCount * sizeof(ICONDIRENTRY), &dwWrite, NULL); delete []((BYTE*)pIconDirEntry); //写每一帧的数据 for (auto& it : mapSizePngImages) { 
    //大于128直接写入png数据 if (it.first > 128) { 
    WriteFile(hIconFile, &it.second.vFileContent[0], it.second.vFileContent.size(), &dwWrite, NULL); } else { 
    BITMAPINFOHEADER bitmapHeader; memset(&bitmapHeader, 0, sizeof(BITMAPINFOHEADER)); bitmapHeader.biWidth = it.first; //图像高度(XOR图高度+AND图高度) bitmapHeader.biHeight = bitmapHeader.biWidth * 2; bitmapHeader.biSize = sizeof(BITMAPINFOHEADER); bitmapHeader.biPlanes = 1; bitmapHeader.biBitCount = 32; bitmapHeader.biSizeImage = it.second.nDataSize; WriteFile(hIconFile, &bitmapHeader, sizeof(BITMAPINFOHEADER), &dwWrite, NULL); //因为icon宽高相等,都等于it.first //XOR mask int imageDataSize = it.first * it.first; int* imageDataBuf = new int[imageDataSize]; memset(imageDataBuf, 0, imageDataSize); Gdiplus::Color bmpColor; for (int y = 0; y < it.first; y++) { 
    for (int x = 0; x < it.first; x++) { 
    it.second.pImg->GetPixel(x, y, &bmpColor); BYTE a = bmpColor.GetAlpha(); BYTE r = bmpColor.GetRed(); BYTE b = bmpColor.GetBlue(); BYTE g = bmpColor.GetGreen(); int index = y * it.first + x; char* p = (char*)(imageDataBuf + index); p[0] = b; p[1] = g; p[2] = r; p[3] = a; } } char* body = (char*)imageDataBuf; for (int y = it.first - 1; y >= 0; --y) { 
    for (int x = 0; x < it.first; ++x) { 
    int index = (y * it.first + x) * 4; char c = body[index]; WriteFile(hIconFile, &c, 1, &dwWrite, NULL); //Blue c = body[index + 1]; WriteFile(hIconFile, &c, 1, &dwWrite, NULL); //Green c = body[index + 2]; WriteFile(hIconFile, &c, 1, &dwWrite, NULL); //Red c = body[index + 3]; WriteFile(hIconFile, &c, 1, &dwWrite, NULL); //Alpha } } delete[]imageDataBuf; //AND mask  for (int y = 0; y < (it.first * ((it.first + 31) / 32 * 32 / 8)); ++y) { 
    char c = 0; WriteFile(hIconFile, &c, 1, &dwWrite, NULL); } } } CloseHandle(hIconFile); return true; } 

GetEncoderClsid

L"image/bmp" L"image/jpeg" L"image/gif" L"image/tiff" L"image/png" static bool GetEncoderClsid(const WCHAR* format, CLSID* pClsid) { 
    if (format == nullptr || pClsid == nullptr) return false; UINT num = 0; //number of image encoders UINT size = 0; //size of the image encoder array in bytes int nRet = Gdiplus::GetImageEncodersSize(&num, &size); if (nRet != Gdiplus::Status::Ok) { 
    return false; } Gdiplus::ImageCodecInfo* pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size)); if (pImageCodecInfo == NULL) { 
    return false; } Gdiplus::GetImageEncoders(num, size, pImageCodecInfo); for (int i = 0; i < num; i++) { 
    if (wcscmp(pImageCodecInfo[i].MimeType, format) == 0) { 
    *pClsid = pImageCodecInfo[i].Clsid; free(pImageCodecInfo); return true; } } free(pImageCodecInfo); return false; } 
CreateAlphaBmpFromHBITMAP
 static Gdiplus::Bitmap* CreateAlphaBmpFromHBITMAP(HBITMAP hBmp) { 
    DIBSECTION dibsection = { 
    0 }; int nBytes = ::GetObject(hBmp, sizeof(DIBSECTION), &dibsection); if (dibsection.dsBm.bmBitsPixel != 32) { 
    return Gdiplus::Bitmap::FromHBITMAP(hBmp, NULL); } int width = dibsection.dsBm.bmWidth; int height = abs(dibsection.dsBm.bmHeight); int pitch = (((width * dibsection.dsBm.bmBitsPixel) + 31) / 32) * 4; //计算行宽,四字节对齐 ATL::CImage::ComputePitch // 32位位图不存在对齐问题,so其实没必要 LPVOID bits = dibsection.dsBm.bmBits; if (dibsection.dsBmih.biHeight > 0) // 对于DDB,不会取到dsBmih数据,所以biHeight成员始终为0 { 
    bits = LPBYTE(bits) + ((height - 1) * pitch); pitch = -pitch; } return new Gdiplus::Bitmap(width, height, pitch, PixelFormat32bppARGB, static_cast<BYTE*>(bits)); } 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/119523.html

(0)
上一篇 2025-11-04 20:45
下一篇 2025-11-04 21:10

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信