大家好,欢迎来到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