VC如何将资源中包含的位图释放成文件
2015-05-13 18:02
267 查看
前两天一个朋友叫我帮他写一段代码,想把资源中包含的图片释放成磁盘文件,我想这个应该很简单啊,于是便写了如下函数:
调用代码为:
奇怪的是,上述代码对自定义类型的资源,如GIF、JPEG甚至EXE都能正确释放,但对于BMP类型的却无能为力。虽然保存到了磁盘上,却无法打开,提示为格式错误!
于是,我又自作聪明地使用流技术,把内存中的图像数据写回磁盘,代码如下:
果然不出所料,资源中所包含的位图被成功地保存到磁盘,并能被正确地打开了。于是我把代码给了朋友,算是完成了一个小任务。
今天下午,突然想起第一个函数写成的文件总比源文件少14个字节,使用流技术会不会自动补全啊,于是对比了一下图片文件,意外发现生成的目标文件竟然比源文件多出了2倍多的字节,我顿时惊呆了。这是为什么呢?
14字节!14字节?我脑海里反复想到这个数字,因为按照常理,第一个函数便能正确运行的啊。第二函数虽然运行成功了,但文件大小又有了出入。这中间一定有鬼。
肯定是VC开发环境对BITMAP、ICON之类的资源作了手脚。
14字节!——这不正是位图文件头的结构大小吗?哦,也许是VC对位图资源忽略了文件头。于是赶快实验,便写了第三个函数,代码如下:
这下,资源中包含的位图被正确地释放到了文件中,目标文件的大小也与被包含的资源文件一样。
总结:VC在对BITMAP资源包含时,去除了源文件的文件头,使用流技术时,会自动将位图转换成24位真彩色,而我测试时用了一幅256色位图,所以造成目标文件的尺寸大于源文件的现象。
由于API,现在编程非常简单,但越是简单,越不能掉以轻心,否则,摘不尽的BUG会毁掉你辛苦完成的程序。
BOOL FreeSource_1(LPCTSTR pszResName,LPCTSTR pszResType,LPCTSTR szFileName) { BOOL bRet = TRUE; HINSTANCE hInst = GetModuleHandle(NULL); //判断指定的资源是否存在 HRSRC hResInfo = FindResource(hInst,pszResName,pszResType); if(hResInfo == NULL) return FALSE; HANDLE hFile = NULL; DWORD dwWritten = 0; //调入指定的资源到内存 HGLOBAL hResData = LoadResource(hInst,hResInfo); LPVOID pvResData = LockResource(hResData); DWORD dwResSize = SizeofResource(hInst,hResInfo); //创建目标文件并保存数据至文件 hFile = CreateFile( szFileName, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL ); WriteFile(hFile, pvResData, dwResSize, &dwWritten, NULL); //释放有关内存资源 CloseHandle(hFile); FreeResource(hResData); return TRUE; }
调用代码为:
FreeSource(MAKEINTRESOURCE(IDB_BITMAP1), RT_BITMAP, "C://TEMP1.BMP"); FreeSource(MAKEINTRESOURCE(IDR_JPG1), "JPG", "C://TEMP2.JPG");
奇怪的是,上述代码对自定义类型的资源,如GIF、JPEG甚至EXE都能正确释放,但对于BMP类型的却无能为力。虽然保存到了磁盘上,却无法打开,提示为格式错误!
于是,我又自作聪明地使用流技术,把内存中的图像数据写回磁盘,代码如下:
BOOL FreeSource_2(LPCTSTR pszResName,LPCTSTR pszResType,LPCTSTR szFileName) { BOOL bRet = TRUE; HINSTANCE hInst = GetModuleHandle(NULL); //判断指定的资源是否存在 HRSRC hResInfo = FindResource(hInst,pszResName,pszResType); if(hResInfo == NULL)return FALSE; HANDLE hFile = NULL; DWORD dwWritten = 0; //直接保存自定义资源,如JPG、GIF、EXE等 if(pszResType != RT_BITMAP) { //使用LoadResource调入指定的资源到内存 HGLOBAL hResData = LoadResource(hInst,hResInfo); LPVOID pvResData = LockResource(hResData); DWORD dwResSize = SizeofResource(hInst,hResInfo); //创建目标文件并保存数据至文件 hFile = CreateFile( szFileName, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL ); WriteFile(hFile, pvResData, dwResSize, &dwWritten, NULL); //释放有关内存资源 CloseHandle(hFile); FreeResource(hResData); } else //使用流技术保存BITMAP位图 { //使用LoadBitmap调入指定的位图资源 HBITMAP hBitmap = LoadBitmap(hInst, pszResName); if(hBitmap == NULL)return FALSE; //创建一个IPicture接口的实例 PICTDESC ps; IPicture* pIPic=NULL; ps.cbSizeofstruct = sizeof(PICTDESC); ps.picType = PICTYPE_BITMAP; ps.bmp.hbitmap = hBitmap; ps.bmp.hpal = NULL; if(OleCreatePictureIndirect(&ps, IID_IPicture, TRUE,(LPVOID*)&pIPic) != ERROR_SUCCESS) { DeleteObject(hBitmap); return FALSE; } //将IPicture接口实例中的数据写入流接口中 LONG lSize = 0; IStream* pIStm = NULL; CreateStreamOnHGlobal(NULL,TRUE,&pIStm); if(pIPic->SaveAsFile(pIStm,TRUE,&lSize) != ERROR_SUCCESS) { pIPic->Release(); DeleteObject(hBitmap); return FALSE; } //保存流接口中的数据 LARGE_INTEGER li; li.HighPart = 0; li.LowPart = 0; ULARGE_INTEGER uli; uli.HighPart = 0; uli.LowPart = 0; pIStm->Seek(li, STREAM_SEEK_SET, &uli); //创建目标文件并循环读取流中的数据保存至文件 char buffer[1024]; hFile = CreateFile( szFileName, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL); DWORD dwRead = 1; while(dwRead>0) { pIStm->Read(buffer, 1024, &dwRead); if(dwRead > 0) WriteFile(hFile, buffer, dwRead, &dwWritten, NULL); } //释放有关内存资源 CloseHandle(hFile); DeleteObject(hBitmap); pIPic->Release(); pIStm->Release(); } return TRUE; }
果然不出所料,资源中所包含的位图被成功地保存到磁盘,并能被正确地打开了。于是我把代码给了朋友,算是完成了一个小任务。
今天下午,突然想起第一个函数写成的文件总比源文件少14个字节,使用流技术会不会自动补全啊,于是对比了一下图片文件,意外发现生成的目标文件竟然比源文件多出了2倍多的字节,我顿时惊呆了。这是为什么呢?
14字节!14字节?我脑海里反复想到这个数字,因为按照常理,第一个函数便能正确运行的啊。第二函数虽然运行成功了,但文件大小又有了出入。这中间一定有鬼。
肯定是VC开发环境对BITMAP、ICON之类的资源作了手脚。
14字节!——这不正是位图文件头的结构大小吗?哦,也许是VC对位图资源忽略了文件头。于是赶快实验,便写了第三个函数,代码如下:
BOOL FreeSource_3(LPCTSTR pszResName,LPCTSTR pszResType,LPCTSTR szFileName) { BOOL bRet = TRUE; HINSTANCE hInst = GetModuleHandle(NULL); //判断指定的资源是否存在 HRSRC hResInfo = FindResource(hInst,pszResName,pszResType); if(hResInfo == NULL) return FALSE; HANDLE hFile = NULL; DWORD dwWritten = 0; //调入指定的资源到内存 HGLOBAL hResData = LoadResource(hInst,hResInfo); LPVOID pvResData = LockResource(hResData); DWORD dwResSize = SizeofResource(hInst,hResInfo); //创建目标文件并保存数据至文件 hFile = CreateFile(szFileName, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL); if(pszResType == RT_BITMAP) { //获得位图信息头 BITMAPINFOHEADER bmpInfoHdr; CopyMemory(&bmpInfoHdr, pvResData, sizeof(BITMAPINFOHEADER)); //获得位图颜色表中RGBQUAD结构的个数 long nColorEntries; switch(bmpInfoHdr.biBitCount) { case 1: nColorEntries = 2; break; case 4: nColorEntries = 16; break; case 8: nColorEntries = 256; break; default: nColorEntries = 0; } //根据位图信息头创建位图文件头 BITMAPFILEHEADER bmpFileHdr; bmpFileHdr.bfType = 0x4d42; // 'BM' bmpFileHdr.bfSize = sizeof(BITMAPINFOHEADER) + dwResSize; bmpFileHdr.bfReserved1 = bmpFileHdr.bfReserved2 = 0; bmpFileHdr.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorEntries; //写入位图文件头 WriteFile(hFile, &bmpFileHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL); } WriteFile(hFile, pvResData, dwResSize, &dwWritten, NULL); //释放有关内存资源 CloseHandle(hFile); FreeResource(hResData); return TRUE; };
这下,资源中包含的位图被正确地释放到了文件中,目标文件的大小也与被包含的资源文件一样。
总结:VC在对BITMAP资源包含时,去除了源文件的文件头,使用流技术时,会自动将位图转换成24位真彩色,而我测试时用了一幅256色位图,所以造成目标文件的尺寸大于源文件的现象。
由于API,现在编程非常简单,但越是简单,越不能掉以轻心,否则,摘不尽的BUG会毁掉你辛苦完成的程序。
相关文章推荐
- VC如何将资源中包含的位图释放成文件
- VC如何将资源中包含的位图释放成文件
- VC如何将资源中包含的位图释放成文件
- 如何在Qt资源文件中包含和释放exe等各种类型文件?
- 如何将自己的文件作为资源文件放入VC工程中?如何在运行时,从EXE文件中提取(释放)出这个文件?
- VC释放资源到文件
- VC释放EXE资源文件
- 如何在VC中通过添加资源文件,使程序在Vista上用管理员权限运行
- [VC++]释放资源文件
- 将二进制文件加入VC资源后释放执行
- VC++图片控件(Picture Control)显示资源位图(BMP)、文件位图(BMP)、其它格式文件图片(JPG\PNG\BMP)的方法
- VC中如何将资源打包并释放到指定文件夹
- VC 如何Copy一个项目的资源文件中的对话框到另一个项目
- VB中如何把资源器的文件释放出来,并且允许。。如把1.bat载入资源编辑器
- 如何用VC60实现类似windows搜索文件的功能,针对文件夹中包含的文件名进行模糊查
- VC释放EXE资源文件
- VC释放EXE资源文件
- VC释放EXE资源文件
- 将文件作为资源放入VC工程中?在运行时从EXE文件中提取(释放)出这个文件?
- 利用MAVEN打包时,如何包含更多的资源文件