您的位置:首页 > 其它

在MFC/WTL中如何绘制Gif动态图片

2012-10-16 15:30 381 查看
说明:本文内容参考了 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 。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: