热门文章 | 热门软件| 热门源码 | 热门电影 | 知识库 | 联系我们
软件 源码 教程 影视 健康 招聘
  HTML | JavaScript | ASP | PHP | JSP | NET | VB | VC | VF | Windows | Linux | Mysql | Mssql | Oracle | Struts 
当前位置: 创世纪计算机资源网 -> 文章频道 ->vc 
站内搜索:
PictureEx.h和PictureEx.cpp源文件(3)
作者:loose_went 来源:VC在线 整理日期:2007-10-26

 {
  if (!SkipNextBlock()) return NULL;
  nBlock = GetNextBlock();
 };

 if ((nBlock == BLOCK_UNKNOWN) ||
  (nBlock == BLOCK_TRAILER))
  return FALSE;

 // its either a control ext.block, an image or a plain text

 if (GetNextBlockLen() <= 0) return FALSE;

 if (nBlock == BLOCK_CONTROLEXT)
 {
  if (!SkipNextBlock()) return FALSE;
  nBlock = GetNextBlock();

  // skip everything until we meet an image block or a plain-text block
  while ((nBlock != BLOCK_IMAGE) &&
      (nBlock != BLOCK_PLAINTEXT) &&
      (nBlock != BLOCK_UNKNOWN) &&
      (nBlock != BLOCK_TRAILER) )
  {
   if (!SkipNextBlock()) return NULL;
   nBlock = GetNextBlock();
  };

  if ((nBlock == BLOCK_UNKNOWN) ||
   (nBlock == BLOCK_TRAILER))
   return FALSE;
 };

 // skip the found data block (image or plain-text)
 if (!SkipNextBlock()) return FALSE;

 return TRUE;
}

UINT CPictureEx::GetSubBlocksLen(UINT nStartingOffset) const
{
 UINT nRet = 0;
 UINT nCurOffset = nStartingOffset;
 
 while (m_pRawData[nCurOffset] != 0)
 {
  nRet += m_pRawData[nCurOffset]+1;
  nCurOffset += m_pRawData[nCurOffset]+1;
 };

 return nRet+1;
}

enum CPictureEx::GIFBlockTypes CPictureEx::GetNextBlock() const
{
 switch(m_pRawData[m_nCurrOffset])
 {
 case 0x21:
 // extension block
  switch(m_pRawData[m_nCurrOffset+1])
  {
  case 0x01:
  // plain text extension
   return BLOCK_PLAINTEXT;
   break;

  case 0xF9:
  // graphic control extension
   return BLOCK_CONTROLEXT;
   break;

  case 0xFE:
  // comment extension
   return BLOCK_COMMEXT;
   break;

  case 0xFF:
  // application extension
   return BLOCK_APPEXT;
   break;
  };
  break;
 
 case 0x3B:
 // trailer
  return BLOCK_TRAILER;
  break;

 case 0x2C:
 // image data
  return BLOCK_IMAGE;
  break;
 };

 return BLOCK_UNKNOWN;
}

BOOL CPictureEx::SkipNextBlock()
{
 if (!m_pRawData) return FALSE;

 int nLen = GetNextBlockLen();
 if ((nLen <= 0) || ((m_nCurrOffset+nLen) > m_nDataSize))
  return FALSE;

 m_nCurrOffset += nLen;
 return TRUE;
}

int CPictureEx::GetNextBlockLen() const
{
 GIFBlockTypes nBlock = GetNextBlock();

 int nTmp;

 switch(nBlock)
 {
 case BLOCK_UNKNOWN:
  return -1;
  break;

 case BLOCK_TRAILER:
  return 1;
  break;

 case BLOCK_APPEXT:
  nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFAppExtension));
  if (nTmp > 0)
   return sizeof(TGIFAppExtension)+nTmp;
  break;

 case BLOCK_COMMEXT:
  nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFCommentExt));
  if (nTmp > 0)
   return sizeof(TGIFCommentExt)+nTmp;
  break;

 case BLOCK_CONTROLEXT:
  return sizeof(TGIFControlExt);
  break;

 case BLOCK_PLAINTEXT:
  nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFPlainTextExt));
  if (nTmp > 0)
   return sizeof(TGIFPlainTextExt)+nTmp;
  break;

 case BLOCK_IMAGE:
  TGIFImageDescriptor *pIDescr =
   reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);
  int nLCTSize = (int)
   (pIDescr->GetPackedValue(ID_PACKED_LOCALCT)*3*
   (1 << (pIDescr->GetPackedValue(ID_PACKED_LOCALCTSIZE)+1)));

  int nTmp = GetSubBlocksLen(m_nCurrOffset+
   sizeof(TGIFImageDescriptor) + nLCTSize + 1);
  if (nTmp > 0)
   return sizeof(TGIFImageDescriptor) + nLCTSize + 1 + nTmp;
  break;
 };

 return 0;
}

