最近要使用动态gif播放技术,翻了一下没有看见轻量的类,便写了个CStatic子类化的类。
代码如下:
<script type="text/javascript"> </script>
/**/ /*
* GDI+ 应用 之 GIF播放类
* GIF; 动态GIF; 播放; GDI plus,GDI+
*
* 本类作者:webmote 2006-11 原创出版
* 有任何问题,请email: luo31@yahoo.com.cn
* !!!!引用本类,请不要删除此段注释!!!!
*/
#pragma once
#include < gdiplus.h >
using namespace Gdiplus;
// CGifCtrl
class CGifCtrl : public CStatic
... {
DECLARE_DYNAMIC(CGifCtrl)
public:
CGifCtrl();
virtual ~CGifCtrl();
/**//************************************************************************/
/**//* SetImg 设置播放的图片路径 播放速度 透明颜色 */
/**//* 路径为空,则只重设 播放速度 和 透明颜色 */
/**//************************************************************************/
BOOL SetImg(LPCTSTR pszPath,UINT nMilliSeconds=200,COLORREF clrBg=-1);
public:
//播放gif动画的速度
CWinThread* m_pThread;
CRITICAL_SECTION m_csGDILock;
static UINT DrawGif(LPVOID lpParam);
protected:
COLORREF m_clrBg;
Image* m_pImg;
GUID* m_pDimensionIDs;
UINT m_nTotalFrame;
UINT m_nCurrFrame;
UINT m_nWaitTime;
HANDLE m_hEventKill;
HANDLE m_hEventDead;
HANDLE m_thread;
protected:
DECLARE_MESSAGE_MAP()
virtual void PreSubclassWindow();
public:
afx_msg void OnDestroy();
void KillThread(void);
afx_msg void OnPaint();
} ;
类中使用了线程来定制播放时间。也采用了透明技巧。
// GifCtrl.cpp : 实现文件
//
#include " stdafx.h "
#include " TestAt.h "
#include " GifCtrl.h "
#include " .gifctrl.h "
// CGifCtrl
IMPLEMENT_DYNAMIC(CGifCtrl, CStatic)
CGifCtrl::CGifCtrl()
... {
m_clrBg=-1;
m_pImg=NULL;
m_pDimensionIDs=NULL;
m_pThread=NULL;
m_nTotalFrame=0;
m_nCurrFrame=0;
m_nWaitTime=0;
m_thread=NULL;
::InitializeCriticalSection(&m_csGDILock);
// kill event starts out in the signaled state
m_hEventKill = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hEventDead = CreateEvent(NULL, TRUE, FALSE, NULL);
}
CGifCtrl:: ~ CGifCtrl()
... {
if(m_pDimensionIDs!=NULL)
...{
delete m_pDimensionIDs;
m_pDimensionIDs=NULL;
}
CloseHandle(m_hEventKill);
CloseHandle(m_hEventDead);
}
BEGIN_MESSAGE_MAP(CGifCtrl, CStatic)
ON_WM_DESTROY()
ON_WM_PAINT()
END_MESSAGE_MAP()
BOOL CGifCtrl::SetImg(LPCTSTR pszPath,UINT nMilliSeconds,COLORREF clrBg)
... {
::EnterCriticalSection(&m_csGDILock);
m_nWaitTime=nMilliSeconds;
m_clrBg=clrBg;
::LeaveCriticalSection(&m_csGDILock);
//ASSERT(pszPath!=NULL);
if(pszPath!=NULL)
...{
USES_CONVERSION;
UINT count = 0;
::EnterCriticalSection(&m_csGDILock);
m_pImg=Image::FromFile(T2W(pszPath),TRUE);
if(m_pImg!=NULL)
...{
// How many frame dimensions does the Image object have?
count = m_pImg->GetFrameDimensionsCount();
//ASSERT(count!=0);
if(count>0)
...{
if(count!=m_nTotalFrame)
...{
if(m_pDimensionIDs!=NULL)
...{
delete m_pDimensionIDs;
m_pDimensionIDs=NULL;
}
m_pDimensionIDs=new GUID[count];
}
if(m_pDimensionIDs!=NULL)
...{
m_nCurrFrame=1;
m_pImg->GetFrameDimensionsList(m_pDimensionIDs, count);
m_nTotalFrame = m_pImg->GetFrameCount(&m_pDimensionIDs[0]);
//m_pImg->SelectActiveFrame(&m_pDimensionIDs[0],m_nCurrFrame);
TRACE("The number of frame is %d. ", m_nTotalFrame);
}
}
else
...{
TRACE("载入图片有误 ");
//delete m_pImg;
m_pImg=NULL;
}
}
::LeaveCriticalSection(&m_csGDILock);
if(m_pImg!=NULL)
...{
//调整控件大小
CRect rt,rtClient;
GetWindowRect(&rt);
GetClientRect(&rtClient);
int nOffsetX=rt.Width()-rtClient.Width();
int nOffsetY=rt.Height()-rtClient.Height();
CWnd* pParent=GetParent();
if(pParent!=NULL)
...{
pParent->ScreenToClient(&rt);
}
rt.SetRect(rt.left,rt.top,rt.left+m_pImg->GetWidth()+nOffsetX,
rt.top+m_pImg->GetHeight()+nOffsetY);
MoveWindow(&rt,TRUE);
}
}
return (m_pImg!=NULL);
}
// CGifCtrl 消息处理程序
UINT CGifCtrl::DrawGif(LPVOID lpParam)
... {
CGifCtrl* pCtrl=static_cast<CGifCtrl*>(lpParam);
if(pCtrl!=NULL)
...{
TRACE("start gif thread ");
while (::WaitForSingleObject(pCtrl->m_hEventKill, pCtrl->m_nWaitTime) == WAIT_TIMEOUT)
...{
//线程体
//CDC* pDC=pCtrl->GetDC();
if(/**//*pDC!=NULL &&*/ pCtrl->m_pImg!=NULL && pCtrl->m_pDimensionIDs!=NULL && pCtrl->m_nTotalFrame>1)
...{
::EnterCriticalSection(&pCtrl->m_csGDILock);
//Graphics g(pDC->GetSafeHdc());
pCtrl->m_pImg->SelectActiveFrame(&(pCtrl->m_pDimensionIDs[0]),pCtrl->m_nCurrFrame);
//g.DrawImage(pCtrl->m_pImg,0,0);
//pCtrl->ReleaseDC(pDC);
::LeaveCriticalSection(&pCtrl->m_csGDILock);
//设定当前播放帧
pCtrl->m_nCurrFrame++;
if(pCtrl->m_nCurrFrame<=0 || pCtrl->m_nCurrFrame>pCtrl->m_nTotalFrame)
pCtrl->m_nCurrFrame=1;
pCtrl->Invalidate();
}
}
}
TRACE("end gif thread ");
VERIFY(SetEvent(pCtrl->m_hEventDead));
return 0;
}
void CGifCtrl::PreSubclassWindow()
... {
// 建立线程
m_pThread=AfxBeginThread(DrawGif,static_cast<LPVOID>(this),THREAD_PRIORITY_IDLE,CREATE_SUSPENDED);
if(m_pThread!=NULL)
...{
SetWindowText(_T(""));
m_pThread->m_bAutoDelete=TRUE;
//复制线程句柄,以便更好的跟踪线程的关闭
::DuplicateHandle(GetCurrentProcess(),m_pThread->m_hThread,
GetCurrentProcess(),&m_thread,0,FALSE,DUPLICATE_SAME_ACCESS);
m_pThread->ResumeThread();
}
CStatic::PreSubclassWindow();
}
void CGifCtrl::OnDestroy()
... {
CStatic::OnDestroy();
// 摧毁线程
KillThread();
}
void CGifCtrl::KillThread( void )
... {
// reset the m_hEventKill which signals the thread to shutdown
VERIFY(SetEvent(m_hEventKill));
// allow thread to run at higher priority during kill process
SetThreadPriority(m_thread,THREAD_PRIORITY_ABOVE_NORMAL);
WaitForSingleObject(m_hEventDead, INFINITE);
WaitForSingleObject(m_thread, INFINITE);
::DeleteCriticalSection(&m_csGDILock);
// now delete CWinThread object since no longer necessary
//delete this;
}
void CGifCtrl::OnPaint()
... {
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
// 不为绘图消息调用 CStatic::OnPaint()
if(m_pImg!=NULL)
...{
//使用内存DC 加快显示图片
CRect rt;
GetClientRect(&rt);
//1.建立内存DC ,设置透明
CDC dcMem;
dcMem.CreateCompatibleDC(&dc);
dcMem.SetBkMode(TRANSPARENT);
//2.选入内存图片
CBitmap bmp;
bmp.CreateCompatibleBitmap(&dc,rt.Width(),rt.Height());
CBitmap* pOldBmp=dcMem.SelectObject(&bmp);
//3.建立透明蒙照
CBrush brush;
if(m_clrBg==-1)
...{
m_clrBg=dc.GetBkColor();
}
brush.CreateSolidBrush(m_clrBg);
dcMem.FillRect(&CRect(0,0,rt.Width(),rt.Height()),&brush);
//4.绘制到内存DC中
Graphics g(dcMem.GetSafeHdc());
g.DrawImage(m_pImg,0,0);
::EnterCriticalSection(&m_csGDILock);
if(!dc.TransparentBlt(rt.left,rt.top,rt.Width(),rt.Height(),&dcMem,0,0,rt.Width(),rt.Height(),m_clrBg))
dc.BitBlt(rt.left,rt.top,rt.Width(),rt.Height(),&dcMem,0,0,SRCCOPY);
::LeaveCriticalSection(&m_csGDILock);
//施放资源
dcMem.SelectObject(pOldBmp);
}
}
调用时需要 声明一个CStatic类,
然后使用 子类化为CGifCtrl类, 调用SetImg方法即可。
<script type="text/javascript"> </script>