首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

VC++ 中播放動態 GIF 的完整實作方案

     編輯:關於VC++

核心思路:兩步走

  1. 利用 IPicture COM 介面繪製靜態圖片(支援 GIF 首幀)
  2. 解析 GIF 檔案結構,將後續幀依序覆蓋至首幀位置,再重複呼叫 IPicture::Render 形成動畫

動態 GIF 播放效果

關鍵技術點

1. IPicture 介面基本用法

  • get_Width/get_Height:取得圖片尺寸(HIMETRIC 單位)
  • Render(hDC, x, y, w, h, srcX, srcY, srcW, srcH, rc):繪製到指定 DC
  • 建立方式:OleLoadPicture(IStream*, size, FALSE, IID_IPicture, (void**)&pic)

2. GIF 多幀結構解析

每幀以 0x2C 開頭(前一位元組必為 0x00),後接 GifImage 結構:

typedef struct {
    WORD logX, logY, width, height;
    struct { BYTE d:3, c:1, b:3, a:1; } Flag; // a=1 表示有區域調色盤
} GifImage;

資料區塊:長度位元組 + 資料 重複,以 0x00 結束。

3. 完整播放迴圈程式碼

// 1. 從資源載入 GIF 原始資料
HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(IDR_GIF), "IMAGE");
DWORD size = SizeofResource(hInst, hRes);
BYTE* pSrc = (BYTE*)LoadResource(hInst, hRes);

// 2. 掃描所有幀位置與大小
BYTE* frames[20]; DWORD frameSize[20]; int frameCnt = 0;
DWORD firstPos = 0;
for (DWORD i = 0; i < size; i++) {
    if (pSrc[i] == 0x2C && pSrc[i-1] == 0x00) {
        GifImage* gif = (GifImage*)&pSrc[i+1];
        DWORD offset = 1 + sizeof(GifImage);
        if (gif->Flag.a) offset += 3 * (1 << (gif->Flag.d + 1)); // 區域調色盤
        while (pSrc[i+offset] != 0) offset += pSrc[i+offset] + 1;
        offset++; // 含結束 0x00
        if (frameCnt == 0) firstPos = i;
        frames[frameCnt] = new BYTE[offset];
        memcpy(frames[frameCnt], &pSrc[i], offset);
        frameSize[frameCnt] = offset;
        i += offset - 1;
        frameCnt++;
    }
}

// 3. 播放迴圈(建議放在獨立執行緒)
while (playing) {
    for (int f = 0; f < frameCnt; f++) {
        // 覆蓋首幀資料
        DWORD oldProtect;
        VirtualProtect(pSrc, size, PAGE_READWRITE, &oldProtect);
        memcpy(&pSrc[firstPos], frames[f], frameSize[f]);
        VirtualProtect(pSrc, size, oldProtect, NULL);

        // 建立串流並載入 IPicture
        CMemFile mem(pSrc, size);
        CArchive ar(&mem, CArchive::load | CArchive::bNoFlushOnDelete);
        CArchiveStream stream(&ar);
        CComQIPtr pic;
        OleLoadPicture((LPSTREAM)&stream, 0, FALSE, IID_IPicture, (void**)&pic);

        // 繪製
        long w, h; pic->get_Width(&w); pic->get_Height(&h);
        CSize sz(w, h); pDC->HIMETRICtoDP(&sz);
        CRect rc(0,0,sz.cx,sz.cy);
        pic->Render(*pDC, 0,0,sz.cx,sz.cy, 0,h,w,-h, &rc);

        Sleep(100); // 幀延遲,可依 GIF 內建延遲調整
    }
}

補充說明

  • 建議將播放迴圈置於 Worker Thread,避免阻塞 UI
  • GIF 內建幀延遲位於圖形控制擴充區塊,本範例以固定 Sleep(100) 簡化
  • 記憶體保護 VirtualProtect 必須成對呼叫
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved