說明:本文內容參考了 codeproject 的此文,http://www.codeproject.com/Articles/1776/Adding-GIF-animation-using-GDI 。
本文所寫代碼針對多幀gif,如果是單幀gif,則會出錯(可以把Load中的IsAnimate函數放到Start開頭判斷,如果是單幀,就返回,否則,啓動定時器)。代碼中有判斷的函數。
思路:首先獲取幀數,然後每間隔一段時間就繪製一幀。可通過兩種方式實現動態,一種是線程,參考上文,另一種是Timer定時器,參考本文。
注:本人不是高手,代碼質量不必考究。歡迎改裝(因爲此代碼運行於WTL環境中,改成對應的MFC代碼即可)此代碼到工程中。
OK,廢話別說了,代碼開始:
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib") //gdi+相關文件 和 庫
// Gif控件
typedef CWinTraits<WS_VISIBLE | WS_CHILD,0> GifTraits; //控制窗口樣式
class GifWnd : public CWindowImpl<GifWnd,CStatic,GifTraits> //(此處繼承CStatic就可以拖動窗口(當窗口響應了NCHITTEST消息的時候)了)
{
public:
GifWnd() //初始化gdi+ 這種對gdi+環境的初始化和釋放在整個程序做一次就行了。因此,可考慮封裝到一個類中,此處是爲了簡便。
{
GdiplusStartupInput in;
GdiplusStartup(&token,&in,NULL);
}
~GifWnd() //釋放gdi+
{
GdiplusShutdown(token);
}
void Load(const wchar_t* path) //Image的參數要求的是unicode
{
img = Image::FromFile(path);
width = img->GetWidth();
height = img->GetHeight();
frame_pos = 0;
IsAnimate();
}
void Create(HWND hWnd,CPoint pt)
{
__super::Create(hWnd);
SetWindowPos(hWnd,pt.x,pt.y,width,height,SWP_NOZORDER);
}
void Start() //在Start之前,OnPaint已經繪製了第0幀
{
long pause = ((long *) pro_item->value)[frame_pos]; //獲取第0幀的間隔時間
pause = pause <= 5 ? 100 : pause * 10; //這個是爲了讓gif顯示速度適中,原因參考上面鏈接中原作者的回答
SetTimer(1212,pause,NULL);
}
public:
BEGIN_MSG_MAP(GifWnd)
MSG_WM_TIMER(OnTimer)
MSG_WM_PAINT(OnPaint)
END_MSG_MAP()
public:
void OnTimer(UINT_PTR)
{
GUID guid = FrameDimensionTime;
frame_pos++;
if(frame_pos >= frame_count)
frame_pos = 0;
img->SelectActiveFrame(&guid,frame_pos); //指針移到下一幀
Invalidate();
KillTimer(1212);
long pause = ((long *) pro_item->value)[frame_pos];
pause = pause <= 5 ? 100 : pause * 10;
SetTimer(1212,pause,NULL); //每次間隔時間不一樣,我記得CPictureEx類中設置成100了。
}
void OnPaint(CDCHandle)
{
CPaintDC dc(m_hWnd);
CMemoryDC mem(dc,CRect(0,0,width,height)); //WTL的雙緩存類,析構時自動繪製到dc上。這個是解決閃爍的
Graphics graph(mem);
graph.DrawImage(img,0,0,width,height);
}
private:
bool IsAnimate()
{
UINT cn = img->GetFrameDimensionsCount();
GUID* pGuid = new GUID[cn];
img->GetFrameDimensionsList(pGuid,cn);
frame_count = img->GetFrameCount(&pGuid[0]);
int sz = img->GetPropertyItemSize(PropertyTagFrameDelay);
pro_item = (PropertyItem *) malloc(sz);
img->GetPropertyItem(PropertyTagFrameDelay,sz,pro_item);
delete pGuid;
return frame_count > 1;
}
private:
int width,height;
Image *img;
int frame_count;
int frame_pos;
PropertyItem *pro_item;
ULONG_PTR token;
};
使用方法:
GifWnd gif;
gif.Load("res/star.gif"); //注意,路徑不得有誤,否則Image::FromFile返回爲NULL,接下來自然就會出錯。
gif.Create(m_hWnd,CPoint(20,20));
gif.Start();
以下爲測試用圖,歡迎copy test 。