00001
00002
00003
00004
00005
00006 #include "stdafx.h"
00007 #include "FdmApp.h"
00008 #include "vmsAnimatedGIF.h"
00009 #include <math.h>
00010
00011 #ifdef _DEBUG
00012 #undef THIS_FILE
00013 static char THIS_FILE[]=__FILE__;
00014 #define new DEBUG_NEW
00015 #endif
00016
00017 vmsAnimatedGIF::vmsAnimatedGIF()
00018 {
00019 m_hGIF = NULL;
00020 m_bAutoFree = FALSE;
00021 m_nDataSize = 0;
00022 m_nCurrOffset = 0;
00023 m_pGIFHeader = NULL;
00024 m_pGIFLSDescriptor = NULL;
00025 }
00026
00027 vmsAnimatedGIF::~vmsAnimatedGIF()
00028 {
00029 Free ();
00030 }
00031
00032 BOOL vmsAnimatedGIF::Load(LPCSTR pszFile)
00033 {
00034 LOG ("GIF: 1st point" << nl);
00035
00036 HANDLE hFile = CreateFile (pszFile, GENERIC_READ, FILE_SHARE_READ,
00037 NULL, OPEN_EXISTING, 0, NULL);
00038 if (hFile == INVALID_HANDLE_VALUE)
00039 return FALSE;
00040
00041 DWORD dwSize;
00042
00043 dwSize = GetFileSize (hFile, NULL);
00044 m_hGIF = GlobalAlloc (GMEM_MOVEABLE | GMEM_NODISCARD, dwSize);
00045 if (m_hGIF == NULL)
00046 return FALSE;
00047 m_bAutoFree = TRUE;
00048
00049 char *pData = reinterpret_cast<char*>(GlobalLock(m_hGIF));
00050 if (!pData)
00051 {
00052 CloseHandle (hFile);
00053 return FALSE;
00054 };
00055
00056 DWORD dw;
00057 if (FALSE == ReadFile (hFile, pData, dwSize, &dw, NULL))
00058 {
00059 CloseHandle (hFile);
00060 return FALSE;
00061 }
00062
00063 GlobalUnlock (m_hGIF);
00064 CloseHandle (hFile);
00065
00066 m_nDataSize = dwSize;
00067 return Load ();
00068 }
00069
00070 BOOL vmsAnimatedGIF::Load(HGLOBAL hGlobal, DWORD dwSize)
00071 {
00072 Free ();
00073 m_hGIF = hGlobal;
00074 m_nDataSize = dwSize;
00075 return Load ();
00076 }
00077
00078 void vmsAnimatedGIF::Free()
00079 {
00080 if (m_hGIF)
00081 {
00082 if (m_bAutoFree)
00083 {
00084 GlobalFree (m_hGIF);
00085 m_bAutoFree = FALSE;
00086 }
00087 m_hGIF = NULL;
00088 }
00089 m_vFramesInfo.clear ();
00090 }
00091
00092 void vmsAnimatedGIF::ResetDataPointer()
00093 {
00094
00095 m_nCurrOffset =
00096 sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize;
00097 }
00098
00099 BOOL vmsAnimatedGIF::SkipNextGraphicBlock()
00100 {
00101 if (!m_pRawData) return FALSE;
00102
00103
00104
00105 enum GIFBlockTypes nBlock;
00106
00107 nBlock = GetNextBlock();
00108
00109 while ((nBlock != BLOCK_CONTROLEXT) &&
00110 (nBlock != BLOCK_IMAGE) &&
00111 (nBlock != BLOCK_PLAINTEXT) &&
00112 (nBlock != BLOCK_UNKNOWN) &&
00113 (nBlock != BLOCK_TRAILER) )
00114 {
00115 LOG ("GIF: m_nCurrOffset = " << (DWORD)m_nCurrOffset << nl);
00116
00117 if (!SkipNextBlock()) return NULL;
00118
00119 LOG ("GIF: m_nCurrOffset = " << (DWORD)m_nCurrOffset << nl);
00120
00121 nBlock = GetNextBlock();
00122
00123 LOG ("GIF: m_nCurrOffset = " << (DWORD)m_nCurrOffset << nl);
00124 };
00125
00126 if ((nBlock == BLOCK_UNKNOWN) ||
00127 (nBlock == BLOCK_TRAILER))
00128 return FALSE;
00129
00130
00131
00132 if (GetNextBlockLen() <= 0) return FALSE;
00133
00134 LOG ("m_nDataSize = " << (DWORD)m_nDataSize << nl);
00135 LOG ("m_nGlobalCTSize = " << (DWORD)m_nGlobalCTSize << nl);
00136
00137 LOG ("GIF: m_nCurrOffset = " << (DWORD)m_nCurrOffset << nl);
00138
00139 if (nBlock == BLOCK_CONTROLEXT)
00140 {
00141 if (!SkipNextBlock()) return FALSE;
00142 nBlock = GetNextBlock();
00143
00144
00145 while ((nBlock != BLOCK_IMAGE) &&
00146 (nBlock != BLOCK_PLAINTEXT) &&
00147 (nBlock != BLOCK_UNKNOWN) &&
00148 (nBlock != BLOCK_TRAILER) )
00149 {
00150 if (!SkipNextBlock()) return NULL;
00151 nBlock = GetNextBlock();
00152 };
00153
00154 if ((nBlock == BLOCK_UNKNOWN) ||
00155 (nBlock == BLOCK_TRAILER))
00156 return FALSE;
00157 };
00158
00159
00160 if (!SkipNextBlock()) return FALSE;
00161
00162 return TRUE;
00163 }
00164
00165 vmsAnimatedGIF::GIFBlockTypes vmsAnimatedGIF::GetNextBlock()
00166 {
00167 switch(m_pRawData[m_nCurrOffset])
00168 {
00169 case 0x21:
00170
00171 switch(m_pRawData[m_nCurrOffset+1])
00172 {
00173 case 0x01:
00174
00175 return BLOCK_PLAINTEXT;
00176 break;
00177
00178 case 0xF9:
00179
00180 return BLOCK_CONTROLEXT;
00181 break;
00182
00183 case 0xFE:
00184
00185 return BLOCK_COMMEXT;
00186 break;
00187
00188 case 0xFF:
00189
00190 return BLOCK_APPEXT;
00191 break;
00192 };
00193 break;
00194
00195 case 0x3B:
00196
00197 return BLOCK_TRAILER;
00198 break;
00199
00200 case 0x2C:
00201
00202 return BLOCK_IMAGE;
00203 break;
00204 };
00205
00206 return BLOCK_UNKNOWN;
00207 }
00208
00209 BOOL vmsAnimatedGIF::SkipNextBlock()
00210 {
00211 if (!m_pRawData) return FALSE;
00212
00213 int nLen = GetNextBlockLen();
00214 if ((nLen <= 0) || ((m_nCurrOffset+nLen) > m_nDataSize))
00215 return FALSE;
00216
00217 m_nCurrOffset += nLen;
00218 return TRUE;
00219 }
00220
00221 int vmsAnimatedGIF::GetNextBlockLen()
00222 {
00223 GIFBlockTypes nBlock = GetNextBlock();
00224
00225 int nTmp;
00226
00227 switch(nBlock)
00228 {
00229 case BLOCK_UNKNOWN:
00230 return -1;
00231 break;
00232
00233 case BLOCK_TRAILER:
00234 return 1;
00235 break;
00236
00237 case BLOCK_APPEXT:
00238 nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFAppExtension));
00239 if (nTmp > 0)
00240 return sizeof(TGIFAppExtension)+nTmp;
00241 break;
00242
00243 case BLOCK_COMMEXT:
00244 nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFCommentExt));
00245 if (nTmp > 0)
00246 return sizeof(TGIFCommentExt)+nTmp;
00247 break;
00248
00249 case BLOCK_CONTROLEXT:
00250 return sizeof(TGIFControlExt);
00251 break;
00252
00253 case BLOCK_PLAINTEXT:
00254 nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFPlainTextExt));
00255 if (nTmp > 0)
00256 return sizeof(TGIFPlainTextExt)+nTmp;
00257 break;
00258
00259 case BLOCK_IMAGE:
00260 TGIFImageDescriptor *pIDescr =
00261 reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);
00262 int nLCTSize = (int)
00263 (pIDescr->GetPackedValue(ID_PACKED_LOCALCT)*3*
00264 pow(2,pIDescr->GetPackedValue(ID_PACKED_LOCALCTSIZE)+1));
00265
00266 int nTmp = GetSubBlocksLen(m_nCurrOffset+
00267 sizeof(TGIFImageDescriptor) + nLCTSize + 1);
00268 if (nTmp > 0)
00269 return sizeof(TGIFImageDescriptor) + nLCTSize + 1 + nTmp;
00270 break;
00271 };
00272
00273 return 0;
00274 }
00275
00276 UINT vmsAnimatedGIF::GetSubBlocksLen(UINT nStartingOffset)
00277 {
00278 UINT nRet = 0;
00279 UINT nCurOffset = nStartingOffset;
00280
00281 while (m_pRawData[nCurOffset] != 0)
00282 {
00283 nRet += m_pRawData[nCurOffset]+1;
00284 nCurOffset += m_pRawData[nCurOffset]+1;
00285 };
00286
00287 return nRet+1;
00288 }
00289
00290 inline int vmsAnimatedGIF::TGIFControlExt::GetPackedValue(enum vmsAnimatedGIF::ControlExtValues Value)
00291 {
00292 int nRet = (int)m_cPacked;
00293 switch (Value)
00294 {
00295 case GCX_PACKED_DISPOSAL:
00296 nRet = (nRet & 28) >> 2;
00297 break;
00298
00299 case GCX_PACKED_USERINPUT:
00300 nRet = (nRet & 2) >> 1;
00301 break;
00302
00303 case GCX_PACKED_TRANSPCOLOR:
00304 nRet &= 1;
00305 break;
00306 };
00307
00308 return nRet;
00309 }
00310
00311 inline int vmsAnimatedGIF::TGIFLSDescriptor::GetPackedValue(enum LSDPackedValues Value)
00312 {
00313 int nRet = (int)m_cPacked;
00314
00315 switch (Value)
00316 {
00317 case LSD_PACKED_GLOBALCT:
00318 nRet = nRet >> 7;
00319 break;
00320
00321 case LSD_PACKED_CRESOLUTION:
00322 nRet = ((nRet & 0x70) >> 4) + 1;
00323 break;
00324
00325 case LSD_PACKED_SORT:
00326 nRet = (nRet & 8) >> 3;
00327 break;
00328
00329 case LSD_PACKED_GLOBALCTSIZE:
00330 nRet &= 7;
00331 break;
00332 };
00333
00334 return nRet;
00335 }
00336
00337 inline int vmsAnimatedGIF::TGIFImageDescriptor::GetPackedValue(enum IDPackedValues Value)
00338 {
00339 int nRet = (int)m_cPacked;
00340
00341 switch (Value)
00342 {
00343 case ID_PACKED_LOCALCT:
00344 nRet >>= 7;
00345 break;
00346
00347 case ID_PACKED_INTERLACE:
00348 nRet = ((nRet & 0x40) >> 6);
00349 break;
00350
00351 case ID_PACKED_SORT:
00352 nRet = (nRet & 0x20) >> 5;
00353 break;
00354
00355 case ID_PACKED_LOCALCTSIZE:
00356 nRet &= 7;
00357 break;
00358 };
00359
00360 return nRet;
00361 }
00362
00363 HGLOBAL vmsAnimatedGIF::GetNextGraphicBlock(UINT *pBlockLen, UINT *pDelay, SIZE *pBlockSize, SIZE *pBlockOffset, UINT *pDisposal)
00364 {
00365 if (!m_pRawData) return NULL;
00366
00367
00368
00369 *pDisposal = 0;
00370 enum GIFBlockTypes nBlock;
00371 nBlock = GetNextBlock();
00372
00373 while (
00374 (nBlock != BLOCK_CONTROLEXT) &&
00375 (nBlock != BLOCK_IMAGE) &&
00376 (nBlock != BLOCK_PLAINTEXT) &&
00377 (nBlock != BLOCK_UNKNOWN) &&
00378 (nBlock != BLOCK_TRAILER)
00379 )
00380 {
00381 if (!SkipNextBlock()) return NULL;
00382 nBlock = GetNextBlock();
00383 };
00384
00385 if ((nBlock == BLOCK_UNKNOWN) ||
00386 (nBlock == BLOCK_TRAILER))
00387 return NULL;
00388
00389
00390
00391 int nStart = m_nCurrOffset;
00392 int nBlockLen = GetNextBlockLen();
00393
00394 if (nBlockLen <= 0) return NULL;
00395
00396 if (nBlock == BLOCK_CONTROLEXT)
00397 {
00398
00399 TGIFControlExt *pControl =
00400 reinterpret_cast<TGIFControlExt *> (&m_pRawData[m_nCurrOffset]);
00401
00402 *pDelay = pControl->m_wDelayTime;
00403
00404 *pDisposal = pControl->GetPackedValue(GCX_PACKED_DISPOSAL);
00405
00406 if (!SkipNextBlock()) return NULL;
00407 nBlock = GetNextBlock();
00408
00409
00410
00411
00412 while (
00413 (nBlock != BLOCK_IMAGE) &&
00414 (nBlock != BLOCK_PLAINTEXT) &&
00415 (nBlock != BLOCK_UNKNOWN) &&
00416 (nBlock != BLOCK_TRAILER)
00417 )
00418 {
00419 if (!SkipNextBlock()) return NULL;
00420 nBlock = GetNextBlock();
00421 nBlockLen += GetNextBlockLen();
00422 };
00423
00424 if ((nBlock == BLOCK_UNKNOWN) || (nBlock == BLOCK_TRAILER))
00425 return NULL;
00426 nBlockLen += GetNextBlockLen();
00427 }
00428 else
00429 *pDelay = (UINT)-1;
00430
00431 if (nBlock == BLOCK_IMAGE)
00432 {
00433
00434 TGIFImageDescriptor *pImage =
00435 reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);
00436 pBlockSize->cx = pImage->m_wWidth;
00437 pBlockSize->cy = pImage->m_wHeight;
00438 pBlockOffset->cx = pImage->m_wLeftPos;
00439 pBlockOffset->cy = pImage->m_wTopPos;
00440 };
00441
00442 if (!SkipNextBlock()) return NULL;
00443
00444 HGLOBAL hGlobal = GlobalAlloc(GMEM_FIXED,
00445 sizeof(TGIFHeader) +
00446 sizeof(TGIFLSDescriptor) +
00447 m_nGlobalCTSize +
00448 nBlockLen +
00449 1);
00450
00451 if (!hGlobal) return NULL;
00452
00453 int nOffset = 0;
00454
00455
00456 unsigned char *pGlobal = reinterpret_cast<unsigned char *> (hGlobal);
00457
00458 CopyMemory(pGlobal,m_pRawData,
00459 sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize);
00460 nOffset += sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize;
00461
00462 CopyMemory(pGlobal + nOffset,&m_pRawData[nStart], nBlockLen);
00463 nOffset += nBlockLen;
00464
00465 pGlobal[nOffset] = 0x3B;
00466 nOffset++;
00467
00468 *pBlockLen = nOffset;
00469
00470 return hGlobal;
00471 }
00472
00473 int vmsAnimatedGIF::SaveGIFFrames(LPCSTR pszFileTemplate)
00474 {
00475 UINT nBlockLen;
00476 HGLOBAL hFrameData;
00477 UINT nCurFrame = 0;
00478 TFrame frame;
00479
00480 m_pRawData = (LPBYTE) GlobalLock (m_hGIF);
00481 m_vFramesInfo.clear ();
00482
00483 ResetDataPointer();
00484 while ((hFrameData = GetNextGraphicBlock(&nBlockLen,
00485 &frame.m_nDelay, &frame.m_frameSize,
00486 &frame.m_frameOffset, &frame.m_nDisposal)) != NULL)
00487 {
00488 char szFile [MY_MAX_PATH];
00489 wsprintf (szFile, pszFileTemplate, nCurFrame);
00490 if (FALSE == WriteDataOnDisk (szFile, hFrameData, nBlockLen))
00491 break;
00492
00493 m_vFramesInfo.push_back (frame);
00494 nCurFrame++;
00495 }
00496
00497 GlobalUnlock (m_hGIF);
00498 return nCurFrame;
00499 }
00500
00501 BOOL vmsAnimatedGIF::Load()
00502 {
00503 m_pRawData = (LPBYTE) GlobalLock (m_hGIF);
00504 if (m_pRawData == NULL)
00505 return FALSE;
00506
00507 m_pGIFHeader = (TGIFHeader*) m_pRawData;
00508
00509 if ((memcmp(&m_pGIFHeader->m_cSignature,"GIF", 3) != 0) &&
00510 ((memcmp(&m_pGIFHeader->m_cVersion,"87a", 3) != 0) ||
00511 (memcmp(&m_pGIFHeader->m_cVersion,"89a", 3) != 0)) )
00512 {
00513 GlobalUnlock (m_hGIF);
00514 return FALSE;
00515 }
00516
00517 m_pGIFLSDescriptor = (TGIFLSDescriptor*) (m_pRawData + sizeof (TGIFHeader));
00518
00519 if (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT) == 1)
00520 {
00521
00522 m_nGlobalCTSize = static_cast<int>
00523 (3*pow(2,m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE)+1));
00524
00525 unsigned char *pBkClr = m_pRawData + sizeof(TGIFHeader) +
00526 sizeof(TGIFLSDescriptor) + 3*m_pGIFLSDescriptor->m_cBkIndex;
00527 m_clrBackground = RGB(pBkClr[0],pBkClr[1],pBkClr[2]);
00528 };
00529
00530
00531 m_PictureSize.cx = m_pGIFLSDescriptor->m_wWidth;
00532 m_PictureSize.cy = m_pGIFLSDescriptor->m_wHeight;
00533
00534
00535 UINT nFrameCount=0;
00536 ResetDataPointer();
00537 while (SkipNextGraphicBlock())
00538 nFrameCount++;
00539
00540 GlobalUnlock (m_hGIF);
00541
00542 if (nFrameCount < 2)
00543 {
00544 m_pRawData = NULL;
00545 return FALSE;
00546 };
00547
00548 return TRUE;
00549 }
00550
00551 BOOL vmsAnimatedGIF::WriteDataOnDisk(LPCSTR pszFile, HGLOBAL hData, DWORD dwSize)
00552 {
00553 HANDLE hFile = CreateFile (pszFile, GENERIC_WRITE, 0, NULL,
00554 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
00555 if (hFile == INVALID_HANDLE_VALUE)
00556 return FALSE;
00557
00558 LPBYTE pData = (LPBYTE) GlobalLock (hData);
00559 if (pData == NULL)
00560 return FALSE;
00561
00562 DWORD dw;
00563 BOOL b = WriteFile (hFile, pData, dwSize, &dw, NULL);
00564
00565 CloseHandle (hFile);
00566 GlobalUnlock (hData);
00567
00568 return b;
00569 }
00570
00571 vmsAnimatedGIF::TFrame* vmsAnimatedGIF::get_FrameInfo(int iIndex)
00572 {
00573 return &m_vFramesInfo [iIndex];
00574 }