Motive
How many of
you developers are using
GDI+? I
reckon, not many. As a seasoned Windows
C++ programmer
developing for desktop
applications, I've been using the archaic
GDI on
regular basis. Since the release of
GDI+
(see (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdicpp)
I've been using GDI+
in new applications and also converting
existing applications to use
GDI+.
There numerous compelling reasons why you
should be using GDI+,
here are some:
-
Successor to
GDI
-
Compatible with
.NET
-
Optimizes many of the capabilities of
GDI
-
Supports:
Gradient Brushes, Independent
Path Objects,
Transformations and the Matrix Object,
Scalable Regions,
Alpha Blending and support
for multiple image formats:
-
BMP
-
GIF
-
JPEG
-
Exif
-
PNG
-
TIFF
-
ICON
-
WMF
-
EMF
During my
development of Windows GUI based
applications with
GDI+, I've come across the need
to display animated
GIFs, whilst
GDI+
does not support
displaying animated GIFs
directly, in can be done with a little
coding.
Implementation
Firstly
lets look at
drawing a simple image using
GDI+.
void CMyWnd::OnPaint()
{
CPaintDC dc(this);
Graphics graphics(&dc);
Image image(L"Test.Gif");
graphics.DrawImage(&image, 0, 0, image.GetWidth(), image.GetHeight());
}
Straight
away we can see the simplistic
C++
interface for using
GDI objects. This makes it a
sure fire way for using
GDI objects.
There is no need for using
SelectObject
to select GDI objects in and out of the
device context.
For those
of the readers who are not familiar with the
format of an
animated GIF,
animated GIF
is actually a series of
GIF
frames with a delay time associated each
frame, therefore each frame can have a
different delay time.
My
implementation of encapsulating an
animated GIF
functionality derives a class called from
ImageEx
from the
GDI+
Image
class. The first tucancode.net is to determine
whether or not a
GIF is of the animated kind. The
following code demonstrates this:
bool ImageEx::TestForAnimatedGIF()
{
UINT count = 0;
count = GetFrameDimensionsCount();
GUID* pDimensionIDs = new GUID[count];
GetFrameDimensionsList(pDimensionIDs, count);
m_nFrameCount = GetFrameCount(&pDimensionIDs[0]);
int nSize = GetPropertyItemSize(PropertyTagFrameDelay);
m_pPropertyItem = (PropertyItem*) malloc(nSize);
GetPropertyItem(PropertyTagFrameDelay, nSize, m_pPropertyItem);
delete pDimensionIDs;
return m_nFrameCount > 1;
}
m_pPropertyItem->value
is actually a pointer
to an array of longs, each long is a delay
time which corresponds to a GIF
frame. Because
GetPropertyItem
returns a different size depending on what
property using interested in, a Size is
require and its the programmer
responsibility to allocate and deallocate
the memory associated with
GetPropertyItem
.
The size is determined by calling
GetPropertyItemSize
supplying property tag your interested in.
Once the
number of frames and delay times have been
retrieved from the image, a thread is
created which calls to
DrawFrameGIF
until the object
destructs. See
DrawFrameGIF
below:
Collapse
bool ImageEx::DrawFrameGIF()
{
::WaitForSingleObject(m_hPause, INFINITE);
GUID pageGuid = FrameDimensionTime;
long hmWidth = GetWidth();
long hmHeight = GetHeight();
HDC hDC = GetDC(m_hWnd);
if (hDC)
{
Graphics graphics(hDC);
graphics.DrawImage(this, m_rc.left, m_rc.top, hmWidth, hmHeight);
ReleaseDC(m_hWnd, hDC);
}
SelectActiveFrame(&pageGuid, m_nFramePosition++);
if (m_nFramePosition == m_nFrameCount)
m_nFramePosition = 0;
long lPause = ((long*) m_pPropertyItem->value)[m_nFramePosition] * 10;
DWORD dwErr = WaitForSingleObject(m_hExitEvent, lPause);
return dwErr == WAIT_OBJECT_0;
}
One other
interesting aspect of this class is it has
the ability of loading a image directly as a
resource from an executable. I usually
import my GIF into a project and give it a
resource type of "GIF"
and then rename the resource ID from a
numeric constant to a string (see the
example
code).
Conclusion
If you
familiar with the concepts and programming
of GDI,
GDI+
provides some advance features and the
interface almost mirrors the
.NET GDI
namespace. The sample apps and code
include the full listings for implementing
animated GIF in your code
applications. For code reference just search
for GDI+
within the code. One thing I haven't
included in this
article is starting up and
shutting the GDI+ subsystem.