使用GDI+显示GIF图像
GIF(Graphics Interchange Format,图形交换格式)文件是由 CompuServe公司开发的图形文件格式,用户在浏览网页时,可以经常看到GIF格式的动画。在设计应用程序时,该如何显示GIF动画呢?
用户可以通过显示JPEG图像的方法显示GIF图像,但是它只能显示一幅静态的图像,如果GIF文件中包含有多帧,不能显示动画效果。下面将介绍如何使用GDI+实现GIF动画的显示。GDI+中提供了一个Image类,使用该类的GetFrameDimensionsCount方法可以获取GIF文件中的帧的维数,通过GetFrameDimensionsList方法获取图像帧的GUID,通过GetFrameCount方法根据GUID获取图像的帧数,通过SelectActiveFrame方法设置图像显示的当前帧,最后使用Graphics类的DrawImage方法显示当前帧的图像就可以了。下面通过一个示例介绍GIF图像的显示。
例如,显示GIF图像
(1)创建一个文档/视图结构的应用程序,工程名称为“ShowGIF”。
(2)引用GID+的头文件、命名空间和库文件。
#include "Gdiplus//Gdiplus.h" //引用头文件
using namespace Gdiplus; //引用命名空间
#pragma comment (lib,"Gdiplus//gdiplus.lib") //引用库文件
(3)向视图类中添加成员变量
GdiplusStartupInput m_Gdiplus; //定义GDI+初始化变量
ULONG_PTR m_pGdiToken; //定义GID+标识
Bitmap *m_pBmp; //定义位图对象,派生于Image类
UINT m_Count; //记录维数
UINT m_FrameCount; //帧数
PropertyItem* pItem ; //定义图像属性
int fcount; //定义一个临时整型变量
UINT delay; //第一帧的延时
(4)在视图类的构造函数中初始化GDI+,并读取GIF文件的相关信息。
CShowGIFView::CShowGIFView()
{
GdiplusStartup(&m_pGdiToken,&m_Gdiplus,NULL); //初始化GDI+
m_pBmp = Bitmap::FromFile(L"query.gif"); //加载GIF图像
m_Count = m_pBmp->GetFrameDimensionsCount(); //获取帧维数
GUID *pGuids = new GUID[m_Count]; //定义一个GUID数组
m_pBmp->GetFrameDimensionsList(pGuids,m_Count); //获取图像帧的GUID
m_FrameCount = m_pBmp->GetFrameCount(pGuids); //获取GIF帧数
UINT size; //定义一个整型变量
m_Count = 0; //初始化成员变量
m_pBmp->GetPropertySize(&size,&delay); //获取属性大小
PropertyItem *pItem = NULL; //定义属性指针
pItem = (PropertyItem*)malloc(size); //为属性指针分配合适的空间
m_pBmp->GetAllPropertyItems(size,delay,pItem); //获取属性信息
delay = ((long*)pItem->value)[0]; //获取第一帧的延时
free(pItem); //释放属性对象
delete [] pGuids; //释放GUID
fcount = 0; //初始化成员变量
}
(5)定义一个内存画布类,防止图像闪烁。
class CMemDC : public CDC //定义一个CmemDC类
{
private:
CBitmap* m_bmp; //定义一个位图对象
CBitmap* m_oldbmp; //定义一个位图对象
CDC* m_pDC; //定义一个设备上下文指针
CRect m_Rect; //定义一个区域对象
public:
CMemDC(CDC* pDC, const CRect& rect) : CDC() //定义构造函数
{
CreateCompatibleDC(pDC); //创建一个兼容的设备上下文
m_bmp = new CBitmap; //为位图对象分配空间
//创建位图对象
m_bmp->CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
m_oldbmp = SelectObject(m_bmp); //选中创建的位图
m_pDC = pDC; //设置成员变量
m_Rect = rect; //设置区域对象
this->BitBlt(m_Rect.left, m_Rect.top, m_Rect.Width(), m_Rect.Height(),
pDC, m_Rect.left, m_Rect.top,WHITENESS); //绘制白色背景
}
~CMemDC() //析构函数
{
m_pDC->BitBlt(m_Rect.left, m_Rect.top, m_Rect.Width(), m_Rect.Height(),
this, m_Rect.left, m_Rect.top,SRCCOPY);//绘制图像
SelectObject(m_oldbmp); //选中原来的位图对象
if (m_bmp != NULL) //判断位图对象是否为空
delete m_bmp; //删除位图对象
DeleteObject(this); //释放设备上下文
}
};
(6)处理视图类的WM_TIMER消息,按照一定的时间间隔绘制不同的图像帧。
void CShowGIFView::OnTimer(UINT nIDEvent)
{
GUID Guid = FrameDimensionTime; //定义一个GUID
CDC* pDC = GetDC(); //获取视图窗口的设备上下文
//定义一个内存画布
CMemDC dc(pDC,CRect(0,0,m_pBmp->GetWidth(),m_pBmp->GetHeight()));
Graphics gh(dc.m_hDC); //定义一个图像对象
//向设备上下文中绘制图像
gh.DrawImage(m_pBmp,0,0,m_pBmp->GetWidth(),m_pBmp->GetHeight());
m_pBmp->SelectActiveFrame(&Guid,fcount++); //设置下一帧
if(fcount == m_FrameCount) //判断当前帧是否为尾帧
fcount = 0; //将当前帧设置为第一帧
CView::OnTimer(nIDEvent);
}
注意:由于GIF图像是由多幅图像组成,如果想显示可运动的GIF图像就必需绘制出每幅图像。
(7)处理视图类的WM_CREATE消息,在视图窗口创建后开始一个计时器。
int CShowGIFView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1) //调用父类的放阿凡
return -1;
SetTimer(0,delay*10,NULL); //开始一个计时器
return 0;
}
(8)在视图类的析构函数中卸载GDI+。
CShowGIFView::~CShowGIFView()
{
GdiplusShutdown(m_pGdiToken); //释放GDI+
}
(9)运行程序,效果如图1所示。
.jpg)
图1 显示GIF图像