vc中如何显示GIF动画

csdnchen 2004-08-25 09:11:04
vc中如何显示GIF动画,最好有例子或现成类
...全文
794 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
inwindfighter 2004-11-01
  • 打赏
  • 举报
回复
chenhq(chenhq),请您给我发一份好么,
inwind78@yahoo.com.cn
谢谢!
问道er 2004-08-26
  • 打赏
  • 举报
回复
哇靠,大家都用PictureEx啊!我也是,嘿嘿!
suisuibianbian 2004-08-26
  • 打赏
  • 举报
回复
支持chenhq(chenhq),很好用,这里是使用方法
http://www.gjwtech.com/vcandc/vc1loadgifpicture.htm
lfpsoft 2004-08-26
  • 打赏
  • 举报
回复
admin@soft520.com
谢谢!!
lqlq99612 2004-08-25
  • 打赏
  • 举报
回复
chenhq(chenhq),麻烦也发一个给我吧。

dsnnq@163.com
chenhq 2004-08-25
  • 打赏
  • 举报
回复
上面的程序完全了!!
bohut 2004-08-25
  • 打赏
  • 举报
回复
已发,查收!
xzchina 2004-08-25
  • 打赏
  • 举报
回复
哪位大虾给我发个例子!~~~~~再次感谢了!

       virus_jiangmin@163.com
bohut 2004-08-25
  • 打赏
  • 举报
回复
兄弟,贴完没有啊
chenhq 2004-08-25
  • 打赏
  • 举报
回复

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);
}

void CPictureEx::SetBkNoColor()
{
LOGBRUSH brush;
brush.lbColor = RGB(255,255,255);
brush.lbStyle = HS_CROSS;
brush.lbHatch = BS_HOLLOW;
HBRUSH hBrush = CreateBrushIndirect(&brush);
if (hBrush)
{
RECT rect = {0,0,m_PictureSize.cx,m_PictureSize.cy};
FillRect(m_hMemDC,&rect,hBrush);
DeleteObject(hBrush);
};
}
chenhq 2004-08-25
  • 打赏
  • 举报
回复

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,
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);
};
};
};
}
chenhq 2004-08-25
  • 打赏
  • 举报
回复

void CPictureEx::UnLoad()
{
Stop();
if (m_pPicture)
{
m_pPicture->Release();
m_pPicture = NULL;
};

std::vector<TFrame>::iterator it;
for (it=m_arrFrames.begin();it<m_arrFrames.end();it++)
(*it).m_pPicture->Release();
m_arrFrames.clear();

if (m_hMemDC)
{
SelectObject(m_hMemDC,m_hOldBitmap);
::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;
}
chenhq 2004-08-25
  • 打赏
  • 举报
回复

CPictureEx::~CPictureEx()
{
UnLoad();
CloseHandle(m_hExitEvent);
}

BEGIN_MESSAGE_MAP(CPictureEx, CStatic)
//{{AFX_MSG_MAP(CPictureEx)
ON_WM_DESTROY()
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL CPictureEx::Load(HGLOBAL hGlobal, DWORD dwSize)
{
IStream *pStream = NULL;
UnLoad();

if (!(m_pRawData = reinterpret_cast<unsigned char*> (GlobalLock(hGlobal))) )
{
TRACE(_T("Load: Error locking memory\n"));
return FALSE;
};

m_nDataSize = dwSize;
m_pGIFHeader = reinterpret_cast<TGIFHeader *> (m_pRawData);

if ((memcmp(&m_pGIFHeader->m_cSignature,"GIF",3) != 0) &&
((memcmp(&m_pGIFHeader->m_cVersion,"87a",3) != 0) ||
(memcmp(&m_pGIFHeader->m_cVersion,"89a",3) != 0)) )
{
// it's neither GIF87a nor GIF89a
// do the default processing

// clear GIF variables
m_pRawData = NULL;
GlobalUnlock(hGlobal);

// don't delete memory on object's release
if (CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK)
return FALSE;

if (OleLoadPicture(pStream,dwSize,FALSE,IID_IPicture,
reinterpret_cast<LPVOID *>(&m_pPicture)) != S_OK)
{
pStream->Release();
return FALSE;
};
pStream->Release();

// store picture's size

long hmWidth;
long hmHeight;
m_pPicture->get_Width(&hmWidth);
m_pPicture->get_Height(&hmHeight);

HDC hDC = ::GetDC(m_hWnd);
m_PictureSize.cx = MulDiv(hmWidth, GetDeviceCaps(hDC,LOGPIXELSX), 2540);
m_PictureSize.cy = MulDiv(hmHeight, GetDeviceCaps(hDC,LOGPIXELSY), 2540);
::ReleaseDC(m_hWnd,hDC);
}
else
{
// it's a GIF
m_bIsGIF = TRUE;
m_pGIFLSDescriptor = reinterpret_cast<TGIFLSDescriptor *>
(m_pRawData + sizeof(TGIFHeader));
if (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT) == 1)
{
// calculate the globat color table size
m_nGlobalCTSize = static_cast<int>
(3* (1 << (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE)+1)));
// get the background color if GCT is present
unsigned char *pBkClr = m_pRawData + sizeof(TGIFHeader) +
sizeof(TGIFLSDescriptor) + 3*m_pGIFLSDescriptor->m_cBkIndex;
m_clrBackground = RGB(pBkClr[0],pBkClr[1],pBkClr[2]);
};

// store the picture's size
m_PictureSize.cx = m_pGIFLSDescriptor->m_wWidth;
m_PictureSize.cy = m_pGIFLSDescriptor->m_wHeight;

// determine frame count for this picture
UINT nFrameCount=0;
ResetDataPointer();
while (SkipNextGraphicBlock())
nFrameCount++;

#ifdef GIF_TRACING
TRACE(
_T(" -= GIF encountered\n"
"Logical Screen dimensions = %dx%d\n"
"Global color table = %d\n"
"Color depth = %d\n"
"Sort flag = %d\n"
"Size of Global Color Table = %d\n"
"Background color index = %d\n"
"Pixel aspect ratio = %d\n"
"Frame count = %d\n"
"Background color = %06Xh\n\n"
),
m_pGIFLSDescriptor->m_wWidth,
m_pGIFLSDescriptor->m_wHeight,
m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT),
m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_CRESOLUTION),
m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_SORT),
m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE),
m_pGIFLSDescriptor->m_cBkIndex,
m_pGIFLSDescriptor->m_cPixelAspect,
nFrameCount,
m_clrBackground
);
EnumGIFBlocks();
#endif

