在MFC/WTL中如何繪製Gif動態圖片

說明:本文內容參考了 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 。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章