wince5.0, eVC4.0下bmp到jpg格式转换,使用Imagefactory,两头都是Stream内存

15 篇文章 0 订阅

原先的编码太慢了,jpg编码要800ms,解码要1000ms,疯了。

于是开始用Imagefactory,经测试320x240的图片jpg编码67ms,解码38ms,太帅了,差距竟然这么大,经过的过程见:

http://topic.csdn.net/u/20121009/00/a4c385d9-62a4-48d7-ba03-a48495ecd068.html

代码如下:
将如下文件放到StdAfx.h中:

#include <imaging.h>
#include <initguid.h>
#include <imgguids.h>

其中imgguids.h要加防止重编译宏,原因见:
http://topic.csdn.net/u/20121011/12/0d353742-82bb-4089-8e40-16d9db489bf7.html?1158181987

.h文件:

#ifndef _JPG_IMGFAC_LIB_H_
#define _JPG_IMGFAC_LIB_H_

void ConvBmp2jpg(char *bmpbuf, int bmpsize, char *jpgbuf, int *jpgsize);
void ConvJpg2bmp(char *jpgbuf, int jpgsize, char *bmpbuf, int *bmpsize);

BOOL CreateStreamOnBuffer(const char * pBuffer, DWORD bufsize, IStream ** ppStream);
BOOL GetEnCodecCLSID(IImagingFactory* pImagingFactory,WCHAR * wszMimeType ,CLSID * pclsid );

#endif

.cpp文件:
#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;  //编码器CLSID
	
	TCHAR *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;
	}

	//根据编码器类型名称得到编码器CLSID
	if (!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;  //编码器CLSID
	
	TCHAR *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;
	}

	//根据编码器类型名称得到编码器CLSID
	if (!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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值