if (nFrameCount == 0) // it's an empty GIF!
{
m_pRawData = NULL;
GlobalUnlock(hGlobal);
return FALSE;
};

// now check the frame count
// if there's only one frame, no need to animate this GIF
// therefore, treat it like any other pic

if (nFrameCount == 1)
{
// clear GIF variables
m_pRawData = NULL;
GlobalUnlock(hGlobal);

// don't delete memory on object's release
if (CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK)
return FALSE;

if (OleLoadPicture(pStream,dwSize,FALSE,IID_IPicture,
(LPVOID *)&m_pPicture) != S_OK)
{
pStream->Release();
return FALSE;
};

pStream->Release();
}
else
{
// if, on the contrary, there are several frames
// then store separate frames in an array

TFrame frame;
UINT nBlockLen;
HGLOBAL hFrameData;
UINT nCurFrame = 0;

ResetDataPointer();
while (hFrameData = GetNextGraphicBlock(&nBlockLen,
&frame.m_nDelay, &frame.m_frameSize,
&frame.m_frameOffset, &frame.m_nDisposal) )
{
#ifdef GIF_TRACING
//////////////////////////////////////////////
// uncomment the following strings if you want
// to write separate frames on disk
//
// CString szName;
// szName.Format(_T("%.4d.gif"),nCurFrame);
// WriteDataOnDisk(szName,hFrameData,nBlockLen);
// nCurFrame++;
#endif // GIF_TRACING

IStream *pStream = NULL;

// delete memory on object's release
if (CreateStreamOnHGlobal(hFrameData,TRUE,&pStream) != S_OK)
{
GlobalFree(hFrameData);
continue;
};

if (OleLoadPicture(pStream,nBlockLen,FALSE,
IID_IPicture,
reinterpret_cast<LPVOID *>(&frame.m_pPicture)) != S_OK)
{
pStream->Release();
continue;
};
pStream->Release();

// everything went well, add this frame
m_arrFrames.push_back(frame);
};

// clean after ourselves
m_pRawData = NULL;
GlobalUnlock(hGlobal);

if (m_arrFrames.empty()) // couldn't load any frames
return FALSE;
};
}; // if (!IsGIF...

return PrepareDC(m_PictureSize.cx,m_PictureSize.cy);
}
chenhq 2004-08-25
  • 打赏
  • 举报
