Develop and Download Open Source Software

Browse Subversion Repository

Contents of /WinCS/PictureEx.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11 - (show 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 //////////////////////////////////////////////////////////////////////////
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