UINT WINAPI CPictureEx::_ThreadAnimation(LPVOID pParam)
{
 ASSERT(pParam);
 CPictureEx *pPic = reinterpret_cast<CPictureEx *> (pParam);

 pPic->m_bIsPlaying = TRUE;
 pPic->ThreadAnimation();
 pPic->m_bIsPlaying = FALSE;

 // this thread has finished its work so we close the handle
 CloseHandle(pPic->m_hThread);
 // and init the handle to zero (so that Stop() doesnt Wait on it)
 pPic->m_hThread = 0;
 return 0;
}

void CPictureEx::ThreadAnimation()
{
 // first, restore background (for stop/draw support)
 // disposal method #2
 if (m_arrFrames[m_nCurrFrame].m_nDisposal == 2)
 {
  HBRUSH hBrush = CreateSolidBrush(m_clrBackground);
  if (hBrush)
  {
   RECT rect = {
    m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
    m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
    m_arrFrames[m_nCurrFrame].m_frameOffset.cx + m_arrFrames[m_nCurrFrame].m_frameSize.cx,
    m_arrFrames[m_nCurrFrame].m_frameOffset.cy + m_arrFrames[m_nCurrFrame].m_frameSize.cy };
   FillRect(m_hMemDC,&rect,hBrush);
   DeleteObject(hBrush);
  };
 }
 else
  // disposal method #3
  if (m_hDispMemDC && (m_arrFrames[m_nCurrFrame].m_nDisposal == 3) )
  {
   // put it back
   BitBlt(m_hMemDC,
    m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
    m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
    m_arrFrames[m_nCurrFrame].m_frameSize.cx,
    m_arrFrames[m_nCurrFrame].m_frameSize.cy,
    m_hDispMemDC,0,0, SRCCOPY);
   // init variables
   SelectObject(m_hDispMemDC,m_hDispOldBM);
   DeleteDC(m_hDispMemDC); m_hDispMemDC = NULL;
   DeleteObject(m_hDispMemBM); m_hDispMemBM = NULL;
  };

 while (!m_bExitThread)
 {
  if (m_arrFrames[m_nCurrFrame].m_pPicture)
  {
  ///////////////////////////////////////////////////////
  // Before rendering a frame we should take care of whats
  // behind that frame. TFrame::m_nDisposal will be our guide:
  //   0 - no disposal specified (do nothing)
  //   1 - do not dispose (again, do nothing)
  //   2 - restore to background color (m_clrBackground)
  //   3 - restore to previous

   //////// disposal method #3
   if (m_arrFrames[m_nCurrFrame].m_nDisposal == 3)
   {
    // prepare a memory DC and store the background in it
    m_hDispMemDC = CreateCompatibleDC(m_hMemDC);
    m_hDispMemBM = CreateCompatibleBitmap(m_hMemDC,
       m_arrFrames[m_nCurrFrame].m_frameSize.cx,
       m_arrFrames[m_nCurrFrame].m_frameSize.cy);
   
    if (m_hDispMemDC && m_hDispMemBM)
    {
     m_hDispOldBM = reinterpret_cast<HBITMAP> (SelectObject(m_hDispMemDC,m_hDispMemBM));
     BitBlt(m_hDispMemDC,0,0,
      m_arrFrames[m_nCurrFrame].m_frameSize.cx,
      m_arrFrames[m_nCurrFrame].m_frameSize.cy,
      m_hMemDC,
      m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
      m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
      SRCCOPY);
    };
   };
   ///////////////////////

   long hmWidth;
   long hmHeight;
   m_arrFrames[m_nCurrFrame].m_pPicture->get_Width(&hmWidth);
   m_arrFrames[m_nCurrFrame].m_pPicture->get_Height(&hmHeight);

   if (m_arrFrames[m_nCurrFrame].m_pPicture->Render(m_hMemDC,
    m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
    m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
    m_arrFrames[m_nCurrFrame].m_frameSize.cx,
    m_arrFrames[m_nCurrFrame].m_frameSize.cy,
    0, hmHeight, hmWidth, -hmHeight, NULL) == S_OK)
   {
    Invalidate(FALSE);
   };
  
   if (m_bExitThread) break;

   // if the delay time is too short (like in old GIFs), wait for 100ms
   if (m_arrFrames[m_nCurrFrame].m_nDelay < 5)
    WaitForSingleObject(m_hExitEvent, 100);
   else
    WaitForSingleObject(m_hExitEvent, 10*m_arrFrames[m_nCurrFrame].m_nDelay);

   if (m_bExitThread) break;

   // disposal method #2
,   if (m_arrFrames[m_nCurrFrame].m_nDisposal == 2)
   {
    HBRUSH hBrush = CreateSolidBrush(m_clrBackground);
    if (hBrush)
    {
     RECT rect = {
      m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
      m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
      m_arrFrames[m_nCurrFrame].m_frameOffset.cx + m_arrFrames[m_nCurrFrame].m_frameSize.cx,
      m_arrFrames[m_nCurrFrame].m_frameOffset.cy + m_arrFrames[m_nCurrFrame].m_frameSize.cy };
     FillRect(m_hMemDC,&rect,hBrush);
     DeleteObject(hBrush);
    };
   }
   else
    if (m_hDispMemDC && (m_arrFrames[m_nCurrFrame].m_nDisposal == 3) )
    {
     // put it back
     BitBlt(m_hMemDC,
      m_arrFrames[m_nCurrFrame].m_frameOffset.cx,
      m_arrFrames[m_nCurrFrame].m_frameOffset.cy,
      m_arrFrames[m_nCurrFrame].m_frameSize.cx,
      m_arrFrames[m_nCurrFrame].m_frameSize.cy,
      m_hDispMemDC,0,0, SRCCOPY);
     // init variables
     SelectObject(m_hDispMemDC,m_hDispOldBM);
     DeleteDC(m_hDispMemDC); m_hDispMemDC = NULL;
     DeleteObject(m_hDispMemBM); m_hDispMemBM = NULL;
    };
  };
  m_nCurrFrame++;
  if (m_nCurrFrame == m_arrFrames.size())
  {
   m_nCurrFrame
    = 0;
  // init the screen for the first frame,
   HBRUSH hBrush = CreateSolidBrush(m_clrBackground);
   if (hBrush)
   {
    RECT rect = {0,0,m_PictureSize.cx,m_PictureSize.cy};
    FillRect(m_hMemDC,&rect,hBrush);
    DeleteObject(hBrush);
   };
  };
 };
}