回复
不好意思 CPP文件错了,正确的如下:
//////////////////////////////////////////////////////////////////////
// PictureEx.cpp: implementation of the CPictureEx class.
//
// Picture displaying control with support for the following formats:
// GIF (including animated GIF87a and GIF89a), JPEG, BMP, WMF, ICO, CUR
//
// Written by Oleg Bykov (oleg_bykoff@rsdn.ru)
// Copyright (c) 2001
//
// To use CPictureEx, follow these steps:
// - place a static control on your dialog (either a text or a bitmap)
// - change its identifier to something else (e.g. IDC_MYPIC)
// - associate a CStatic with it using ClassWizard
// - in your dialog's header file replace CStatic with CPictureEx
// (don't forget to #include "PictureEx.h" and add
// PictureEx.h and PictureEx.cpp to your project)
// - call one of the overloaded CPictureEx::Load() functions somewhere
// (OnInitDialog is a good place to start)
// - if the preceding Load() succeeded call Draw()
//
// You can also add the control by defining a member variable of type
// CPictureEx, calling CPictureEx::Create (derived from CStatic), then
// CPictureEx::Load and CPictureEx::Draw.
//
// By default, the control initializes its background to COLOR_3DFACE
// (see CPictureEx::PrepareDC()). You can change the background by
// calling CPictureEx::SetBkColor(COLORREF) after CPictureEx::Load().
//
// I decided to leave in the class the functions to write separate frames from
// animated GIF to disk. If you want to use them, uncomment #define GIF_TRACING
// and an appropriate section in CPictureEx::Load(HGLOBAL, DWORD). These functions
// won't be compiled and linked to your project unless you uncomment #define GIF_TRACING,
// so you don't have to worry.
//
// Warning: this code hasn't been subject to a heavy testing, so
// use it on your own risk. The author accepts no liability for the
// possible damage caused by this code.
//
// Version 1.0 7 Aug 2001
// Initial release
//
// Version 1.1 6 Sept 2001
// ATL version of the class
//
// Version 1.2 14 Oct 2001
// - Fixed a problem with loading GIFs from resources
// in MFC-version of the class for multi-modules apps.
// Thanks to Ruben Avila-Carretero for finding this out.
//
// - Got rid of waitable timer in ThreadAnimation()
// Now CPictureEx[Wnd] works in Win95 too.
// Thanks to Alex Egiazarov and Wayne King for the idea.
//
// - Fixed a visual glitch of using SetBkColor.
// Thanks to Kwangjin Lee for finding this out.
//
// Version 1.3 10 Nov 2001
// - Fixed a DC leak. One DC leaked per each UnLoad()
// (forgot to put a ReleaseDC() in the end of
// CPictureExWnd::PrepareDC() function).
//
// - Now it is possible to set a clipping rectangle using
// CPictureEx[Wnd]::SetPaintRect(const LPRECT) function.
// The LPRECT parameter tells the class what portion of
// a picture should it display. If the clipping rect is
// not set, the whole picture is shown.
// Thanks to Fabrice Rodriguez for the idea.
//
// - Added support for Stop/Draw. Now you can Stop() an
// animated GIF, then Draw() it again, it will continue
// animation from the frame it was stopped on. You can
// also know if a GIF is currently playing with the
// IsPlaying() function.
//
// - Got rid of math.h and made m_bExitThread volatile.
// Thanks to Piotr Sawicki for the suggestion.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "PictureEx.h"
#include <process.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Nested structures member functions
//////////////////////////////////////////////////////////////////////

inline int CPictureEx::TGIFControlExt::GetPackedValue(enum ControlExtValues Value)
{
int nRet = (int)m_cPacked;
switch (Value)
{
case GCX_PACKED_DISPOSAL:
nRet = (nRet & 28) >> 2;
break;

case GCX_PACKED_USERINPUT:
nRet = (nRet & 2) >> 1;
break;

case GCX_PACKED_TRANSPCOLOR:
nRet &= 1;
break;
};

return nRet;
}

inline int CPictureEx::TGIFLSDescriptor::GetPackedValue(enum LSDPackedValues Value)
{
int nRet = (int)m_cPacked;

switch (Value)
{
case LSD_PACKED_GLOBALCT:
nRet = nRet >> 7;
break;

case LSD_PACKED_CRESOLUTION:
nRet = ((nRet & 0x70) >> 4) + 1;
break;

case LSD_PACKED_SORT:
nRet = (nRet & 8) >> 3;
break;

case LSD_PACKED_GLOBALCTSIZE:
nRet &= 7;
break;
};

return nRet;
}

