/*
函数介绍:将文件加载到内存流中
入口参数:wzFilename:表示要打开的文件
出口参数:ppStream : 表示内存流,将文件中的内容输出到此内存流中
返回值:S_OK :表示成功,否则失败
*/
HRESULT CreateStreamOnFile(const TCHAR * wzFilename, IStream ** ppStream)
{
HRESULT hrRet = S_FALSE;
HGLOBAL hg = NULL;
HANDLE hFile = NULL;
DWORD dwSize, dwRead;
BYTE* pbLocked = NULL;
//打开文件
hFile = CreateFile(wzFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
goto error;
}
//得到文件大小
dwSize = GetFileSize(hFile, NULL);
if (0xffffffff == dwSize)
{
goto error;
}
//分配内存
hg = GlobalAlloc(GMEM_MOVEABLE, dwSize);
if (NULL == hg)
{
goto error;
}
//得到已经分配的内存指针
pbLocked = (BYTE*) GlobalLock(hg);
if (NULL == pbLocked)
{
goto error;
}
//读取文件内容到内存中
if (!ReadFile(hFile, pbLocked, dwSize, &dwRead, NULL))
{
goto error;
}
//解锁已经分配全局内存,对应GlobalLock(hg)
GlobalUnlock(hg);
//创建Stream对象
hrRet = CreateStreamOnHGlobal(hg, TRUE, ppStream);
//关闭文件流
CloseHandle(hFile);
return hrRet;
error: //错误处理,并释放内存
if (pbLocked) GlobalUnlock(hg);
if (hg) GlobalFree(hg);
if (hFile) CloseHandle(hFile);
return hrRet;
}
/*
函数介绍:根据编码器类型名称,得到指定的编码器CLSID
入口参数:pImagingFactory: Image工厂接口对象
wzMimeType : Image编码格式名称
出口参数:pclsid :编码器的CLSID
返回值:TRUE : 成功; FALSE: 失败
*/
BOOL GetEnCodecCLSID(IImagingFactory* pImagingFactory, WCHAR * wzMimeType, 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 (wzMimeType && !wcscmp(wzMimeType, codecs[i].MimeType))
{
*pclsid = codecs[i].Clsid;
fRet = TRUE;
break;
}
}
//释放内存
CoTaskMemFree(codecs);
return fRet;
}
/*
函数介绍:BMP,JPG,GIF,PNG图片格式互相转换,通过IStream
入口参数:wzInFileName: 指定待转换的图象文件
wzOutFileName: 指定转换后的图象文件
wzMimeType: 指定转换后,图象文件的格式
L"image/bmp", L"image/jpeg", L"image/gif", L"image/png"
返回值:TRUE : 成功; FALSE: 失败
*/
BOOL ImageConvert(TCHAR *wzInFileName, TCHAR *wzOutFileName, TCHAR *wzMimeType)
{
HRESULT hr;
IImagingFactory * pImagingFactory = NULL; //Image工厂接口对象
IStream *pStream = NULL; // 流接口对象
IImageSink *pImageSink = NULL; //Image Sink接口对象
IImageDecoder *pImageDecoder = NULL; //解码器接口对象
IImageEncoder *pImageEncoder = NULL; //编码器接口对象
CLSID clsidEncoder; //编码器CLSID
BOOL fRet = FALSE;
//初始化COM环境
if (FAILED(hr = CoInitializeEx(NULL, COINIT_MULTITHREADED)))
{
TRACE(L"COINIT_MULTITHREADED ERROR");
return fRet;
}
//得到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 = CreateStreamOnFile(wzInFileName, &pStream)))
{
goto finish;
}
//根据编码器类型名称得到编码器CLSID
if (!GetEnCodecCLSID(pImagingFactory,wzMimeType, &clsidEncoder ))
{
goto finish;
}
//创建编码器接口,并关联到输出文件中
if (FAILED(hr = pImagingFactory->CreateImageEncoderToFile(&clsidEncoder, wzOutFileName, &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
{
//解码成功
fRet = TRUE;
break;
}
}
//结束解码
pImageDecoder->EndDecode(hr);
//释放pImageSink对象
pImageSink->Release();
pImageSink = NULL;
//结束编码,此时就已经完成了文件格式的转换
pImageEncoder->TerminateEncoder();
finish:
//释放pStream对象
if (pStream) pStream->Release();
//释放pImageSink对象
if (pImageSink) pImageSink->Release();
//释放pImageDecoder对象
if (pImageDecoder) pImageDecoder->Release();
//释放pImageEncoder对象
if (pImageEncoder) pImageEncoder->Release();
//释放IImagingFactory接口对象
if (pImagingFactory) pImagingFactory->Release();
//释放程序占用的COM资源
CoUninitialize();
return fRet;
}
/*
函数介绍:BMP,JPG,GIF,PNG图片格式互相转换,通过IImage
入口参数:wzInFileName: 指定待转换的图象文件
wzOutFileName: 指定转换后的图象文件
wzMimeType: 指定转换后,图象文件的格式
L"image/bmp", L"image/jpeg", L"image/gif", L"image/png"
返回值:TRUE : 成功; FALSE: 失败
*/
BOOL ImageConvert(TCHAR *wzInFileName, TCHAR *wzOutFileName, TCHAR *wzMimeType)
{
HRESULT hr;
IImage *pImage = NULL;
IImagingFactory * pImagingFactory = NULL; //Image工厂接口对象
IImageSink *pImageSink = NULL; //Image Sink接口对象
IImageEncoder *pImageEncoder = NULL; //编码器接口对象
CLSID clsidEncoder; //编码器CLSID
BOOL fRet = FALSE;
//初始化COM环境
if (FAILED(hr = CoInitializeEx(NULL, COINIT_MULTITHREADED)))
{
TRACE(L"COINIT_MULTITHREADED ERROR");
return fRet;
}
//得到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 = pImagingFactory->CreateImageFromFile(wzInFileName,&pImage)))
{
goto finish;
}
//根据编码器类型名称得到编码器CLSID
if (!GetEnCodecCLSID(pImagingFactory,wzMimeType, &clsidEncoder ))
{
goto finish;
}
//创建编码器接口,并关联到输出文件中
if (FAILED(hr = pImagingFactory->CreateImageEncoderToFile(&clsidEncoder, wzOutFileName, &pImageEncoder)))
{
goto finish;
}
//得到编码器接口的sink对象。此ImageSink接口作为一个槽或者管道来理解
if (FAILED(hr = pImageEncoder->GetEncodeSink(&pImageSink)))
{
goto finish;
}
if(FAILED(hr = pImage->PushIntoSink(pImageSink)))
{
goto finish;
}
//释放pImageSink对象
pImageSink->Release();
pImageSink = NULL;
//结束编码,此时就已经完成了文件格式的转换
pImageEncoder->TerminateEncoder();
finish:
if (pImage) pImage->Release();
//释放pImageSink对象
if (pImageSink) pImageSink->Release();
//释放pImageEncoder对象
if (pImageEncoder) pImageEncoder->Release();
//释放IImagingFactory接口对象
if (pImagingFactory) pImagingFactory->Release();
//释放程序占用的COM资源
CoUninitialize();
return fRet;
}