Play GIF using GDI+
A new choice for playing GIF using GDI+
Introduction
In the past, there was no convenient enough way to play GIF using functions provided by Microsoft Windows but you may need a reference of 3rd libs. Well, now we have an alternative choice from using GDI+
Base of GDI+
First of all, you need to include GDI+ headers, link the libs and using the namespace. In my sample, I did it in stdafx.h.
//GDI+ references
#include
using namespace Gdiplus;
#pragma comment(lib,"gdiplus.lib")
Before using GDI+ in your application, you should initialize the enviroment code below:
//Init GDI+
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
Status state = GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
Correspondent to initialize, you should clean up the environment.
GdiplusShutdown(gdiplusToken);
Critical Code
//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
Step 1: Set control correspondence in DoDataExchange
method of sample dialog:
DDX_Control(pDX,IDC_GIF_PLAY,m_Gif);
Step 2: Load the gif image in OnInitDialog
:
m_Gif.Load(_T("Sample.gif"));
Finally, add start and finish code in button event handler:
void CGifControlSampleDlg::OnBnClickedBtnPlay()
{
m_Gif.Play();
}
void CGifControlSampleDlg::OnBnClickedBtnStop()
{
m_Gif.Stop();
}
About the Source
Binary files in attachment archive are compiled by VS2005SP1, so you may need to install the suit vcredist package by yourself first.