pictureex.cpp

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

CPP
1,294
字号
  ::DeleteDC(m_hMemDC);
  ::DeleteObject(m_hBitmap);
  m_hMemDC  = NULL;
  m_hBitmap = NULL;
 };

 if (m_hDispMemDC)
 {
  SelectObject(m_hDispMemDC,m_hDispOldBM);
  ::DeleteDC(m_hDispMemDC);
  ::DeleteObject(m_hDispMemBM);
  m_hDispMemDC  = NULL;
  m_hDispMemBM = NULL;
 };

 SetRect(&m_PaintRect,0,0,0,0);
 m_pGIFLSDescriptor = NULL;
 m_pGIFHeader    = NULL;
 m_pRawData     = NULL;
 m_hThread     = NULL;
 m_bIsInitialized   = FALSE;
 m_bExitThread    = FALSE;
 m_bIsGIF     = FALSE;
 m_clrBackground    = RGB(255,255,255); // white by default
 m_nGlobalCTSize    = 0;
 m_nCurrOffset    = 0;
 m_nCurrFrame    = 0;
 m_nDataSize     = 0;
}

BOOL CPictureEx::Draw()
{
 if (!m_bIsInitialized)
 {
  TRACE(_T("Call one of the CPictureEx::Load() member functions before calling Draw()\n"));
  return FALSE;
 };

 if (IsAnimatedGIF())
 {
 // the picture needs animation
 // we'll start the thread that will handle it for us
 
  unsigned int nDummy;
  m_hThread = (HANDLE) _beginthreadex(NULL,0,_ThreadAnimation,this,
   CREATE_SUSPENDED,&nDummy);
  if (!m_hThread)
  {
   TRACE(_T("Draw: Couldn't start a GIF animation thread\n"));
   return FALSE;
  } 
  else 
   ResumeThread(m_hThread);
 } 
 else
 {
  if (m_pPicture)
  {
   long hmWidth;
   long hmHeight;
   m_pPicture->get_Width(&hmWidth);
   m_pPicture->get_Height(&hmHeight);
   if (m_pPicture->Render(m_hMemDC, 0, 0, m_PictureSize.cx, m_PictureSize.cy, 
    0, hmHeight, hmWidth, -hmHeight, NULL) == S_OK)
   {
    Invalidate(FALSE);
    return TRUE;
   };
  };
 };

 return FALSE; 
}

SIZE CPictureEx::GetSize() const
{
 return m_PictureSize;
}

BOOL CPictureEx::Load(LPCTSTR szFileName)
{
 ASSERT(szFileName);
 
 CFile file;
 HGLOBAL hGlobal;
 DWORD dwSize;

 if (!file.Open(szFileName,
    CFile::modeRead | 
    CFile::shareDenyWrite) )
 {
  TRACE(_T("Load (file): Error opening file %s\n"),szFileName);
  return FALSE;
 };

 dwSize = file.GetLength();
 hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD,dwSize);
 if (!hGlobal)
 {
  TRACE(_T("Load (file): Error allocating memory\n"));
  return FALSE;
 };
 
 char *pData = reinterpret_cast<char*>(GlobalLock(hGlobal));
 if (!pData)
 {
  TRACE(_T("Load (file): Error locking memory\n"));
  GlobalFree(hGlobal);
  return FALSE;
 };

 TRY
 {
  file.Read(pData,dwSize);
 }
 CATCH(CFileException, e);                                          
 {
  TRACE(_T("Load (file): An exception occured while reading the file %s\n"),
   szFileName);
  GlobalFree(hGlobal);
  e->Delete();
  file.Close();
  return FALSE;
 }
 END_CATCH
 GlobalUnlock(hGlobal);
 file.Close();

 BOOL bRetValue = Load(hGlobal,dwSize);
 GlobalFree(hGlobal);
 return bRetValue;
}

BOOL CPictureEx::Load(LPCTSTR szResourceName, LPCTSTR szResourceType)
{
 ASSERT(szResourceName);
 ASSERT(szResourceType);

 HRSRC hPicture = FindResource(AfxGetResourceHandle(),szResourceName,szResourceType);
 HGLOBAL hResData;
 if (!hPicture || !(hResData = LoadResource(AfxGetResourceHandle(),hPicture)))
 {
  TRACE(_T("Load (resource): Error loading resource %s\n"),szResourceName);
  return FALSE;
 };
 DWORD dwSize = SizeofResource(AfxGetResourceHandle(),hPicture);

 // hResData is not the real HGLOBAL (we can't lock it)
 // let's make it real

 HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD,dwSize);
 if (!hGlobal)
 {
  TRACE(_T("Load (resource): Error allocating memory\n"));
  FreeResource(hResData);
  return FALSE;
 };
 
 char *pDest = reinterpret_cast<char *> (GlobalLock(hGlobal));
 char *pSrc = reinterpret_cast<char *> (LockResource(hResData));
 if (!pSrc || !pDest)
 {
  TRACE(_T("Load (resource): Error locking memory\n"));
  GlobalFree(hGlobal);
  FreeResource(hResData);
  return FALSE;
 };
 CopyMemory(pDest,pSrc,dwSize);
 FreeResource(hResData);
 GlobalUnlock(hGlobal);

 BOOL bRetValue = Load(hGlobal,dwSize);
 GlobalFree(hGlobal);
 return bRetValue;
}

void CPictureEx::ResetDataPointer()
{
 // skip header and logical screen descriptor
 m_nCurrOffset = 
  sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize;
}

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

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

 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 FALSE;

 // it's 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() doesn't 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 what's 
  // 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,

⌨️ 快捷键说明

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