Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /WinCS/PictureEx.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11 - (hide annotations) (download) (as text)
Wed Feb 10 18:21:00 2010 UTC (14 years, 2 months ago) by sho1get
File MIME type: text/x-c++src
File size: 29632 byte(s)


1 sho1get 11 //////////////////////////////////////////////////////////////////////////
2     // PictureEx.cpp: implementation of the CPictureEx class.
3     //
4     // Picture displaying control with support for the following formats:
5     // GIF (including animated GIF87a and GIF89a), JPEG, BMP, WMF, ICO, CUR
6     //
7     // Written by Oleg Bykov (oleg_bykoff@rsdn.ru)
8     // Copyright (c) 2001
9     //
10     //////////////////////////////////////////////////////////////////////////
11    
12     #include "stdafx.h"
13     #include "PictureEx.h"
14     #include <process.h>
15    
16     #ifdef _DEBUG
17     #undef THIS_FILE
18     static char THIS_FILE[]=__FILE__;
19     #define new DEBUG_NEW
20     #endif
21    
22     //////////////////////////////////////////////////////////////////////////
23     // Nested structures member functions
24     //////////////////////////////////////////////////////////////////////////
25    
26     inline int CPictureEx::TGIFControlExt::GetPackedValue(
27     enum ControlExtValues Value)
28     {
29     int nRet = (int) m_cPacked;
30     switch (Value)
31     {
32     case GCX_PACKED_DISPOSAL:
33     nRet = (nRet & 28) >> 2;
34     break;
35    
36     case GCX_PACKED_USERINPUT:
37     nRet = (nRet & 2) >> 1;
38     break;
39    
40     case GCX_PACKED_TRANSPCOLOR:
41     nRet &= 1;
42     break;
43     };
44    
45     return nRet;
46     }
47    
48     inline int CPictureEx::TGIFLSDescriptor::GetPackedValue(
49     enum LSDPackedValues Value)
50     {
51     int nRet = (int) m_cPacked;
52    
53     switch (Value)
54     {
55     case LSD_PACKED_GLOBALCT:
56     nRet = nRet >> 7;
57     break;
58    
59     case LSD_PACKED_CRESOLUTION:
60     nRet = ((nRet & 0x70) >> 4) + 1;
61     break;
62    
63     case LSD_PACKED_SORT:
64     nRet = (nRet & 8) >> 3;
65     break;
66    
67     case LSD_PACKED_GLOBALCTSIZE:
68     nRet &= 7;
69     break;
70     };
71    
72     return nRet;
73     }
74    
75     inline int CPictureEx::TGIFImageDescriptor::GetPackedValue(
76     enum IDPackedValues Value)
77     {
78     int nRet = (int) m_cPacked;
79    
80     switch (Value)
81     {
82     case ID_PACKED_LOCALCT:
83     nRet >>= 7;
84     break;
85    
86     case ID_PACKED_INTERLACE:
87     nRet = ((nRet & 0x40) >> 6);
88     break;
89    
90     case ID_PACKED_SORT:
91     nRet = (nRet & 0x20) >> 5;
92     break;
93    
94     case ID_PACKED_LOCALCTSIZE:
95     nRet &= 7;
96     break;
97     };
98    
99     return nRet;
100     }
101    
102     //////////////////////////////////////////////////////////////////////////
103     // Construction/Destruction
104     //////////////////////////////////////////////////////////////////////////
105    
106     CPictureEx::CPictureEx()
107     {
108     // check structures size
109     ASSERT(sizeof(TGIFImageDescriptor) == 10);
110     ASSERT(sizeof(TGIFAppExtension) == 14);
111     ASSERT(sizeof(TGIFPlainTextExt) == 15);
112     ASSERT(sizeof(TGIFLSDescriptor) == 7);
113     ASSERT(sizeof(TGIFControlExt) == 8);
114     ASSERT(sizeof(TGIFCommentExt) == 2);
115     ASSERT(sizeof(TGIFHeader) == 6);
116    
117     m_pGIFLSDescriptor = NULL;
118     m_pGIFHeader = NULL;
119     m_pPicture = NULL;
120     m_pRawData = NULL;
121     m_hThread = NULL;
122     m_hBitmap = NULL;
123     m_hMemDC = NULL;
124    
125     m_hDispMemDC = NULL;
126     m_hDispMemBM = NULL;
127     m_hDispOldBM = NULL;
128    
129     m_bIsInitialized = FALSE;
130     m_bExitThread = FALSE;
131     m_bIsPlaying = FALSE;
132     m_bIsGIF = FALSE;
133     m_clrBackground = RGB(255, 255, 255); // white by default
134     m_nGlobalCTSize = 0;
135     m_nCurrOffset = 0;
136     m_nCurrFrame = 0;
137     m_nDataSize = 0;
138     m_PictureSize.cx = m_PictureSize.cy = 0;
139     SetRect(&m_PaintRect, 0, 0, 0, 0);
140    
141     m_hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
142     }
143    
144     CPictureEx::~CPictureEx()
145     {
146     UnLoad();
147     CloseHandle( m_hExitEvent);
148     }
149    
150     BEGIN_MESSAGE_MAP(CPictureEx, CStatic)
151     //{{AFX_MSG_MAP(CPictureEx)
152     ON_WM_DESTROY()
153     ON_WM_PAINT()
154     //}}AFX_MSG_MAP
155     END_MESSAGE_MAP()
156    
157     BOOL CPictureEx::Load(HGLOBAL hGlobal, DWORD dwSize)
158     {
159     IStream *pStream = NULL;
160     UnLoad();
161    
162     if (!(m_pRawData = reinterpret_cast<unsigned char*> (GlobalLock(hGlobal))) )
163     {
164     TRACE(_T("Load: Error locking memory\n"));
165     return FALSE;
166     };
167    
168     m_nDataSize = dwSize;
169     m_pGIFHeader = reinterpret_cast<TGIFHeader *> (m_pRawData);
170    
171     if ((memcmp(&m_pGIFHeader->m_cSignature,"GIF",3) != 0) &&
172     ((memcmp(&m_pGIFHeader->m_cVersion,"87a",3) != 0) ||
173     (memcmp(&m_pGIFHeader->m_cVersion,"89a",3) != 0)) )
174     {
175     // it's neither GIF87a nor GIF89a
176     // do the default processing
177    
178     // clear GIF variables
179     m_pRawData = NULL;
180     GlobalUnlock(hGlobal);
181    
182     // don't delete memory on object's release
183     if (CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK)
184     return FALSE;
185    
186     if (OleLoadPicture(pStream,dwSize,FALSE,IID_IPicture,
187     reinterpret_cast<LPVOID *>(&m_pPicture)) != S_OK)
188     {
189     pStream->Release();
190     return FALSE;
191     };
192     pStream->Release();
193    
194     // store picture's size
195    
196     long hmWidth;
197     long hmHeight;
198     m_pPicture->get_Width(&hmWidth);
199     m_pPicture->get_Height(&hmHeight);
200    
201     HDC hDC = ::GetDC(m_hWnd);
202     m_PictureSize.cx = MulDiv(hmWidth, GetDeviceCaps(hDC,LOGPIXELSX), 2540);
203     m_PictureSize.cy = MulDiv(hmHeight, GetDeviceCaps(hDC,LOGPIXELSY), 2540);
204     ::ReleaseDC(m_hWnd,hDC);
205     }
206     else
207     {
208     // it's a GIF
209     m_bIsGIF = TRUE;
210     m_pGIFLSDescriptor = reinterpret_cast<TGIFLSDescriptor *>
211     (m_pRawData + sizeof(TGIFHeader));
212     if (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT) == 1)
213     {
214     // calculate the globat color table size
215     m_nGlobalCTSize = static_cast<int>
216     (3* (1 << (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE)+1)));
217     // get the background color if GCT is present
218     unsigned char *pBkClr = m_pRawData + sizeof(TGIFHeader) +
219     sizeof(TGIFLSDescriptor) + 3*m_pGIFLSDescriptor->m_cBkIndex;
220     m_clrBackground = RGB(pBkClr[0],pBkClr[1],pBkClr[2]);
221     };
222    
223     // store the picture's size
224     m_PictureSize.cx = m_pGIFLSDescriptor->m_wWidth;
225     m_PictureSize.cy = m_pGIFLSDescriptor->m_wHeight;
226    
227     // determine frame count for this picture
228     UINT nFrameCount=0;
229     ResetDataPointer();
230     while (SkipNextGraphicBlock())
231     nFrameCount++;
232    
233     #ifdef GIF_TRACING
234     TRACE(
235     _T(" -= GIF encountered\n"
236     "Logical Screen dimensions = %dx%d\n"
237     "Global color table = %d\n"
238     "Color depth = %d\n"
239     "Sort flag = %d\n"
240     "Size of Global Color Table = %d\n"
241     "Background color index = %d\n"
242     "Pixel aspect ratio = %d\n"
243     "Frame count = %d\n"
244     "Background color = %06Xh\n\n"
245     ),
246     m_pGIFLSDescriptor->m_wWidth,
247     m_pGIFLSDescriptor->m_wHeight,
248     m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT),
249     m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_CRESOLUTION),
250     m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_SORT),
251     m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE),
252     m_pGIFLSDescriptor->m_cBkIndex,
253     m_pGIFLSDescriptor->m_cPixelAspect,
254     nFrameCount,
255     m_clrBackground
256     );
257     EnumGIFBlocks();
258     #endif
259    
260     if (nFrameCount == 0) // it's an empty GIF!
261    
262     {
263     m_pRawData = NULL;
264     GlobalUnlock(hGlobal);
265     return FALSE;
266     };
267    
268     // now check the frame count
269     // if there's only one frame, no need to animate this GIF
270     // therefore, treat it like any other pic
271    
272     if (nFrameCount == 1)
273     {
274     // clear GIF variables
275     m_pRawData = NULL;
276     GlobalUnlock(hGlobal);
277    
278     // don't delete memory on object's release
279     if (CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK)
280     return FALSE;
281    
282     if (OleLoadPicture(pStream,dwSize,FALSE,IID_IPicture,
283     (LPVOID *)&m_pPicture) != S_OK)
284     {
285     pStream->Release();
286     return FALSE;
287     };
288    
289     pStream->Release();
290     }
291     else
292     {
293     // if, on the contrary, there are several frames
294     // then store separate frames in an array
295    
296     TFrame frame;
297     UINT nBlockLen;
298     HGLOBAL hFrameData;
299     UINT nCurFrame = 0;
300    
301     ResetDataPointer();
302     while (hFrameData = GetNextGraphicBlock(&nBlockLen,
303     &frame.m_nDelay, &frame.m_frameSize,
304     &frame.m_frameOffset, &frame.m_nDisposal) )
305     {
306     #ifdef GIF_TRACING
307     //////////////////////////////////////////////
308     // uncomment the following strings if you want
309     // to write separate frames on disk
310     //
311     // CString szName;
312     // szName.Format(_T("%.4d.gif"),nCurFrame);
313     // WriteDataOnDisk(szName,hFrameData,nBlockLen);
314     // nCurFrame++;
315     #endif // GIF_TRACING
316     IStream *pStream = NULL;
317    
318     // delete memory on object's release
319     if (CreateStreamOnHGlobal(hFrameData,TRUE,&pStream) != S_OK)
320     {
321     GlobalFree(hFrameData);
322     continue;
323     };
324    
325     if (OleLoadPicture(pStream,nBlockLen,FALSE,
326     IID_IPicture,
327     reinterpret_cast<LPVOID *>(&frame.m_pPicture)) != S_OK)
328     {
329     pStream->Release();
330     continue;
331     };
332     pStream->Release();
333    
334     // everything went well, add this frame
335     m_arrFrames.push_back(frame);
336     };
337    
338     // clean after ourselves
339     m_pRawData = NULL;
340     GlobalUnlock(hGlobal);
341    
342     if (m_arrFrames.empty()) // couldn't load any frames
343     return FALSE;
344     };
345     }; // if (!IsGIF...
346    
347     return PrepareDC(m_PictureSize.cx,m_PictureSize.cy);
348     }
349    
350     void CPictureEx::UnLoad()
351     {
352     Stop();
353     if (m_pPicture)
354     {
355     m_pPicture->Release();
356     m_pPicture = NULL;
357     };
358    
359     std::vector<TFrame>::iterator it;
360     for (it = m_arrFrames.begin(); it < m_arrFrames.end(); it++)
361     (*it).m_pPicture->Release();
362     m_arrFrames.clear();
363    
364     if (m_hMemDC)
365     {
366     SelectObject(m_hMemDC, m_hOldBitmap);
367     ::DeleteDC( m_hMemDC);
368     ::DeleteObject( m_hBitmap);
369     m_hMemDC = NULL;
370     m_hBitmap = NULL;
371     };
372    
373     if (m_hDispMemDC)
374     {
375     SelectObject(m_hDispMemDC, m_hDispOldBM);
376     ::DeleteDC( m_hDispMemDC);
377     ::DeleteObject( m_hDispMemBM);
378     m_hDispMemDC = NULL;
379     m_hDispMemBM = NULL;
380     };
381    
382     SetRect(&m_PaintRect, 0, 0, 0, 0);
383     m_pGIFLSDescriptor = NULL;
384     m_pGIFHeader = NULL;
385     m_pRawData = NULL;
386     m_hThread = NULL;
387     m_bIsInitialized = FALSE;
388     m_bExitThread = FALSE;
389     m_bIsGIF = FALSE;
390     m_clrBackground = RGB(255, 255, 255); // white by default
391     m_nGlobalCTSize = 0;
392     m_nCurrOffset = 0;
393     m_nCurrFrame = 0;
394     m_nDataSize = 0;
395     }
396    
397     BOOL CPictureEx::Draw()
398     {
399     if (!m_bIsInitialized)
400     {
401     TRACE(
402     _T(
403     "Call one of the CPictureEx::Load() member functions before calling Draw()\n"));
404     return FALSE;
405     };
406    
407     if (IsAnimatedGIF())
408     {
409     // the picture needs animation
410     // we'll start the thread that will handle it for us
411    
412     unsigned int nDummy;
413     m_hThread = (HANDLE) _beginthreadex(NULL, 0, _ThreadAnimation, this,
414     CREATE_SUSPENDED, &nDummy);
415     if (!m_hThread)
416     {
417     TRACE(_T("Draw: Couldn't start a GIF animation thread\n"));
418     return FALSE;
419     }
420     else
421     ResumeThread( m_hThread);
422     }
423     else
424     {
425     if (m_pPicture)
426     {
427     long hmWidth;
428     long hmHeight;
429     m_pPicture->get_Width(&hmWidth);
430     m_pPicture->get_Height(&hmHeight);
431     if (m_pPicture->Render(m_hMemDC, 0, 0, m_PictureSize.cx,
432     m_PictureSize.cy, 0, hmHeight, hmWidth, -hmHeight, NULL)
433     == S_OK)
434     {
435     Invalidate( FALSE);
436     return TRUE;
437     };
438     };
439     };
440    
441     return FALSE;
442     }
443    
444     SIZE CPictureEx::GetSize() const
445     {
446     return m_PictureSize;
447     }
448    
449     BOOL CPictureEx::Load(LPCTSTR szFileName)
450     {
451     ASSERT(szFileName);
452    
453     CFile file;
454     HGLOBAL hGlobal;
455     DWORD dwSize;
456    
457     if (!file.Open(szFileName, CFile::modeRead | CFile::shareDenyWrite))
458     {
459     TRACE(_T("Load (file): Error opening file %s\n"), szFileName);
460     return FALSE;
461     };
462    
463     dwSize = (DWORD) file.GetLength();
464     hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, dwSize);
465     if (!hGlobal)
466     {
467     TRACE(_T("Load (file): Error allocating memory\n"));
468     return FALSE;
469     };
470    
471     char *pData = reinterpret_cast<char*> (GlobalLock(hGlobal));
472     if (!pData)
473     {
474     TRACE(_T("Load (file): Error locking memory\n"));
475     GlobalFree(hGlobal);
476     return FALSE;
477     };
478    
479     TRY
480     {
481     file.Read(pData,dwSize);
482     }
483     CATCH(CFileException, e);
484     {
485     TRACE(
486     _T(
487     "Load (file): An exception occured while reading the file %s\n"),
488     szFileName);
489     GlobalFree(hGlobal);
490     e->Delete();
491     file.Close();
492     return FALSE;
493     }
494     END_CATCH GlobalUnlock(hGlobal);
495     file.Close();
496    
497     BOOL bRetValue = Load(hGlobal, dwSize);
498     GlobalFree(hGlobal);
499     return bRetValue;
500     }
501    
502     BOOL CPictureEx::Load(LPCTSTR szResourceName, LPCTSTR szResourceType)
503     {
504     ASSERT(szResourceName);
505     ASSERT(szResourceType);
506    
507     HRSRC hPicture = FindResource(AfxGetResourceHandle(), szResourceName,
508     szResourceType);
509     HGLOBAL hResData;
510     if (!hPicture || !(hResData
511     = LoadResource(AfxGetResourceHandle(), hPicture)))
512     {
513     TRACE(_T("Load (resource): Error loading resource %s\n"),
514     szResourceName);
515     return FALSE;
516     };
517     DWORD dwSize = SizeofResource(AfxGetResourceHandle(), hPicture);
518    
519     // hResData is not the real HGLOBAL (we can't lock it)
520     // let's make it real
521    
522     HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, dwSize);
523     if (!hGlobal)
524     {
525     TRACE(_T("Load (resource): Error allocating memory\n"));
526     FreeResource(hResData);
527     return FALSE;
528     };
529    
530     char *pDest = reinterpret_cast<char *> (GlobalLock(hGlobal));
531     char *pSrc = reinterpret_cast<char *> (LockResource(hResData));
532     if (!pSrc || !pDest)
533     {
534     TRACE(_T("Load (resource): Error locking memory\n"));
535     GlobalFree(hGlobal);
536     FreeResource(hResData);
537     return FALSE;
538     };
539     CopyMemory(pDest, pSrc, dwSize);
540     FreeResource(hResData);
541     GlobalUnlock(hGlobal);
542    
543     BOOL bRetValue = Load(hGlobal, dwSize);
544     GlobalFree(hGlobal);
545     return bRetValue;
546     }
547    
548     void CPictureEx::ResetDataPointer()
549     {
550     // skip header and logical screen descriptor
551     m_nCurrOffset = sizeof(TGIFHeader) + sizeof(TGIFLSDescriptor)
552     + m_nGlobalCTSize;
553     }
554    
555     BOOL CPictureEx::SkipNextGraphicBlock()
556     {
557     if (!m_pRawData)
558     return FALSE;
559    
560     // GIF header + LSDescriptor [+ GCT] [+ Control block] + Data
561    
562     enum GIFBlockTypes nBlock;
563    
564     nBlock = GetNextBlock();
565    
566     while ((nBlock != BLOCK_CONTROLEXT) && (nBlock != BLOCK_IMAGE) && (nBlock
567     != BLOCK_PLAINTEXT) && (nBlock != BLOCK_UNKNOWN) && (nBlock
568     != BLOCK_TRAILER))
569     {
570     if (!SkipNextBlock())
571     return NULL;
572     nBlock = GetNextBlock();
573     };
574    
575     if ((nBlock == BLOCK_UNKNOWN) || (nBlock == BLOCK_TRAILER))
576     return FALSE;
577    
578     // it's either a control ext.block, an image or a plain text
579    
580     if (GetNextBlockLen() <= 0)
581     return FALSE;
582    
583     if (nBlock == BLOCK_CONTROLEXT)
584     {
585     if (!SkipNextBlock())
586     return FALSE;
587     nBlock = GetNextBlock();
588    
589     // skip everything until we meet an image block or a plain-text block
590     while ((nBlock != BLOCK_IMAGE) && (nBlock != BLOCK_PLAINTEXT)
591     && (nBlock != BLOCK_UNKNOWN) && (nBlock != BLOCK_TRAILER))
592     {
593     if (!SkipNextBlock())
594     return NULL;
595     nBlock = GetNextBlock();
596     };
597    
598     if ((nBlock == BLOCK_UNKNOWN) || (nBlock == BLOCK_TRAILER))
599     return FALSE;
600     };
601    
602     // skip the found data block (image or plain-text)
603     if (!SkipNextBlock())
604     return FALSE;
605    
606     return TRUE;
607     }
608    
609     UINT CPictureEx::GetSubBlocksLen(UINT nStartingOffset) const
610     {
611     UINT nRet = 0;
612     UINT nCurOffset = nStartingOffset;
613    
614     while (m_pRawData[nCurOffset] != 0)
615     {
616     nRet += m_pRawData[nCurOffset] + 1;
617     nCurOffset += m_pRawData[nCurOffset] + 1;
618     };
619    
620     return nRet + 1;
621     }
622    
623     enum CPictureEx::GIFBlockTypes CPictureEx::GetNextBlock() const
624     {
625     switch (m_pRawData[m_nCurrOffset])
626     {
627     case 0x21:
628     // extension block
629     switch (m_pRawData[m_nCurrOffset + 1])
630     {
631     case 0x01:
632     // plain text extension
633     return BLOCK_PLAINTEXT;
634     break;
635    
636     case 0xF9:
637     // graphic control extension
638     return BLOCK_CONTROLEXT;
639     break;
640    
641     case 0xFE:
642     // comment extension
643     return BLOCK_COMMEXT;
644     break;
645    
646     case 0xFF:
647     // application extension
648     return BLOCK_APPEXT;
649     break;
650     }
651     ;
652     break;
653    
654     case 0x3B:
655     // trailer
656     return BLOCK_TRAILER;
657     break;
658    
659     case 0x2C:
660     // image data
661     return BLOCK_IMAGE;
662     break;
663     };
664    
665     return BLOCK_UNKNOWN;
666     }
667    
668     BOOL CPictureEx::SkipNextBlock()
669     {
670     if (!m_pRawData)
671     return FALSE;
672    
673     int nLen = GetNextBlockLen();
674     if ((nLen <= 0) || ((m_nCurrOffset + nLen) > m_nDataSize))
675     return FALSE;
676    
677     m_nCurrOffset += nLen;
678     return TRUE;
679     }
680    
681     int CPictureEx::GetNextBlockLen() const
682     {
683     GIFBlockTypes nBlock = GetNextBlock();
684    
685     int nTmp;
686    
687     switch (nBlock)
688     {
689     case BLOCK_UNKNOWN:
690     return -1;
691     break;
692    
693     case BLOCK_TRAILER:
694     return 1;
695     break;
696    
697     case BLOCK_APPEXT:
698     nTmp = GetSubBlocksLen(m_nCurrOffset + sizeof(TGIFAppExtension));
699     if (nTmp > 0)
700     return sizeof(TGIFAppExtension) + nTmp;
701     break;
702    
703     case BLOCK_COMMEXT:
704     nTmp = GetSubBlocksLen(m_nCurrOffset + sizeof(TGIFCommentExt));
705     if (nTmp > 0)
706     return sizeof(TGIFCommentExt) + nTmp;
707     break;
708    
709     case BLOCK_CONTROLEXT:
710     return sizeof(TGIFControlExt);
711     break;
712    
713     case BLOCK_PLAINTEXT:
714     nTmp = GetSubBlocksLen(m_nCurrOffset + sizeof(TGIFPlainTextExt));
715     if (nTmp > 0)
716     return sizeof(TGIFPlainTextExt) + nTmp;
717     break;
718    
719     case BLOCK_IMAGE:
720     TGIFImageDescriptor
721     *pIDescr =
722     reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);
723     int nLCTSize = (int) (pIDescr->GetPackedValue(ID_PACKED_LOCALCT) * 3
724     * (1 << (pIDescr->GetPackedValue(ID_PACKED_LOCALCTSIZE) + 1)));
725    
726     int nTmp = GetSubBlocksLen(m_nCurrOffset + sizeof(TGIFImageDescriptor)
727     + nLCTSize + 1);
728     if (nTmp > 0)
729     return sizeof(TGIFImageDescriptor) + nLCTSize + 1 + nTmp;
730     break;
731     };
732    
733     return 0;
734     }
735    
736     UINT WINAPI CPictureEx::_ThreadAnimation(LPVOID pParam)
737     {
738     ASSERT(pParam);
739     CPictureEx *pPic = reinterpret_cast<CPictureEx *> (pParam);
740    
741     pPic->m_bIsPlaying = TRUE;
742     pPic->ThreadAnimation();
743     pPic->m_bIsPlaying = FALSE;
744    
745     // this thread has finished its work so we close the handle
746     CloseHandle(pPic->m_hThread);
747     // and init the handle to zero (so that Stop() doesn't Wait on it)
748     pPic->m_hThread = 0;
749     return 0;
750     }
751    
752     void CPictureEx::ThreadAnimation()
753     {
754     // first, restore background (for stop/draw support)
755     // disposal method #2
756     if (m_arrFrames[m_nCurrFrame].m_nDisposal == 2)
757     {
758     HBRUSH hBrush = CreateSolidBrush(m_clrBackground);
759     if (hBrush)
760     {
761     RECT rect =
762     { m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
763     m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
764     m_arrFrames[m_nCurrFrame].m_frameOffset.cx
765     + m_arrFrames[m_nCurrFrame].m_frameSize.cx,
766     m_arrFrames[m_nCurrFrame].m_frameOffset.cy
767     + m_arrFrames[m_nCurrFrame].m_frameSize.cy };
768     FillRect(m_hMemDC, &rect, hBrush);
769     DeleteObject(hBrush);
770     };
771     }
772     else
773     // disposal method #3
774     if (m_hDispMemDC && (m_arrFrames[m_nCurrFrame].m_nDisposal == 3))
775     {
776     // put it back
777     BitBlt(m_hMemDC, m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
778     m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
779     m_arrFrames[m_nCurrFrame].m_frameSize.cx,
780     m_arrFrames[m_nCurrFrame].m_frameSize.cy, m_hDispMemDC, 0, 0,
781     SRCCOPY);
782     // init variables
783     SelectObject(m_hDispMemDC, m_hDispOldBM);
784     DeleteDC( m_hDispMemDC);
785     m_hDispMemDC = NULL;
786     DeleteObject( m_hDispMemBM);
787     m_hDispMemBM = NULL;
788     };
789    
790     while (!m_bExitThread)
791     {
792     if (m_arrFrames[m_nCurrFrame].m_pPicture)
793     {
794     ///////////////////////////////////////////////////////
795     // Before rendering a frame we should take care of what's
796     // behind that frame. TFrame::m_nDisposal will be our guide:
797     // 0 - no disposal specified (do nothing)
798     // 1 - do not dispose (again, do nothing)
799     // 2 - restore to background color (m_clrBackground)
800     // 3 - restore to previous
801    
802     //////// disposal method #3
803     if (m_arrFrames[m_nCurrFrame].m_nDisposal == 3)
804     {
805     // prepare a memory DC and store the background in it
806     m_hDispMemDC = CreateCompatibleDC(m_hMemDC);
807     m_hDispMemBM = CreateCompatibleBitmap(m_hMemDC,
808     m_arrFrames[m_nCurrFrame].m_frameSize.cx,
809     m_arrFrames[m_nCurrFrame].m_frameSize.cy);
810    
811     if (m_hDispMemDC && m_hDispMemBM)
812     {
813     m_hDispOldBM = reinterpret_cast<HBITMAP> (SelectObject(
814     m_hDispMemDC, m_hDispMemBM));
815     BitBlt(m_hDispMemDC, 0, 0,
816     m_arrFrames[m_nCurrFrame].m_frameSize.cx,
817     m_arrFrames[m_nCurrFrame].m_frameSize.cy, m_hMemDC,
818     m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
819     m_arrFrames[m_nCurrFrame].m_frameOffset.cy, SRCCOPY);
820     };
821     };
822     ///////////////////////
823    
824     long hmWidth;
825     long hmHeight;
826     m_arrFrames[m_nCurrFrame].m_pPicture->get_Width(&hmWidth);
827     m_arrFrames[m_nCurrFrame].m_pPicture->get_Height(&hmHeight);
828    
829     if (m_arrFrames[m_nCurrFrame].m_pPicture->Render(m_hMemDC,
830     m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
831     m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
832     m_arrFrames[m_nCurrFrame].m_frameSize.cx,
833     m_arrFrames[m_nCurrFrame].m_frameSize.cy, 0, hmHeight,
834     hmWidth, -hmHeight, NULL) == S_OK)
835     {
836     Invalidate( FALSE);
837     };
838    
839     if (m_bExitThread)
840     break;
841    
842     // if the delay time is too short (like in old GIFs), wait for 100ms
843     if (m_arrFrames[m_nCurrFrame].m_nDelay < 5)
844     WaitForSingleObject(m_hExitEvent, 100);
845     else
846     WaitForSingleObject(m_hExitEvent, 10
847     * m_arrFrames[m_nCurrFrame].m_nDelay);
848    
849     if (m_bExitThread)
850     break;
851    
852     // disposal method #2
853     if (m_arrFrames[m_nCurrFrame].m_nDisposal == 2)
854     {
855     HBRUSH hBrush = CreateSolidBrush(m_clrBackground);
856     if (hBrush)
857     {
858     RECT
859     rect =
860     {
861     m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
862     m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
863     m_arrFrames[m_nCurrFrame].m_frameOffset.cx
864     + m_arrFrames[m_nCurrFrame].m_frameSize.cx,
865     m_arrFrames[m_nCurrFrame].m_frameOffset.cy
866     + m_arrFrames[m_nCurrFrame].m_frameSize.cy };
867     FillRect(m_hMemDC, &rect, hBrush);
868     DeleteObject(hBrush);
869     };
870     }
871     else if (m_hDispMemDC && (m_arrFrames[m_nCurrFrame].m_nDisposal
872     == 3))
873     {
874     // put it back
875     BitBlt(m_hMemDC, m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
876     m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
877     m_arrFrames[m_nCurrFrame].m_frameSize.cx,
878     m_arrFrames[m_nCurrFrame].m_frameSize.cy, m_hDispMemDC,
879     0, 0, SRCCOPY);
880     // init variables
881     SelectObject(m_hDispMemDC, m_hDispOldBM);
882     DeleteDC( m_hDispMemDC);
883     m_hDispMemDC = NULL;
884     DeleteObject( m_hDispMemBM);
885     m_hDispMemBM = NULL;
886     };
887     };
888     m_nCurrFrame++;
889     if (m_nCurrFrame == m_arrFrames.size())
890     {
891     m_nCurrFrame = 0;
892     // init the screen for the first frame,
893     HBRUSH hBrush = CreateSolidBrush(m_clrBackground);
894     if (hBrush)
895     {
896     RECT rect =
897     { 0, 0, m_PictureSize.cx, m_PictureSize.cy };
898     FillRect(m_hMemDC, &rect, hBrush);
899     DeleteObject(hBrush);
900     };
901     };
902     };
903     }
904    
905     void CPictureEx::Stop()
906     {
907     m_bIsPlaying = FALSE;
908     m_bExitThread = TRUE;
909     SetEvent( m_hExitEvent);
910     if (m_hThread)
911     {
912     // we'll wait for 5 seconds then continue execution
913     WaitForSingleObject(m_hThread, 5000);
914     CloseHandle( m_hThread);
915     m_hThread = NULL;
916     }
917    
918     // make it possible to Draw() again
919     ResetEvent(m_hExitEvent);
920     m_bExitThread = FALSE;
921     }
922    
923     HGLOBAL CPictureEx::GetNextGraphicBlock(UINT *pBlockLen, UINT *pDelay,
924     SIZE *pBlockSize, SIZE *pBlockOffset, UINT *pDisposal)
925     {
926     if (!m_pRawData)
927     return NULL;
928    
929     // GIF header + LSDescriptor [+ GCT] [+ Control block] + Data
930    
931     *pDisposal = 0;
932     enum GIFBlockTypes nBlock;
933     nBlock = GetNextBlock();
934    
935     while ((nBlock != BLOCK_CONTROLEXT) && (nBlock != BLOCK_IMAGE) && (nBlock
936     != BLOCK_PLAINTEXT) && (nBlock != BLOCK_UNKNOWN) && (nBlock
937     != BLOCK_TRAILER))
938     {
939     if (!SkipNextBlock())
940     return NULL;
941     nBlock = GetNextBlock();
942     };
943    
944     if ((nBlock == BLOCK_UNKNOWN) || (nBlock == BLOCK_TRAILER))
945     return NULL;
946    
947     // it's either a control ext.block, an image or a plain text
948    
949     int nStart = m_nCurrOffset;
950     int nBlockLen = GetNextBlockLen();
951    
952     if (nBlockLen <= 0)
953     return NULL;
954    
955     if (nBlock == BLOCK_CONTROLEXT)
956     {
957     // get the following data
958     TGIFControlExt *pControl =
959     reinterpret_cast<TGIFControlExt *> (&m_pRawData[m_nCurrOffset]);
960     // store delay time
961     *pDelay = pControl->m_wDelayTime;
962     // store disposal method
963     *pDisposal = pControl->GetPackedValue(GCX_PACKED_DISPOSAL);
964    
965     if (!SkipNextBlock())
966     return NULL;
967     nBlock = GetNextBlock();
968    
969     // skip everything until we find data to display
970     // (image block or plain-text block)
971    
972     while ((nBlock != BLOCK_IMAGE) && (nBlock != BLOCK_PLAINTEXT)
973     && (nBlock != BLOCK_UNKNOWN) && (nBlock != BLOCK_TRAILER))
974     {
975     if (!SkipNextBlock())
976     return NULL;
977     nBlock = GetNextBlock();
978     nBlockLen += GetNextBlockLen();
979     };
980    
981     if ((nBlock == BLOCK_UNKNOWN) || (nBlock == BLOCK_TRAILER))
982     return NULL;
983     nBlockLen += GetNextBlockLen();
984     }
985     else
986     *pDelay = -1; // to indicate that there was no delay value
987    
988     if (nBlock == BLOCK_IMAGE)
989     {
990     // store size and offsets
991     TGIFImageDescriptor
992     *pImage =
993     reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);
994     pBlockSize->cx = pImage->m_wWidth;
995     pBlockSize->cy = pImage->m_wHeight;
996     pBlockOffset->cx = pImage->m_wLeftPos;
997     pBlockOffset->cy = pImage->m_wTopPos;
998     };
999    
1000     if (!SkipNextBlock())
1001     return NULL;
1002    
1003     HGLOBAL hGlobal = GlobalAlloc(GMEM_FIXED, sizeof(TGIFHeader)
1004     + sizeof(TGIFLSDescriptor) + m_nGlobalCTSize + nBlockLen + 1); // for the trailer
1005    
1006     if (!hGlobal)
1007     return NULL;
1008    
1009     int nOffset = 0;
1010    
1011     // GMEM_FIXED means we get a pointer
1012     unsigned char *pGlobal = reinterpret_cast<unsigned char *> (hGlobal);
1013    
1014     CopyMemory(pGlobal, m_pRawData, sizeof(TGIFHeader)
1015     + sizeof(TGIFLSDescriptor) + m_nGlobalCTSize);
1016     nOffset += sizeof(TGIFHeader) + sizeof(TGIFLSDescriptor) + m_nGlobalCTSize;
1017    
1018     CopyMemory(pGlobal + nOffset, &m_pRawData[nStart], nBlockLen);
1019     nOffset += nBlockLen;
1020    
1021     pGlobal[nOffset] = 0x3B; // trailer
1022     nOffset++;
1023    
1024     *pBlockLen = nOffset;
1025    
1026     return hGlobal;
1027     }
1028    
1029     BOOL CPictureEx::IsGIF() const
1030     {
1031     return m_bIsGIF;
1032     }
1033    
1034     BOOL CPictureEx::IsAnimatedGIF() const
1035     {
1036     return (m_bIsGIF && (m_arrFrames.size() > 1));
1037     }
1038    
1039     BOOL CPictureEx::IsPlaying() const
1040     {
1041     return m_bIsPlaying;
1042     }
1043    
1044     int CPictureEx::GetFrameCount() const
1045     {
1046     if (!IsAnimatedGIF())
1047     return 0;
1048    
1049     return m_arrFrames.size();
1050     }
1051    
1052     COLORREF CPictureEx::GetBkColor() const
1053     {
1054     return m_clrBackground;
1055     }
1056    
1057     void CPictureEx::OnPaint()
1058     {
1059     CPaintDC dc(this); // device context for painting
1060    
1061     LONG nPaintWidth = m_PaintRect.right - m_PaintRect.left;
1062    
1063     if (nPaintWidth > 0)
1064     {
1065     LONG nPaintHeight = m_PaintRect.bottom - m_PaintRect.top;
1066     ::BitBlt(dc.m_hDC, 0, 0, nPaintWidth, nPaintHeight, m_hMemDC,
1067     m_PaintRect.left, m_PaintRect.top, SRCCOPY);
1068     }
1069     else
1070     {
1071     ::BitBlt(dc.m_hDC, 0, 0, m_PictureSize.cx, m_PictureSize.cy, m_hMemDC,
1072     0, 0, SRCCOPY);
1073     };
1074     }
1075    
1076     BOOL CPictureEx::PrepareDC(int nWidth, int nHeight)
1077     {
1078     SetWindowPos(NULL, 0, 0, nWidth, nHeight, SWP_NOMOVE | SWP_NOZORDER);
1079    
1080     HDC hWinDC = ::GetDC(m_hWnd);
1081     if (!hWinDC)
1082     return FALSE;
1083    
1084     m_hMemDC = CreateCompatibleDC(hWinDC);
1085     if (!m_hMemDC)
1086     {
1087     ::ReleaseDC(m_hWnd, hWinDC);
1088     return FALSE;
1089     };
1090    
1091     m_hBitmap = CreateCompatibleBitmap(hWinDC, nWidth, nHeight);
1092     if (!m_hBitmap)
1093     {
1094     ::ReleaseDC(m_hWnd, hWinDC);
1095     ::DeleteDC( m_hMemDC);
1096     return FALSE;
1097     };
1098    
1099     m_hOldBitmap
1100     = reinterpret_cast<HBITMAP> (SelectObject(m_hMemDC, m_hBitmap));
1101    
1102     // fill the background
1103     m_clrBackground = GetSysColor(COLOR_3DFACE);
1104     RECT rect =
1105     { 0, 0, nWidth, nHeight };
1106     FillRect(m_hMemDC, &rect, (HBRUSH)(COLOR_WINDOW));
1107    
1108     ::ReleaseDC(m_hWnd, hWinDC);
1109     m_bIsInitialized = TRUE;
1110     return TRUE;
1111     }
1112    
1113     void CPictureEx::OnDestroy()
1114     {
1115     Stop();
1116     CStatic::OnDestroy();
1117     }
1118    
1119     void CPictureEx::SetBkColor(COLORREF clr)
1120     {
1121     if (!m_bIsInitialized)
1122     return;
1123    
1124     m_clrBackground = clr;
1125    
1126     HBRUSH hBrush = CreateSolidBrush(clr);
1127     if (hBrush)
1128     {
1129     RECT rect =
1130     { 0, 0, m_PictureSize.cx, m_PictureSize.cy };
1131     FillRect(m_hMemDC, &rect, hBrush);
1132     DeleteObject(hBrush);
1133     };
1134     }
1135    
1136     #ifdef GIF_TRACING
1137     void CPictureEx::WriteDataOnDisk(CString szFileName, HGLOBAL hData, DWORD dwSize)
1138     {
1139     CFile file;
1140    
1141     if (!file.Open(szFileName,
1142     CFile::modeCreate |
1143     CFile::modeWrite |
1144     CFile::shareDenyNone))
1145     {
1146     TRACE(_T("WriteData: Error creating file %s\n"),szFileName);
1147     return;
1148     };
1149    
1150     char *pData = reinterpret_cast<char *> (GlobalLock(hData));
1151     if (!pData)
1152     {
1153     TRACE(_T("WriteData: Error locking memory\n"));
1154     return;
1155     };
1156    
1157     TRY
1158     {
1159     file.Write(pData,dwSize);
1160     }
1161     CATCH(CFileException, e);
1162     {
1163     TRACE(_T("WriteData: An exception occured while writing to the file %s\n"),
1164     szFileName);
1165     e->Delete();
1166     GlobalUnlock(hData);
1167     file.Close();
1168     return;
1169     }
1170     END_CATCH
1171    
1172     GlobalUnlock(hData);
1173     file.Close();
1174     }
1175    
1176     void CPictureEx::EnumGIFBlocks()
1177     {
1178     enum GIFBlockTypes nBlock;
1179    
1180     ResetDataPointer();
1181     while(m_nCurrOffset < m_nDataSize)
1182     {
1183     nBlock = GetNextBlock();
1184     switch(nBlock)
1185     {
1186     case BLOCK_UNKNOWN:
1187     TRACE(_T("- Unknown block\n"));
1188     return;
1189     break;
1190    
1191     case BLOCK_TRAILER:
1192     TRACE(_T("- Trailer block\n"));
1193     break;
1194    
1195     case BLOCK_APPEXT:
1196     TRACE(_T("- Application extension block\n"));
1197     break;
1198    
1199     case BLOCK_COMMEXT:
1200     TRACE(_T("- Comment extension block\n"));
1201     break;
1202    
1203     case BLOCK_CONTROLEXT:
1204     {
1205     TGIFControlExt *pControl =
1206     reinterpret_cast<TGIFControlExt *> (&m_pRawData[m_nCurrOffset]);
1207     TRACE(_T("- Graphic control extension block (delay %d, disposal %d)\n"),
1208     pControl->m_wDelayTime, pControl->GetPackedValue(GCX_PACKED_DISPOSAL));
1209     };
1210     break;
1211    
1212     case BLOCK_PLAINTEXT:
1213     TRACE(_T("- Plain text extension block\n"));
1214     break;
1215    
1216     case BLOCK_IMAGE:
1217     TGIFImageDescriptor *pIDescr =
1218     reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);
1219     TRACE(_T("- Image data block (%dx%d %d,%d)\n"),
1220     pIDescr->m_wWidth,
1221     pIDescr->m_wHeight,
1222     pIDescr->m_wLeftPos,
1223     pIDescr->m_wTopPos);
1224     break;
1225     };
1226    
1227     SkipNextBlock();
1228     };
1229    
1230     TRACE(_T("\n"));
1231     }
1232    
1233     #endif // GIF_TRACING
1234    
1235     BOOL CPictureEx::SetPaintRect(const RECT *lpRect)
1236     {
1237     return CopyRect(&m_PaintRect, lpRect);
1238     }
1239    
1240     BOOL CPictureEx::GetPaintRect(RECT *lpRect)
1241     {
1242     return CopyRect(lpRect, &m_PaintRect);
1243     }
1244    
1245     //////////////////////////////////////////////////////////////////////////

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26