inline int CPictureEx::TGIFImageDescriptor::GetPackedValue(enum IDPackedValues Value)
{
int nRet = (int)m_cPacked;

switch (Value)
{
case ID_PACKED_LOCALCT:
nRet >>= 7;
break;

case ID_PACKED_INTERLACE:
nRet = ((nRet & 0x40) >> 6);
break;

case ID_PACKED_SORT:
nRet = (nRet & 0x20) >> 5;
break;

case ID_PACKED_LOCALCTSIZE:
nRet &= 7;
break;
};

return nRet;
}


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPictureEx::CPictureEx()
{
// check structures size
ASSERT(sizeof(TGIFImageDescriptor) == 10);
ASSERT(sizeof(TGIFAppExtension) == 14);
ASSERT(sizeof(TGIFPlainTextExt) == 15);
ASSERT(sizeof(TGIFLSDescriptor) == 7);
ASSERT(sizeof(TGIFControlExt) == 8);
ASSERT(sizeof(TGIFCommentExt) == 2);
ASSERT(sizeof(TGIFHeader) == 6);

m_pGIFLSDescriptor = NULL;
m_pGIFHeader = NULL;
m_pPicture = NULL;
m_pRawData = NULL;
m_hThread = NULL;
m_hBitmap = NULL;
m_hMemDC = NULL;

m_hDispMemDC = NULL;
m_hDispMemBM = NULL;
m_hDispOldBM = NULL;

m_bIsInitialized = FALSE;
m_bExitThread = FALSE;
m_bIsPlaying = 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;
m_PictureSize.cx = m_PictureSize.cy = 0;
SetRect(&m_PaintRect,0,0,0,0);

m_hExitEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
}

chenhq 2004-08-25
  • 打赏
  • 举报
回复
struct TGIFAppExtension // application extension block
{
unsigned char m_cExtIntroducer; // extension introducer (0x21)
unsigned char m_cExtLabel; // app. extension label (0xFF)
unsigned char m_cBlockSize; // fixed value of 11
char m_cAppIdentifier[8]; // application identifier
char m_cAppAuth[3]; // application authentication code
};

struct TGIFControlExt // graphic control extension block
{
unsigned char m_cExtIntroducer; // extension introducer (0x21)
unsigned char m_cControlLabel; // control extension label (0xF9)
unsigned char m_cBlockSize; // fixed value of 4
unsigned char m_cPacked; // packed field
WORD m_wDelayTime; // delay time
unsigned char m_cTColorIndex; // transparent color index
unsigned char m_cBlockTerm; // block terminator (0x00)
public:
inline int GetPackedValue(enum ControlExtValues Value);
};

struct TGIFCommentExt // comment extension block
{
unsigned char m_cExtIntroducer; // extension introducer (0x21)
unsigned char m_cCommentLabel; // comment extension label (0xFE)
};

struct TGIFPlainTextExt // plain text extension block
{
unsigned char m_cExtIntroducer; // extension introducer (0x21)
unsigned char m_cPlainTextLabel; // text extension label (0x01)
unsigned char m_cBlockSize; // fixed value of 12
WORD m_wLeftPos; // text grid left position
WORD m_wTopPos; // text grid top position
WORD m_wGridWidth; // text grid width
WORD m_wGridHeight; // text grid height
unsigned char m_cCellWidth; // character cell width
unsigned char m_cCellHeight; // character cell height
unsigned char m_cFgColor; // text foreground color index
unsigned char m_cBkColor; // text background color index
};

struct TGIFImageDescriptor // image descriptor block
{
unsigned char m_cImageSeparator; // image separator byte (0x2C)
WORD m_wLeftPos; // image left position
WORD m_wTopPos; // image top position
WORD m_wWidth; // image width
WORD m_wHeight; // image height
unsigned char m_cPacked; // packed field
inline int GetPackedValue(enum IDPackedValues Value);
};

#pragma pack() // turn byte alignment off

public:
void SetBkNoColor();
BOOL GetPaintRect(RECT *lpRect);
BOOL SetPaintRect(const RECT *lpRect);
CPictureEx();
virtual ~CPictureEx();
void Stop(); // stops animation
void UnLoad(); // stops animation plus releases all resources

BOOL IsGIF() const;
BOOL IsPlaying() const;
BOOL IsAnimatedGIF() const;
SIZE GetSize() const;
int GetFrameCount() const;
COLORREF GetBkColor() const;
void SetBkColor(COLORREF clr);

// draws the picture (starts an animation thread if needed)
// if an animation was previously stopped by Stop(),
// continues it from the last displayed frame
BOOL Draw();

// loads a picture from a file
// i.e. Load(_T("mypic.gif"));
BOOL Load(LPCTSTR szFileName);

// loads a picture from a global memory block (allocated by GlobalAlloc)
// Warning: this function DOES NOT free the global memory, pointed to by hGlobal
BOOL Load(HGLOBAL hGlobal, DWORD dwSize);

// loads a picture from a program resource
// i.e. Load(MAKEINTRESOURCE(IDR_MYPIC),_T("GIFTYPE"));
BOOL Load(LPCTSTR szResourceName,LPCTSTR szResourceType);

protected:

#ifdef GIF_TRACING
void EnumGIFBlocks();
void WriteDataOnDisk(CString szFileName, HGLOBAL hData, DWORD dwSize);
#endif // GIF_TRACING

