利用GDI plus 播放GIF图片

最近要使用动态gif播放技术,翻了一下没有看见轻量的类,便写了个CStatic子类化的类。
代码如下:

/*
*  GDI+ 应用 之 GIF播放类
*  GIF; 动态GIF; 播放; GDI plus,GDI+
*  
*  本类作者:webmote 2006-11 原创出版
*  有任何问题,请email: [email protected]
*  !!!!引用本类,请不要删除此段注释!!!!
*/

#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方法即可。

你可能感兴趣的:(VC++)