65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 GDI+ 播放 GIF

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.34/5 (22投票s)

2008年7月1日

CPOL
viewsIcon

80293

downloadIcon

3931

使用 GDI+ 播放 GIF 的新选择。

引言

过去,使用 Microsoft Windows 提供的函数播放 GIF 没有足够方便的方法,但你可能需要引用第三方的库。现在,我们有了另一种选择,那就是使用 GDI+。

GDI+ 的基础

首先,你需要包含 GDI+ 头文件,链接库并使用命名空间。在我的示例中,我是在 stdafx.h 中完成的。

//GDI+ references
#include
using namespace Gdiplus;
#pragma comment(lib,"gdiplus.lib")

在使用 GDI+ 之前,你应该初始化以下环境代码

//Init GDI+
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
Status state = GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

与初始化相对应,你应该清理环境。

GdiplusShutdown(gdiplusToken);

关键代码

//Here, we load a GIF image file
void CGIFControl::Load(LPCTSTR sFileName)
{
	m_pImage = new Image(sFileName);
	
	//First of all we should get the number of frame dimensions
	//Images considered by GDI+ as:
	//frames[animation_frame_index][how_many_animation];
	UINT count = m_pImage->GetFrameDimensionsCount();

	//Now we should get the identifiers for the frame dimensions 
	m_pDimensionIDs =new GUID[count];
	m_pImage->GetFrameDimensionsList(m_pDimensionIDs, count);
	
	//For gif image , we only care about animation set#0
	WCHAR strGuid[39];
	StringFromGUID2(m_pDimensionIDs[0], strGuid, 39);
	m_FrameCount = m_pImage->GetFrameCount(&m_pDimensionIDs[0]);

	//PropertyTagFrameDelay is a pre-defined identifier 
	//to present frame-delays by GDI+
	UINT TotalBuffer = m_pImage->GetPropertyItemSize(PropertyTagFrameDelay);
	m_pItem = (PropertyItem*)malloc(TotalBuffer);
	m_pImage->GetPropertyItem(PropertyTagFrameDelay,TotalBuffer,m_pItem);
}

//To start play
void CGIFControl::Play()
{
	//Set Current Frame at #0
	m_iCurrentFrame = 0;
	GUID Guid = FrameDimensionTime;
	m_pImage->SelectActiveFrame(&Guid,m_iCurrentFrame);

	//Use Timer
	//NOTE HERE: frame-delay values should be multiply by 10
	SetTimer(1,((UINT*)m_pItem[0].value)[m_iCurrentFrame]  * 10,NULL);

	//Move to the next frame
	++ m_iCurrentFrame;
	Invalidate(FALSE);
}

//Using timer
void CGIFControl::OnTimer(UINT_PTR nIDEvent)
{
	//Because there will be a new delay value
	KillTimer(nIDEvent);

	//Change Active frame
	GUID Guid = FrameDimensionTime;
	m_pImage->SelectActiveFrame(&Guid,m_iCurrentFrame);

	//New timer
	SetTimer(1,((UINT*)m_pItem[0].value)[m_iCurrentFrame] * 10,NULL);

	//Again move to the next
	m_iCurrentFrame = (++ m_iCurrentFrame) % m_FrameCount;
	Invalidate(FALSE);
}

//Present current frame
void CGIFControl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	Graphics g(lpDrawItemStruct->hDC);

	DrawBorder(g);

	CRect rcClient;
	GetClientRect(&rcClient);

	if(m_bBorderEnable)
	{
		rcClient.DeflateRect(m_iBorderLineWidth,
			m_iBorderLineWidth,m_iBorderLineWidth,m_iBorderLineWidth);
	}

	g.DrawImage(m_pImage,rcClient.left,rcClient.top,rcClient.Width(),
			rcClient.Height());
}

Using the Code

步骤 1:在示例对话框的 DoDataExchange 方法中设置控件关联

DDX_Control(pDX,IDC_GIF_PLAY,m_Gif);

步骤 2:在 OnInitDialog 中加载 GIF 图像

m_Gif.Load(_T("Sample.gif"));

最后,在按钮事件处理程序中添加开始和结束代码

void CGifControlSampleDlg::OnBnClickedBtnPlay()
{
	m_Gif.Play();
}

void CGifControlSampleDlg::OnBnClickedBtnStop()
{
	m_Gif.Stop();
}

关于源代码

附件存档中的二进制文件由 VS2005SP1 编译,因此你可能需要先自行安装相应的 vcredist 包。

© . All rights reserved.