void CPictureEx::Stop()
{
 m_bIsPlaying = FALSE;
 m_bExitThread = TRUE;
 SetEvent(m_hExitEvent);
 if (m_hThread)
 {
  // well wait for 5 seconds then continue execution
  WaitForSingleObject(m_hThread,5000);
  CloseHandle(m_hThread);
  m_hThread = NULL;
 }

 // make it possible to Draw() again
 ResetEvent(m_hExitEvent);
 m_bExitThread = FALSE;
}

HGLOBAL CPictureEx::GetNextGraphicBlock(UINT *pBlockLen,
 UINT *pDelay, SIZE *pBlockSize, SIZE *pBlockOffset,
 UINT *pDisposal)
{
 if (!m_pRawData) return NULL;

 // GIF header + LSDescriptor [+ GCT] [+ Control block] + Data

 *pDisposal = 0;
 enum GIFBlockTypes nBlock;
 nBlock = GetNextBlock();

 while (
  (nBlock != BLOCK_CONTROLEXT) &&
  (nBlock != BLOCK_IMAGE) &&
  (nBlock != BLOCK_PLAINTEXT) &&
  (nBlock != BLOCK_UNKNOWN) &&
  (nBlock != BLOCK_TRAILER)
  )
 {
  if (!SkipNextBlock()) return NULL;
  nBlock = GetNextBlock();
 };

 if ((nBlock == BLOCK_UNKNOWN) ||
  (nBlock == BLOCK_TRAILER))
  return NULL;

 // its either a control ext.block, an image or a plain text

 int nStart = m_nCurrOffset;
 int nBlockLen = GetNextBlockLen();

 if (nBlockLen <= 0) return NULL;

 if (nBlock == BLOCK_CONTROLEXT)
 {
  // get the following data
  TGIFControlExt *pControl =
   reinterpret_cast<TGIFControlExt *> (&m_pRawData[m_nCurrOffset]);
  // store delay time
  *pDelay = pControl->m_wDelayTime;
  // store disposal method
  *pDisposal = pControl->GetPackedValue(GCX_PACKED_DISPOSAL);

  if (!SkipNextBlock()) return NULL;
  nBlock = GetNextBlock();
 
  // skip everything until we find data to display
  // (image block or plain-text block)
 
  while (
   (nBlock != BLOCK_IMAGE) &&
   (nBlock != BLOCK_PLAINTEXT) &&
   (nBlock != BLOCK_UNKNOWN) &&
   (nBlock != BLOCK_TRAILER)
   )
  {
   if (!SkipNextBlock()) return NULL;
   nBlock = GetNextBlock();
   nBlockLen += GetNextBlockLen();
  };

  if ((nBlock == BLOCK_UNKNOWN) || (nBlock == BLOCK_TRAILER))
   return NULL;
  nBlockLen += GetNextBlockLen();
 }
 else
  *pDelay = -1; // to indicate that there was no delay value

 if (nBlock == BLOCK_IMAGE)
 {
  // store size and offsets
  TGIFImageDescriptor *pImage =
   reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);
  pBlockSize->cx = pImage->m_wWidth;
  pBlockSize->cy = pImage->m_wHeight;
  pBlockOffset->cx = pImage->m_wLeftPos;
  pBlockOffset->cy = pImage->m_wTopPos;
 };

 if (!SkipNextBlock()) return NULL;

 HGLOBAL hGlobal = GlobalAlloc(GMEM_FIXED,
  sizeof(TGIFHeader) +
  sizeof(TGIFLSDescriptor) +
  m_nGlobalCTSize +
  nBlockLen +
  1);  // for the trailer

 if (!hGlobal) return NULL;

 int nOffset = 0;

 // GMEM_FIXED means we get a pointer
 unsigned char *pGlobal = reinterpret_cast<unsigned char *> (hGlobal);

 CopyMemory(pGlobal,m_pRawData,
  sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize);
 nOffset += sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize;

 CopyMemory(pGlobal + nOffset,&m_pRawData[nStart], nBlockLen);
 nOffset += nBlockLen;

 pGlobal[nOffset] = 0x3B; // trailer
 nOffset++;

 *pBlockLen = nOffset;

 return hGlobal;
}

