duilib 增加gif控件(基于gdi+,可控制播放暂停,自动设置大小)
转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42502081
因为项目需要我需要给duilib增加一个gif控件,目前已经有了gif控件有很多版本,我去搜集了一些控件,但是都没有自己满意的。原uilib库中已经有GifAnim控件,但是这个控件给出的控制功能不足,不可以控制播放、暂停、停止。当控件隐藏时也不会停止播放动画,会影响效率。
于是在原GifAnim的基础上做了增强,增加了PlayGif、PauseGif、StopGif函数来控制播放、暂停、停止。增加autoplay属性控制控件初始时是否自动播放。
GifAnim的属性如下:
<GifAnim parent="Control" notifies="setfocus killfocus timer menu windowinit(root)"> <Attribute name="bkimage" default="" type="STRING" comment="Gif动画图片路径"/> <Attribute name="autoplay" default="true" type="BOOL" comment="是否自动播放GIF动画"/> <Attribute name="autosize" default="false" type="BOOL" comment="是否根据图片自动设置控件大小"/> </GifAnim>
xml代码对应为:
<GifAnim name="gif" bkimage="0.gif" autoplay="true" autosize="true" width="100" height="100" />
gif控件用gdi+函数来解析图片,所以要初始化gdi+接口,为了避免多次重复初始化gdi+,所以把初始化函数写到了CPaintManager的构造函数里。
UIGifAnim.h源码如下:
#ifndef GifAnimUI_h__ #define GifAnimUI_h__ #pragma once namespace DuiLib { class CControl; #define EVENT_TIEM_ID 100 class UILIB_API CGifAnimUI : public CControlUI { public: CGifAnimUI(void); ~CGifAnimUI(void); LPCTSTR GetClass() const; LPVOID GetInterface(LPCTSTR pstrName); void DoInit() override; void DoPaint(HDC hDC, const RECT& rcPaint) override; void DoEvent(TEventUI& event) override; void SetVisible(bool bVisible = true ) override; void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue) override; void SetBkImage(LPCTSTR pStrImage); LPCTSTR GetBkImage(); void SetAutoPlay(bool bIsAuto = true ); bool IsAutoPlay() const; void SetAutoSize(bool bIsAuto = true ); bool IsAutoSize() const; void PlayGif(); void PauseGif(); void StopGif(); private: void InitGifImage(); void DeleteGif(); void OnTimer( UINT_PTR idEvent ); void DrawFrame( HDC hDC ); // 绘制GIF每帧 Gdiplus::Image* LoadGifFromFile(LPCTSTR pstrGifPath); Gdiplus::Image* LoadGifFromMemory( LPVOID pBuf,size_t dwSize ); private: Gdiplus::Image *m_pGifImage; UINT m_nFrameCount; // gif图片总帧数 UINT m_nFramePosition; // 当前放到第几帧 Gdiplus::PropertyItem* m_pPropertyItem; // 帧与帧之间间隔时间 CDuiString m_sBkImage; bool m_bIsAutoPlay; // 是否自动播放gif bool m_bIsAutoSize; // 是否自动根据图片设置大小 bool m_bIsPlaying; }; } #endif // GifAnimUI_h__
UIGifAnim.cpp源码如下:
#include "StdAfx.h" #include "UIGifAnim.h" /////////////////////////////////////////////////////////////////////////////////////// DECLARE_HANDLE(HZIP); // An HZIP identifies a zip file that has been opened typedef DWORD ZRESULT; typedef struct { int index; // index of this file within the zip char name[MAX_PATH]; // filename within the zip DWORD attr; // attributes, as in GetFileAttributes. FILETIME atime,ctime,mtime;// access, create, modify filetimes long comp_size; // sizes of item, compressed and uncompressed. These long unc_size; // may be -1 if not yet known (e.g. being streamed in) } ZIPENTRY; typedef struct { int index; // index of this file within the zip TCHAR name[MAX_PATH]; // filename within the zip DWORD attr; // attributes, as in GetFileAttributes. FILETIME atime,ctime,mtime;// access, create, modify filetimes long comp_size; // sizes of item, compressed and uncompressed. These long unc_size; // may be -1 if not yet known (e.g. being streamed in) } ZIPENTRYW; #define OpenZip OpenZipU #define CloseZip(hz) CloseZipU(hz) extern HZIP OpenZipU(void *z,unsigned int len,DWORD flags); extern ZRESULT CloseZipU(HZIP hz); #ifdef _UNICODE #define ZIPENTRY ZIPENTRYW #define GetZipItem GetZipItemW #define FindZipItem FindZipItemW #else #define GetZipItem GetZipItemA #define FindZipItem FindZipItemA #endif extern ZRESULT GetZipItemA(HZIP hz, int index, ZIPENTRY *ze); extern ZRESULT GetZipItemW(HZIP hz, int index, ZIPENTRYW *ze); extern ZRESULT FindZipItemA(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze); extern ZRESULT FindZipItemW(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRYW *ze); extern ZRESULT UnzipItem(HZIP hz, int index, void *dst, unsigned int len, DWORD flags); /////////////////////////////////////////////////////////////////////////////////////// namespace DuiLib { CGifAnimUI::CGifAnimUI(void) { m_pGifImage = NULL; m_pPropertyItem = NULL; m_nFrameCount = 0; m_nFramePosition = 0; m_bIsAutoPlay = true; m_bIsAutoSize = false; m_bIsPlaying = false; } CGifAnimUI::~CGifAnimUI(void) { DeleteGif(); m_pManager->KillTimer( this, EVENT_TIEM_ID ); } LPCTSTR CGifAnimUI::GetClass() const { return _T("GifAnimUI"); } LPVOID CGifAnimUI::GetInterface( LPCTSTR pstrName ) { if( _tcscmp(pstrName, DUI_CTR_GIFANIM) == 0 ) return static_cast<CGifAnimUI*>(this); return CControlUI::GetInterface(pstrName); } void CGifAnimUI::DoInit() { InitGifImage(); } void CGifAnimUI::DoPaint( HDC hDC, const RECT& rcPaint ) { if( !::IntersectRect( &m_rcPaint, &rcPaint, &m_rcItem ) ) return; if ( NULL == m_pGifImage ) { InitGifImage(); } DrawFrame( hDC ); } void CGifAnimUI::DoEvent( TEventUI& event ) { if( event.Type == UIEVENT_TIMER ) OnTimer( (UINT_PTR)event.wParam ); } void CGifAnimUI::SetVisible(bool bVisible /* = true */) { CControlUI::SetVisible(bVisible); if (bVisible) PlayGif(); else StopGif(); } void CGifAnimUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue) { if( _tcscmp(pstrName, _T("bkimage")) == 0 ) SetBkImage(pstrValue); else if( _tcscmp(pstrName, _T("autoplay")) == 0 ) { SetAutoPlay(_tcscmp(pstrValue, _T("true")) == 0); } else if( _tcscmp(pstrName, _T("autosize")) == 0 ) { SetAutoSize(_tcscmp(pstrValue, _T("true")) == 0); } else CControlUI::SetAttribute(pstrName, pstrValue); } void CGifAnimUI::SetBkImage(LPCTSTR pStrImage) { if( m_sBkImage == pStrImage || NULL == pStrImage) return; m_sBkImage = pStrImage; StopGif(); DeleteGif(); Invalidate(); } LPCTSTR CGifAnimUI::GetBkImage() { return m_sBkImage.GetData(); } void CGifAnimUI::SetAutoPlay(bool bIsAuto) { m_bIsAutoPlay = bIsAuto; } bool CGifAnimUI::IsAutoPlay() const { return m_bIsAutoPlay; } void CGifAnimUI::SetAutoSize(bool bIsAuto) { m_bIsAutoSize = bIsAuto; } bool CGifAnimUI::IsAutoSize() const { return m_bIsAutoSize; } void CGifAnimUI::PlayGif() { if (m_bIsPlaying || m_pGifImage == NULL) { return; } long lPause = ((long*) m_pPropertyItem->value)[m_nFramePosition] * 10; if ( lPause == 0 ) lPause = 100; m_pManager->SetTimer( this, EVENT_TIEM_ID, lPause ); m_bIsPlaying = true; } void CGifAnimUI::PauseGif() { if (!m_bIsPlaying || m_pGifImage == NULL) { return; } m_pManager->KillTimer(this, EVENT_TIEM_ID); this->Invalidate(); m_bIsPlaying = false; } void CGifAnimUI::StopGif() { if (!m_bIsPlaying) { return; } m_pManager->KillTimer(this, EVENT_TIEM_ID); m_nFramePosition = 0; this->Invalidate(); m_bIsPlaying = false; } void CGifAnimUI::InitGifImage() { m_pGifImage = LoadGifFromFile(GetBkImage()); if ( NULL == m_pGifImage ) return; UINT nCount = 0; nCount = m_pGifImage->GetFrameDimensionsCount(); GUID* pDimensionIDs = new GUID[ nCount ]; m_pGifImage->GetFrameDimensionsList( pDimensionIDs, nCount ); m_nFrameCount = m_pGifImage->GetFrameCount( &pDimensionIDs[0] ); int nSize = m_pGifImage->GetPropertyItemSize( PropertyTagFrameDelay ); m_pPropertyItem = (Gdiplus::PropertyItem*) malloc( nSize ); m_pGifImage->GetPropertyItem( PropertyTagFrameDelay, nSize, m_pPropertyItem ); delete pDimensionIDs; pDimensionIDs = NULL; if (m_bIsAutoSize) { SetFixedWidth(m_pGifImage->GetWidth()); SetFixedHeight(m_pGifImage->GetHeight()); } if (m_bIsAutoPlay) { PlayGif(); } } void CGifAnimUI::DeleteGif() { if ( m_pGifImage != NULL ) { delete m_pGifImage; m_pGifImage = NULL; } if ( m_pPropertyItem != NULL ) { free( m_pPropertyItem ); m_pPropertyItem = NULL; } m_nFrameCount = 0; m_nFramePosition = 0; } void CGifAnimUI::OnTimer( UINT_PTR idEvent ) { if ( idEvent != EVENT_TIEM_ID ) return; m_pManager->KillTimer( this, EVENT_TIEM_ID ); this->Invalidate(); m_nFramePosition = (++m_nFramePosition) % m_nFrameCount; long lPause = ((long*) m_pPropertyItem->value)[m_nFramePosition] * 10; if ( lPause == 0 ) lPause = 100; m_pManager->SetTimer( this, EVENT_TIEM_ID, lPause ); } void CGifAnimUI::DrawFrame( HDC hDC ) { if ( NULL == hDC || NULL == m_pGifImage ) return; GUID pageGuid = Gdiplus::FrameDimensionTime; Gdiplus::Graphics graphics( hDC ); graphics.DrawImage( m_pGifImage, m_rcItem.left, m_rcItem.top, m_rcItem.right-m_rcItem.left, m_rcItem.bottom-m_rcItem.top ); m_pGifImage->SelectActiveFrame( &pageGuid, m_nFramePosition ); } Gdiplus::Image* CGifAnimUI::LoadGifFromFile(LPCTSTR pstrGifPath) { LPBYTE pData = NULL; DWORD dwSize = 0; do { CDuiString sFile = CPaintManagerUI::GetResourcePath(); if( CPaintManagerUI::GetResourceZip().IsEmpty() ) { sFile += pstrGifPath; HANDLE hFile = ::CreateFile(sFile.GetData(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, \ FILE_ATTRIBUTE_NORMAL, NULL); if( hFile == INVALID_HANDLE_VALUE ) break; dwSize = ::GetFileSize(hFile, NULL); if( dwSize == 0 ) break; DWORD dwRead = 0; pData = new BYTE[ dwSize ]; ::ReadFile( hFile, pData, dwSize, &dwRead, NULL ); ::CloseHandle( hFile ); if( dwRead != dwSize ) { delete[] pData; pData = NULL; break; } } else { sFile += CPaintManagerUI::GetResourceZip(); HZIP hz = NULL; if( CPaintManagerUI::IsCachedResourceZip() ) hz = (HZIP)CPaintManagerUI::GetResourceZipHandle(); else hz = OpenZip((void*)sFile.GetData(), 0, 2); if( hz == NULL ) break; ZIPENTRY ze; int i; if( FindZipItem(hz, pstrGifPath, true, &i, &ze) != 0 ) break; dwSize = ze.unc_size; if( dwSize == 0 ) break; pData = new BYTE[ dwSize ]; int res = UnzipItem(hz, i, pData, dwSize, 3); if( res != 0x00000000 && res != 0x00000600) { delete[] pData; pData = NULL; if( !CPaintManagerUI::IsCachedResourceZip() ) CloseZip(hz); break; } if( !CPaintManagerUI::IsCachedResourceZip() ) CloseZip(hz); } } while (0); while (!pData) { //读不到图片, 则直接去读取bitmap.m_lpstr指向的路径 HANDLE hFile = ::CreateFile(pstrGifPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, \ FILE_ATTRIBUTE_NORMAL, NULL); if( hFile == INVALID_HANDLE_VALUE ) break; dwSize = ::GetFileSize(hFile, NULL); if( dwSize == 0 ) break; DWORD dwRead = 0; pData = new BYTE[ dwSize ]; ::ReadFile( hFile, pData, dwSize, &dwRead, NULL ); ::CloseHandle( hFile ); if( dwRead != dwSize ) { delete[] pData; pData = NULL; } break; } if (!pData) { return NULL; } return LoadGifFromMemory(pData, dwSize); } Gdiplus::Image* CGifAnimUI::LoadGifFromMemory( LPVOID pBuf,size_t dwSize ) { HGLOBAL hMem = ::GlobalAlloc(GMEM_FIXED, dwSize); BYTE* pMem = (BYTE*)::GlobalLock(hMem); memcpy(pMem, pBuf, dwSize); IStream* pStm = NULL; ::CreateStreamOnHGlobal(hMem, TRUE, &pStm); Gdiplus::Image *pImg = Gdiplus::Image::FromStream(pStm); if(!pImg || pImg->GetLastStatus() != Gdiplus::Ok) { pStm->Release(); ::GlobalUnlock(hMem); return 0; } return pImg; } }
总结:
Gif控件已经同步更新到我的duilib库里:点击打开链接
Redrain 2015.1.7