WTL
和 Gdiplus
开发界面程序时,我们需要在界面显示 GIF
的动画,可惜 WTL
和 Gdiplus
并没有执行显示 GIF
动画的API. 那我们如何做?GIF
文件关键的2个参数, 图片的帧数,每帧的时间间隔. 如果能获取到这2个参数,那么我们就可以让帧索引递增,并逐帧绘制图片。
获取图片的帧数,可以通过以下方法,我们需要做的是构造方法的参数. 在Image::GetFrameDimensionsList method 里有讲.
Gdiplus::Image::GetFrameCount(const GUID* dimensionID)
image->GetPropertyItem(PropertyTagFrameDelay,nsize,pItem);
image->SelectActiveFrame(&Guid, frame_index++);
SetTimer(nIDEvent,milliseconds);
gif
图片分析完,直接获取所有的帧的时间间隔, 从而在定时器里只是进行选择活动帧和绘制图片.bool CView::StoreGifInternal(Gdiplus::Bitmap* image,std::vector<long>& internals)
{
int ncount = image->GetFrameDimensionsCount();
GUID *pDimensionIDs=(GUID*)new GUID[ncount];
image->GetFrameDimensionsList(pDimensionIDs,ncount);
// 获取帧数
UINT framecount = image->GetFrameCount(&pDimensionIDs[0]);
delete []pDimensionIDs;
if (1 == framecount)
return false;
int nsize=image->GetPropertyItemSize(PropertyTagFrameDelay);
Gdiplus::PropertyItem* pItem=NULL;
pItem = (Gdiplus::PropertyItem*)malloc(nsize);
//// GIF动画图像中两帧之间的时间延迟,以百分之一秒为单位。
image->GetPropertyItem(PropertyTagFrameDelay,nsize,pItem);
for(long i = 0;i<framecount;++i){
// 百分之一秒转换为毫秒,需要*10
long lPause = ((long*)pItem->value)[i]*10;
internals.push_back(lPause);
}
free(pItem);
return true;
}
// View.h : interface of the CView class
//
/////////////////////////////////////////////////////////////////////////////
#pragma once
#include
#include
class CView : public CWindowImpl<CView>
{
public:
DECLARE_WND_CLASS(NULL)
BOOL PreTranslateMessage(MSG* pMsg);
BEGIN_MSG_MAP_EX(CView)
MSG_WM_CREATE(OnCreate)
MSG_WM_TIMER(OnTimer)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
REFLECT_NOTIFICATIONS()
END_MSG_MAP()
protected:
int OnCreate(LPCREATESTRUCT lpCreateStruct);
LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
LRESULT OnCtlColor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
void OnTimer(UINT_PTR nIDEvent);
bool StoreGifInternal(Gdiplus::Bitmap* image,std::vector<long>& internals);
private:
int frame_index_; // 当前GIF的可见帧索引.
std::vector<long> frame_internal_; // 每帧时间间隔,毫秒.
Gdiplus::RectF rect_image_;
Gdiplus::Bitmap* image_;
};
// View.cpp : implementation of the CView class
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "resource.h"
#include "View.h"
#include
#include
#include
#include
#include
enum{
kOneGifTimerID = 1
};
void CView::OnTimer(UINT_PTR nIDEvent)
{
switch(nIDEvent)
{
case kOneGifTimerID:
{
frame_index_++;
if(frame_index_ == frame_internal_.size())
frame_index_ = 0;
GUID guid = Gdiplus::FrameDimensionTime;
// 选择当前GIF哪帧作为当前可见绘制帧.
image_->SelectActiveFrame(&guid,frame_index_);
auto milliseconds = frame_internal_[frame_index_];
SetTimer(nIDEvent,milliseconds);
CRect rect(rect_image_.X,rect_image_.Y,rect_image_.GetRight(),rect_image_.GetBottom());
InvalidateRect(rect,FALSE);
break;
}
}
}
bool CView::StoreGifInternal(Gdiplus::Bitmap* image,std::vector<long>& internals)
{
int ncount = image->GetFrameDimensionsCount();
GUID *pDimensionIDs=(GUID*)new GUID[ncount];
image->GetFrameDimensionsList(pDimensionIDs,ncount);
// 获取帧数
UINT framecount = image->GetFrameCount(&pDimensionIDs[0]);
delete []pDimensionIDs;
if (1 == framecount)
return false;
int nsize=image->GetPropertyItemSize(PropertyTagFrameDelay);
Gdiplus::PropertyItem* pItem=NULL;
pItem = (Gdiplus::PropertyItem*)malloc(nsize);
//// GIF动画图像中两帧之间的时间延迟,以百分之一秒为单位。
image->GetPropertyItem(PropertyTagFrameDelay,nsize,pItem);
for(long i = 0;i<framecount;++i){
// 百分之一秒转换为毫秒,需要*10
long lPause = ((long*)pItem->value)[i]*10;
internals.push_back(lPause);
}
free(pItem);
return true;
}
BOOL CView::PreTranslateMessage(MSG* pMsg)
{
pMsg;
return FALSE;
}
LRESULT CView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
CRect rect;
GetClientRect(&rect);
CPaintDC dc(m_hWnd);
CMemoryDC mdc(dc,dc.m_ps.rcPaint);
mdc.FillSolidRect(rect,RGB(255,255,255));
Gdiplus::Graphics graphics(mdc);
graphics.DrawImage(image_,rect_image_,0,0,
image_->GetWidth(),image_->GetHeight(),Gdiplus::UnitPixel);
return 0;
}
static std::wstring GetProductBinDir()
{
static wchar_t szbuf[MAX_PATH];
::GetModuleFileNameW(NULL,szbuf,MAX_PATH);
::PathRemoveFileSpecW(szbuf);
int length = lstrlen(szbuf);
szbuf[length] = L'\\';
szbuf[length+1] = 0;
return szbuf;
}
int CView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
frame_index_ = 0;
auto binDir = GetProductBinDir();
binDir.append(L"wtf.gif");
image_ = new Gdiplus::Bitmap(binDir.c_str());
if(image_->GetLastStatus() == Gdiplus::Ok){
rect_image_.X = 200;
rect_image_.Y = 200;
rect_image_.Width = image_->GetWidth();
rect_image_.Height = image_->GetHeight();
}
assert(image_);
StoreGifInternal(image_,frame_internal_);
SetTimer(kOneGifTimerID,100);
return 0;
}
使用vs2010, WTL(Win32)库开发.
https://download.csdn.net/download/infoworld/12391893
PropertyTagFrameDelay
SetTimer function
Copy individual frames from a multiple-frame image
Image::GetFrameDimensionsList method