BOOL CPictureEx::IsGIF() const
{
 return m_bIsGIF;
}

BOOL CPictureEx::IsAnimatedGIF() const
{
 return (m_bIsGIF && (m_arrFrames.size() > 1));
}

BOOL CPictureEx::IsPlaying() const
{
 return m_bIsPlaying;
}

int CPictureEx::GetFrameCount() const
{
 if (!IsAnimatedGIF())
  return 0;

 return m_arrFrames.size();
}

COLORREF CPictureEx::GetBkColor() const
{
 return m_clrBackground;
}

void CPictureEx::OnPaint()
{
 CPaintDC dc(this); // device context for painting

 LONG nPaintWidth = m_PaintRect.right-m_PaintRect.left;

 if (nPaintWidth > 0)
 {
  LONG nPaintHeight = m_PaintRect.bottom - m_PaintRect.top;
  ::BitBlt(dc.m_hDC, 0, 0, nPaintWidth, nPaintHeight,
   m_hMemDC, m_PaintRect.left, m_PaintRect.top, SRCCOPY);
 }
 else
 {
  ::BitBlt(dc.m_hDC, 0, 0, m_PictureSize.cx, m_PictureSize.cy,
   m_hMemDC, 0, 0, SRCCOPY);
 };
}

BOOL CPictureEx::PrepareDC(int nWidth, int nHeight)
{
 SetWindowPos(NULL,0,0,nWidth,nHeight,SWP_NOMOVE | SWP_NOZORDER);

 HDC hWinDC = ::GetDC(m_hWnd);
 if (!hWinDC) return FALSE;
 
 m_hMemDC = CreateCompatibleDC(hWinDC);
 if (!m_hMemDC)
 {
  ::ReleaseDC(m_hWnd,hWinDC);
  return FALSE;
 };

 m_hBitmap  = CreateCompatibleBitmap(hWinDC,nWidth,nHeight);
 if (!m_hBitmap)
 {
  ::ReleaseDC(m_hWnd,hWinDC);
  ::DeleteDC(m_hMemDC);
  return FALSE;
 };

 m_hOldBitmap = reinterpret_cast<HBITMAP>
      (SelectObject(m_hMemDC,m_hBitmap));
 
 // fill the background
 m_clrBackground = GetSysColor(COLOR_3DFACE);
 RECT rect = {0,0,nWidth,nHeight};
 FillRect(m_hMemDC,&rect,(HBRUSH)(COLOR_WINDOW));

 ::ReleaseDC(m_hWnd,hWinDC);
 m_bIsInitialized = TRUE;
 return TRUE;
}

