wince5.0, eVC4.0下bmp到jpg格式转换,使用Imagefactory,两头都是Stream内存
原先的编码太慢了,jpg编码要800ms,解码要1000ms,疯了。
于是开始用Imagefactory,经测试320x240的图片jpg编码67ms,解码38ms,太帅了,差距竟然这么大,经过的过程见:
http://topic.csdn.net/u/20121009/00/a4c385d9-62a4-48d7-ba03-a48495ecd068.html
代码如下:
将如下文件放到StdAfx.h中:
#include "StdAfx.h"#include "jpgimgfaclib.h"DEFINE_GUID(IID_IImagingFactory, 0x327abda7,0x072b,0x11d3,0x9d,0x7b,0x00,0x00,0xf8,0x1e,0xf3,0x2e);DEFINE_GUID(CLSID_ImagingFactory, 0x327abda8,0x072b,0x11d3,0x9d,0x7b,0x00,0x00,0xf8,0x1e,0xf3,0x2e);void ConvBmp2jpg(char *bmpbuf, int bmpsize, char *jpgbuf, int *jpgsize){HRESULT hr;IImagingFactory * pImagingFactory = NULL ; //Image工厂接口对象IStream *pStream = NULL;// 流接口对象IStream *pOutStream = NULL;// 流接口对象LARGE_INTEGER liTemp = {0};STATSTG stats={0};IImageSink *pImageSink = NULL; //Image Sink接口对象IImageDecoder *pImageDecoder = NULL; //解码器接口对象IImageEncoder *pImageEncoder = NULL;//编码器接口对象CLSID clsidEncoder; //编码器CLSIDTCHAR *tszMime = L"image/jpeg"; //指定转换后,图象文件的格式// tszMime = L"image/bmp"; //指定转换后,图象文件的格式//初始化COM环境if (FAILED(hr = CoInitializeEx(NULL, COINIT_MULTITHREADED))){TRACE(L"COINIT_MULTITHREADED ERROR");return;}//得到Image工厂接口对象 hr = CoCreateInstance(CLSID_ImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void**) &pImagingFactory);if (FAILED(hr)){TRACE(L"IMAGE FACTORY CREATED ERROR");goto finish;}if (FAILED(hr = CreateStreamOnBuffer(bmpbuf, bmpsize, &pStream))){goto finish;}//根据编码器类型名称得到编码器CLSIDif (!GetEnCodecCLSID(pImagingFactory,tszMime, &clsidEncoder )){goto finish;}if (FAILED(hr = CreateStreamOnHGlobal(NULL,TRUE,&pOutStream))){goto finish; }//创建编码器接口,并关联到输出流中if (FAILED(hr = pImagingFactory->CreateImageEncoderToStream(&clsidEncoder, pOutStream, &pImageEncoder))){goto finish;}//创建解码器接口if (FAILED(hr = pImagingFactory->CreateImageDecoder(pStream, DecoderInitFlagBuiltIn1st, &pImageDecoder))){goto finish;}//得到编码器接口的sink对象。此ImageSink接口作为一个槽或者管道来理解;//是用于负责pImageEncoder和pImageDecoder之间的传输if (FAILED(hr = pImageEncoder->GetEncodeSink(&pImageSink))){goto finish;}//开始解码if (FAILED(hr = pImageDecoder->BeginDecode(pImageSink, NULL))){goto finish;}//循环解码,直到结束for(;;){//解码hr = pImageDecoder->Decode();//继续解码后面的部分if (E_PENDING == hr){Sleep(500);}//失败else if (FAILED(hr)){//终止解码pImageDecoder->EndDecode(hr);goto finish;}else{//解码成功break;}}//结束解码pImageDecoder->EndDecode(hr);//释放pImageSink对象pImageSink->Release();pImageSink = NULL;//结束编码,此时就已经完成了文件格式的转换pImageEncoder->TerminateEncoder();pOutStream->Stat(&stats, 0);*jpgsize = (int)stats.cbSize.QuadPart;pOutStream->Seek(liTemp, STREAM_SEEK_SET, NULL);pOutStream->Read(jpgbuf, (unsigned long)stats.cbSize.QuadPart, NULL);finish: //释放pStream对象 if (pStream) pStream->Release();if (pOutStream) pOutStream->Release(); //释放pImageSink对象 if (pImageSink) pImageSink->Release();//释放pImageDecoder对象 if (pImageDecoder) pImageDecoder->Release();//释放pImageEncoder对象 if (pImageEncoder) pImageEncoder->Release();//释放IImagingFactory接口对象 if (pImagingFactory) pImagingFactory->Release();//释放程序占用的COM资源 CoUninitialize();}//虽然是到Stream,但转换出来是完整的图像文件,可能需要用完整的图像文件获取图像参数之类的void ConvJpg2bmp(char *jpgbuf, int jpgsize, char *bmpbuf, int *bmpsize){HRESULT hr;IImagingFactory * pImagingFactory = NULL ; //Image工厂接口对象IStream *pStream = NULL;// 流接口对象IStream *pOutStream = NULL;// 流接口对象LARGE_INTEGER liTemp = {0};STATSTG stats={0};IImageSink *pImageSink = NULL; //Image Sink接口对象IImageDecoder *pImageDecoder = NULL; //解码器接口对象IImageEncoder *pImageEncoder = NULL;//编码器接口对象CLSID clsidEncoder; //编码器CLSIDTCHAR *tszMime = L"image/bmp"; //指定转换后,图象文件的格式// tszInFileName = L"\\1.jpg"; //指定待转换的图象文件// tszOutFileName = L"\\11.bmp"; //指定转换后的图象文件// tszMime = L"image/bmp"; //指定转换后,图象文件的格式//初始化COM环境if (FAILED(hr = CoInitializeEx(NULL, COINIT_MULTITHREADED))){TRACE(L"COINIT_MULTITHREADED ERROR");return;}//得到Image工厂接口对象 hr = CoCreateInstance(CLSID_ImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void**) &pImagingFactory);if (FAILED(hr)){TRACE(L"IMAGE FACTORY CREATED ERROR");goto finish;}if (FAILED(hr = CreateStreamOnBuffer(jpgbuf, jpgsize, &pStream))){goto finish;}//根据编码器类型名称得到编码器CLSIDif (!GetEnCodecCLSID(pImagingFactory,tszMime, &clsidEncoder )){goto finish;}if (FAILED(hr = CreateStreamOnHGlobal(NULL,TRUE,&pOutStream))){goto finish; }//创建编码器接口,并关联到输出流中if (FAILED(hr = pImagingFactory->CreateImageEncoderToStream(&clsidEncoder, pOutStream, &pImageEncoder))){goto finish;}//创建解码器接口if (FAILED(hr = pImagingFactory->CreateImageDecoder(pStream, DecoderInitFlagBuiltIn1st, &pImageDecoder))){goto finish;}//得到编码器接口的sink对象。此ImageSink接口作为一个槽或者管道来理解;//是用于负责pImageEncoder和pImageDecoder之间的传输if (FAILED(hr = pImageEncoder->GetEncodeSink(&pImageSink))){goto finish;}//开始解码if (FAILED(hr = pImageDecoder->BeginDecode(pImageSink, NULL))){goto finish;}//循环解码,直到结束for(;;){//解码hr = pImageDecoder->Decode();//继续解码后面的部分if (E_PENDING == hr){Sleep(500);}//失败else if (FAILED(hr)){//终止解码pImageDecoder->EndDecode(hr);goto finish;}else{//解码成功break;}}//结束解码pImageDecoder->EndDecode(hr);//释放pImageSink对象pImageSink->Release();pImageSink = NULL;//结束编码,此时就已经完成了文件格式的转换pImageEncoder->TerminateEncoder();pOutStream->Stat(&stats, 0);*bmpsize = (int)stats.cbSize.QuadPart;pOutStream->Seek(liTemp, STREAM_SEEK_SET, NULL);pOutStream->Read(bmpbuf, (unsigned long)stats.cbSize.QuadPart, NULL);finish: //释放pStream对象 if (pStream) pStream->Release();if (pOutStream) pOutStream->Release(); //释放pImageSink对象 if (pImageSink) pImageSink->Release();//释放pImageDecoder对象 if (pImageDecoder) pImageDecoder->Release();//释放pImageEncoder对象 if (pImageEncoder) pImageEncoder->Release();//释放IImagingFactory接口对象 if (pImagingFactory) pImagingFactory->Release();//释放程序占用的COM资源 CoUninitialize();}/**函数介绍:将文件加载到内存流中*入口参数:pBuffer:表示要打开的文件*出口参数: ppStream : 表示内存流,将文件中的内容输出到此内存流中*返回值:S_OK :表示成功,否则失败*/BOOL CreateStreamOnBuffer(const char * pBuffer, DWORD bufsize, IStream ** ppStream){ HGLOBAL hg = NULL; BYTE* pbLocked = NULL; //分配内存 hg = GlobalAlloc(GMEM_MOVEABLE, bufsize); if (NULL == hg) { goto error; } //得到已经分配的内存指针 pbLocked = (BYTE*) GlobalLock(hg); if (NULL == pbLocked) { goto error; } //读取文件内容到内存中memcpy(pbLocked, pBuffer, bufsize);//解锁已经分配全局内存,对应GlobalLock(hg) GlobalUnlock(hg); //创建Stream对象 CreateStreamOnHGlobal(hg, TRUE, ppStream); return TRUE;error: //错误处理,并释放内存 if (pbLocked) GlobalUnlock(hg); if (hg) GlobalFree(hg); return TRUE;}/**函数介绍:根据编码器类型名称,得到指定的编码器CLSID*入口参数:pImagingFactory: Image工厂接口对象 wszMimeType : Image编码格式名称 *出口参数:pclsid :编码器的CLSID*返回值:TRUE : 成功; FALSE: 失败*/BOOL GetEnCodecCLSID(IImagingFactory* pImagingFactory,WCHAR * wszMimeType ,CLSID * pclsid ){ UINT uiCount; ImageCodecInfo * codecs; HRESULT hr; BOOL fRet = FALSE;//枚举系统已经安装的编码器hr = pImagingFactory->GetInstalledEncoders(&uiCount, &codecs);//查找制定编码器的CLSID for (UINT i = 0; i < uiCount; i++) { if (wszMimeType && !wcscmp(wszMimeType, codecs[i].MimeType)) { *pclsid = codecs[i].Clsid; fRet = TRUE; break; } }//释放内存 CoTaskMemFree(codecs);// return fRet;}