RECT m_PaintRect;
SIZE m_PictureSize;
COLORREF m_clrBackground;
UINT m_nCurrFrame;
UINT m_nDataSize;
UINT m_nCurrOffset;
UINT m_nGlobalCTSize;
BOOL m_bIsGIF;
BOOL m_bIsPlaying;
volatile BOOL m_bExitThread;
BOOL m_bIsInitialized;
HDC m_hMemDC;

HDC m_hDispMemDC;
HBITMAP m_hDispMemBM;
HBITMAP m_hDispOldBM;

HBITMAP m_hBitmap;
HBITMAP m_hOldBitmap;
HANDLE m_hThread;
HANDLE m_hExitEvent;
IPicture * m_pPicture;
TGIFHeader * m_pGIFHeader;
unsigned char * m_pRawData;
TGIFLSDescriptor * m_pGIFLSDescriptor;
std::vector<TFrame> m_arrFrames;

void ThreadAnimation();
static UINT WINAPI _ThreadAnimation(LPVOID pParam);

int GetNextBlockLen() const;
BOOL SkipNextBlock();
BOOL SkipNextGraphicBlock();
BOOL PrepareDC(int nWidth, int nHeight);
void ResetDataPointer();
enum GIFBlockTypes GetNextBlock() const;
UINT GetSubBlocksLen(UINT nStartingOffset) const;
HGLOBAL GetNextGraphicBlock(UINT *pBlockLen, UINT *pDelay,
SIZE *pBlockSize, SIZE *pBlockOffset, UINT *pDisposal);

// Generated message map functions
//{{AFX_MSG(CPictureEx)
afx_msg void OnDestroy();
afx_msg void OnPaint();
//}}AFX_MSG

DECLARE_MESSAGE_MAP()
};

#endif // !defined(AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_)


使用范例
CPictureEx m_wndAnimation;

CRect rect;
GetClientRect(rect);
if(m_wndAnimation.GetSafeHwnd()==NULL)
{
m_wndAnimation.Create("",WS_CHILD|WS_VISIBLE,rect,this,1001);

if (m_wndAnimation.Load("Splash.gif"))
{
m_wndAnimation.SetBkColor(RGB(0,0,0));
m_wndAnimation.Draw();
}
}
rect.NormalizeRect();
m_wndAnimation.MoveWindow(rect);


chenhq 2004-08-25
  • 打赏
  • 举报
回复

CPP文件
//////////////////////////////////////////////////////////////////////
// PictureEx.cpp: implementation of the CPictureEx class.
//
// Picture displaying control with support for the following formats:
// GIF (including animated GIF87a and GIF89a), JPEG, BMP, WMF, ICO, CUR
//
// Written by Oleg Bykov (oleg_bykoff@rsdn.ru)
// Copyright (c) 2001
//
// To use CPictureEx, follow these steps:
// - place a static control on your dialog (either a text or a bitmap)
// - change its identifier to something else (e.g. IDC_MYPIC)
// - associate a CStatic with it using ClassWizard
// - in your dialog's header file replace CStatic with CPictureEx
// (don't forget to #include "PictureEx.h" and add
// PictureEx.h and PictureEx.cpp to your project)
// - call one of the overloaded CPictureEx::Load() functions somewhere
// (OnInitDialog is a good place to start)
// - if the preceding Load() succeeded call Draw()
//
// You can also add the control by defining a member variable of type
// CPictureEx, calling CPictureEx::Create (derived from CStatic), then
// CPictureEx::Load and CPictureEx::Draw.
//
// By default, the control initializes its background to COLOR_3DFACE
// (see CPictureEx::PrepareDC()). You can change the background by
// calling CPictureEx::SetBkColor(COLORREF) after CPictureEx::Load().
//
// I decided to leave in the class the functions to write separate frames from
// animated GIF to disk. If you want to use them, uncomment #define GIF_TRACING
// and an appropriate section in CPictureEx::Load(HGLOBAL, DWORD). These functions
// won't be compiled and linked to your project unless you uncomment #define GIF_TRACING,
// so you don't have to worry.
//
// Warning: this code hasn't been subject to a heavy testing, so
// use it on your own risk. The author accepts no liability for the
// possible damage caused by this code.
//
// Version 1.0 7 Aug 2001
// Initial release
//
// Version 1.1 6 Sept 2001
// ATL version of the class
//
// Version 1.2 14 Oct 2001
// - Fixed a problem with loading GIFs from resources
// in MFC-version of the class for multi-modules apps.
// Thanks to Ruben Avila-Carretero for finding this out.
//
// - Got rid of waitable timer in ThreadAnimation()
// Now CPictureEx[Wnd] works in Win95 too.
// Thanks to Alex Egiazarov and Wayne King for the idea.
//
// - Fixed a visual glitch of using SetBkColor.
// Thanks to Kwangjin Lee for finding this out.
//
// Version 1.3 10 Nov 2001
// - Fixed a DC leak. One DC leaked per each UnLoad()
// (forgot to put a ReleaseDC() in the end of
// CPictureExWnd::PrepareDC() function).
//
// - Now it is possible to set a clipping rectangle using
// CPictureEx[Wnd]::SetPaintRect(const LPRECT) function.
// The LPRECT parameter tells the class what portion of
// a picture should it display. If the clipping rect is
// not set, the whole picture is shown.
// Thanks to Fabrice Rodriguez for the idea.
//
// - Added support for Stop/Draw. Now you can Stop() an
// animated GIF, then Draw() it again, it will continue
// animation from the frame it was stopped on. You can
// also know if a GIF is currently playing with the
// IsPlaying() function.
//
// - Got rid of math.h and made m_bExitThread volatile.
// Thanks to Piotr Sawicki for the suggestion.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_)
#define AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <vector>

