vc应用CPictureEx类(重载CStatic类)加载gif动画
1.PictureEx.h文件:
//
// PictureEx.cpp: implementation of the CPictureEx class.
//
// Picture displaying control with support for the following formats:
// GIF (including animated GIF87a and GIF89a), JPEG, BMP, WMF, ICO, CUR
//
// Written by Oleg Bykov (oleg_bykoff@rsdn.ru)
// Copyright (c) 2001
//
// To use CPictureEx, follow these steps:
//?? - place a static control on your dialog (either a text or a bitmap)
//?? - change its identifier to something else (e.g. IDC_MYPIC)
//?? - associate a CStatic with it using ClassWizard
//?? - in your dialog's header file replace CStatic with CPictureEx
//???? (don't forget to #include "PictureEx.h" and add
//???? PictureEx.h and PictureEx.cpp to your project)
//?? - call one of the overloaded CPictureEx::Load() functions somewhere
//???? (OnInitDialog is a good place to start)
//?? - if the preceding Load() succeeded call Draw()
//?
// You can also add the control by defining a member variable of type
// CPictureEx, calling CPictureEx::Create (derived from CStatic), then
// CPictureEx::Load and CPictureEx::Draw.
//
// By default, the control initializes its background to COLOR_3DFACE
// (see CPictureEx::PrepareDC()). You can change the background by
// calling CPictureEx::SetBkColor(COLORREF) after CPictureEx::Load().
//
// I decided to leave in the class the functions to write separate frames from
// animated GIF to disk. If you want to use them, uncomment #define GIF_TRACING
// and an appropriate section in CPictureEx::Load(HGLOBAL, DWORD). These functions
// won't be compiled and linked to your project unless you uncomment #define GIF_TRACING,
// so you don't have to worry.
//
// Warning: this code hasn't been subject to a heavy testing, so
// use it on your own risk. The author accepts no liability for the
// possible damage caused by this code.
//
// Version 1.0? 7 Aug 2001
//????????????? Initial release
//
// Version 1.1? 6 Sept 2001
//????????????? ATL version of the class
//
// Version 1.2? 14 Oct 2001
//????????????? - Fixed a problem with loading GIFs from resources
//??????????????? in MFC-version of the class for multi-modules apps.
//??????????????? Thanks to Ruben Avila-Carretero for finding this out.
//
//????????????? - Got rid of waitable timer in ThreadAnimation()
//??????????????? Now CPictureEx[Wnd] works in Win95 too.
//??????????????? Thanks to Alex Egiazarov and Wayne King for the idea.
//
//????????????? - Fixed a visual glitch of using SetBkColor.
//??????????????? Thanks to Kwangjin Lee for finding this out.
//
// Version 1.3? 10 Nov 2001
//????????????? - Fixed a DC leak. One DC leaked per each UnLoad()
//??????????????? (forgot to put a ReleaseDC() in the end of
//??????????????? CPictureExWnd::PrepareDC() function).
//
//????????????? - Now it is possible to set a clipping rectangle using
//??????????????? CPictureEx[Wnd]::SetPaintRect(const LPRECT) function.
//??????????????? The LPRECT parameter tells the class what portion of
//??????????????? a picture should it display. If the clipping rect is
//??????????????? not set, the whole picture is shown.
//??????????????? Thanks to Fabrice Rodriguez for the idea.
//
//????????????? - Added support for Stop/Draw. Now you can Stop() an
//??????????????? animated GIF, then Draw() it again, it will continue
//??????????????? animation from the frame it was stopped on. You can
//??????????????? also know if a GIF is currently playing with the
//??????????????? IsPlaying() function.
//????????????
//????????????? - Got rid of math.h and made m_bExitThread volatile.
//??????????????? Thanks to Piotr Sawicki for the suggestion.
//
//
#if !defined(AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_)
#define AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <vector>
//#define GIF_TRACING? // uncomment it if you want detailed TRACEs
class CPictureEx : public CStatic
{
public:
struct TFrame??? // structure that keeps a single frame info
{
?IPicture *m_pPicture;? // pointer to the interface used for drawing
?SIZE???? m_frameSize;
?SIZE???? m_frameOffset;
?UINT???? m_nDelay;???? // delay (in 1/100s of a second)
?UINT???? m_nDisposal;? // disposal method
};
#pragma pack(1)?? // turn byte alignment on
enum GIFBlockTypes
{
?BLOCK_UNKNOWN,
?BLOCK_APPEXT,
?BLOCK_COMMEXT,
?BLOCK_CONTROLEXT,
?BLOCK_PLAINTEXT,
?BLOCK_IMAGE,
?BLOCK_TRAILER
};
enum ControlExtValues // graphic control extension packed field values
{
?GCX_PACKED_DISPOSAL,? // disposal method
?GCX_PACKED_USERINPUT,
?GCX_PACKED_TRANSPCOLOR
};
enum LSDPackedValues? // logical screen descriptor packed field values
{
?LSD_PACKED_GLOBALCT,
?LSD_PACKED_CRESOLUTION,
?LSD_PACKED_SORT,
?LSD_PACKED_GLOBALCTSIZE
};
enum IDPackedValues?? // image descriptor packed field values
{
?ID_PACKED_LOCALCT,
?ID_PACKED_INTERLACE,
?ID_PACKED_SORT,
?ID_PACKED_LOCALCTSIZE
};
struct TGIFHeader?????? // GIF header?
{
?char m_cSignature[3]; // Signature - Identifies the GIF Data Stream
??????? // This field contains the fixed value 'GIF'
?char m_cVersion[3];?// Version number. May be one of the following:
??????// "87a" or "89a"
};
struct TGIFLSDescriptor // Logical Screen Descriptor
{
?WORD m_wWidth;?// 2 bytes. Logical screen width
?WORD m_wHeight; // 2 bytes. Logical screen height
?unsigned char m_cPacked;????? // packed field?
?unsigned char m_cBkIndex;???? // 1 byte. Background color index
?unsigned char m_cPixelAspect; // 1 byte. Pixel aspect ratio
?inline int GetPackedValue(enum LSDPackedValues Value);
};
struct TGIFAppExtension // application extension block
{
?unsigned char m_cExtIntroducer; // extension introducer (0x21)
?unsigned char m_cExtLabel; // app. extension label (0xFF)
?unsigned char m_cBlockSize; // fixed value of 11
?char m_cAppIdentifier[8];?? // application identifier
?char m_cAppAuth[3];? // application authentication code
};
struct TGIFControlExt // graphic control extension block
{
?unsigned char m_cExtIntroducer; // extension introducer (0x21)
?unsigned char m_cControlLabel;? // control extension label (0xF9)
?unsigned char m_cBlockSize; // fixed value of 4
?unsigned char m_cPacked;??? // packed field
?WORD m_wDelayTime;?// delay time
?unsigned char m_cTColorIndex; // transparent color index
?unsigned char m_cBlockTerm;?? // block terminator (0x00)
public:
?inline int GetPackedValue(enum ControlExtValues Value);
};
struct TGIFCommentExt? // comment extension block
{
?unsigned char m_cExtIntroducer; // extension introducer (0x21)
?unsigned char m_cCommentLabel;? // comment extension label (0xFE)
};
struct TGIFPlainTextExt // plain text extension block
{
?unsigned char m_cExtIntroducer;? // extension introducer (0x21)
?unsigned char m_cPlainTextLabel; // text extension label (0x01)
?unsigned char m_cBlockSize; // fixed value of 12
?WORD m_wLeftPos;??? // text grid left position
?WORD m_wTopPos;???? // text grid top position
?WORD m_wGridWidth;? // text grid width
?WORD m_wGridHeight; // text grid height
?unsigned char m_cCellWidth;? // character cell width
?unsigned char m_cCellHeight; // character cell height
?unsigned char m_cFgColor; // text foreground color index
?unsigned char m_cBkColor; // text background color index
};
struct TGIFImageDescriptor // image descriptor block
{
?unsigned char m_cImageSeparator; // image separator byte (0x2C)
?WORD m_wLeftPos; // image left position
?WORD m_wTopPos;? // image top position
?WORD m_wWidth;?? // image width
?WORD m_wHeight;? // image height
?unsigned char m_cPacked; // packed field
?inline int GetPackedValue(enum IDPackedValues Value);
};
#pragma pack() // turn byte alignment off
public:
?BOOL GetPaintRect(RECT *lpRect);
?BOOL SetPaintRect(const RECT *lpRect);
?CPictureEx();
?virtual ~CPictureEx();
?void Stop();?? // stops animation
?void UnLoad(); // stops animation plus releases all resources
?BOOL IsGIF() const;
?BOOL IsPlaying() const;
?BOOL IsAnimatedGIF() const;
?SIZE GetSize() const;
?int GetFrameCount() const;
?COLORREF GetBkColor() const;
?void SetBkColor(COLORREF clr);
?// draws the picture (starts an animation thread if needed)
?// if an animation was previously stopped by Stop(),
?// continues it from the last displayed frame
?BOOL Draw();
?// loads a picture from a file
?// i.e. Load(_T("mypic.gif"));
?BOOL Load(LPCTSTR szFileName);
?// loads a picture from a global memory block (allocated by GlobalAlloc)
?// Warning: this function DOES NOT free the global memory, pointed to by hGlobal
?BOOL Load(HGLOBAL hGlobal, DWORD dwSize);
?// loads a picture from a program resource
?// i.e. Load(IDR_MYPIC,_T("GIFTYPE"));
?BOOL Load(UINT nResourceID , LPCTSTR szResourceType);
protected:
#ifdef GIF_TRACING
?void EnumGIFBlocks();
?void WriteDataOnDisk(CString szFileName, HGLOBAL hData, DWORD dwSize);
#endif // GIF_TRACING
?RECT m_PaintRect;
?SIZE m_PictureSize;
?COLORREF m_clrBackground;
?UINT m_nCurrFrame;
?UINT m_nDataSize;
?UINT m_nCurrOffset;
?UINT m_nGlobalCTSize;
?BOOL m_bIsGIF;
?BOOL m_bIsPlaying;
?volatile BOOL m_bExitThread;
?BOOL m_bIsInitialized;
?HDC m_hMemDC;
?HDC m_hDispMemDC;
?HBITMAP m_hDispMemBM;
?HBITMAP m_hDispOldBM;
?HBITMAP m_hBitmap;
?HBITMAP m_hOldBitmap;
?HANDLE m_hThread;
?HANDLE m_hExitEvent;
?IPicture * m_pPicture;
?TGIFHeader * m_pGIFHeader;
?unsigned char * m_pRawData;
?TGIFLSDescriptor * m_pGIFLSDescriptor;
?std::vector<TFrame> m_arrFrames;
?void ThreadAnimation();
?static UINT WINAPI _ThreadAnimation(LPVOID pParam);
?int GetNextBlockLen() const;
?BOOL SkipNextBlock();
?BOOL SkipNextGraphicBlock();
?BOOL PrepareDC(int nWidth, int nHeight);
?void ResetDataPointer();
?enum GIFBlockTypes GetNextBlock() const;
?UINT GetSubBlocksLen(UINT nStartingOffset) const;
?HGLOBAL GetNextGraphicBlock(UINT *pBlockLen, UINT *pDelay,
??SIZE *pBlockSize, SIZE *pBlockOffset, UINT *pDisposal);
?// Generated message map functions
?//{{AFX_MSG(CPictureEx)
?afx_msg void OnDestroy();
?afx_msg void OnPaint();
?//}}AFX_MSG
?
?DECLARE_MESSAGE_MAP()
};
#endif // !defined(AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_)
?
2.PictureEx.cpp文件:
//
// PictureEx.cpp: implementation of the CPictureEx class.
//
// Picture displaying control with support for the following formats:
// GIF (including animated GIF87a and GIF89a), JPEG, BMP, WMF, ICO, CUR
//
// Written by Oleg Bykov (oleg_bykoff@rsdn.ru)
// Copyright (c) 2001
//
// To use CPictureEx, follow these steps:
//?? - place a static control on your dialog (either a text or a bitmap)
//?? - change its identifier to something else (e.g. IDC_MYPIC)
//?? - associate a CStatic with it using ClassWizard
//?? - in your dialog's header file replace CStatic with CPictureEx
//???? (don't forget to #include "PictureEx.h" and add
//???? PictureEx.h and PictureEx.cpp to your project)
//?? - call one of the overloaded CPictureEx::Load() functions somewhere
//???? (OnInitDialog is a good place to start)
//?? - if the preceding Load() succeeded call Draw()
//?
// You can also add the control by defining a member variable of type
// CPictureEx, calling CPictureEx::Create (derived from CStatic), then
// CPictureEx::Load and CPictureEx::Draw.
//
// By default, the control initializes its background to COLOR_3DFACE
// (see CPictureEx::PrepareDC()). You can change the background by
// calling CPictureEx::SetBkColor(COLORREF) after CPictureEx::Load().
//
// I decided to leave in the class the functions to write separate frames from
// animated GIF to disk. If you want to use them, uncomment #define GIF_TRACING
// and an appropriate section in CPictureEx::Load(HGLOBAL, DWORD). These functions
// won't be compiled and linked to your project unless you uncomment #define GIF_TRACING,
// so you don't have to worry.
//
// Warning: this code hasn't been subject to a heavy testing, so
// use it on your own risk. The author accepts no liability for the
// possible damage caused by this code.
//
// Version 1.0? 7 Aug 2001
//????????????? Initial release
//
// Version 1.1? 6 Sept 2001
//????????????? ATL version of the class
//
// Version 1.2? 14 Oct 2001
//????????????? - Fixed a problem with loading GIFs from resources
//??????????????? in MFC-version of the class for multi-modules apps.
//??????????????? Thanks to Ruben Avila-Carretero for finding this out.
//
//????????????? - Got rid of waitable timer in ThreadAnimation()
//??????????????? Now CPictureEx[Wnd] works in Win95 too.
//??????????????? Thanks to Alex Egiazarov and Wayne King for the idea.
//
//????????????? - Fixed a visual glitch of using SetBkColor.
//??????????????? Thanks to Kwangjin Lee for finding this out.
//
// Version 1.3? 10 Nov 2001
//????????????? - Fixed a DC leak. One DC leaked per each UnLoad()
//??????????????? (forgot to put a ReleaseDC() in the end of
//??????????????? CPictureExWnd::PrepareDC() function).
//
//????????????? - Now it is possible to set a clipping rectangle using
//??????????????? CPictureEx[Wnd]::SetPaintRect(const LPRECT) function.
//??????????????? The LPRECT parameter tells the class what portion of
//??????????????? a picture should it display. If the clipping rect is
//??????????????? not set, the whole picture is shown.
//??????????????? Thanks to Fabrice Rodriguez for the idea.
//
//????????????? - Added support for Stop/Draw. Now you can Stop() an
//??????????????? animated GIF, then Draw() it again, it will continue
//??????????????? animation from the frame it was stopped on. You can
//??????????????? also know if a GIF is currently playing with the
//??????????????? IsPlaying() function.
//????????????
//????????????? - Got rid of math.h and made m_bExitThread volatile.
//??????????????? Thanks to Piotr Sawicki for the suggestion.
//
//
#include "stdafx.h"
#include "PictureEx.h"
#include <process.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//
// Nested structures member functions
//
inline int CPictureEx::TGIFControlExt::GetPackedValue(enum ControlExtValues Value)
{
?int nRet = (int)m_cPacked;
?switch (Value)
?{
?case GCX_PACKED_DISPOSAL:
??nRet = (nRet & 28) >> 2;
??break;
?case GCX_PACKED_USERINPUT:
??nRet = (nRet & 2) >> 1;
??break;
?case GCX_PACKED_TRANSPCOLOR:
??nRet &= 1;
??break;
?};
?return nRet;
}
inline int CPictureEx::TGIFLSDescriptor::GetPackedValue(enum LSDPackedValues Value)
{
?int nRet = (int)m_cPacked;
?switch (Value)
?{
?case LSD_PACKED_GLOBALCT:
??nRet = nRet >> 7;
??break;
?case LSD_PACKED_CRESOLUTION:
??nRet = ((nRet & 0x70) >> 4) + 1;
??break;
?case LSD_PACKED_SORT:
??nRet = (nRet & 8) >> 3;
??break;
?case LSD_PACKED_GLOBALCTSIZE:
??nRet &= 7;
??break;
?};
?return nRet;
}
inline int CPictureEx::TGIFImageDescriptor::GetPackedValue(enum IDPackedValues Value)
{
?int nRet = (int)m_cPacked;
?switch (Value)
?{
?case ID_PACKED_LOCALCT:
??nRet >>= 7;
??break;
?case ID_PACKED_INTERLACE:
??nRet = ((nRet & 0x40) >> 6);
??break;
?case ID_PACKED_SORT:
??nRet = (nRet & 0x20) >> 5;
??break;
?case ID_PACKED_LOCALCTSIZE:
??nRet &= 7;
??break;
?};
?return nRet;
}
//
// Construction/Destruction
//
CPictureEx::CPictureEx()
{
?// check structures size
?ASSERT(sizeof(TGIFImageDescriptor) == 10);
?ASSERT(sizeof(TGIFAppExtension)??? == 14);
?ASSERT(sizeof(TGIFPlainTextExt)??? == 15);
?ASSERT(sizeof(TGIFLSDescriptor)??? ==? 7);
?ASSERT(sizeof(TGIFControlExt)??? ==? 8);
?ASSERT(sizeof(TGIFCommentExt)??? ==? 2);
?ASSERT(sizeof(TGIFHeader)???? ==? 6);
?m_pGIFLSDescriptor = NULL;
?m_pGIFHeader??? = NULL;
?m_pPicture???? = NULL;
?m_pRawData???? = NULL;
?m_hThread???? = NULL;
?m_hBitmap????????? = NULL;
?m_hMemDC???? = NULL;
?m_hDispMemDC?????? = NULL;
?m_hDispMemBM?????? = NULL;
?m_hDispOldBM?????? = NULL;
?m_bIsInitialized?? = FALSE;
?m_bExitThread??? = FALSE;
?m_bIsPlaying?????? = FALSE;
?m_bIsGIF???? = FALSE;
?m_clrBackground??? = RGB(255,255,255); // white by default
?m_nGlobalCTSize??? = 0;
?m_nCurrOffset??? = 0;
?m_nCurrFrame??? = 0;
?m_nDataSize???? = 0;
?m_PictureSize.cx = m_PictureSize.cy = 0;
?SetRect(&m_PaintRect,0,0,0,0);
?m_hExitEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
}
CPictureEx::~CPictureEx()
{
?UnLoad();
?CloseHandle(m_hExitEvent);
}
BEGIN_MESSAGE_MAP(CPictureEx, CStatic)
?//{{AFX_MSG_MAP(CPictureEx)
?ON_WM_DESTROY()
?ON_WM_PAINT()
?//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CPictureEx::Load(HGLOBAL hGlobal, DWORD dwSize)
{
?IStream *pStream = NULL;
?UnLoad();
?if (!(m_pRawData = reinterpret_cast<unsigned char*> (GlobalLock(hGlobal))) )
?{
??TRACE(_T("Load: Error locking memory\n"));
??return FALSE;
?};
?m_nDataSize = dwSize;
?m_pGIFHeader = reinterpret_cast<TGIFHeader *> (m_pRawData);
?if ((memcmp(&m_pGIFHeader->m_cSignature,"GIF",3) != 0) &&
??((memcmp(&m_pGIFHeader->m_cVersion,"87a",3) != 0) ||
?? (memcmp(&m_pGIFHeader->m_cVersion,"89a",3) != 0)) )
?{
?// it's neither GIF87a nor GIF89a
?// do the default processing
??// clear GIF variables
??m_pRawData = NULL;
??GlobalUnlock(hGlobal);
??// don't delete memory on object's release
??if (CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK)
???return FALSE;
??if (OleLoadPicture(pStream,dwSize,FALSE,IID_IPicture,
???reinterpret_cast<LPVOID *>(&m_pPicture)) != S_OK)
??{
???pStream->Release();
???return FALSE;
??};
??pStream->Release();
??// store picture's size
??long hmWidth;
??long hmHeight;
??m_pPicture->get_Width(&hmWidth);
??m_pPicture->get_Height(&hmHeight);
??HDC hDC = ::GetDC(m_hWnd);
??m_PictureSize.cx = MulDiv(hmWidth, GetDeviceCaps(hDC,LOGPIXELSX), 2540);
??m_PictureSize.cy = MulDiv(hmHeight, GetDeviceCaps(hDC,LOGPIXELSY), 2540);
??::ReleaseDC(m_hWnd,hDC);
?}
?else
?{
??// it's a GIF
??m_bIsGIF = TRUE;
??m_pGIFLSDescriptor = reinterpret_cast<TGIFLSDescriptor *>
???(m_pRawData + sizeof(TGIFHeader));
??if (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT) == 1)
??{
???// calculate the globat color table size
???m_nGlobalCTSize = static_cast<int>
????(3* (1 << (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE)+1)));
???// get the background color if GCT is present
???unsigned char *pBkClr = m_pRawData + sizeof(TGIFHeader) +
????sizeof(TGIFLSDescriptor) + 3*m_pGIFLSDescriptor->m_cBkIndex;
???m_clrBackground = RGB(pBkClr[0],pBkClr[1],pBkClr[2]);
??};
??// store the picture's size
??m_PictureSize.cx = m_pGIFLSDescriptor->m_wWidth;
??m_PictureSize.cy = m_pGIFLSDescriptor->m_wHeight;
??// determine frame count for this picture
??UINT nFrameCount=0;
??ResetDataPointer();
??while (SkipNextGraphicBlock())
???nFrameCount++;
#ifdef GIF_TRACING
??TRACE(
???_T(" -= GIF encountered\n"
????? "Logical Screen dimensions = %dx%d\n"
????? "Global color table = %d\n"
????? "Color depth = %d\n"
????? "Sort flag = %d\n"
????? "Size of Global Color Table = %d\n"
????? "Background color index = %d\n"
????? "Pixel aspect ratio = %d\n"
????? "Frame count = %d\n"
????? "Background color = %06Xh\n\n"
???? ),
???m_pGIFLSDescriptor->m_wWidth,
???m_pGIFLSDescriptor->m_wHeight,
???m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT),
???m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_CRESOLUTION),
???m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_SORT),
???m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE),
???m_pGIFLSDescriptor->m_cBkIndex,
???m_pGIFLSDescriptor->m_cPixelAspect,
???nFrameCount,
???m_clrBackground
???);
??EnumGIFBlocks();
#endif
??if (nFrameCount == 0) // it's an empty GIF!
??{
???m_pRawData = NULL;
???GlobalUnlock(hGlobal);
???return FALSE;
??};
??// now check the frame count
??// if there's only one frame, no need to animate this GIF
??// therefore, treat it like any other pic
??if (nFrameCount == 1)
??{
???// clear GIF variables
???m_pRawData = NULL;
???GlobalUnlock(hGlobal);
???// don't delete memory on object's release
???if (CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK)
????return FALSE;
???if (OleLoadPicture(pStream,dwSize,FALSE,IID_IPicture,
????(LPVOID *)&m_pPicture) != S_OK)
???{
????pStream->Release();
????return FALSE;
???};
???pStream->Release();
??}
??else
??{
??// if, on the contrary, there are several frames
??// then store separate frames in an array
???TFrame frame;
???UINT nBlockLen;
???HGLOBAL hFrameData;
???UINT nCurFrame = 0;
???ResetDataPointer();
???while (hFrameData = GetNextGraphicBlock(&nBlockLen,
????&frame.m_nDelay, &frame.m_frameSize,
????&frame.m_frameOffset, &frame.m_nDisposal) )
???{
????#ifdef GIF_TRACING
????//
????// uncomment the following strings if you want
????// to write separate frames on disk
????//
????//?CString szName;
????//?szName.Format(_T("%.4d.gif"),nCurFrame);
????//?WriteDataOnDisk(szName,hFrameData,nBlockLen);
????//?nCurFrame++;
????#endif // GIF_TRACING
????IStream *pStream = NULL;
????// delete memory on object's release
????if (CreateStreamOnHGlobal(hFrameData,TRUE,&pStream) != S_OK)
????{
?????GlobalFree(hFrameData);
?????continue;
????};
????if (OleLoadPicture(pStream,nBlockLen,FALSE,
?????IID_IPicture,
?????reinterpret_cast<LPVOID *>(&frame.m_pPicture)) != S_OK)
????{
?????pStream->Release();
?????continue;
????};
????pStream->Release();
???
????// everything went well, add this frame
????m_arrFrames.push_back(frame);
???};
???// clean after ourselves
???m_pRawData = NULL;
???GlobalUnlock(hGlobal);
???if (m_arrFrames.empty()) // couldn't load any frames
????return FALSE;
??};
?}; // if (!IsGIF...
?return PrepareDC(m_PictureSize.cx,m_PictureSize.cy);
}
void CPictureEx::UnLoad()
{
?Stop();
?if (m_pPicture)
?{
??m_pPicture->Release();
??m_pPicture = NULL;
?};
?
?std::vector<TFrame>::iterator it;
?for (it=m_arrFrames.begin();it<m_arrFrames.end();it++)
??(*it).m_pPicture->Release();
?m_arrFrames.clear();
?if (m_hMemDC)
?{
??SelectObject(m_hMemDC,m_hOldBitmap);
??::DeleteDC(m_hMemDC);
??::DeleteObject(m_hBitmap);
??m_hMemDC? = NULL;
??m_hBitmap = NULL;
?};
?if (m_hDispMemDC)
?{
??SelectObject(m_hDispMemDC,m_hDispOldBM);
??::DeleteDC(m_hDispMemDC);
??::DeleteObject(m_hDispMemBM);
??m_hDispMemDC? = NULL;
??m_hDispMemBM = NULL;
?};
?SetRect(&m_PaintRect,0,0,0,0);
?m_pGIFLSDescriptor = NULL;
?m_pGIFHeader??? = NULL;
?m_pRawData???? = NULL;
?m_hThread???? = NULL;
?m_bIsInitialized?? = FALSE;
?m_bExitThread??? = FALSE;
?m_bIsGIF???? = FALSE;
?m_clrBackground??? = RGB(255,255,255); // white by default
?m_nGlobalCTSize??? = 0;
?m_nCurrOffset??? = 0;
?m_nCurrFrame??? = 0;
?m_nDataSize???? = 0;
}
BOOL CPictureEx::Draw()
{
?if (!m_bIsInitialized)
?{
??TRACE(_T("Call one of the CPictureEx::Load() member functions before calling Draw()\n"));
??return FALSE;
?};
?if (IsAnimatedGIF())
?{
?// the picture needs animation
?// we'll start the thread that will handle it for us
?
??unsigned int nDummy;
??m_hThread = (HANDLE) _beginthreadex(NULL,0,_ThreadAnimation,this,
???CREATE_SUSPENDED,&nDummy);
??if (!m_hThread)
??{
???TRACE(_T("Draw: Couldn't start a GIF animation thread\n"));
???return FALSE;
??}
??else
???ResumeThread(m_hThread);
?}
?else
?{
??if (m_pPicture)
??{
???long hmWidth;
???long hmHeight;
???m_pPicture->get_Width(&hmWidth);
???m_pPicture->get_Height(&hmHeight);
???if (m_pPicture->Render(m_hMemDC, 0, 0, m_PictureSize.cx, m_PictureSize.cy,
????0, hmHeight, hmWidth, -hmHeight, NULL) == S_OK)
???{
????Invalidate(FALSE);
????return TRUE;
???};
??};
?};
?return FALSE;?
}
SIZE CPictureEx::GetSize() const
{
?return m_PictureSize;
}
BOOL CPictureEx::Load(LPCTSTR szFileName)
{
?ASSERT(szFileName);
?
?CFile file;
?HGLOBAL hGlobal;
?DWORD dwSize;
?if (!file.Open(szFileName,
????CFile::modeRead |
????CFile::shareDenyWrite) )
?{
??TRACE(_T("Load (file): Error opening file %s\n"),szFileName);
??return FALSE;
?};
?dwSize = file.GetLength();
?hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD,dwSize);
?if (!hGlobal)
?{
??TRACE(_T("Load (file): Error allocating memory\n"));
??return FALSE;
?};
?
?char *pData = reinterpret_cast<char*>(GlobalLock(hGlobal));
?if (!pData)
?{
??TRACE(_T("Load (file): Error locking memory\n"));
??GlobalFree(hGlobal);
??return FALSE;
?};
?TRY
?{
??file.Read(pData,dwSize);
?}
?CATCH(CFileException, e);?????????????????????????????????????????
?{
??TRACE(_T("Load (file): An exception occured while reading the file %s\n"),
???szFileName);
??GlobalFree(hGlobal);
??e->Delete();
??file.Close();
??return FALSE;
?}
?END_CATCH
?GlobalUnlock(hGlobal);
?file.Close();
?BOOL bRetValue = Load(hGlobal,dwSize);
?GlobalFree(hGlobal);
?return bRetValue;
}
BOOL CPictureEx::Load(UINT nResourceID , LPCTSTR szResourceType)
{
?ASSERT(szResourceType);
?HINSTANCE hInst = AfxFindResourceHandle(MAKEINTRESOURCE(nResourceID),RT_GROUP_ICON) ;
?
?HRSRC hPicture = NULL ;
?FindResource(hInst,MAKEINTRESOURCE(nResourceID),szResourceType);
?HGLOBAL hResData;
?if (!hPicture || !(hResData = LoadResource(hInst,hPicture)))
?{
??return FALSE;
?};
?DWORD dwSize = SizeofResource(hInst,hPicture);
?// hResData is not the real HGLOBAL (we can't lock it)
?// let's make it real
?HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD,dwSize);
?if (!hGlobal)
?{
??TRACE(_T("Load (resource): Error allocating memory\n"));
??FreeResource(hResData);
??return FALSE;
?};
?
?char *pDest = reinterpret_cast<char *> (GlobalLock(hGlobal));
?char *pSrc = reinterpret_cast<char *> (LockResource(hResData));
?if (!pSrc || !pDest)
?{
??TRACE(_T("Load (resource): Error locking memory\n"));
??GlobalFree(hGlobal);
??FreeResource(hResData);
??return FALSE;
?};
?CopyMemory(pDest,pSrc,dwSize);
?FreeResource(hResData);
?GlobalUnlock(hGlobal);
?BOOL bRetValue = Load(hGlobal,dwSize);
?GlobalFree(hGlobal);
?return bRetValue;
}
void CPictureEx::ResetDataPointer()
{
?// skip header and logical screen descriptor
?m_nCurrOffset =
??sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize;
}
BOOL CPictureEx::SkipNextGraphicBlock()
{
?if (!m_pRawData) return FALSE;
?// GIF header + LSDescriptor [+ GCT] [+ Control block] + Data
?enum GIFBlockTypes nBlock;
?nBlock = GetNextBlock();
?while ((nBlock != BLOCK_CONTROLEXT) &&
???? (nBlock != BLOCK_IMAGE) &&
???? (nBlock != BLOCK_PLAINTEXT) &&
???? (nBlock != BLOCK_UNKNOWN) &&
???? (nBlock != BLOCK_TRAILER) )
?{
??if (!SkipNextBlock()) return NULL;
??nBlock = GetNextBlock();
?};
?if ((nBlock == BLOCK_UNKNOWN) ||
??(nBlock == BLOCK_TRAILER))
??return FALSE;
?// it's either a control ext.block, an image or a plain text
?if (GetNextBlockLen() <= 0) return FALSE;
?if (nBlock == BLOCK_CONTROLEXT)
?{
??if (!SkipNextBlock()) return FALSE;
??nBlock = GetNextBlock();
??// skip everything until we meet an image block or a plain-text block
??while ((nBlock != BLOCK_IMAGE) &&
????? (nBlock != BLOCK_PLAINTEXT) &&
????? (nBlock != BLOCK_UNKNOWN) &&
????? (nBlock != BLOCK_TRAILER) )
??{
???if (!SkipNextBlock()) return NULL;
???nBlock = GetNextBlock();
??};
??if ((nBlock == BLOCK_UNKNOWN) ||
???(nBlock == BLOCK_TRAILER))
???return FALSE;
?};
?// skip the found data block (image or plain-text)
?if (!SkipNextBlock()) return FALSE;
?return TRUE;
}
UINT CPictureEx::GetSubBlocksLen(UINT nStartingOffset) const
{
?UINT nRet = 0;
?UINT nCurOffset = nStartingOffset;
?while (m_pRawData[nCurOffset] != 0)
?{
??nRet += m_pRawData[nCurOffset]+1;
??nCurOffset += m_pRawData[nCurOffset]+1;
?};
?return nRet+1;
}
enum CPictureEx::GIFBlockTypes CPictureEx::GetNextBlock() const
{
?switch(m_pRawData[m_nCurrOffset])
?{
?case 0x21:
?// extension block
??switch(m_pRawData[m_nCurrOffset+1])
??{
??case 0x01:
??// plain text extension
???return BLOCK_PLAINTEXT;
???break;
??case 0xF9:
??// graphic control extension
???return BLOCK_CONTROLEXT;
???break;
??case 0xFE:
??// comment extension
???return BLOCK_COMMEXT;
???break;
??case 0xFF:
??// application extension
???return BLOCK_APPEXT;
???break;
??};
??break;
?
?case 0x3B:
?// trailer
??return BLOCK_TRAILER;
??break;
?case 0x2C:
?// image data
??return BLOCK_IMAGE;
??break;
?};
?return BLOCK_UNKNOWN;
}
BOOL CPictureEx::SkipNextBlock()
{
?if (!m_pRawData) return FALSE;
?int nLen = GetNextBlockLen();
?if ((nLen <= 0) || ((m_nCurrOffset+nLen) > m_nDataSize))
??return FALSE;
?m_nCurrOffset += nLen;
?return TRUE;
}
int CPictureEx::GetNextBlockLen() const
{
?GIFBlockTypes nBlock = GetNextBlock();
?int nTmp;
?switch(nBlock)
?{
?case BLOCK_UNKNOWN:
??return -1;
??break;
?case BLOCK_TRAILER:
??return 1;
??break;
?case BLOCK_APPEXT:
??nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFAppExtension));
??if (nTmp > 0)
???return sizeof(TGIFAppExtension)+nTmp;
??break;
?case BLOCK_COMMEXT:
??nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFCommentExt));
??if (nTmp > 0)
???return sizeof(TGIFCommentExt)+nTmp;
??break;
?case BLOCK_CONTROLEXT:
??return sizeof(TGIFControlExt);
??break;
?case BLOCK_PLAINTEXT:
??nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFPlainTextExt));
??if (nTmp > 0)
???return sizeof(TGIFPlainTextExt)+nTmp;
??break;
?case BLOCK_IMAGE:
??TGIFImageDescriptor *pIDescr =
???reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);
??int nLCTSize = (int)
???(pIDescr->GetPackedValue(ID_PACKED_LOCALCT)*3*
???(1 << (pIDescr->GetPackedValue(ID_PACKED_LOCALCTSIZE)+1)));
??int nTmp = GetSubBlocksLen(m_nCurrOffset+
???sizeof(TGIFImageDescriptor) + nLCTSize + 1);
??if (nTmp > 0)
???return sizeof(TGIFImageDescriptor) + nLCTSize + 1 + nTmp;
??break;
?};
?return 0;
}
UINT WINAPI CPictureEx::_ThreadAnimation(LPVOID pParam)
{
?ASSERT(pParam);
?CPictureEx *pPic = reinterpret_cast<CPictureEx *> (pParam);
?pPic->m_bIsPlaying = TRUE;
?pPic->ThreadAnimation();
?pPic->m_bIsPlaying = FALSE;
?// this thread has finished its work so we close the handle
?CloseHandle(pPic->m_hThread);
?// and init the handle to zero (so that Stop() doesn't Wait on it)
?pPic->m_hThread = 0;
?return 0;
}
void CPictureEx::ThreadAnimation()
{
?// first, restore background (for stop/draw support)
?// disposal method #2
?if (m_arrFrames[m_nCurrFrame].m_nDisposal == 2)
?{
??HBRUSH hBrush = CreateSolidBrush(m_clrBackground);
??if (hBrush)
??{
???RECT rect = {
????m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
????m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
????m_arrFrames[m_nCurrFrame].m_frameOffset.cx + m_arrFrames[m_nCurrFrame].m_frameSize.cx,
????m_arrFrames[m_nCurrFrame].m_frameOffset.cy + m_arrFrames[m_nCurrFrame].m_frameSize.cy };
???FillRect(m_hMemDC,&rect,hBrush);
???DeleteObject(hBrush);
??};
?}
?else
??// disposal method #3
??if (m_hDispMemDC && (m_arrFrames[m_nCurrFrame].m_nDisposal == 3) )
??{
???// put it back
???BitBlt(m_hMemDC,
????m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
????m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
????m_arrFrames[m_nCurrFrame].m_frameSize.cx,
????m_arrFrames[m_nCurrFrame].m_frameSize.cy,
????m_hDispMemDC,0,0, SRCCOPY);
???// init variables
???SelectObject(m_hDispMemDC,m_hDispOldBM);
???DeleteDC(m_hDispMemDC); m_hDispMemDC = NULL;
???DeleteObject(m_hDispMemBM); m_hDispMemBM = NULL;
??};
?while (!m_bExitThread)
?{
??if (m_arrFrames[m_nCurrFrame].m_pPicture)
??{
??///
??// Before rendering a frame we should take care of what's
??// behind that frame. TFrame::m_nDisposal will be our guide:
??//?? 0 - no disposal specified (do nothing)
??//?? 1 - do not dispose (again, do nothing)
??//?? 2 - restore to background color (m_clrBackground)
??//?? 3 - restore to previous
??? disposal method #3
???if (m_arrFrames[m_nCurrFrame].m_nDisposal == 3)
???{
????// prepare a memory DC and store the background in it
????m_hDispMemDC = CreateCompatibleDC(m_hMemDC);
????m_hDispMemBM = CreateCompatibleBitmap(m_hMemDC,
???????m_arrFrames[m_nCurrFrame].m_frameSize.cx,
???????m_arrFrames[m_nCurrFrame].m_frameSize.cy);
????
????if (m_hDispMemDC && m_hDispMemBM)
????{
?????m_hDispOldBM = reinterpret_cast<HBITMAP> (SelectObject(m_hDispMemDC,m_hDispMemBM));
?????BitBlt(m_hDispMemDC,0,0,
??????m_arrFrames[m_nCurrFrame].m_frameSize.cx,
??????m_arrFrames[m_nCurrFrame].m_frameSize.cy,
??????m_hMemDC,
??????m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
??????m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
??????SRCCOPY);
????};
???};
???///
???long hmWidth;
???long hmHeight;
???m_arrFrames[m_nCurrFrame].m_pPicture->get_Width(&hmWidth);
???m_arrFrames[m_nCurrFrame].m_pPicture->get_Height(&hmHeight);
???if (m_arrFrames[m_nCurrFrame].m_pPicture->Render(m_hMemDC,
????m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
????m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
????m_arrFrames[m_nCurrFrame].m_frameSize.cx,
????m_arrFrames[m_nCurrFrame].m_frameSize.cy,
????0, hmHeight, hmWidth, -hmHeight, NULL) == S_OK)
???{
????Invalidate(FALSE);
???};
???
???if (m_bExitThread) break;
???// if the delay time is too short (like in old GIFs), wait for 100ms
???if (m_arrFrames[m_nCurrFrame].m_nDelay < 5)
????WaitForSingleObject(m_hExitEvent, 100);
???else
????WaitForSingleObject(m_hExitEvent, 10*m_arrFrames[m_nCurrFrame].m_nDelay);
???if (m_bExitThread) break;
???// disposal method #2
???if (m_arrFrames[m_nCurrFrame].m_nDisposal == 2)
???{
????HBRUSH hBrush = CreateSolidBrush(m_clrBackground);
????if (hBrush)
????{
?????RECT rect = {
??????m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
??????m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
??????m_arrFrames[m_nCurrFrame].m_frameOffset.cx + m_arrFrames[m_nCurrFrame].m_frameSize.cx,
??????m_arrFrames[m_nCurrFrame].m_frameOffset.cy + m_arrFrames[m_nCurrFrame].m_frameSize.cy };
?????FillRect(m_hMemDC,&rect,hBrush);
?????DeleteObject(hBrush);
????};
???}
???else
????if (m_hDispMemDC && (m_arrFrames[m_nCurrFrame].m_nDisposal == 3) )
????{
?????// put it back
?????BitBlt(m_hMemDC,
??????m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
??????m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
??????m_arrFrames[m_nCurrFrame].m_frameSize.cx,
??????m_arrFrames[m_nCurrFrame].m_frameSize.cy,
??????m_hDispMemDC,0,0, SRCCOPY);
?????// init variables
?????SelectObject(m_hDispMemDC,m_hDispOldBM);
?????DeleteDC(m_hDispMemDC); m_hDispMemDC = NULL;
?????DeleteObject(m_hDispMemBM); m_hDispMemBM = NULL;
????};
??};
??m_nCurrFrame++;
??if (m_nCurrFrame == m_arrFrames.size())
??{
???m_nCurrFrame
????= 0;
??// init the screen for the first frame,
???HBRUSH hBrush = CreateSolidBrush(m_clrBackground);
???if (hBrush)
???{
????RECT rect = {0,0,m_PictureSize.cx,m_PictureSize.cy};
????FillRect(m_hMemDC,&rect,hBrush);
????DeleteObject(hBrush);
???};
??};
?};
}
void CPictureEx::Stop()
{
?m_bIsPlaying = FALSE;
?m_bExitThread = TRUE;
?SetEvent(m_hExitEvent);
?if (m_hThread)
?{
??// we'll wait for 5 seconds then continue execution
??WaitForSingleObject(m_hThread,5000);
??CloseHandle(m_hThread);
??m_hThread = NULL;
?}
?// make it possible to Draw() again
?ResetEvent(m_hExitEvent);
?m_bExitThread = FALSE;
}
HGLOBAL CPictureEx::GetNextGraphicBlock(UINT *pBlockLen,
?UINT *pDelay, SIZE *pBlockSize, SIZE *pBlockOffset,
?UINT *pDisposal)
{
?if (!m_pRawData) return NULL;
?// GIF header + LSDescriptor [+ GCT] [+ Control block] + Data
?*pDisposal = 0;
?enum GIFBlockTypes nBlock;
?nBlock = GetNextBlock();
?while (
??(nBlock != BLOCK_CONTROLEXT) &&
??(nBlock != BLOCK_IMAGE) &&
??(nBlock != BLOCK_PLAINTEXT) &&
??(nBlock != BLOCK_UNKNOWN) &&
??(nBlock != BLOCK_TRAILER)
??)
?{
??if (!SkipNextBlock()) return NULL;
??nBlock = GetNextBlock();
?};
?if ((nBlock == BLOCK_UNKNOWN) ||
??(nBlock == BLOCK_TRAILER))
??return NULL;
?// it's either a control ext.block, an image or a plain text
?int nStart = m_nCurrOffset;
?int nBlockLen = GetNextBlockLen();
?if (nBlockLen <= 0) return NULL;
?if (nBlock == BLOCK_CONTROLEXT)
?{
??// get the following data
??TGIFControlExt *pControl =
???reinterpret_cast<TGIFControlExt *> (&m_pRawData[m_nCurrOffset]);
??// store delay time
??*pDelay = pControl->m_wDelayTime;
??// store disposal method
??*pDisposal = pControl->GetPackedValue(GCX_PACKED_DISPOSAL);
??if (!SkipNextBlock()) return NULL;
??nBlock = GetNextBlock();
??
??// skip everything until we find data to display
??// (image block or plain-text block)
??
??while (
???(nBlock != BLOCK_IMAGE) &&
???(nBlock != BLOCK_PLAINTEXT) &&
???(nBlock != BLOCK_UNKNOWN) &&
???(nBlock != BLOCK_TRAILER)
???)
??{
???if (!SkipNextBlock()) return NULL;
???nBlock = GetNextBlock();
???nBlockLen += GetNextBlockLen();
??};
??if ((nBlock == BLOCK_UNKNOWN) || (nBlock == BLOCK_TRAILER))
???return NULL;
??nBlockLen += GetNextBlockLen();
?}
?else
??*pDelay = -1; // to indicate that there was no delay value
?if (nBlock == BLOCK_IMAGE)
?{
??// store size and offsets
??TGIFImageDescriptor *pImage =
???reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);
??pBlockSize->cx = pImage->m_wWidth;
??pBlockSize->cy = pImage->m_wHeight;
??pBlockOffset->cx = pImage->m_wLeftPos;
??pBlockOffset->cy = pImage->m_wTopPos;
?};
?if (!SkipNextBlock()) return NULL;
?HGLOBAL hGlobal = GlobalAlloc(GMEM_FIXED,
??sizeof(TGIFHeader) +
??sizeof(TGIFLSDescriptor) +
??m_nGlobalCTSize +
??nBlockLen +
??1);? // for the trailer
?if (!hGlobal) return NULL;
?int nOffset = 0;
?// GMEM_FIXED means we get a pointer
?unsigned char *pGlobal = reinterpret_cast<unsigned char *> (hGlobal);
?CopyMemory(pGlobal,m_pRawData,
??sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize);
?nOffset += sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize;
?CopyMemory(pGlobal + nOffset,&m_pRawData[nStart], nBlockLen);
?nOffset += nBlockLen;
?pGlobal[nOffset] = 0x3B; // trailer
?nOffset++;
?*pBlockLen = nOffset;
?return hGlobal;
}
BOOL CPictureEx::IsGIF() const
{
?return m_bIsGIF;
}
BOOL CPictureEx::IsAnimatedGIF() const
{
?return (m_bIsGIF && (m_arrFrames.size() > 1));
}
BOOL CPictureEx::IsPlaying() const
{
?return m_bIsPlaying;
}
int CPictureEx::GetFrameCount() const
{
?if (!IsAnimatedGIF())
??return 0;
?return m_arrFrames.size();
}
COLORREF CPictureEx::GetBkColor() const
{
?return m_clrBackground;
}
void CPictureEx::OnPaint()
{
?CPaintDC dc(this); // device context for painting
?LONG nPaintWidth = m_PaintRect.right-m_PaintRect.left;
?if (nPaintWidth > 0)
?{
??LONG nPaintHeight = m_PaintRect.bottom - m_PaintRect.top;
??::BitBlt(dc.m_hDC, 0, 0, nPaintWidth, nPaintHeight,?
???m_hMemDC, m_PaintRect.left, m_PaintRect.top, SRCCOPY);
?}
?else
?{
??::BitBlt(dc.m_hDC, 0, 0, m_PictureSize.cx, m_PictureSize.cy,
???m_hMemDC, 0, 0, SRCCOPY);
?};
}
BOOL CPictureEx::PrepareDC(int nWidth, int nHeight)
{
?SetWindowPos(NULL,0,0,nWidth,nHeight,SWP_NOMOVE | SWP_NOZORDER);
?HDC hWinDC = ::GetDC(m_hWnd);
?if (!hWinDC) return FALSE;
?
?m_hMemDC = CreateCompatibleDC(hWinDC);
?if (!m_hMemDC)
?{
??::ReleaseDC(m_hWnd,hWinDC);
??return FALSE;
?};
?m_hBitmap? = CreateCompatibleBitmap(hWinDC,nWidth,nHeight);
?if (!m_hBitmap)
?{
??::ReleaseDC(m_hWnd,hWinDC);
??::DeleteDC(m_hMemDC);
??return FALSE;
?};
?m_hOldBitmap = reinterpret_cast<HBITMAP>
??????(SelectObject(m_hMemDC,m_hBitmap));
?
?// fill the background
?m_clrBackground = GetSysColor(COLOR_3DFACE);
?RECT rect = {0,0,nWidth,nHeight};
?FillRect(m_hMemDC,&rect,(HBRUSH)(COLOR_WINDOW));
?::ReleaseDC(m_hWnd,hWinDC);
?m_bIsInitialized = TRUE;
?return TRUE;
}
void CPictureEx::OnDestroy()
{
?Stop();?
?CStatic::OnDestroy();
}
void CPictureEx::SetBkColor(COLORREF clr)
{
?if (!m_bIsInitialized) return;
?m_clrBackground = clr;
?HBRUSH hBrush = CreateSolidBrush(clr);
?if (hBrush)
?{
??RECT rect = {0,0,m_PictureSize.cx,m_PictureSize.cy};
??FillRect(m_hMemDC,&rect,hBrush);
??DeleteObject(hBrush);
?};
}
#ifdef GIF_TRACING
void CPictureEx::WriteDataOnDisk(CString szFileName, HGLOBAL hData, DWORD dwSize)
{
?CFile file;
?if (!file.Open(szFileName,
???CFile::modeCreate |
???CFile::modeWrite |
???CFile::shareDenyNone))
?{
??TRACE(_T("WriteData: Error creating file %s\n"),szFileName);
??return;
?};
?char *pData = reinterpret_cast<char *> (GlobalLock(hData));
?if (!pData)
?{
??TRACE(_T("WriteData: Error locking memory\n"));
??return;
?};
?TRY
?{
??file.Write(pData,dwSize);
?}
?CATCH(CFileException, e);?????????????????????????????????????????
?{
??TRACE(_T("WriteData: An exception occured while writing to the file %s\n"),
???szFileName);
??e->Delete();
??GlobalUnlock(hData);
??file.Close();
??return;
?}
?END_CATCH
?
?GlobalUnlock(hData);
?file.Close();
}
void CPictureEx::EnumGIFBlocks()
{
?enum GIFBlockTypes nBlock;
?ResetDataPointer();
?while(m_nCurrOffset < m_nDataSize)
?{
??nBlock = GetNextBlock();
??switch(nBlock)
??{
??case BLOCK_UNKNOWN:
???TRACE(_T("- Unknown block\n"));
???return;
???break;
??case BLOCK_TRAILER:
???TRACE(_T("- Trailer block\n"));
???break;
??case BLOCK_APPEXT:
???TRACE(_T("- Application extension block\n"));
???break;
??case BLOCK_COMMEXT:
???TRACE(_T("- Comment extension block\n"));
???break;
??case BLOCK_CONTROLEXT:
???{
???TGIFControlExt *pControl =
????reinterpret_cast<TGIFControlExt *> (&m_pRawData[m_nCurrOffset]);
???TRACE(_T("- Graphic control extension block (delay %d, disposal %d)\n"),
?????pControl->m_wDelayTime, pControl->GetPackedValue(GCX_PACKED_DISPOSAL));
???};
???break;
??case BLOCK_PLAINTEXT:
???TRACE(_T("- Plain text extension block\n"));
???break;
??case BLOCK_IMAGE:
???TGIFImageDescriptor *pIDescr =
????reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);
???TRACE(_T("- Image data block (%dx%d? %d,%d)\n"),
?????pIDescr->m_wWidth,
?????pIDescr->m_wHeight,
?????pIDescr->m_wLeftPos,
?????pIDescr->m_wTopPos);
???break;
??};
??SkipNextBlock();?
?};
?TRACE(_T("\n"));
}
#endif // GIF_TRACING
BOOL CPictureEx::SetPaintRect(const RECT *lpRect)
{
?return CopyRect(&m_PaintRect, lpRect);
}
BOOL CPictureEx::GetPaintRect(RECT *lpRect)
{
?return CopyRect(lpRect, &m_PaintRect);
}
?
3.dlg頭文件定義:CPictureEx *pAutoGif;
?? 要包含#include "PictureEx.h"
4.dlg的cpp文件實現動態加載gif:
void C**Dlg::OnOK()
{
?// TODO: Add extra validation here
?pAutoGif=new CPictureEx();
?pAutoGif->Create(NULL,WS_CHILD | WS_VISIBLE |SS_ENHMETAFILE,CRect(50,50,100,100),this,1234);
??? if(pAutoGif->Load(_T("g1.gif")))
??pAutoGif->Draw();
?//CDialog::OnOK();
}
5.靜態加載:可以預先加入圖片控件,在ClassWiard中為圖片控件加入CSatic控制變量m_GifPic,然后將CSatic更改成CPictureEx的變量,當然要加上#include "PictureEx.h",可以將gif預先通過resourceview導入到工程中,之后可以在OnInitDialog()加載:
if (m_GifPic.Load(MAKEINTRESOURCE(IDR_GIF),_T("Gif")))//IDR_GIF導入工程gif的id屬性
m_GifPic.Draw();
6.可以在onpaint()中移動加載gif的圖片控件:
CRect rc =CRect(100,400,150,450);
?m_GifPic.MoveWindow(&rc,true);
?m_GifPic.Draw();
?
總結
以上是生活随笔為你收集整理的vc应用CPictureEx类(重载CStatic类)加载gif动画的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vc设置ani动画光标
- 下一篇: vc关于dialog绘图闪屏和多层覆盖的