近天要用到bmp与jpg之间互想转换,在网上查看了许多资料,如jpeglib,cximage,zlib,最后找到了GDI+利用流来转换,此方法最简单,可以实现在文件->文件,文件->内存,内存->内存,内存->文件保存,对于网络传送图片非常实用,通常320*240*24b的225k的BMP转成JPG后大约15.6K,压缩比15:1.
转换逻辑如下:
1.载入bmp或jpg文件,取得文件数据大小通过GlobalAlloc分配堆内存空间返回的内存句柄作为创建流接口指针的内存句柄,创建流接口.
2.锁定此内存空间,将图片数据memcpy到此空间中
3.通过流创建GDI+中的图片
Image *imImage = NULL;
imImage = Image::FromStream(pStmBmp, FALSE);
4.取得要编码的GUID详见后代码
5.保存此图到文件或流中
如果只是BMP位图数据则需自已构建位图文件头和位图信息头
代码:
int 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;
}
void CTest_GDI2Dlg::BMP2JPG()
{
CFile file(“test.bmp”, CFile::modeRead);
int fileLen = file.GetLength();
HGLOBAL hMemBmp = GlobalAlloc(GPTR, fileLen);
BYTE *pbyBmp = (BYTE *)GlobalLock(hMemBmp);
file.ReadHuge(pbyBmp, fileLen);
file.Close();
GlobalUnlock(hMemBmp);
//如果只有图位数据信息则要自已构建信息头,下面注释部分测试构建320*240*24b位图文件
/*BITMAPFILEHEADER fileheader;
BITMAPINFOHEADER infoH;
memset(&fileheader, 0, sizeof(BITMAPFILEHEADER));
fileheader.bfType = 19778;//固定为’BM’
fileheader.bfSize = 320*240*3+54;//构造时注意+54字节头
fileheader.bfOffBits = 54;
infoH.biSize = sizeof(BITMAPINFOHEADER);
infoH.biWidth = 320;
infoH.biHeight = 240;
infoH.biPlanes = 1;
infoH.biBitCount = 24;
infoH.biCompression = BI_RGB;
infoH.biSizeImage = 320*240*3;
infoH.biXPelsPerMeter = 0;
infoH.biYPelsPerMeter = 0;
infoH.biClrUsed = 0;
infoH.biClrImportant = 0;
memcpy(pbyBmp, &fileheader, 14);
memcpy(pbyBmp+14, &infoH, 40);*/
//构建指向BMP的流
IStream *pStmBmp = NULL;
CreateStreamOnHGlobal(hMemBmp, FALSE, &pStmBmp);
Image *imImage = NULL;
imImage = Image::FromStream(pStmBmp, FALSE);
USES_CONVERSION;
CLSID clImageClsid;//这里是要转为jpeg格式
GetImageCLSID(A2W(“image/jpeg”), &clImageClsid);
int ret = imImage->Save(A2W(“1.jpg”), &clImageClsid);//直接保存为文件
//下面可直接保存在流中
/*HGLOBAL hMemJpg = GlobalAlloc(GMEM_MOVEABLE, 0);
IStream *pStmImage = NULL;
CreateStreamOnHGlobal(hMemJpg, FALSE, &pStmImage);
imImage->Save(pStmImage, &clImageClsid);
LARGE_INTEGER liBegin = {0};
pStmImage->Seek(liBegin, STREAM_SEEK_SET, NULL);
BYTE *pbyjpg = (BYTE *)GlobalLock(hMemJpg);//这里的pbyjpg就是转换后的JPG数据可直接通过网络发送
int Len = GlobalSize(hMemJpg);//这就是转为JPG后文件的大小了
CFile filejpg(“2.jpg”, CFile::modeCreate | CFile::modeWrite);
filejpg.Write(pbyjpg, Len);//这里写成文件和前面直接保存为文件效果一样
filejpg.Close();
m_pBuf = new char[Len];
memcpy(m_pBuf, pbyjpg, Len);//可以保存此数据,任你操作哦
GlobalUnlock(hMemJpg);
GlobalFree(hMemJpg);
pStmImage->Release();*/
pStmBmp->Release();
GlobalFree(hMemBmp);
}
反之JPG转BMP是1个道理,只是中间取得的编码类型不同应该是GetImageCLSID(A2W(“image/bmp”), &clImageClsid);
下面演示接收到网络上的JPG数据转为BMP:m_pBuf假设保存了接收到的JPG数据m_len是此JPG数据大小
void CTest_GDI2Dlg::JPG2BMP()
{
// TODO: Add your control notification handler code here
HGLOBAL hMemJpg = GlobalAlloc(GPTR, m_len);
BYTE *pbyjpg = (BYTE *)GlobalLock(hMemJpg);
memcpy(pbyjpg, m_pBuf, m_len);
GlobalUnlock(hMemJpg);
IStream *pStmJpg = NULL;
CreateStreamOnHGlobal(hMemJpg, FALSE, &pStmJpg);
Image *imImage = NULL; //从流中还原图片
imImage = Image::FromStream(pStmJpg, FALSE);
USES_CONVERSION;
CLSID clImageClsid;
GetImageCLSID(A2W(“image/bmp”), &clImageClsid);//取得BMP编码
int ret = imImage->Save(A2W(“3.bmp”), &clImageClsid);
//可直接保存在流中,任你操作了哦
/*HGLOBAL hMemBmp = GlobalAlloc(GMEM_MOVEABLE, 0);
IStream *pStmBmp = NULL;
CreateStreamOnHGlobal(hMemBmp, FALSE, &pStmBmp);
imImage->Save(pStmBmp, &clImageClsid);
int Len = GlobalSize(hMemBmp);//转换后BMP文件大小
BYTE *pbyBmp = (BYTE *)GlobalLock(hMemBmp);//此数据就可直接调用API画出来了
CFile filejpg(“4.bmp”, CFile::modeCreate | CFile::modeWrite);
filejpg.Write(pbyBmp, Len);
filejpg.Close();
GlobalUnlock(hMemBmp);
pStmBmp->Release();
GlobalFree(hMemBmp);*/
pStmJpg->Release();
GlobalFree(hMemJpg);
}