//#define GIF_TRACING // uncomment it if you want detailed TRACEs

class CPictureEx : public CStatic
{
public:

struct TFrame // structure that keeps a single frame info
{
IPicture *m_pPicture; // pointer to the interface used for drawing
SIZE m_frameSize;
SIZE m_frameOffset;
UINT m_nDelay; // delay (in 1/100s of a second)
UINT m_nDisposal; // disposal method
};

#pragma pack(1) // turn byte alignment on

enum GIFBlockTypes
{
BLOCK_UNKNOWN,
BLOCK_APPEXT,
BLOCK_COMMEXT,
BLOCK_CONTROLEXT,
BLOCK_PLAINTEXT,
BLOCK_IMAGE,
BLOCK_TRAILER
};

enum ControlExtValues // graphic control extension packed field values
{
GCX_PACKED_DISPOSAL, // disposal method
GCX_PACKED_USERINPUT,
GCX_PACKED_TRANSPCOLOR
};

enum LSDPackedValues // logical screen descriptor packed field values
{
LSD_PACKED_GLOBALCT,
LSD_PACKED_CRESOLUTION,
LSD_PACKED_SORT,
LSD_PACKED_GLOBALCTSIZE
};

enum IDPackedValues // image descriptor packed field values
{
ID_PACKED_LOCALCT,
ID_PACKED_INTERLACE,
ID_PACKED_SORT,
ID_PACKED_LOCALCTSIZE
};

struct TGIFHeader // GIF header
{
char m_cSignature[3]; // Signature - Identifies the GIF Data Stream
// This field contains the fixed value 'GIF'
char m_cVersion[3]; // Version number. May be one of the following:
// "87a" or "89a"
};

struct TGIFLSDescriptor // Logical Screen Descriptor
{
WORD m_wWidth; // 2 bytes. Logical screen width
WORD m_wHeight; // 2 bytes. Logical screen height

unsigned char m_cPacked; // packed field

unsigned char m_cBkIndex; // 1 byte. Background color index
unsigned char m_cPixelAspect; // 1 byte. Pixel aspect ratio
inline int GetPackedValue(enum LSDPackedValues Value);
};

chenhq 2004-08-25
  • 打赏
  • 举报
回复
enum GIFBlockTypes
{
BLOCK_UNKNOWN,
BLOCK_APPEXT,
BLOCK_COMMEXT,
BLOCK_CONTROLEXT,
BLOCK_PLAINTEXT,
BLOCK_IMAGE,
BLOCK_TRAILER
};

enum ControlExtValues // graphic control extension packed field values
{
GCX_PACKED_DISPOSAL, // disposal method
GCX_PACKED_USERINPUT,
GCX_PACKED_TRANSPCOLOR
};

enum LSDPackedValues // logical screen descriptor packed field values
{
LSD_PACKED_GLOBALCT,
LSD_PACKED_CRESOLUTION,
LSD_PACKED_SORT,
LSD_PACKED_GLOBALCTSIZE
};

enum IDPackedValues // image descriptor packed field values
{
ID_PACKED_LOCALCT,
ID_PACKED_INTERLACE,
ID_PACKED_SORT,
ID_PACKED_LOCALCTSIZE
};

struct TGIFHeader // GIF header
{
char m_cSignature[3]; // Signature - Identifies the GIF Data Stream
// This field contains the fixed value 'GIF'
char m_cVersion[3]; // Version number. May be one of the following:
// "87a" or "89a"
};

struct TGIFLSDescriptor // Logical Screen Descriptor
{
WORD m_wWidth; // 2 bytes. Logical screen width
WORD m_wHeight; // 2 bytes. Logical screen height

unsigned char m_cPacked; // packed field

unsigned char m_cBkIndex; // 1 byte. Background color index
unsigned char m_cPixelAspect; // 1 byte. Pixel aspect ratio
inline int GetPackedValue(enum LSDPackedValues Value);
};

struct TGIFAppExtension // application extension block
{
unsigned char m_cExtIntroducer; // extension introducer (0x21)
unsigned char m_cExtLabel; // app. extension label (0xFF)
unsigned char m_cBlockSize; // fixed value of 11
char m_cAppIdentifier[8]; // application identifier
char m_cAppAuth[3]; // application authentication code
};

struct TGIFControlExt // graphic control extension block
{
unsigned char m_cExtIntroducer; // extension introducer (0x21)
unsigned char m_cControlLabel; // control extension label (0xF9)
unsigned char m_cBlockSize; // fixed value of 4
unsigned char m_cPacked; // packed field
WORD m_wDelayTime; // delay time
unsigned char m_cTColorIndex; // transparent color index
unsigned char m_cBlockTerm; // block terminator (0x00)
public:
inline int GetPackedValue(enum ControlExtValues Value);
};

struct TGIFCommentExt // comment extension block
{
unsigned char m_cExtIntroducer; // extension introducer (0x21)
unsigned char m_cCommentLabel; // comment extension label (0xFE)
};

struct TGIFPlainTextExt // plain text extension block
{
unsigned char m_cExtIntroducer; // extension introducer (0x21)
unsigned char m_cPlainTextLabel; // text extension label (0x01)
unsigned char m_cBlockSize; // fixed value of 12
WORD m_wLeftPos; // text grid left position
WORD m_wTopPos; // text grid top position
WORD m_wGridWidth; // text grid width
WORD m_wGridHeight; // text grid height
unsigned char m_cCellWidth; // character cell width
unsigned char m_cCellHeight; // character cell height
unsigned char m_cFgColor; // text foreground color index
unsigned char m_cBkColor; // text background color index
};

struct TGIFImageDescriptor // image descriptor block
{
unsigned char m_cImageSeparator; // image separator byte (0x2C)
WORD m_wLeftPos; // image left position
WORD m_wTopPos; // image top position
WORD m_wWidth; // image width
WORD m_wHeight; // image height
unsigned char m_cPacked; // packed field
inline int GetPackedValue(enum IDPackedValues Value);
};

#pragma pack() // turn byte alignment off

public:
void SetBkNoColor();
BOOL GetPaintRect(RECT *lpRect);
BOOL SetPaintRect(const RECT *lpRect);
CPictureEx();
virtual ~CPictureEx();
void Stop(); // stops animation
void UnLoad(); // stops animation plus releases all resources

BOOL IsGIF() const;
BOOL IsPlaying() const;
BOOL IsAnimatedGIF() const;
SIZE GetSize() const;
int GetFrameCount() const;
COLORREF GetBkColor() const;
void SetBkColor(COLORREF clr);

// draws the picture (starts an animation thread if needed)
// if an animation was previously stopped by Stop(),
// continues it from the last displayed frame
BOOL Draw();

// loads a picture from a file
// i.e. Load(_T("mypic.gif"));
BOOL Load(LPCTSTR szFileName);

// loads a picture from a global memory block (allocated by GlobalAlloc)
// Warning: this function DOES NOT free the global memory, pointed to by hGlobal
BOOL Load(HGLOBAL hGlobal, DWORD dwSize);

// loads a picture from a program resource
// i.e. Load(MAKEINTRESOURCE(IDR_MYPIC),_T("GIFTYPE"));
BOOL Load(LPCTSTR szResourceName,LPCTSTR szResourceType);

protected:

#ifdef GIF_TRACING
void EnumGIFBlocks();
void WriteDataOnDisk(CString szFileName, HGLOBAL hData, DWORD dwSize);
#endif // GIF_TRACING

RECT m_PaintRect;
SIZE m_PictureSize;
COLORREF m_clrBackground;
UINT m_nCurrFrame;
UINT m_nDataSize;
UINT m_nCurrOffset;
UINT m_nGlobalCTSize;
BOOL m_bIsGIF;
BOOL m_bIsPlaying;
volatile BOOL m_bExitThread;
BOOL m_bIsInitialized;
HDC m_hMemDC;

HDC m_hDispMemDC;
HBITMAP m_hDispMemBM;
HBITMAP m_hDispOldBM;

HBITMAP m_hBitmap;
HBITMAP m_hOldBitmap;
HANDLE m_hThread;
HANDLE m_hExitEvent;
IPicture * m_pPicture;
TGIFHeader * m_pGIFHeader;
unsigned char * m_pRawData;
TGIFLSDescriptor * m_pGIFLSDescriptor;
std::vector<TFrame> m_arrFrames;

void ThreadAnimation();
static UINT WINAPI _ThreadAnimation(LPVOID pParam);

int GetNextBlockLen() const;
BOOL SkipNextBlock();
BOOL SkipNextGraphicBlock();
BOOL PrepareDC(int nWidth, int nHeight);
void ResetDataPointer();
enum GIFBlockTypes GetNextBlock() const;
UINT GetSubBlocksLen(UINT nStartingOffset) const;
HGLOBAL GetNextGraphicBlock(UINT *pBlockLen, UINT *pDelay,
SIZE *pBlockSize, SIZE *pBlockOffset, UINT *pDisposal);

// Generated message map functions
//{{AFX_MSG(CPictureEx)
afx_msg void OnDestroy();
afx_msg void OnPaint();
//}}AFX_MSG

DECLARE_MESSAGE_MAP()
};

