pictureex.cpp

来自「仿造QQ聊天界面 超级相向 第一次作品 不足之处见谅」· C++ 代码 · 共 1,294 行 · 第 1/3 页

CPP
1,294
字号
       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)
 {
  // we'll 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;

 // it's 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);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?