mirror of
https://github.com/duilib/duilib.git
synced 2026-10-17 06:01:08 +08:00
378 lines
9.2 KiB
C++
378 lines
9.2 KiB
C++
#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;
|
|
m_pStream = NULL;
|
|
}
|
|
|
|
|
|
CGifAnimUI::~CGifAnimUI(void)
|
|
{
|
|
DeleteGif();
|
|
m_pManager->KillTimer( this, EVENT_TIEM_ID );
|
|
|
|
}
|
|
|
|
LPCTSTR CGifAnimUI::GetClass() const
|
|
{
|
|
return DUI_CTR_GIFANIM;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
bool CGifAnimUI::DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl)
|
|
{
|
|
if ( NULL == m_pGifImage )
|
|
{
|
|
InitGifImage();
|
|
}
|
|
DrawFrame( hDC );
|
|
return true;
|
|
}
|
|
|
|
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 && nSize > 0)
|
|
{
|
|
PlayGif();
|
|
}
|
|
}
|
|
|
|
void CGifAnimUI::DeleteGif()
|
|
{
|
|
if (m_pStream != NULL )
|
|
{
|
|
m_pStream->Release();
|
|
m_pStream = NULL;
|
|
}
|
|
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 )
|
|
{
|
|
::CloseHandle(hFile);
|
|
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 )
|
|
{
|
|
::CloseHandle(hFile);
|
|
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;
|
|
}
|
|
|
|
Gdiplus::Image* pImage = LoadGifFromMemory(pData, dwSize);
|
|
delete[] pData;
|
|
return pImage;
|
|
}
|
|
|
|
Gdiplus::Image* CGifAnimUI::LoadGifFromMemory( LPVOID pBuf,size_t dwSize )
|
|
{
|
|
HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE, dwSize);
|
|
BYTE* pMem = (BYTE*)::GlobalLock(hMem);
|
|
|
|
memcpy(pMem, pBuf, dwSize);
|
|
::GlobalUnlock(hMem);
|
|
|
|
::CreateStreamOnHGlobal(hMem, TRUE, &m_pStream);
|
|
Gdiplus::Image *pImg = Gdiplus::Image::FromStream(m_pStream);
|
|
if(!pImg || pImg->GetLastStatus() != Gdiplus::Ok)
|
|
{
|
|
m_pStream->Release();
|
|
m_pStream = NULL;
|
|
return 0;
|
|
}
|
|
return pImg;
|
|
}
|
|
|
|
}
|