void CPictureEx::OnDestroy()
{
 Stop();
 CStatic::OnDestroy();
}

void CPictureEx::SetBkColor(COLORREF clr)
{
 if (!m_bIsInitialized) return;

 m_clrBackground = clr;

 HBRUSH hBrush = CreateSolidBrush(clr);
 if (hBrush)
 {
  RECT rect = {0,0,m_PictureSize.cx,m_PictureSize.cy};
  FillRect(m_hMemDC,&rect,hBrush);
  DeleteObject(hBrush);
 };
}

#ifdef GIF_TRACING
void CPictureEx::WriteDataOnDisk(CString szFileName, HGLOBAL hData, DWORD dwSize)
{
 CFile file;

 if (!file.Open(szFileName,
   CFile::modeCreate |
   CFile::modeWrite |
   CFile::shareDenyNone))
 {
  TRACE(_T("WriteData: Error creating file %s\n"),szFileName);
  return;
 };

 char *pData = reinterpret_cast<char *> (GlobalLock(hData));
 if (!pData)
 {
  TRACE(_T("WriteData: Error locking memory\n"));
  return;
 };

 TRY
 {
  file.Write(pData,dwSize);
 }
 CATCH(CFileException, e);                                         
 {
  TRACE(_T("WriteData: An exception occured while writing to the file %s\n"),
   szFileName);
  e->Delete();
  GlobalUnlock(hData);
  file.Close();
  return;
 }
 END_CATCH
 
 GlobalUnlock(hData);
 file.Close();
}

void CPictureEx::EnumGIFBlocks()
{
 enum GIFBlockTypes nBlock;

 ResetDataPointer();
 while(m_nCurrOffset < m_nDataSize)
 {
  nBlock = GetNextBlock();
  switch(nBlock)
  {
  case BLOCK_UNKNOWN:
   TRACE(_T("- Unknown block\n"));
   return;
   break;

  case BLOCK_TRAILER:
   TRACE(_T("- Trailer block\n"));
   break;

  case BLOCK_APPEXT:
   TRACE(_T("- Application extension block\n"));
   break;

  case BLOCK_COMMEXT:
   TRACE(_T("- Comment extension block\n"));
   break;

  case BLOCK_CONTROLEXT:
   {
   TGIFControlExt *pControl =
    reinterpret_cast<TGIFControlExt *> (&m_pRawData[m_nCurrOffset]);
   TRACE(_T("- Graphic control extension block (delay %d, disposal %d)\n"),
     pControl->m_wDelayTime, pControl->GetPackedValue(GCX_PACKED_DISPOSAL));
   };
   break;

  case BLOCK_PLAINTEXT:
   TRACE(_T("- Plain text extension block\n"));
   break;

  case BLOCK_IMAGE:
   TGIFImageDescriptor *pIDescr =
    reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);
   TRACE(_T("- Image data block (%dx%d  %d,%d)\n"),
     pIDescr->m_wWidth,
     pIDescr->m_wHeight,
     pIDescr->m_wLeftPos,
     pIDescr->m_wTopPos);
   break;
  };

  SkipNextBlock();
 };

 TRACE(_T("\n"));
}
#endif // GIF_TRACING

BOOL CPictureEx::SetPaintRect(const RECT *lpRect)
{
 return CopyRect(&m_PaintRect, lpRect);
}

BOOL CPictureEx::GetPaintRect(RECT *lpRect)
{
 return CopyRect(lpRect, &m_PaintRect);
}
 


  希望能为大家提供方便。

[1]  [2]  [3]  
相关文章
暂无