Click here to Skip to main content
Click here to Skip to main content

Play GIF using GDI+

By , 1 Sep 2011
 

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<gdiplus.h />
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Yi Li
China China
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 4membershetkarabhijeet23 Nov '12 - 6:56 
nice and simple!
QuestionAbout interval of timermembergeorgezzt12 Apr '12 - 15:21 
((UINT*)m_pItem[0].value)[m_iCurrentFrame] is always 0. why?
GeneralMy vote of 5memberAbu Mami19 Feb '12 - 1:13 
A nice, simple example - just what I needed.
 
(BTW - UCanCode should be named UCanCopy. Yours isn't the only project that they've stolen.)
GeneralMy vote of 5memberTage Lejon6 Sep '11 - 5:27 
Nice article!
GeneralRe: My vote of 5memberYi Li6 Sep '11 - 6:31 
Thanks for your reply.I hope it helpful to you.
Best regards. Smile | :)
QuestionNo copy,thx!memberAric Green4 Sep '11 - 22:51 
Please do not copy others,in other,it's the basic usage of GDI plus.
I am not a genius, but shed more sweat!

AnswerRe: No copy,thx!memberYi Li6 Sep '11 - 6:24 
Thanks for your reply.Yes it's REALLY the basic usage of GDI+.When I wrote linabot with MFC I needed a control that can play GIF image but I can't find any.Finally I wrote the control and shared it.I hope it will be useful.
Best regards.
Questionsame codemembermerano23 Aug '11 - 7:26 
This article is a copy:
 
http://www.ucancode.net/Play-GIF-Load-GIF-GIF-Animate-with-GDIPlus-Example.htm#[^]
AnswerRe: same codememberYi Li31 Aug '11 - 21:54 
Thanks for your reply.
 
I've carefully read the given page but I'm afraid the fact is that the article quoted my code because of a keyword "Linabot" in "LinaBot::CommonCtrl::CGIFControl"."Linabot" is a web-based chating bot with "Linabot" as its both project name and code name,and I used the name as a namespace in the project.
 
First version of the attachment code was a part of the project without "making clean",that mean some addtional infomations about the linabot project was provided.I'm very sorry that the version of it can not be compiled directly , but in the next version I'v made it clean and provide a sample project then you can compile it directly.I'v commite the update,and I think the article will be updated in few days).
 
Best regard.
Questionvery bad dokumembermerano23 Aug '11 - 6:50 
Without projectfile we have to guess what type of project is needed.
 
Because of Messagemap it should be MFC (not Win32 ..).
 
I tried with VisualStudio 2010 and cant get it running.
 
The first Problem ist this line
 
class __LINABOT_COMMON_CTRL_API__ CGIFControl : public CStatic
 
__LINABOT_COMMON_CTRL_API__ is not declared
 
The chinese text comment is unreadable
 
I tried this:
 
class  CGIFControl : public CStatic
 
After this the file compiles.
 
Then i guessed where to place the rest of the code
 
pCtrl->Create(rcCreate,TopWindow,c.wData.nID);
 
rcCreate not declared ...
 
c.wData.nID not declared ...
 
CRect rcCreate;
CWnd *TopWindow = m_pMainWnd;
UINT nID = 0;
 
The remaining lines are also bad:
 
c.wData.BackGround and c.wData.sURL not declared ...
AnswerRe: very bad dokumemberYi Li31 Aug '11 - 22:01 
I'm very sorry for my bad work Sigh | :sigh: .I've commited an update and I think the article will be updated in few days.In new version,an entire sample project in VS2005SP1 and executables will be provided.
Thanks for your reply.Best regards.
GeneralJust a suggestionmembersandeepkavade19 Nov '08 - 18:38 
Hi
It would really be great if you post whole project as zip file instead of just .cpp and .h file.
GeneralRe: Just a suggestionmemberYi Li6 Sep '11 - 6:33 
I'm sorry for my laten reply.I've submitted an update and the article has done.
Best regards. Smile | :)
GeneralWhich LibrarymemberDileep.M1 Jul '08 - 2:04 
Which Library you have used and where can I get?
 
Dileep.M

GeneralRe: Which LibrarymemberYi Li1 Jul '08 - 17:14 
Hi, the only lib you need is GDI+ which provided by Microsoft Visual Studio 2003/2005 by default. You can follow the step to use the code:
1.#include within stdafx.h or any other header files you want to refer to gdi+
2.declare "using namespace Gdiplus;" directly follow step#1
3.import "gdiplus.lib" by declare "#pragma comment(lib,"gdiplus.lib")" or specified within project settings.
 
an example given here:
// stdafx.h : include file for standard system include files,
//  or project specific include files that are used frequently, but
//      are changed infrequently
//

#if !defined(AFX_STDAFX_H__2C6822B8_F873_453B_A37D_24F966BDD5D5__INCLUDED_)
#define AFX_STDAFX_H__2C6822B8_F873_453B_A37D_24F966BDD5D5__INCLUDED_
 
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define VC_EXTRALEAN		// Exclude rarely-used stuff from Windows headers

#include <afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions

#ifndef _AFX_NO_OLE_SUPPORT
#include <afxole.h>         // MFC OLE classes
#include <afxodlgs.h>       // MFC OLE dialog classes
#include <afxdisp.h>        // MFC Automation classes
#endif // _AFX_NO_OLE_SUPPORT

 
#ifndef _AFX_NO_DB_SUPPORT
#include <afxdb.h>			// MFC ODBC database classes
#endif // _AFX_NO_DB_SUPPORT

#ifndef _AFX_NO_DAO_SUPPORT
#include <afxdao.h>			// MFC DAO database classes
#endif // _AFX_NO_DAO_SUPPORT

#include <afxdtctl.h>		// MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>			// MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT

#include <gdiplus.h>
#pragma comment(lib,"gdiplus.lib")
using namespace Gdiplus;
 
#include "resource.h"
 
Then the only thing left is that add the two files from the package into your project and that's ok.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 1 Sep 2011
Article Copyright 2008 by Yi Li
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid