一个任务中需要将内存中的图片bmp文件,保存为png格式的图片,上网google了一下,找到一篇文章,介绍可以用gdi+将内存文件保存为其它格式的图片文件,参见《使用GDI+在内存中转换图片类型》, 作者:芦伟。在vc知识库网站上的,url:http://www.vckbase.com/document/viewdoc/?id=1177。参考了这篇文章,写个测试程序,源代码如下,在vc6.0下进行试验,将tmp.bmp转成newimg.png格式文件,效果不错,而且文件大小明显变小了。
这是调用函数,从本地读取tmp.bmp文件到内存中,然后绑定到cmemfile对象上,并且创建了newimg文件的cfile对象,打开这个文件(注意:原作者介绍的函数的输出对象仍然是cmemfile,而我需要在本地保存这个文件,所以用了cfile直接替换)
void CMybmpView::myconvbmp()
{
CFile file;
file.Open("temp.bmp", CFile::modeReadWrite,NULL);
BYTE* buffer=(BYTE*) malloc(file.GetLength());
file.Read(buffer,file.GetLength());
CMemFile memfile;
memfile.Attach(buffer,file.GetLength(),1024);
memfile.SetLength(file.GetLength());
CFile imgf;
if(!imgf.Open("newimg.png", CFile::modeCreate | CFile::modeWrite))
return;
MBmpToMImage(memfile, imgf, "png");
imgf.Close();
}
这个函数是将内存bmp转换成png的函数,这是转换主要实现部分,我没有太仔细研究这段代码,目前能实现转换功能。
BOOL CMybmpView::MBmpToMImage(CMemFile& cbfBmp, CFile& cbfImage, CString strType)
{
int iBmpSize = cbfBmp.GetLength();
HGLOBAL hMemBmp = GlobalAlloc(GMEM_FIXED, iBmpSize);
if (hMemBmp == NULL) return FALSE;
IStream* pStmBmp = NULL;
CreateStreamOnHGlobal(hMemBmp, FALSE, &pStmBmp);
if (pStmBmp == NULL)
{
GlobalFree(hMemBmp);
return FALSE;
}
BYTE* pbyBmp = (BYTE *)GlobalLock(hMemBmp);
cbfBmp.SeekToBegin();
cbfBmp.Read(pbyBmp, iBmpSize);
Image* imImage = NULL;
imImage = Image::FromStream(pStmBmp, FALSE);
if (imImage == NULL)
{
GlobalUnlock(hMemBmp);
GlobalFree(hMemBmp);
return FALSE;
}
USES_CONVERSION;
CLSID clImageClsid;
GetImageCLSID(A2W(("image/"+strType).GetBuffer(0)), &clImageClsid);
HGLOBAL hMemImage = GlobalAlloc(GMEM_MOVEABLE, 0);
if (hMemImage == NULL)
{
pStmBmp->Release();
GlobalUnlock(hMemBmp);
GlobalFree(hMemBmp);
if (imImage != NULL) delete imImage;
return FALSE;
}
IStream* pStmImage = NULL;
CreateStreamOnHGlobal(hMemImage, TRUE, &pStmImage);
if (pStmImage == NULL)
{
pStmBmp->Release();
GlobalUnlock(hMemBmp);
GlobalFree(hMemBmp);
GlobalFree(hMemImage);
if (imImage != NULL) delete imImage;
return FALSE;
}
imImage->Save(pStmImage, &clImageClsid);
if (pStmImage == NULL)
{
pStmBmp->Release();
pStmImage->Release();
GlobalUnlock(hMemBmp);
GlobalFree(hMemBmp);
GlobalFree(hMemImage);
if (imImage != NULL) delete imImage;
return FALSE;
}
LARGE_INTEGER liBegin = {0};
pStmImage->Seek(liBegin, STREAM_SEEK_SET, NULL);
BYTE* pbyImage = (BYTE *)GlobalLock(hMemImage);
cbfImage.SeekToBegin();
cbfImage.Write(pbyImage, GlobalSize(hMemImage));
if (imImage != NULL) delete imImage;
pStmBmp->Release();
pStmImage->Release();
GlobalUnlock(hMemBmp);
GlobalUnlock(hMemImage);
GlobalFree(hMemBmp);
GlobalFree(hMemImage);
return TRUE;
}
这个函数同样是在网站上找的代码,是上面函数用到的
int CMybmpView::GetImageCLSID(const WCHAR* format, CLSID* pCLSID)
{
//得到格式为format的图像文件的编码值,访问该格式图像的COM组件的GUID值保存在pCLSID中
UINT num = 0;
UINT size = 0;
ImageCodecInfo* pImageCodecInfo = NULL;
GetImageEncodersSize(&num, &size);
if(size == 0)
return FALSE; // 编码信息不可用
//分配内存
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == NULL)
return FALSE; // 分配失败
//获得系统中可用的编码方式的所有信息
GetImageEncoders(num, size, pImageCodecInfo);
//在可用编码信息中查找format格式是否被支持
for(UINT i = 0; i < num; ++i)
{
//MimeType:编码方式的具体描述
if(wcscmp(pImageCodecInfo[i].MimeType, format) == 0)
{
*pCLSID = pImageCodecInfo[i].Clsid;
free(pImageCodecInfo);
return TRUE;
}
}
free(pImageCodecInfo);
return FALSE;
}