Mobil手机加载GIF动态图像的方法有两种,一个就是使用GIF89a标准算法,另一个就是使用SDK自带的Imaging组件,这两种方法是很典型的手机图像处理技术的实践。使用Imaging组件加载GIF比使用标准算法处理高效的多,特别是在处理真彩GIF动画表现更加突出。
Imaging组件中封装了对大部分图片格式的编解码算法,并以接口的形式提供给开发人员使用。Imaging组件是GDI+的微缩版。但是在实际使用上又有很大的不同。使用Imaging组件来加载GIF动态图片调用了几乎所有的Imaging接口
看看我们将要用到的接口:
IImagingFactory:图像操作最初要用到的接口,它的接口方法全是带CreateXXX的函数,可见他的制造工厂的特性。使用前需要调用CoCreateInstance初始化。
IImageDecoder:主要的图像操作接口,用来处理从大部分图像格式中获取数据。
IbitmapImage:主要的图位操作接口,这里能够对具体的图像像素进行运算。
IImage:主要的图形控制接口,也许是Imaging组件唯一的绘制接口
IImageSink:这个东东似乎是一个过渡性质的接口,它的亮点在它的sink的动词解释上:沉!
操作:
首先我们要使用IImagingFactory的CreateImageDecoderppy初始化IimageDecoder。使用这个接口的方法取得GIF图像数据信息,再用IimagingFactory的CreateNewBitmap初始化IbitmapImage。通过这个接口执行QueryInterface取得IImage和IimageSink,然后调用IimageDecoder的SelectActiveFrame设定当前的图像块数据。此时对获得的IimageSink进行decode,decode完毕后调用Iimage接口的draw方法,此时画出的就是指定的那个图像块图像。
部分代码:
文件到流的转化
HRESULT CGIFImage::CreateStreamOnFile(const TCHAR * tszFilename, IStream ** ppStream)
{
HRESULT hrRet = S_OK;
HGLOBAL hg = NULL;
HANDLE hGIFFile = NULL;
DWORD dwSize, dwRead;
BYTE* pbLocked = NULL;
// 建立一个文件池,我管CreateFile返回的handle这个叫文件池
hGIFFile = CreateFile(tszFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
//当handle地址为-1时表示没有创建成功
if (INVALID_HANDLE_VALUE == hGIFFile)
{
hrRet = E_PENDING + GetLastError();
goto error;
}
dwSize = GetFileSize(hGIFFile, NULL);
//当尺寸溢出时放弃
if (INVALID_FILE_SIZE == dwSize)
{
hrRet = E_PENDING + GetLastError();
goto error;
}
// 分配一个文件尺寸相同的活动内存池
hg = GlobalAlloc(GMEM_MOVEABLE, dwSize);
//分配失败即放弃
if (NULL == hg)
{
hrRet = E_PENDING + GetLastError();
goto error;
}
//使用GlobalLock得到内存指针
pbLocked = (BYTE*) GlobalLock(hg);
//lock失败放弃
if (NULL == pbLocked)
{
hrRet = E_PENDING + GetLastError();
goto error;
}
// copy the file
if (!ReadFile(hGIFFile, pbLocked, dwSize, &dwRead, NULL))
{
hrRet = E_PENDING + GetLastError();
goto error;
}
GlobalUnlock(hg);
// 创建文件流
hrRet = CreateStreamOnHGlobal(hg, TRUE, ppStream);
CloseHandle(hGIFFile);
return hrRet;
error:
if (pbLocked)
GlobalUnlock(hg);
if (hg)
GlobalFree(hg);
if (hGIFFile)
CloseHandle(hGIFFile);
return hrRet;
}
文件加载
Load(fn)方法
IStream* gifStream;//GIF文件数据流
CreateStreamOnFile(fn,&gifStream);//加载文件到流中
//对GIF流解码,取decoad对象
if(SUCCEEDED(m_GIFImageFactory->CreateImageDecoder(gifStream,DecoderInitFlagBuiltIn1st,&m_GIFImageDecoder)))
{
UINT num;
UINT delaySize;
IBitmapImage* ibGif;
//GUID pdi;
//获取图像的dimension数
m_GIFImageDecoder->GetFrameDimensionsCount(&num);
//获取图像的dimension列表
m_GIFImageDecoder->GetFrameDimensionsList(&m_pdi,num);
m_GIFImageDecoder->GetFrameCount(&m_pdi,&m_nPageQuantity);
//获取图像间的延迟时间
m_GIFImageDecoder->GetPropertyItemSize(PropertyTagFrameDelay,&delaySize);
PropertyItem* pItem = NULL;
pItem = (PropertyItem*)malloc(delaySize);
m_GIFImageDecoder->GetPropertyItem(PropertyTagFrameDelay,delaySize,pItem);
m_nRate=((UINT*)pItem->value)[0];
m_GIFImageDecoder->GetImageInfo(&m_iif);
m_GIFImageFactory->CreateNewBitmap(m_iif.Width,m_iif.Height,m_iif.PixelFormat,&ibGif);
ibGif->QueryInterface(IID_IImageSink,(void**)&m_GIFImageSink);
ibGif->QueryInterface(IID_IImage,(void**)&m_GIFImage);
}
在定时器中执行下面代码,不仅实现了GIF动画的播放,还支持透明GIF动画的播放
Draw(HDC hDC,HWND hWnd,int XDest,int YDest)方法
if(m_GIFImageDecoder==0)
{
return 0;
}
//选择某个维面上的某一贞做为当前的活动贞
m_GIFImageDecoder->SelectActiveFrame(&m_pdi,m_nCurPage);
m_GIFImageDecoder->BeginDecode(m_GIFImageSink,NULL);
/*while (E_PENDING == (m_GIFImageDecoder->Decode()))
{
Sleep(10);
}*/
m_GIFImageDecoder->Decode();
m_GIFImageDecoder->EndDecode(E_FAIL);
RECT rt;
rt.left=XDest;
rt.top=YDest;
rt.right=XDest+m_iif.Width;
rt.bottom=YDest+m_iif.Height;
HDC hdcMemory=CreateCompatibleDC(hDC);
HBITMAP hBitmapMemory=CreateCompatibleBitmap(hDC,m_iif.Width,m_iif.Height);
HBITMAP hOldBitmapMemory=(HBITMAP)SelectObject(hdcMemory,hBitmapMemory);
HDC hdcbkMemory=CreateCompatibleDC(hDC);
HBITMAP hBitmapbkMemory=CreateCompatibleBitmap(hDC,m_iif.Width,m_iif.Height);
HBITMAP hOldbkBitmap=(HBITMAP)SelectObject(hdcbkMemory,hBitmapbkMemory);
if(NULL==m_hBKBitmap)
{
BitBlt(hdcbkMemory,0,0,m_iif.Width,m_iif.Height,hDC,rt.left,rt.top,SRCCOPY);
m_hBKBitmap=(HBITMAP)SelectObject(hdcbkMemory,hOldbkBitmap);
}
SelectObject(hdcbkMemory,m_hBKBitmap);
BitBlt(hdcMemory,0,0,m_iif.Width,m_iif.Height,hdcbkMemory,0,0,SRCCOPY);
//SelectObject(hdcbkMemory,hOldbkBitmap);
DeleteObject(hOldbkBitmap);
DeleteObject(hBitmapbkMemory);
DeleteDC(hdcbkMemory);
hdcbkMemory=NULL;
hOldbkBitmap=NULL;
hBitmapbkMemory=NULL;
m_GIFImage->Draw(hdcMemory,CRect(0,0,m_iif.Width,m_iif.Height),NULL);
BitBlt(hDC,rt.left,rt.top,m_iif.Width,m_iif.Height,hdcMemory,0,0,SRCCOPY);
SelectObject(hdcMemory,hOldBitmapMemory);
DeleteObject(hBitmapMemory);
DeleteObject(hOldBitmapMemory);
//DeleteObject(hBitmapbkMemory);
hBitmapMemory=NULL;
hOldBitmapMemory=NULL;
//hBitmapbkMemory=NULL;
DeleteDC(hdcMemory);
ReleaseDC(hWnd,hDC);
//m_GIFImage->Draw(hDC,&rt,NULL);
return TRUE;