• 10619阅读
  • 9回复

[转载]MFC加载gif动态图片的方法 [复制链接]

上一主题 下一主题
离线iokey
 

发帖
15
金钱
854
威望
759
贡献值
0
诚信值
0
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看楼主 倒序阅读 楼主   发表于: 2019-06-24
--------------------- CRb8WD6.  
作者:jiangqin115 _bFUr  
来源:CSDN \Pg~j\;F]  
原文:https://blog.csdn.net/jiangqin115/article/details/44241859 ]?eZDf~  
版权声明:本文为博主原创文章,转载请附上博文链接! R'Sd'pSDN  
---------------------------------------------------------------------------------------- _C?j\Wy  
g{8RPw]  
在一个项目中需要加入GIF动画。一个版本时通过IE浏览器显示网页的形式,js脚本、CSS他人编写较繁琐;另一个VC项目需要使用MFC直接加载GIF动画。加载GIF动画网上有多种方式,大多数是将GIF填进资源,使用PictureEx类load资源文件  如下: QQ*sjK.(  
PictureEx图片显示类支持以下格式的图片:GIF (including animated GIF87a and GIF89a), JPEG, BMP, WMF, ICO, CUR等,我特别推崇的是能够做出动画,而且轻而易举,确实很COOL。 D'"  T'@  
下面是周详的编程过程: $~/2!T_  
{f/qI`  
1. 新建项目:在VC6中用MFC新建一个基于对话框的GifDemo应用程式,接受任何缺省选项即可; D BT4 W/  
sVLvnX,  
2.在项目中插入文档:把PictureEx.h,PictureEx.cpp文档copy 到项目文档夹下,Project->Add to Project->Files中选上PictureEx.h,PictureEx.cpp, Insert; gq+SM  i=  
3.加入图片控件:从对话框控件中把Picture Control(图片控件)拖入主对话框中,修改其属性:ID:IDC_GIF,TYPE:Rectangle,其余接受缺省选项。再在ClassWiard中为IDF_GIF加入CSatic控制变量m_GifPic, vl"w,@V7  
注意看一下,GifDemoDlg.h中是否加上了#include "PictureEx.h"(由ClassWiard加入)。然后将CSatic m_GifPic;更改成CPictureEx m_GifPic; 1Ms[$$b$  
Ot=jwvw  
4.加载动画文档:先将要加载的动画文档放到 res 资源文档夹下,再将其Import进项目中,由于MFC只支持256BMP文档的图片,因此,我们要新建一个图片类型:"GIF",我在这里将我网站的宣传图片roaring.gif放进去 ,并将其ID修改成:IDR_GIFROARING。 U<Pjn)M~B  
WJShN~ E  
import(导入)gif动画的周详过程: _Cmmx`ln  
在resourceview窗口中,单击鼠标右键,在出现的环境菜单中选择“import...”命令,会出现“import resource”选择文档对话框,文档类型选择“任何文档(*.*)”,open as 选项为"auto",再选择动画文档所在目录,选上要载入的动画文档 roaring.gif,再单击 import,由于gif动画类型不是vc默认的文档类型,这时会出现"custom resource type"对话框,键入“"gif"”,再单击ok,然后再修改其id。 *;7y 5ZJ  
5.在程式的适当位置添入加载代码: 这里,我们在CGifDemoDlg::OnInitDialog()函数中加入如下代码: sZ.<:mu[  
// TODO: Add extra initialization here z A,vp^  
if (m_GifPic.Load(MAKEINTRESOURCE(IDR_GIFROARING),_T("Gif"))) m_GifPic.Draw(); b+rxin".  
但是由于我们的软件要写入硬件设备中,对文件大小有严格要求,几个软件间共用同一个GIF,必须采用动态调用GIF文件加载进MFC中。查看PictureEx类,会发现类中有多个load函数,其中一个可以Load文件名,但是调用过程不是简单的Load,在Draw的样子显示GIF动画。试验多次后来发现需要在Load文件之前 Static::Create一下。 源码如下: 2;}leZ@U  
m_GifPic.Create(NULL,WS_CHILD | WS_VISIBLE |SS_ENHMETAFILE,CRect(50,50,100,100),this,1234); B VBn.ut  
m_GifPic.Load(_T("c://1.gif")); (!~cO x   
m_GifPic.Draw();// OK  使用PictureEx动态加载GIF文件完成 h [TwaR  
/x<g$!`X  
PictureEx.h代码如下: Wh[QR-7Ew  
  1. #if !defined(AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_)
  2. #define AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_
  3. #if _MSC_VER > 1000
  4. #pragma once
  5. #endif // _MSC_VER > 1000
  6. #include <vector>
  7. //#define GIF_TRACING  // uncomment it if you want detailed TRACEs
  8. class CPictureEx : public CStatic
  9. {
  10. public:
  11. struct TFrame    // structure that keeps a single frame info
  12. {
  13. IPicture *m_pPicture;  // pointer to the interface used for drawing
  14. SIZE     m_frameSize;
  15. SIZE     m_frameOffset;
  16. UINT     m_nDelay;     // delay (in 1/100s of a second)
  17. UINT     m_nDisposal;  // disposal method
  18. };
  19. #pragma pack(1)   // turn byte alignment on
  20. enum GIFBlockTypes
  21. {
  22. BLOCK_UNKNOWN,
  23. BLOCK_APPEXT,
  24. BLOCK_COMMEXT,
  25. BLOCK_CONTROLEXT,
  26. BLOCK_PLAINTEXT,
  27. BLOCK_IMAGE,
  28. BLOCK_TRAILER
  29. };
  30. enum ControlExtValues // graphic control extension packed field values
  31. {
  32. GCX_PACKED_DISPOSAL,  // disposal method
  33. GCX_PACKED_USERINPUT,
  34. GCX_PACKED_TRANSPCOLOR
  35. };
  36. enum LSDPackedValues  // logical screen descriptor packed field values
  37. {
  38. LSD_PACKED_GLOBALCT,
  39. LSD_PACKED_CRESOLUTION,
  40. LSD_PACKED_SORT,
  41. LSD_PACKED_GLOBALCTSIZE
  42. };
  43. enum IDPackedValues   // image descriptor packed field values
  44. {
  45. ID_PACKED_LOCALCT,
  46. ID_PACKED_INTERLACE,
  47. ID_PACKED_SORT,
  48. ID_PACKED_LOCALCTSIZE
  49. };
  50. struct TGIFHeader       // GIF header  
  51. {
  52. char m_cSignature[3]; // Signature - Identifies the GIF Data Stream
  53.         // This field contains the fixed value 'GIF'
  54. char m_cVersion[3]; // Version number. May be one of the following:
  55.       // "87a" or "89a"
  56. };
  57. struct TGIFLSDescriptor // Logical Screen Descriptor
  58. {
  59. WORD m_wWidth; // 2 bytes. Logical screen width
  60. WORD m_wHeight; // 2 bytes. Logical screen height
  61. unsigned char m_cPacked;      // packed field
  62. unsigned char m_cBkIndex;     // 1 byte. Background color index
  63. unsigned char m_cPixelAspect; // 1 byte. Pixel aspect ratio
  64. inline int GetPackedValue(enum LSDPackedValues Value);
  65. };
  66. struct TGIFAppExtension // application extension block
  67. {
  68. unsigned char m_cExtIntroducer; // extension introducer (0x21)
  69. unsigned char m_cExtLabel; // app. extension label (0xFF)
  70. unsigned char m_cBlockSize; // fixed value of 11
  71. char m_cAppIdentifier[8];   // application identifier
  72. char m_cAppAuth[3];  // application authentication code
  73. };
  74. struct TGIFControlExt // graphic control extension block
  75. {
  76. unsigned char m_cExtIntroducer; // extension introducer (0x21)
  77. unsigned char m_cControlLabel;  // control extension label (0xF9)
  78. unsigned char m_cBlockSize; // fixed value of 4
  79. unsigned char m_cPacked;    // packed field
  80. WORD m_wDelayTime; // delay time
  81. unsigned char m_cTColorIndex; // transparent color index
  82. unsigned char m_cBlockTerm;   // block terminator (0x00)
  83. public:
  84. inline int GetPackedValue(enum ControlExtValues Value);
  85. };
  86. struct TGIFCommentExt  // comment extension block
  87. {
  88. unsigned char m_cExtIntroducer; // extension introducer (0x21)
  89. unsigned char m_cCommentLabel;  // comment extension label (0xFE)
  90. };
  91. struct TGIFPlainTextExt // plain text extension block
  92. {
  93. unsigned char m_cExtIntroducer;  // extension introducer (0x21)
  94. unsigned char m_cPlainTextLabel; // text extension label (0x01)
  95. unsigned char m_cBlockSize; // fixed value of 12
  96. WORD m_wLeftPos;    // text grid left position
  97. WORD m_wTopPos;     // text grid top position
  98. WORD m_wGridWidth;  // text grid width
  99. WORD m_wGridHeight; // text grid height
  100. unsigned char m_cCellWidth;  // character cell width
  101. unsigned char m_cCellHeight; // character cell height
  102. unsigned char m_cFgColor; // text foreground color index
  103. unsigned char m_cBkColor; // text background color index
  104. };
  105. struct TGIFImageDescriptor // image descriptor block
  106. {
  107. unsigned char m_cImageSeparator; // image separator byte (0x2C)
  108. WORD m_wLeftPos; // image left position
  109. WORD m_wTopPos;  // image top position
  110. WORD m_wWidth;   // image width
  111. WORD m_wHeight;  // image height
  112. unsigned char m_cPacked; // packed field
  113. inline int GetPackedValue(enum IDPackedValues Value);
  114. };
  115. #pragma pack() // turn byte alignment off
  116. public:
  117. BOOL GetPaintRect(RECT *lpRect);
  118. BOOL SetPaintRect(const RECT *lpRect);
  119. CPictureEx();
  120. virtual ~CPictureEx();
  121. void Stop();   // stops animation
  122. void UnLoad(); // stops animation plus releases all resources
  123. BOOL IsGIF() const;
  124. BOOL IsPlaying() const;
  125. BOOL IsAnimatedGIF() const;
  126. SIZE GetSize() const;
  127. int GetFrameCount() const;
  128. COLORREF GetBkColor() const;
  129. void SetBkColor(COLORREF clr);
  130. // draws the picture (starts an animation thread if needed)
  131. // if an animation was previously stopped by Stop(),
  132. // continues it from the last displayed frame
  133. BOOL Draw();
  134. // loads a picture from a file
  135. // i.e. Load(_T("mypic.gif"));
  136. BOOL Load(LPCTSTR szFileName);
  137. // loads a picture from a global memory block (allocated by GlobalAlloc)
  138. // Warning: this function DOES NOT free the global memory, pointed to by hGlobal
  139. BOOL Load(HGLOBAL hGlobal, DWORD dwSize);
  140. // loads a picture from a program resource
  141. // i.e. Load(MAKEINTRESOURCE(IDR_MYPIC),_T("GIFTYPE"));
  142. BOOL Load(LPCTSTR szResourceName,LPCTSTR szResourceType);
  143. protected:
  144. #ifdef GIF_TRACING
  145. void EnumGIFBlocks();
  146. void WriteDataOnDisk(CString szFileName, HGLOBAL hData, DWORD dwSize);
  147. #endif // GIF_TRACING
  148. RECT m_PaintRect;
  149. SIZE m_PictureSize;
  150. COLORREF m_clrBackground;
  151. UINT m_nCurrFrame;
  152. UINT m_nDataSize;
  153. UINT m_nCurrOffset;
  154. UINT m_nGlobalCTSize;
  155. BOOL m_bIsGIF;
  156. BOOL m_bIsPlaying;
  157. volatile BOOL m_bExitThread;
  158. BOOL m_bIsInitialized;
  159. HDC m_hMemDC;
  160. HDC m_hDispMemDC;
  161. HBITMAP m_hDispMemBM;
  162. HBITMAP m_hDispOldBM;
  163. HBITMAP m_hBitmap;
  164. HBITMAP m_hOldBitmap;
  165. HANDLE m_hThread;
  166. HANDLE m_hExitEvent;
  167. IPicture * m_pPicture;
  168. TGIFHeader * m_pGIFHeader;
  169. unsigned char * m_pRawData;
  170. TGIFLSDescriptor * m_pGIFLSDescriptor;
  171. std::vector<TFrame> m_arrFrames;
  172. void ThreadAnimation();
  173. static UINT WINAPI _ThreadAnimation(LPVOID pParam);
  174. int GetNextBlockLen() const;
  175. BOOL SkipNextBlock();
  176. BOOL SkipNextGraphicBlock();
  177. BOOL PrepareDC(int nWidth, int nHeight);
  178. void ResetDataPointer();
  179. enum GIFBlockTypes GetNextBlock() const;
  180. UINT GetSubBlocksLen(UINT nStartingOffset) const;
  181. HGLOBAL GetNextGraphicBlock(UINT *pBlockLen, UINT *pDelay,
  182.   SIZE *pBlockSize, SIZE *pBlockOffset, UINT *pDisposal);
  183. // Generated message map functions
  184. //{{AFX_MSG(CPictureEx)
  185. afx_msg void OnDestroy();
  186. afx_msg void OnPaint();
  187. //}}AFX_MSG
  188. DECLARE_MESSAGE_MAP()
  189. };
  190. #endif // !defined(AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_)
 (I[_}l  
615Ya<3f8  
PictureEx.cpp代码如下: ZoW1Cc&p  
  1. #include "stdafx.h"
  2. #include "PictureEx.h"
  3. #include <process.h>
  4. #ifdef _DEBUG
  5. #undef THIS_FILE
  6. static char THIS_FILE[]=__FILE__;
  7. #define new DEBUG_NEW
  8. #endif
  9. //////////////////////////////////////////////////////////////////////
  10. // Nested structures member functions
  11. //////////////////////////////////////////////////////////////////////
  12. inline int CPictureEx::TGIFControlExt::GetPackedValue(enum ControlExtValues Value)
  13. {
  14. int nRet = (int)m_cPacked;
  15. switch (Value)
  16. {
  17. case GCX_PACKED_DISPOSAL:
  18.   nRet = (nRet & 28) >> 2;
  19.   break;
  20. case GCX_PACKED_USERINPUT:
  21.   nRet = (nRet & 2) >> 1;
  22.   break;
  23. case GCX_PACKED_TRANSPCOLOR:
  24.   nRet &= 1;
  25.   break;
  26. };
  27. return nRet;
  28. }
  29. inline int CPictureEx::TGIFLSDescriptor::GetPackedValue(enum LSDPackedValues Value)
  30. {
  31. int nRet = (int)m_cPacked;
  32. switch (Value)
  33. {
  34. case LSD_PACKED_GLOBALCT:
  35.   nRet = nRet >> 7;
  36.   break;
  37. case LSD_PACKED_CRESOLUTION:
  38.   nRet = ((nRet & 0x70) >> 4) + 1;
  39.   break;
  40. case LSD_PACKED_SORT:
  41.   nRet = (nRet & 8) >> 3;
  42.   break;
  43. case LSD_PACKED_GLOBALCTSIZE:
  44.   nRet &= 7;
  45.   break;
  46. };
  47. return nRet;
  48. }
  49. inline int CPictureEx::TGIFImageDescriptor::GetPackedValue(enum IDPackedValues Value)
  50. {
  51. int nRet = (int)m_cPacked;
  52. switch (Value)
  53. {
  54. case ID_PACKED_LOCALCT:
  55.   nRet >>= 7;
  56.   break;
  57. case ID_PACKED_INTERLACE:
  58.   nRet = ((nRet & 0x40) >> 6);
  59.   break;
  60. case ID_PACKED_SORT:
  61.   nRet = (nRet & 0x20) >> 5;
  62.   break;
  63. case ID_PACKED_LOCALCTSIZE:
  64.   nRet &= 7;
  65.   break;
  66. };
  67. return nRet;
  68. }
  69. //////////////////////////////////////////////////////////////////////
  70. // Construction/Destruction
  71. //////////////////////////////////////////////////////////////////////
  72. CPictureEx::CPictureEx()
  73. {
  74. // check structures size
  75. ASSERT(sizeof(TGIFImageDescriptor) == 10);
  76. ASSERT(sizeof(TGIFAppExtension)    == 14);
  77. ASSERT(sizeof(TGIFPlainTextExt)    == 15);
  78. ASSERT(sizeof(TGIFLSDescriptor)    ==  7);
  79. ASSERT(sizeof(TGIFControlExt)    ==  8);
  80. ASSERT(sizeof(TGIFCommentExt)    ==  2);
  81. ASSERT(sizeof(TGIFHeader)     ==  6);
  82. m_pGIFLSDescriptor = NULL;
  83. m_pGIFHeader    = NULL;
  84. m_pPicture     = NULL;
  85. m_pRawData     = NULL;
  86. m_hThread     = NULL;
  87. m_hBitmap          = NULL;
  88. m_hMemDC     = NULL;
  89. m_hDispMemDC       = NULL;
  90. m_hDispMemBM       = NULL;
  91. m_hDispOldBM       = NULL;
  92. m_bIsInitialized   = FALSE;
  93. m_bExitThread    = FALSE;
  94. m_bIsPlaying       = FALSE;
  95. m_bIsGIF     = FALSE;
  96. m_clrBackground    = RGB(255,255,255); // white by default
  97. m_nGlobalCTSize    = 0;
  98. m_nCurrOffset    = 0;
  99. m_nCurrFrame    = 0;
  100. m_nDataSize     = 0;
  101. m_PictureSize.cx = m_PictureSize.cy = 0;
  102. SetRect(&m_PaintRect,0,0,0,0);
  103. m_hExitEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
  104. }
  105. CPictureEx::~CPictureEx()
  106. {
  107. UnLoad();
  108. CloseHandle(m_hExitEvent);
  109. }
  110. BEGIN_MESSAGE_MAP(CPictureEx, CStatic)
  111. //{{AFX_MSG_MAP(CPictureEx)
  112. ON_WM_DESTROY()
  113. ON_WM_PAINT()
  114. //}}AFX_MSG_MAP
  115. END_MESSAGE_MAP()
  116. BOOL CPictureEx::Load(HGLOBAL hGlobal, DWORD dwSize)
  117. {
  118. IStream *pStream = NULL;
  119. UnLoad();
  120. if (!(m_pRawData = reinterpret_cast<unsigned char*> (GlobalLock(hGlobal))) )
  121. {
  122.   TRACE(_T("Load: Error locking memory\n"));
  123.   return FALSE;
  124. };
  125. m_nDataSize = dwSize;
  126. m_pGIFHeader = reinterpret_cast<TGIFHeader *> (m_pRawData);
  127. if ((memcmp(&m_pGIFHeader->m_cSignature,"GIF",3) != 0) &&
  128.   ((memcmp(&m_pGIFHeader->m_cVersion,"87a",3) != 0) ||
  129.    (memcmp(&m_pGIFHeader->m_cVersion,"89a",3) != 0)) )
  130. {
  131. // it's neither GIF87a nor GIF89a
  132. // do the default processing
  133.   // clear GIF variables
  134.   m_pRawData = NULL;
  135.   GlobalUnlock(hGlobal);
  136.   // don't delete memory on object's release
  137.   if (CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK)
  138.    return FALSE;
  139.   if (OleLoadPicture(pStream,dwSize,FALSE,IID_IPicture,
  140.    reinterpret_cast<LPVOID *>(&m_pPicture)) != S_OK)
  141.   {
  142.    pStream->Release();
  143.    return FALSE;
  144.   };
  145.   pStream->Release();
  146.   // store picture's size
  147.   long hmWidth;
  148.   long hmHeight;
  149.   m_pPicture->get_Width(&hmWidth);
  150.   m_pPicture->get_Height(&hmHeight);
  151.   HDC hDC = ::GetDC(m_hWnd);
  152.   m_PictureSize.cx = MulDiv(hmWidth, GetDeviceCaps(hDC,LOGPIXELSX), 2540);
  153.   m_PictureSize.cy = MulDiv(hmHeight, GetDeviceCaps(hDC,LOGPIXELSY), 2540);
  154.   ::ReleaseDC(m_hWnd,hDC);
  155. }
  156. else
  157. {
  158.   // it's a GIF
  159.   m_bIsGIF = TRUE;
  160.   m_pGIFLSDescriptor = reinterpret_cast<TGIFLSDescriptor *>
  161.    (m_pRawData + sizeof(TGIFHeader));
  162.   if (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT) == 1)
  163.   {
  164.    // calculate the globat color table size
  165.    m_nGlobalCTSize = static_cast<int>
  166.     (3* (1 << (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE)+1)));
  167.    // get the background color if GCT is present
  168.    unsigned char *pBkClr = m_pRawData + sizeof(TGIFHeader) +
  169.     sizeof(TGIFLSDescriptor) + 3*m_pGIFLSDescriptor->m_cBkIndex;
  170.    m_clrBackground = RGB(pBkClr[0],pBkClr[1],pBkClr[2]);
  171.   };
  172.   // store the picture's size
  173.   m_PictureSize.cx = m_pGIFLSDescriptor->m_wWidth;
  174.   m_PictureSize.cy = m_pGIFLSDescriptor->m_wHeight;
  175.   // determine frame count for this picture
  176.   UINT nFrameCount=0;
  177.   ResetDataPointer();
  178.   while (SkipNextGraphicBlock())
  179.    nFrameCount++;
  180. #ifdef GIF_TRACING
  181.   TRACE(
  182.    _T(" -= GIF encountered\n"
  183.       "Logical Screen dimensions = %dx%d\n"
  184.       "Global color table = %d\n"
  185.       "Color depth = %d\n"
  186.       "Sort flag = %d\n"
  187.       "Size of Global Color Table = %d\n"
  188.       "Background color index = %d\n"
  189.       "Pixel aspect ratio = %d\n"
  190.       "Frame count = %d\n"
  191.       "Background color = %06Xh\n\n"
  192.      ),
  193.    m_pGIFLSDescriptor->m_wWidth,
  194.    m_pGIFLSDescriptor->m_wHeight,
  195.    m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT),
  196.    m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_CRESOLUTION),
  197.    m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_SORT),
  198.    m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE),
  199.    m_pGIFLSDescriptor->m_cBkIndex,
  200.    m_pGIFLSDescriptor->m_cPixelAspect,
  201.    nFrameCount,
  202.    m_clrBackground
  203.    );
  204.   EnumGIFBlocks();
  205. #endif
  206.   if (nFrameCount == 0) // it's an empty GIF!
  207.   {
  208.    m_pRawData = NULL;
  209.    GlobalUnlock(hGlobal);
  210.    return FALSE;
  211.   };
  212.   // now check the frame count
  213.   // if there's only one frame, no need to animate this GIF
  214.   // therefore, treat it like any other pic
  215.   if (nFrameCount == 1)
  216.   {
  217.    // clear GIF variables
  218.    m_pRawData = NULL;
  219.    GlobalUnlock(hGlobal);
  220.    // don't delete memory on object's release
  221.    if (CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK)
  222.     return FALSE;
  223.    if (OleLoadPicture(pStream,dwSize,FALSE,IID_IPicture,
  224.     (LPVOID *)&m_pPicture) != S_OK)
  225.    {
  226.     pStream->Release();
  227.     return FALSE;
  228.    };
  229.    pStream->Release();
  230.   }
  231.   else
  232.   {
  233.   // if, on the contrary, there are several frames
  234.   // then store separate frames in an array
  235.    TFrame frame;
  236.    UINT nBlockLen;
  237.    HGLOBAL hFrameData;
  238.    UINT nCurFrame = 0;
  239.    ResetDataPointer();
  240.    while (hFrameData = GetNextGraphicBlock(&nBlockLen,
  241.     &frame.m_nDelay, &frame.m_frameSize,
  242.     &frame.m_frameOffset, &frame.m_nDisposal) )
  243.    {
  244.     #ifdef GIF_TRACING
  245.     //////////////////////////////////////////////
  246.     // uncomment the following strings if you want
  247.     // to write separate frames on disk
  248.     //
  249.     // CString szName;
  250.     // szName.Format(_T("%.4d.gif"),nCurFrame);
  251.     // WriteDataOnDisk(szName,hFrameData,nBlockLen);
  252.     // nCurFrame++;
  253.     #endif // GIF_TRACING
  254.     IStream *pStream = NULL;
  255.     // delete memory on object's release
  256.     if (CreateStreamOnHGlobal(hFrameData,TRUE,&pStream) != S_OK)
  257.     {
  258.      GlobalFree(hFrameData);
  259.      continue;
  260.     };
  261.     if (OleLoadPicture(pStream,nBlockLen,FALSE,
  262.      IID_IPicture,
  263.      reinterpret_cast<LPVOID *>(&frame.m_pPicture)) != S_OK)
  264.     {
  265.      pStream->Release();
  266.      continue;
  267.     };
  268.     pStream->Release();
  269.   
  270.     // everything went well, add this frame
  271.     m_arrFrames.push_back(frame);
  272.    };
  273.    // clean after ourselves
  274.    m_pRawData = NULL;
  275.    GlobalUnlock(hGlobal);
  276.    if (m_arrFrames.empty()) // couldn't load any frames
  277.     return FALSE;
  278.   };
  279. }; // if (!IsGIF...
  280. return PrepareDC(m_PictureSize.cx,m_PictureSize.cy);
  281. }
  282. void CPictureEx::UnLoad()
  283. {
  284. Stop();
  285. if (m_pPicture)
  286. {
  287.   m_pPicture->Release();
  288.   m_pPicture = NULL;
  289. };
  290. std::vector<TFrame>::iterator it;
  291. for (it=m_arrFrames.begin();it<m_arrFrames.end();it++)
  292.   (*it).m_pPicture->Release();
  293. m_arrFrames.clear();
  294. if (m_hMemDC)
  295. {
  296.   SelectObject(m_hMemDC,m_hOldBitmap);
  297.   ::DeleteDC(m_hMemDC);
  298.   ::DeleteObject(m_hBitmap);
  299.   m_hMemDC  = NULL;
  300.   m_hBitmap = NULL;
  301. };
  302. if (m_hDispMemDC)
  303. {
  304.   SelectObject(m_hDispMemDC,m_hDispOldBM);
  305.   ::DeleteDC(m_hDispMemDC);
  306.   ::DeleteObject(m_hDispMemBM);
  307.   m_hDispMemDC  = NULL;
  308.   m_hDispMemBM = NULL;
  309. };
  310. SetRect(&m_PaintRect,0,0,0,0);
  311. m_pGIFLSDescriptor = NULL;
  312. m_pGIFHeader    = NULL;
  313. m_pRawData     = NULL;
  314. m_hThread     = NULL;
  315. m_bIsInitialized   = FALSE;
  316. m_bExitThread    = FALSE;
  317. m_bIsGIF     = FALSE;
  318. m_clrBackground    = RGB(255,255,255); // white by default
  319. m_nGlobalCTSize    = 0;
  320. m_nCurrOffset    = 0;
  321. m_nCurrFrame    = 0;
  322. m_nDataSize     = 0;
  323. }
  324. BOOL CPictureEx::Draw()
  325. {
  326. if (!m_bIsInitialized)
  327. {
  328.   TRACE(_T("Call one of the CPictureEx::Load() member functions before calling Draw()\n"));
  329.   return FALSE;
  330. };
  331. if (IsAnimatedGIF())
  332. {
  333. // the picture needs animation
  334. // we'll start the thread that will handle it for us
  335.   unsigned int nDummy;
  336.   m_hThread = (HANDLE) _beginthreadex(NULL,0,_ThreadAnimation,this,
  337.    CREATE_SUSPENDED,&nDummy);
  338.   if (!m_hThread)
  339.   {
  340.    TRACE(_T("Draw: Couldn't start a GIF animation thread\n"));
  341.    return FALSE;
  342.   }
  343.   else
  344.    ResumeThread(m_hThread);
  345. }
  346. else
  347. {
  348.   if (m_pPicture)
  349.   {
  350.    long hmWidth;
  351.    long hmHeight;
  352.    m_pPicture->get_Width(&hmWidth);
  353.    m_pPicture->get_Height(&hmHeight);
  354.    if (m_pPicture->Render(m_hMemDC, 0, 0, m_PictureSize.cx, m_PictureSize.cy,
  355.     0, hmHeight, hmWidth, -hmHeight, NULL) == S_OK)
  356.    {
  357.     Invalidate(FALSE);
  358.     return TRUE;
  359.    };
  360.   };
  361. };
  362. return FALSE;
  363. }
  364. SIZE CPictureEx::GetSize() const
  365. {
  366. return m_PictureSize;
  367. }
  368. BOOL CPictureEx::Load(LPCTSTR szFileName)
  369. {
  370. ASSERT(szFileName);
  371. CFile file;
  372. HGLOBAL hGlobal;
  373. DWORD dwSize;
  374. if (!file.Open(szFileName,
  375.     CFile::modeRead |
  376.     CFile::shareDenyWrite) )
  377. {
  378.   TRACE(_T("Load (file): Error opening file %s\n"),szFileName);
  379.   return FALSE;
  380. };
  381. dwSize = file.GetLength();
  382. hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD,dwSize);
  383. if (!hGlobal)
  384. {
  385.   TRACE(_T("Load (file): Error allocating memory\n"));
  386.   return FALSE;
  387. };
  388. char *pData = reinterpret_cast<char*>(GlobalLock(hGlobal));
  389. if (!pData)
  390. {
  391.   TRACE(_T("Load (file): Error locking memory\n"));
  392.   GlobalFree(hGlobal);
  393.   return FALSE;
  394. };
  395. TRY
  396. {
  397.   file.Read(pData,dwSize);
  398. }
  399. CATCH(CFileException, e);                                          
  400. {
  401.   TRACE(_T("Load (file): An exception occured while reading the file %s\n"),
  402.    szFileName);
  403.   GlobalFree(hGlobal);
  404.   e->Delete();
  405.   file.Close();
  406.   return FALSE;
  407. }
  408. END_CATCH
  409. GlobalUnlock(hGlobal);
  410. file.Close();
  411. BOOL bRetValue = Load(hGlobal,dwSize);
  412. GlobalFree(hGlobal);
  413. return bRetValue;
  414. }
  415. BOOL CPictureEx::Load(LPCTSTR szResourceName, LPCTSTR szResourceType)
  416. {
  417. ASSERT(szResourceName);
  418. ASSERT(szResourceType);
  419. HRSRC hPicture = FindResource(AfxGetResourceHandle(),szResourceName,szResourceType);
  420. HGLOBAL hResData;
  421. if (!hPicture || !(hResData = LoadResource(AfxGetResourceHandle(),hPicture)))
  422. {
  423.   TRACE(_T("Load (resource): Error loading resource %s\n"),szResourceName);
  424.   return FALSE;
  425. };
  426. DWORD dwSize = SizeofResource(AfxGetResourceHandle(),hPicture);
  427. // hResData is not the real HGLOBAL (we can't lock it)
  428. // let's make it real
  429. HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD,dwSize);
  430. if (!hGlobal)
  431. {
  432.   TRACE(_T("Load (resource): Error allocating memory\n"));
  433.   FreeResource(hResData);
  434.   return FALSE;
  435. };
  436. char *pDest = reinterpret_cast<char *> (GlobalLock(hGlobal));
  437. char *pSrc = reinterpret_cast<char *> (LockResource(hResData));
  438. if (!pSrc || !pDest)
  439. {
  440.   TRACE(_T("Load (resource): Error locking memory\n"));
  441.   GlobalFree(hGlobal);
  442.   FreeResource(hResData);
  443.   return FALSE;
  444. };
  445. CopyMemory(pDest,pSrc,dwSize);
  446. FreeResource(hResData);
  447. GlobalUnlock(hGlobal);
  448. BOOL bRetValue = Load(hGlobal,dwSize);
  449. GlobalFree(hGlobal);
  450. return bRetValue;
  451. }
  452. void CPictureEx::ResetDataPointer()
  453. {
  454. // skip header and logical screen descriptor
  455. m_nCurrOffset =
  456.   sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize;
  457. }
  458. BOOL CPictureEx::SkipNextGraphicBlock()
  459. {
  460. if (!m_pRawData) return FALSE;
  461. // GIF header + LSDescriptor [+ GCT] [+ Control block] + Data
  462. enum GIFBlockTypes nBlock;
  463. nBlock = GetNextBlock();
  464. while ((nBlock != BLOCK_CONTROLEXT) &&
  465.      (nBlock != BLOCK_IMAGE) &&
  466.      (nBlock != BLOCK_PLAINTEXT) &&
  467.      (nBlock != BLOCK_UNKNOWN) &&
  468.      (nBlock != BLOCK_TRAILER) )
  469. {
  470.   if (!SkipNextBlock()) return NULL;
  471.   nBlock = GetNextBlock();
  472. };
  473. if ((nBlock == BLOCK_UNKNOWN) ||
  474.   (nBlock == BLOCK_TRAILER))
  475.   return FALSE;
  476. // it's either a control ext.block, an image or a plain text
  477. if (GetNextBlockLen() <= 0) return FALSE;
  478. if (nBlock == BLOCK_CONTROLEXT)
  479. {
  480.   if (!SkipNextBlock()) return FALSE;
  481.   nBlock = GetNextBlock();
  482.   // skip everything until we meet an image block or a plain-text block
  483.   while ((nBlock != BLOCK_IMAGE) &&
  484.       (nBlock != BLOCK_PLAINTEXT) &&
  485.       (nBlock != BLOCK_UNKNOWN) &&
  486.       (nBlock != BLOCK_TRAILER) )
  487.   {
  488.    if (!SkipNextBlock()) return NULL;
  489.    nBlock = GetNextBlock();
  490.   };
  491.   if ((nBlock == BLOCK_UNKNOWN) ||
  492.    (nBlock == BLOCK_TRAILER))
  493.    return FALSE;
  494. };
  495. // skip the found data block (image or plain-text)
  496. if (!SkipNextBlock()) return FALSE;
  497. return TRUE;
  498. }
  499. UINT CPictureEx::GetSubBlocksLen(UINT nStartingOffset) const
  500. {
  501. UINT nRet = 0;
  502. UINT nCurOffset = nStartingOffset;
  503. while (m_pRawData[nCurOffset] != 0)
  504. {
  505.   nRet += m_pRawData[nCurOffset]+1;
  506.   nCurOffset += m_pRawData[nCurOffset]+1;
  507. };
  508. return nRet+1;
  509. }
  510. enum CPictureEx::GIFBlockTypes CPictureEx::GetNextBlock() const
  511. {
  512. switch(m_pRawData[m_nCurrOffset])
  513. {
  514. case 0x21:
  515. // extension block
  516.   switch(m_pRawData[m_nCurrOffset+1])
  517.   {
  518.   case 0x01:
  519.   // plain text extension
  520.    return BLOCK_PLAINTEXT;
  521.    break;
  522.   case 0xF9:
  523.   // graphic control extension
  524.    return BLOCK_CONTROLEXT;
  525.    break;
  526.   case 0xFE:
  527.   // comment extension
  528.    return BLOCK_COMMEXT;
  529.    break;
  530.   case 0xFF:
  531.   // application extension
  532.    return BLOCK_APPEXT;
  533.    break;
  534.   };
  535.   break;
  536. case 0x3B:
  537. // trailer
  538.   return BLOCK_TRAILER;
  539.   break;
  540. case 0x2C:
  541. // image data
  542.   return BLOCK_IMAGE;
  543.   break;
  544. };
  545. return BLOCK_UNKNOWN;
  546. }
  547. BOOL CPictureEx::SkipNextBlock()
  548. {
  549. if (!m_pRawData) return FALSE;
  550. int nLen = GetNextBlockLen();
  551. if ((nLen <= 0) || ((m_nCurrOffset+nLen) > m_nDataSize))
  552.   return FALSE;
  553. m_nCurrOffset += nLen;
  554. return TRUE;
  555. }
  556. int CPictureEx::GetNextBlockLen() const
  557. {
  558. GIFBlockTypes nBlock = GetNextBlock();
  559. int nTmp;
  560. switch(nBlock)
  561. {
  562. case BLOCK_UNKNOWN:
  563.   return -1;
  564.   break;
  565. case BLOCK_TRAILER:
  566.   return 1;
  567.   break;
  568. case BLOCK_APPEXT:
  569.   nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFAppExtension));
  570.   if (nTmp > 0)
  571.    return sizeof(TGIFAppExtension)+nTmp;
  572.   break;
  573. case BLOCK_COMMEXT:
  574.   nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFCommentExt));
  575.   if (nTmp > 0)
  576.    return sizeof(TGIFCommentExt)+nTmp;
  577.   break;
  578. case BLOCK_CONTROLEXT:
  579.   return sizeof(TGIFControlExt);
  580.   break;
  581. case BLOCK_PLAINTEXT:
  582.   nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFPlainTextExt));
  583.   if (nTmp > 0)
  584.    return sizeof(TGIFPlainTextExt)+nTmp;
  585.   break;
  586. case BLOCK_IMAGE:
  587.   TGIFImageDescriptor *pIDescr =
  588.    reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);
  589.   int nLCTSize = (int)
  590.    (pIDescr->GetPackedValue(ID_PACKED_LOCALCT)*3*
  591.    (1 << (pIDescr->GetPackedValue(ID_PACKED_LOCALCTSIZE)+1)));
  592.   int nTmp = GetSubBlocksLen(m_nCurrOffset+
  593.    sizeof(TGIFImageDescriptor) + nLCTSize + 1);
  594.   if (nTmp > 0)
  595.    return sizeof(TGIFImageDescriptor) + nLCTSize + 1 + nTmp;
  596.   break;
  597. };
  598. return 0;
  599. }
  600. UINT WINAPI CPictureEx::_ThreadAnimation(LPVOID pParam)
  601. {
  602. ASSERT(pParam);
  603. CPictureEx *pPic = reinterpret_cast<CPictureEx *> (pParam);
  604. pPic->m_bIsPlaying = TRUE;
  605. pPic->ThreadAnimation();
  606. pPic->m_bIsPlaying = FALSE;
  607. // this thread has finished its work so we close the handle
  608. CloseHandle(pPic->m_hThread);
  609. // and init the handle to zero (so that Stop() doesn't Wait on it)
  610. pPic->m_hThread = 0;
  611. return 0;
  612. }
  613. void CPictureEx::ThreadAnimation()
  614. {
  615. // first, restore background (for stop/draw support)
  616. // disposal method #2
  617. if (m_arrFrames[m_nCurrFrame].m_nDisposal == 2)
  618. {
  619.   HBRUSH hBrush = CreateSolidBrush(m_clrBackground);
  620.   if (hBrush)
  621.   {
  622.    RECT rect = {
  623.     m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
  624.     m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
  625.     m_arrFrames[m_nCurrFrame].m_frameOffset.cx + m_arrFrames[m_nCurrFrame].m_frameSize.cx,
  626.     m_arrFrames[m_nCurrFrame].m_frameOffset.cy + m_arrFrames[m_nCurrFrame].m_frameSize.cy };
  627.    FillRect(m_hMemDC,&rect,hBrush);
  628.    DeleteObject(hBrush);
  629.   };
  630. }
  631. else
  632.   // disposal method #3
  633.   if (m_hDispMemDC && (m_arrFrames[m_nCurrFrame].m_nDisposal == 3) )
  634.   {
  635.    // put it back
  636.    BitBlt(m_hMemDC,
  637.     m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
  638.     m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
  639.     m_arrFrames[m_nCurrFrame].m_frameSize.cx,
  640.     m_arrFrames[m_nCurrFrame].m_frameSize.cy,
  641.     m_hDispMemDC,0,0, SRCCOPY);
  642.    // init variables
  643.    SelectObject(m_hDispMemDC,m_hDispOldBM);
  644.    DeleteDC(m_hDispMemDC); m_hDispMemDC = NULL;
  645.    DeleteObject(m_hDispMemBM); m_hDispMemBM = NULL;
  646.   };
  647. while (!m_bExitThread)
  648. {
  649.   if (m_arrFrames[m_nCurrFrame].m_pPicture)
  650.   {
  651.   ///////////////////////////////////////////////////////
  652.   // Before rendering a frame we should take care of what's
  653.   // behind that frame. TFrame::m_nDisposal will be our guide:
  654.   //   0 - no disposal specified (do nothing)
  655.   //   1 - do not dispose (again, do nothing)
  656.   //   2 - restore to background color (m_clrBackground)
  657.   //   3 - restore to previous
  658.    //////// disposal method #3
  659.    if (m_arrFrames[m_nCurrFrame].m_nDisposal == 3)
  660.    {
  661.     // prepare a memory DC and store the background in it
  662.     m_hDispMemDC = CreateCompatibleDC(m_hMemDC);
  663.     m_hDispMemBM = CreateCompatibleBitmap(m_hMemDC,
  664.        m_arrFrames[m_nCurrFrame].m_frameSize.cx,
  665.        m_arrFrames[m_nCurrFrame].m_frameSize.cy);
  666.     
  667.     if (m_hDispMemDC && m_hDispMemBM)
  668.     {
  669.      m_hDispOldBM = reinterpret_cast<HBITMAP> (SelectObject(m_hDispMemDC,m_hDispMemBM));
  670.      BitBlt(m_hDispMemDC,0,0,
  671.       m_arrFrames[m_nCurrFrame].m_frameSize.cx,
  672.       m_arrFrames[m_nCurrFrame].m_frameSize.cy,
  673.       m_hMemDC,
  674.       m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
  675.       m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
  676.       SRCCOPY);
  677.     };
  678.    };
  679.    ///////////////////////
  680.    long hmWidth;
  681.    long hmHeight;
  682.    m_arrFrames[m_nCurrFrame].m_pPicture->get_Width(&hmWidth);
  683.    m_arrFrames[m_nCurrFrame].m_pPicture->get_Height(&hmHeight);
  684.    if (m_arrFrames[m_nCurrFrame].m_pPicture->Render(m_hMemDC,
  685.     m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
  686.     m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
  687.     m_arrFrames[m_nCurrFrame].m_frameSize.cx,
  688.     m_arrFrames[m_nCurrFrame].m_frameSize.cy,
  689.     0, hmHeight, hmWidth, -hmHeight, NULL) == S_OK)
  690.    {
  691.     Invalidate(FALSE);
  692.    };
  693.   
  694.    if (m_bExitThread) break;
  695.    // if the delay time is too short (like in old GIFs), wait for 100ms
  696.    if (m_arrFrames[m_nCurrFrame].m_nDelay < 5)
  697.     WaitForSingleObject(m_hExitEvent, 100);
  698.    else
  699.     WaitForSingleObject(m_hExitEvent, 10*m_arrFrames[m_nCurrFrame].m_nDelay);
  700.    if (m_bExitThread) break;
  701.    // disposal method #2
  702.    if (m_arrFrames[m_nCurrFrame].m_nDisposal == 2)
  703.    {
  704.     HBRUSH hBrush = CreateSolidBrush(m_clrBackground);
  705.     if (hBrush)
  706.     {
  707.      RECT rect = {
  708.       m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
  709.       m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
  710.       m_arrFrames[m_nCurrFrame].m_frameOffset.cx + m_arrFrames[m_nCurrFrame].m_frameSize.cx,
  711.       m_arrFrames[m_nCurrFrame].m_frameOffset.cy + m_arrFrames[m_nCurrFrame].m_frameSize.cy };
  712.      FillRect(m_hMemDC,&rect,hBrush);
  713.      DeleteObject(hBrush);
  714.     };
  715.    }
  716.    else
  717.     if (m_hDispMemDC && (m_arrFrames[m_nCurrFrame].m_nDisposal == 3) )
  718.     {
  719.      // put it back
  720.      BitBlt(m_hMemDC,
  721.       m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
  722.       m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
  723.       m_arrFrames[m_nCurrFrame].m_frameSize.cx,
  724.       m_arrFrames[m_nCurrFrame].m_frameSize.cy,
  725.       m_hDispMemDC,0,0, SRCCOPY);
  726.      // init variables
  727.      SelectObject(m_hDispMemDC,m_hDispOldBM);
  728.      DeleteDC(m_hDispMemDC); m_hDispMemDC = NULL;
  729.      DeleteObject(m_hDispMemBM); m_hDispMemBM = NULL;
  730.     };
  731.   };
  732.   m_nCurrFrame++;
  733.   if (m_nCurrFrame == m_arrFrames.size())
  734.   {
  735.    m_nCurrFrame
  736.     = 0;
  737.   // init the screen for the first frame,
  738.    HBRUSH hBrush = CreateSolidBrush(m_clrBackground);
  739.    if (hBrush)
  740.    {
  741.     RECT rect = {0,0,m_PictureSize.cx,m_PictureSize.cy};
  742.     FillRect(m_hMemDC,&rect,hBrush);
  743.     DeleteObject(hBrush);
  744.    };
  745.   };
  746. };
  747. }
  748. void CPictureEx::Stop()
  749. {
  750. m_bIsPlaying = FALSE;
  751. m_bExitThread = TRUE;
  752. SetEvent(m_hExitEvent);
  753. if (m_hThread)
  754. {
  755.   // we'll wait for 5 seconds then continue execution
  756.   WaitForSingleObject(m_hThread,5000);
  757.   CloseHandle(m_hThread);
  758.   m_hThread = NULL;
  759. }
  760. // make it possible to Draw() again
  761. ResetEvent(m_hExitEvent);
  762. m_bExitThread = FALSE;
  763. }
  764. HGLOBAL CPictureEx::GetNextGraphicBlock(UINT *pBlockLen,
  765. UINT *pDelay, SIZE *pBlockSize, SIZE *pBlockOffset,
  766. UINT *pDisposal)
  767. {
  768. if (!m_pRawData) return NULL;
  769. // GIF header + LSDescriptor [+ GCT] [+ Control block] + Data
  770. *pDisposal = 0;
  771. enum GIFBlockTypes nBlock;
  772. nBlock = GetNextBlock();
  773. while (
  774.   (nBlock != BLOCK_CONTROLEXT) &&
  775.   (nBlock != BLOCK_IMAGE) &&
  776.   (nBlock != BLOCK_PLAINTEXT) &&
  777.   (nBlock != BLOCK_UNKNOWN) &&
  778.   (nBlock != BLOCK_TRAILER)
  779.   )
  780. {
  781.   if (!SkipNextBlock()) return NULL;
  782.   nBlock = GetNextBlock();
  783. };
  784. if ((nBlock == BLOCK_UNKNOWN) ||
  785.   (nBlock == BLOCK_TRAILER))
  786.   return NULL;
  787. // it's either a control ext.block, an image or a plain text
  788. int nStart = m_nCurrOffset;
  789. int nBlockLen = GetNextBlockLen();
  790. if (nBlockLen <= 0) return NULL;
  791. if (nBlock == BLOCK_CONTROLEXT)
  792. {
  793.   // get the following data
  794.   TGIFControlExt *pControl =
  795.    reinterpret_cast<TGIFControlExt *> (&m_pRawData[m_nCurrOffset]);
  796.   // store delay time
  797.   *pDelay = pControl->m_wDelayTime;
  798.   // store disposal method
  799.   *pDisposal = pControl->GetPackedValue(GCX_PACKED_DISPOSAL);
  800.   if (!SkipNextBlock()) return NULL;
  801.   nBlock = GetNextBlock();
  802.   
  803.   // skip everything until we find data to display
  804.   // (image block or plain-text block)
  805.   
  806.   while (
  807.    (nBlock != BLOCK_IMAGE) &&
  808.    (nBlock != BLOCK_PLAINTEXT) &&
  809.    (nBlock != BLOCK_UNKNOWN) &&
  810.    (nBlock != BLOCK_TRAILER)
  811.    )
  812.   {
  813.    if (!SkipNextBlock()) return NULL;
  814.    nBlock = GetNextBlock();
  815.    nBlockLen += GetNextBlockLen();
  816.   };
  817.   if ((nBlock == BLOCK_UNKNOWN) || (nBlock == BLOCK_TRAILER))
  818.    return NULL;
  819.   nBlockLen += GetNextBlockLen();
  820. }
  821. else
  822.   *pDelay = -1; // to indicate that there was no delay value
  823. if (nBlock == BLOCK_IMAGE)
  824. {
  825.   // store size and offsets
  826.   TGIFImageDescriptor *pImage =
  827.    reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);
  828.   pBlockSize->cx = pImage->m_wWidth;
  829.   pBlockSize->cy = pImage->m_wHeight;
  830.   pBlockOffset->cx = pImage->m_wLeftPos;
  831.   pBlockOffset->cy = pImage->m_wTopPos;
  832. };
  833. if (!SkipNextBlock()) return NULL;
  834. HGLOBAL hGlobal = GlobalAlloc(GMEM_FIXED,
  835.   sizeof(TGIFHeader) +
  836.   sizeof(TGIFLSDescriptor) +
  837.   m_nGlobalCTSize +
  838.   nBlockLen +
  839.   1);  // for the trailer
  840. if (!hGlobal) return NULL;
  841. int nOffset = 0;
  842. // GMEM_FIXED means we get a pointer
  843. unsigned char *pGlobal = reinterpret_cast<unsigned char *> (hGlobal);
  844. CopyMemory(pGlobal,m_pRawData,
  845.   sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize);
  846. nOffset += sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize;
  847. CopyMemory(pGlobal + nOffset,&m_pRawData[nStart], nBlockLen);
  848. nOffset += nBlockLen;
  849. pGlobal[nOffset] = 0x3B; // trailer
  850. nOffset++;
  851. *pBlockLen = nOffset;
  852. return hGlobal;
  853. }
  854. BOOL CPictureEx::IsGIF() const
  855. {
  856. return m_bIsGIF;
  857. }
  858. BOOL CPictureEx::IsAnimatedGIF() const
  859. {
  860. return (m_bIsGIF && (m_arrFrames.size() > 1));
  861. }
  862. BOOL CPictureEx::IsPlaying() const
  863. {
  864. return m_bIsPlaying;
  865. }
  866. int CPictureEx::GetFrameCount() const
  867. {
  868. if (!IsAnimatedGIF())
  869.   return 0;
  870. return m_arrFrames.size();
  871. }
  872. COLORREF CPictureEx::GetBkColor() const
  873. {
  874. return m_clrBackground;
  875. }
  876. void CPictureEx::OnPaint()
  877. {
  878. CPaintDC dc(this); // device context for painting
  879. LONG nPaintWidth = m_PaintRect.right-m_PaintRect.left;
  880. if (nPaintWidth > 0)
  881. {
  882.   LONG nPaintHeight = m_PaintRect.bottom - m_PaintRect.top;
  883.   ::BitBlt(dc.m_hDC, 0, 0, nPaintWidth, nPaintHeight,
  884.    m_hMemDC, m_PaintRect.left, m_PaintRect.top, SRCCOPY);
  885. }
  886. else
  887. {
  888.   ::BitBlt(dc.m_hDC, 0, 0, m_PictureSize.cx, m_PictureSize.cy,
  889.    m_hMemDC, 0, 0, SRCCOPY);
  890. };
  891. }
  892. BOOL CPictureEx::PrepareDC(int nWidth, int nHeight)
  893. {
  894. SetWindowPos(NULL,0,0,nWidth,nHeight,SWP_NOMOVE | SWP_NOZORDER);
  895. HDC hWinDC = ::GetDC(m_hWnd);
  896. if (!hWinDC) return FALSE;
  897. m_hMemDC = CreateCompatibleDC(hWinDC);
  898. if (!m_hMemDC)
  899. {
  900.   ::ReleaseDC(m_hWnd,hWinDC);
  901.   return FALSE;
  902. };
  903. m_hBitmap  = CreateCompatibleBitmap(hWinDC,nWidth,nHeight);
  904. if (!m_hBitmap)
  905. {
  906.   ::ReleaseDC(m_hWnd,hWinDC);
  907.   ::DeleteDC(m_hMemDC);
  908.   return FALSE;
  909. };
  910. m_hOldBitmap = reinterpret_cast<HBITMAP>
  911.       (SelectObject(m_hMemDC,m_hBitmap));
  912. // fill the background
  913. m_clrBackground = GetSysColor(COLOR_3DFACE);
  914. RECT rect = {0,0,nWidth,nHeight};
  915. FillRect(m_hMemDC,&rect,(HBRUSH)(COLOR_WINDOW));
  916. ::ReleaseDC(m_hWnd,hWinDC);
  917. m_bIsInitialized = TRUE;
  918. return TRUE;
  919. }
  920. void CPictureEx::OnDestroy()
  921. {
  922. Stop();
  923. CStatic::OnDestroy();
  924. }
  925. void CPictureEx::SetBkColor(COLORREF clr)
  926. {
  927. if (!m_bIsInitialized) return;
  928. m_clrBackground = clr;
  929. HBRUSH hBrush = CreateSolidBrush(clr);
  930. if (hBrush)
  931. {
  932.   RECT rect = {0,0,m_PictureSize.cx,m_PictureSize.cy};
  933.   FillRect(m_hMemDC,&rect,hBrush);
  934.   DeleteObject(hBrush);
  935. };
  936. }
  937. #ifdef GIF_TRACING
  938. void CPictureEx::WriteDataOnDisk(CString szFileName, HGLOBAL hData, DWORD dwSize)
  939. {
  940. CFile file;
  941. if (!file.Open(szFileName,
  942.    CFile::modeCreate |
  943.    CFile::modeWrite |
  944.    CFile::shareDenyNone))
  945. {
  946.   TRACE(_T("WriteData: Error creating file %s\n"),szFileName);
  947.   return;
  948. };
  949. char *pData = reinterpret_cast<char *> (GlobalLock(hData));
  950. if (!pData)
  951. {
  952.   TRACE(_T("WriteData: Error locking memory\n"));
  953.   return;
  954. };
  955. TRY
  956. {
  957.   file.Write(pData,dwSize);
  958. }
  959. CATCH(CFileException, e);                                          
  960. {
  961.   TRACE(_T("WriteData: An exception occured while writing to the file %s\n"),
  962.    szFileName);
  963.   e->Delete();
  964.   GlobalUnlock(hData);
  965.   file.Close();
  966.   return;
  967. }
  968. END_CATCH
  969. GlobalUnlock(hData);
  970. file.Close();
  971. }
  972. void CPictureEx::EnumGIFBlocks()
  973. {
  974. enum GIFBlockTypes nBlock;
  975. ResetDataPointer();
  976. while(m_nCurrOffset < m_nDataSize)
  977. {
  978.   nBlock = GetNextBlock();
  979.   switch(nBlock)
  980.   {
  981.   case BLOCK_UNKNOWN:
  982.    TRACE(_T("- Unknown block\n"));
  983.    return;
  984.    break;
  985.   case BLOCK_TRAILER:
  986.    TRACE(_T("- Trailer block\n"));
  987.    break;
  988.   case BLOCK_APPEXT:
  989.    TRACE(_T("- Application extension block\n"));
  990.    break;
  991.   case BLOCK_COMMEXT:
  992.    TRACE(_T("- Comment extension block\n"));
  993.    break;
  994.   case BLOCK_CONTROLEXT:
  995.    {
  996.    TGIFControlExt *pControl =
  997.     reinterpret_cast<TGIFControlExt *> (&m_pRawData[m_nCurrOffset]);
  998.    TRACE(_T("- Graphic control extension block (delay %d, disposal %d)\n"),
  999.      pControl->m_wDelayTime, pControl->GetPackedValue(GCX_PACKED_DISPOSAL));
  1000.    };
  1001.    break;
  1002.   case BLOCK_PLAINTEXT:
  1003.    TRACE(_T("- Plain text extension block\n"));
  1004.    break;
  1005.   case BLOCK_IMAGE:
  1006.    TGIFImageDescriptor *pIDescr =
  1007.     reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);
  1008.    TRACE(_T("- Image data block (%dx%d  %d,%d)\n"),
  1009.      pIDescr->m_wWidth,
  1010.      pIDescr->m_wHeight,
  1011.      pIDescr->m_wLeftPos,
  1012.      pIDescr->m_wTopPos);
  1013.    break;
  1014.   };
  1015.   SkipNextBlock();
  1016. };
  1017. TRACE(_T("\n"));
  1018. }
  1019. #endif // GIF_TRACING
  1020. BOOL CPictureEx::SetPaintRect(const RECT *lpRect)
  1021. {
  1022. return CopyRect(&m_PaintRect, lpRect);
  1023. }
  1024. BOOL CPictureEx::GetPaintRect(RECT *lpRect)
  1025. {
  1026. return CopyRect(lpRect, &m_PaintRect);
  1027. }
W^(zP/  
iSW2I~PD  
L 4By5)  
q t"D!S_  
PS:有多少人是被这张美女图片给吸引进来的呢?
广海社区提醒您:
1.忘记账号、密码、安全问题等常见站务问题,请查看论坛左上角站点帮助
2.请理性对待商业信息,如有交易,强烈建议您选择广海中介进行交易
3.欢迎购买广海社区广告位,感谢您的支持,报价及位置详见广海社区广告服务
4.特殊会员售价50元,积分(金钱和威望)无限,更多权限,欢迎到广海淘宝购买
5.广海社区唯一域名ghoffice.net,唯一QQ190959022,其他均为假冒,谨防上当受骗
6.如您被骗,请查看广海社区举报中心,按照要求和流程提交举报材料,未经核实的举报帖子将一律删除
7.如您发现违规违法内容,欢迎点击帖子右下角举报按钮进行举报,也可到站务办公版块匿名发帖举报
免责声明
文中内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。 私下交易造成损失的,本站概不负责。
 
离线huaiyesu

发帖
2
金钱
342
威望
302
贡献值
0
诚信值
0
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看该作者 沙发   发表于: 2019-07-01
看图片的停留时间 超过看代码的时间!
离线龙剑飞

发帖
19
金钱
661
威望
661
贡献值
0
诚信值
0
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看该作者 板凳   发表于: 2019-07-09
感谢分享
离线兔崽子

发帖
1
金钱
1200
威望
1200
贡献值
0
诚信值
0
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看该作者 地板   发表于: 2019-08-03
感谢分享
离线qianlan

发帖
1
金钱
401
威望
401
贡献值
0
诚信值
0
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看该作者 4楼  发表于: 2019-08-03
看看我的ID
离线水上往来

发帖
3
金钱
303
威望
303
贡献值
0
诚信值
0
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看该作者 5楼  发表于: 2019-08-16
貌似不错,学习了
离线bailnln

发帖
1
金钱
1200
威望
1200
贡献值
0
诚信值
0
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看该作者 6楼  发表于: 2019-09-12
能不能出个C++初学教程啊
离线易了科技

发帖
57
金钱
892
威望
892
贡献值
0
诚信值
0
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看该作者 7楼  发表于: 2020-02-14
感谢,很受用呢!
离线daybreak

发帖
9
金钱
516
威望
516
贡献值
0
诚信值
4500
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看该作者 8楼  发表于: 2021-09-04
感谢分享,受用了
离线xiaoxin

发帖
24
金钱
16
威望
0
贡献值
0
诚信值
0
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看该作者 9楼  发表于: 2021-10-05
感谢分享
快速回复
限150 字节
批量上传需要先选择文件,再选择上传
 
上一个 下一个