• 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

  • 相关阅读:
    quora 中有关angular与emberjs的精彩辩论
    迷你MVVM框架 avalonjs 0.94发布
    重写自己,减少判断 ---- 引发的思考
    JSON数据的优化
    记录全局错误
    Bat相关的项目应用
    C#中如何实现json转化时只处理部分属性
    JSON数据的处理中的特殊字符
    C# .net中json字符串和对象之间的转化方法
    VS调试 ---- 监视窗口、即时窗口、输出窗口
  • 原文地址:https://www.cnblogs.com/redrainblog/p/4275829.html
Copyright © 2020-2023  润新知