#endif // !defined(AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_)

chenhq 2004-08-25
  • 打赏
  • 举报
回复
头文件!

//////////////////////////////////////////////////////////////////////
// PictureEx.cpp: implementation of the CPictureEx class.
//
// Picture displaying control with support for the following formats:
// GIF (including animated GIF87a and GIF89a), JPEG, BMP, WMF, ICO, CUR
//
// Written by Oleg Bykov (oleg_bykoff@rsdn.ru)
// Copyright (c) 2001
//
// To use CPictureEx, follow these steps:
// - place a static control on your dialog (either a text or a bitmap)
// - change its identifier to something else (e.g. IDC_MYPIC)
// - associate a CStatic with it using ClassWizard
// - in your dialog's header file replace CStatic with CPictureEx
// (don't forget to #include "PictureEx.h" and add
// PictureEx.h and PictureEx.cpp to your project)
// - call one of the overloaded CPictureEx::Load() functions somewhere
// (OnInitDialog is a good place to start)
// - if the preceding Load() succeeded call Draw()
//
// You can also add the control by defining a member variable of type
// CPictureEx, calling CPictureEx::Create (derived from CStatic), then
// CPictureEx::Load and CPictureEx::Draw.
//
// By default, the control initializes its background to COLOR_3DFACE
// (see CPictureEx::PrepareDC()). You can change the background by
// calling CPictureEx::SetBkColor(COLORREF) after CPictureEx::Load().
//
// I decided to leave in the class the functions to write separate frames from
// animated GIF to disk. If you want to use them, uncomment #define GIF_TRACING
// and an appropriate section in CPictureEx::Load(HGLOBAL, DWORD). These functions
// won't be compiled and linked to your project unless you uncomment #define GIF_TRACING,
// so you don't have to worry.
//
// Warning: this code hasn't been subject to a heavy testing, so
// use it on your own risk. The author accepts no liability for the
// possible damage caused by this code.
//
// Version 1.0 7 Aug 2001
// Initial release
//
// Version 1.1 6 Sept 2001
// ATL version of the class
//
// Version 1.2 14 Oct 2001
// - Fixed a problem with loading GIFs from resources
// in MFC-version of the class for multi-modules apps.
// Thanks to Ruben Avila-Carretero for finding this out.
//
// - Got rid of waitable timer in ThreadAnimation()
// Now CPictureEx[Wnd] works in Win95 too.
// Thanks to Alex Egiazarov and Wayne King for the idea.
//
// - Fixed a visual glitch of using SetBkColor.
// Thanks to Kwangjin Lee for finding this out.
//
// Version 1.3 10 Nov 2001
// - Fixed a DC leak. One DC leaked per each UnLoad()
// (forgot to put a ReleaseDC() in the end of
// CPictureExWnd::PrepareDC() function).
//
// - Now it is possible to set a clipping rectangle using
// CPictureEx[Wnd]::SetPaintRect(const LPRECT) function.
// The LPRECT parameter tells the class what portion of
// a picture should it display. If the clipping rect is
// not set, the whole picture is shown.
// Thanks to Fabrice Rodriguez for the idea.
//
// - Added support for Stop/Draw. Now you can Stop() an
// animated GIF, then Draw() it again, it will continue
// animation from the frame it was stopped on. You can
// also know if a GIF is currently playing with the
// IsPlaying() function.
//
// - Got rid of math.h and made m_bExitThread volatile.
// Thanks to Piotr Sawicki for the suggestion.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_)
#define AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <vector>

//#define GIF_TRACING // uncomment it if you want detailed TRACEs

class CPictureEx : public CStatic
{
public:

struct TFrame // structure that keeps a single frame info
{
IPicture *m_pPicture; // pointer to the interface used for drawing
SIZE m_frameSize;
SIZE m_frameOffset;
UINT m_nDelay; // delay (in 1/100s of a second)
UINT m_nDisposal; // disposal method
};

#pragma pack(1) // turn byte alignment on

bohut 2004-08-25
  • 打赏
  • 举报
回复
你的邮箱,我给你发个例子

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