📄 gifwin.cpp
字号:
// Map color based on pColorMap, uColors long lClosest = 5; for (UINT u = 0; u < uColors; ++u) { const long lDiff = ColorDiff(pColorMap[u].from, rgb); if (lDiff < lClosest) { lClosest = lDiff; rgb = pColorMap[u].to; } } // Check for "solid" color flag (no pixel averaging) if (rgb & 0xff000000) { return rgb; } red += GetRValue(rgb); grn += GetGValue(rgb); blu += GetBValue(rgb); } pSrcRow += dwSrcRowBytes; } // Return "average" pixel return RGB(red / iPower, grn / iPower, blu / iPower);}// Copy (and resize) 24-bit Bitmap mapping colorsLOCAL void CopyBitmap24(LPBYTE pDstRow, LPBYTE pSrcRow, int width, int height, LPCOLORMAP pColorMap, UINT uColors, int iScale){ ASSERT( iScale > 0 ); const DWORD dwSrcRowBytes = DWORD_PAD(width * 3); const DWORD dwDstRowBytes = DWORD_PAD(width / iScale * 3); for (int row = 0; row < height; row += iScale) { LPBYTE pDst = pDstRow; LPBYTE pSrc = pSrcRow + (row * dwSrcRowBytes); for (int col = 0; col < width; col += iScale) { const COLORREF rgb = AvePixel(pSrc, dwSrcRowBytes, pColorMap, uColors, iScale); *pDst++ = GetBValue(rgb); *pDst++ = GetGValue(rgb); *pDst++ = GetRValue(rgb); pSrc += (iScale * 3); } pDstRow += dwDstRowBytes; }}// Create a Device Independent Bitmap from current GIF image// Colorize bitmap to match Windows desktop colors// Returns NULL if error else handle to bitmapHBITMAP CGIFWin::CreateMappedBitmap(LPCOLORMAP pMap, UINT uCount, int iScale /*=1*/){ HBITMAP hBitmap = NULL; ASSERT( m_pGifFile && m_pBits ); // Create memory device context compatible with current screen HDC hDC = ::CreateCompatibleDC(NULL); if (hDC) { // Create bitmap from current image state LPVOID pBits = NULL; BMI256 bmiSize = m_bmiDisplay; if (iScale > 0) { bmiSize.bmi.bmiHeader.biWidth /= iScale; bmiSize.bmi.bmiHeader.biHeight /= iScale; } hBitmap = ::CreateDIBSection(hDC, &bmiSize.bmi, DIB_RGB_COLORS, &pBits, /*handle=*/ NULL, /*offset=*/ 0L); if (hBitmap && pBits) { const int cxScreen = m_pGifFile->SWidth; const int cyScreen = m_pGifFile->SHeight; ASSERT( m_bmiDisplay.bmi.bmiHeader.biBitCount == 24 ); ::CopyBitmap24((LPBYTE) pBits, (LPBYTE) m_pBits, cxScreen, cyScreen, pMap, uCount, iScale); } VERIFY( ::DeleteDC(hDC) ); } return hBitmap;}int CGIFWin::GetHeight(){ return m_pGifFile ? m_pGifFile->SHeight : 0;}int CGIFWin::GetWidth(){ return m_pGifFile ? m_pGifFile->SWidth : 0;}// Netscape 2.0 looping extension blockLOCAL GifByteType szNetscape20ext[] = "\x0bNETSCAPE2.0";#define NSEXT_LOOP 0x01 // Loop Count field code//// Appendix E. Interlaced Images.//// The rows of an Interlaced images are arranged in the following order:// // Group 1 : Every 8th. row, starting with row 0. (Pass 1)// Group 2 : Every 8th. row, starting with row 4. (Pass 2)// Group 3 : Every 4th. row, starting with row 2. (Pass 3)// Group 4 : Every 2nd. row, starting with row 1. (Pass 4)// const int InterlacedOffset[] = { 0, 4, 2, 1 }; /* The way Interlaced image should. */const int InterlacedJumps[] = { 8, 8, 4, 2 }; /* be read - offsets and jumps... *///// The Following example illustrates how the rows of an interlaced image are// ordered.// // Row Number Interlace Pass// // 0 ----------------------------------------- 1// 1 ----------------------------------------- 4// 2 ----------------------------------------- 3// 3 ----------------------------------------- 4// 4 ----------------------------------------- 2// 5 ----------------------------------------- 4// 6 ----------------------------------------- 3// 7 ----------------------------------------- 4// 8 ----------------------------------------- 1// 9 ----------------------------------------- 4// 10 ----------------------------------------- 3// 11 ----------------------------------------- 4// 12 ----------------------------------------- 2// 13 ----------------------------------------- 4// 14 ----------------------------------------- 3// 15 ----------------------------------------- 4// 16 ----------------------------------------- 1// 17 ----------------------------------------- 4// 18 ----------------------------------------- 3// 19 ----------------------------------------- 4//// Fetch next image from GIF file// Returns delay in msec, 0 for end-of-file, negative for error)int CGIFWin::NextImage(){ // Error if no gif file! if (!m_pGifFile) { return -1; } const int cxScreen = m_pGifFile->SWidth; const int cyScreen = m_pGifFile->SHeight; // ___________ // pBits1 -> | | // | current | // | image | // |___________| // pBits2 -> | | // | next | // | image | // |___________| // pLine -> |___________| // const DWORD dwRowBytes = DWORD_PAD(cxScreen * 3);#define XYOFFSET(x,y) ((y) * dwRowBytes + (x) * 3) const DWORD dwScreen = dwRowBytes * cyScreen; LPBYTE pBits1 = m_pBits; LPBYTE pBits2 = pBits1 + dwScreen; GifPixelType *pLine = pBits2 + dwScreen; GifRecordType RecordType; GifByteType *pExtension; int delay = 10; // Default to 100 msec int dispose = 0; int transparent = GIF_NOT_TRANSPARENT; do { int i, ExtCode; if (DGifGetRecordType(m_pGifFile, &RecordType) == GIF_ERROR) { break; } switch (RecordType) { case IMAGE_DESC_RECORD_TYPE: if (DGifGetImageDesc(m_pGifFile) != GIF_ERROR) { const int x = m_pGifFile->Image.Left; const int y = m_pGifFile->Image.Top; ++m_iImageNum; TRACE("\nImage #%d:\n\n\tImage Size - Left = %d, Top = %d, Width = %d, Height = %d.\n", m_iImageNum, x, y, m_pGifFile->Image.Width, m_pGifFile->Image.Height); TRACE("\tImage is %s", m_pGifFile->Image.Interlace ? "Interlaced" : "Non Interlaced"); if (m_pGifFile->Image.ColorMap != NULL) TRACE(", BitsPerPixel = %d.\n", m_pGifFile->Image.ColorMap->BitsPerPixel); else TRACE(".\n"); GifColorType* pColorTable; if (m_pGifFile->Image.ColorMap == NULL) { TRACE("\tNo Image Color Map.\n"); // Copy global bitmap info for display memcpy(&m_bmiDisplay, &m_bmiGlobal, sizeof(m_bmiDisplay)); pColorTable = m_pGifFile->SColorMap->Colors; } else { TRACE("\tImage Has Color Map.\n"); ::InitBitmapInfo(&m_bmiDisplay.bmi, cxScreen, cyScreen); ::CopyColorMap(m_pGifFile->Image.ColorMap, &m_bmiDisplay.bmi); pColorTable = m_pGifFile->Image.ColorMap->Colors; } // Always copy next -> current image memcpy(pBits1, pBits2, dwScreen); const int Width = m_pGifFile->Image.Width; const int Height = m_pGifFile->Image.Height; if (m_pGifFile->Image.Interlace) { // Need to perform 4 passes on the images: for (int pass = 0; pass < 4; pass++) { for (i = InterlacedOffset[pass]; i < Height; i += InterlacedJumps[pass]) { if (DGifGetLine(m_pGifFile, pLine, Width) == GIF_ERROR) { TRACE("DGifGetLine error=%d\n", GifLastError()); return -1; } CopyGIF(pBits1 + XYOFFSET(x, y + i), pLine, Width, transparent, pColorTable); } } } else { // Non-interlaced image for (i = 0; i < Height; i++) { if (DGifGetLine(m_pGifFile, pLine, Width) == GIF_ERROR) { TRACE("DGifGetLine error=%d\n", GifLastError()); return -1; } CopyGIF(pBits1 + XYOFFSET(x, y + i), pLine, Width, transparent, pColorTable); } } // Prepare second image with next starting if (dispose == GIF_DISPOSE_BACKGND) { TRACE("*** GIF_DISPOSE_BACKGND ***\n"); const int x = m_pGifFile->Image.Left; const int y = m_pGifFile->Image.Top; const int Width = m_pGifFile->Image.Width; const int Height = m_pGifFile->Image.Height; // Clear next image to background index // Note: if transparent restore to transparent color (else use GIF background color) const COLORREF rgbFill = (transparent == GIF_NOT_TRANSPARENT) ? m_rgbBackgnd : m_rgbTransparent; for (int i = 0; i < Height; ++i) ::FillGIF(pBits2 + XYOFFSET(x, y + i), rgbFill, Width); } else if (dispose != GIF_DISPOSE_RESTORE) { // Copy current -> next (Update) memcpy(pBits2, pBits1, dwScreen); } dispose = 0; TRACE("\tdelay = %d msec\n", delay * 10); if (delay) { return delay * 10; } } break; case EXTENSION_RECORD_TYPE: { if (DGifGetExtension(m_pGifFile, &ExtCode, &pExtension) == GIF_ERROR) { TRACE("DGifGetExtension error=%d\n", GifLastError()); return -2; } TRACE("\n"); BOOL bNetscapeExt = FALSE; switch (ExtCode) { case COMMENT_EXT_FUNC_CODE: TRACE("GIF89 comment"); break; case GRAPHICS_EXT_FUNC_CODE: { TRACE("GIF89 graphics control"); ASSERT( pExtension[0] == 4 ); // int flag = pExtension[1]; delay = MAKEWORD(pExtension[2], pExtension[3]); transparent = (flag & GIF_TRANSPARENT) ? pExtension[4] : GIF_NOT_TRANSPARENT; dispose = (flag >> GIF_DISPOSE_SHIFT) & GIF_DISPOSE_MASK; TRACE(" delay = %d, dispose = %d transparent = %d\n", delay, dispose, transparent); break; } case PLAINTEXT_EXT_FUNC_CODE: TRACE("GIF89 plaintext"); break; case APPLICATION_EXT_FUNC_CODE: { TRACE("GIF89 application block\n"); ASSERT( pExtension ); if (memcmp(pExtension, szNetscape20ext, szNetscape20ext[0]) == 0) { TRACE("Netscape 2.0 extension\n"); bNetscapeExt = TRUE; } break; } default: TRACE("pExtension record of unknown type"); break; } TRACE(" (Ext Code = %d):\n", ExtCode); do { if (DGifGetExtensionNext(m_pGifFile, &pExtension) == GIF_ERROR) { TRACE("DGifGetExtensionNext error=%d\n", GifLastError()); return -3; } // Process Netscape 2.0 extension (GIF looping) if (pExtension && bNetscapeExt) { GifByteType bLength = pExtension[0]; int iSubCode = pExtension[1] & 0x07; if (bLength == 3 && iSubCode == NSEXT_LOOP) { UINT uLoopCount = MAKEWORD(pExtension[2], pExtension[3]); m_uLoopCount = uLoopCount - 1; TRACE("Looping extension, uLoopCount=%u\n", m_uLoopCount); } } } while (pExtension); break; } case TERMINATE_RECORD_TYPE: break; default: // Should be trapped by DGifGetRecordType break; } } while (RecordType != TERMINATE_RECORD_TYPE); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -