?? gifapi.cpp
字號:
// ************************************************************************// 文件名:GIFAPI.cpp//// GIF(Graphics Interchange Format) API函數庫://// DIBToGIF() - 將指定的DIB對象(< 256色)保存為GIF文件// EncodeGIF_LZW() - 對指定圖像進行GIF_LZW編碼// GIF_LZW_WriteCode() - 輸出一個編碼// ReadGIF() - 讀取GIF文件// DecodeGIF_LZW() - 對GIF_LZW編碼結果進行解碼// ReadSrcData() - 讀取GIF_LZW編碼//// ************************************************************************#include "stdafx.h"#include "DIBAPI.h"#include "GIFAPI.h"#include <io.h>#include <errno.h>#include <math.h>#include <direct.h>/************************************************************************* * * 函數名稱: * DIBToGIF() * * 參數: * LPSTR lpDIB - 指向DIB對象的指針 * CFile& file - 要保存的文件 * BOOL bInterlace - 是否按照交錯方式保存 * * 返回值: * BOOL - 成功返回True,否則返回False。 * * 說明: * 該函數將指定的DIB對象(< 256色)保存為GIF文件。 * *************************************************************************/BOOL WINAPI DIBToGIF(LPSTR lpDIB, CFile& file, BOOL bInterlace){ // 循環變量 WORD i; WORD j; // DIB高度 WORD wHeight; // DIB寬度 WORD wWidth; // 指向DIB象素指針 LPSTR lpDIBBits; // GIF文件頭 GIFHEADER GIFH; // GIF邏輯屏幕描述塊 GIFSCRDESC GIFS; // GIF圖像描述塊 GIFIMAGE GIFI; // GIF編碼參數 GIFC_VAR GIFCVar; // 顏色數目 WORD wColors; // 每行字節數 WORD wWidthBytes; // 調色板 BYTE byGIF_Pal[768]; // 字節變量 BYTE byChar; // 指向BITMAPINFO結構的指針(Win3.0) LPBITMAPINFO lpbmi; // 指向BITMAPCOREINFO結構的指針 LPBITMAPCOREINFO lpbmc; // 表明是否是Win3.0 DIB的標記 BOOL bWinStyleDIB; // 獲取DIB高度 wHeight = (WORD) DIBHeight(lpDIB); // 獲取DIB寬度 wWidth = (WORD) DIBWidth(lpDIB); // 找到DIB圖像象素起始位置 lpDIBBits = FindDIBBits(lpDIB); // 給GIFCVar結構賦值 GIFCVar.wWidth = wWidth; GIFCVar.wDepth = wHeight; GIFCVar.wBits = DIBBitCount(lpDIB); GIFCVar.wLineBytes = (WORD)BYTE_WBYTES((DWORD)GIFCVar.wWidth * (DWORD)GIFCVar.wBits); // 計算每行字節數 wWidthBytes = (WORD)DWORD_WBYTES(wWidth * (DWORD)GIFCVar.wBits); // 計算顏色數目 wColors = 1 << GIFCVar.wBits; // 獲取指向BITMAPINFO結構的指針(Win3.0) lpbmi = (LPBITMAPINFO)lpDIB; // 獲取指向BITMAPCOREINFO結構的指針 lpbmc = (LPBITMAPCOREINFO)lpDIB; // 判斷是否是WIN3.0的DIB bWinStyleDIB = IS_WIN30_DIB(lpDIB); // 給調色板賦值 if (bWinStyleDIB) { j = 0; for (i = 0; i < wColors; i++) { // 讀取紅色分量 byGIF_Pal[j++] = lpbmi->bmiColors[i].rgbRed; // 讀取綠色分量 byGIF_Pal[j++] = lpbmi->bmiColors[i].rgbGreen; // 讀取藍色分量 byGIF_Pal[j++] = lpbmi->bmiColors[i].rgbBlue; } } else { j = 0; for (i = 0; i < wColors; i++) { // 讀取紅色分量 byGIF_Pal[j++] = lpbmc->bmciColors[i].rgbtRed; // 讀取綠色分量 byGIF_Pal[j++] = lpbmc->bmciColors[i].rgbtGreen; // 讀取紅色分量 byGIF_Pal[j++] = lpbmc->bmciColors[i].rgbtBlue; } } //////////////////////////////////////////////////////////////////////////////////////// // 開始寫GIF文件 // 寫GIF文件頭 GIFH.bySignature[0] = 'G'; GIFH.bySignature[1] = 'I'; GIFH.bySignature[2] = 'F'; GIFH.byVersion[0]='8'; GIFH.byVersion[1]='9'; GIFH.byVersion[2]='a'; file.Write((LPSTR)&GIFH, 6); // 寫GIF邏輯屏幕描述塊 GIFS.wWidth = GIFCVar.wWidth; GIFS.wDepth = GIFCVar.wDepth; GIFS.GlobalFlag.PalBits = (BYTE)(GIFCVar.wBits - 1); GIFS.GlobalFlag.SortFlag = 0x00; GIFS.GlobalFlag.ColorRes = (BYTE)(GIFCVar.wBits - 1); GIFS.GlobalFlag.GlobalPal = 0x01; GIFS.byBackground = 0x00; GIFS.byAspect = 0x00; file.Write((LPSTR)&GIFS, 7); // 寫GIF全局調色板 file.Write((LPSTR)byGIF_Pal,(wColors*3)); // 寫GIF圖像描述間隔符 byChar = 0x2C; file.Write((LPSTR)&byChar,1); // 寫GIF圖像描述塊 GIFI.wLeft = 0; GIFI.wTop = 0; GIFI.wWidth = GIFCVar.wWidth; GIFI.wDepth = GIFCVar.wDepth; GIFI.LocalFlag.PalBits = 0x00; GIFI.LocalFlag.Reserved = 0x00; GIFI.LocalFlag.SortFlag = 0x00; GIFI.LocalFlag.Interlace = (BYTE)(bInterlace ? 0x01 : 0x00); GIFI.LocalFlag.LocalPal = 0x00; file.Write((LPSTR)&GIFI, 9); // 寫GIF圖像壓縮數據 HANDLE hSrcBuff = GlobalAlloc(GHND,(DWORD)MAX_BUFF_SIZE); GIFCVar.lpDataBuff = (LPSTR)GlobalLock(hSrcBuff); GIFCVar.lpEndBuff = GIFCVar.lpDataBuff; GIFCVar.dwTempCode = 0UL; GIFCVar.wByteCnt = 0; GIFCVar.wBlockNdx = 1; GIFCVar.byLeftBits = 0x00; // 進行GIF_LZW編碼 EncodeGIF_LZW(lpDIBBits, file, &GIFCVar,wWidthBytes, bInterlace); // 判斷是否編碼成功 if (GIFCVar.wByteCnt) { // 寫入文件 file.Write(GIFCVar.lpDataBuff, GIFCVar.wByteCnt); } // 釋放內存 GlobalUnlock(hSrcBuff); GlobalFree(hSrcBuff); // 寫GIF Block Terminator byChar = 0x00; file.Write((LPSTR)&byChar,1); // 寫GIF文件結尾塊 byChar = 0x3B; file.Write((LPSTR)&byChar,1); // 返回 return TRUE;}/************************************************************************* * * 函數名稱: * EncodeGIF_LZW() * * 參數: * LPSTR lpDIBBits - 指向源DIB圖像指針 * CFile& file - 要保存的文件 * LPGIFC_VAR lpGIFCVar - 指向GIFC_VAR結構的指針 * WORD wWidthBytes - 每行圖像字節數 * BOOL bInterlace - 是否按照交錯方式保存 * * 返回值: * 無 * * 說明: * 該函數對指定圖像進行GIF_LZW編碼。 * *************************************************************************/void WINAPI EncodeGIF_LZW(LPSTR lpDIBBits, CFile& file, LPGIFC_VAR lpGIFCVar,WORD wWidthBytes, BOOL bInterlace){ // 內存分配句柄 HANDLE hTableNdx; HANDLE hPrefix; HANDLE hSuffix; // 指向字串表指針 LPWORD lpwTableNdx; // 用于字串表搜索的索引 LPWORD lpwPrefix; LPBYTE lpbySuffix; // 指向當前編碼像素的指針 LPSTR lpImage; // 計算當前數據圖像的偏移量 DWORD dwDataNdx; // LZW_CLEAR WORD wLZW_CLEAR; // LZW_EOI WORD wLZW_EOI; // LZW_MinCodeLen BYTE byLZW_MinCodeLen; // 字串表索引 WORD wPreTableNdx; WORD wNowTableNdx; WORD wTopTableNdx; // 哈希表索引 WORD wHashNdx; WORD wHashGap; WORD wPrefix; WORD wShiftBits; // 當前圖像的行數 WORD wRowNum; WORD wWidthCnt; // 循環變量 WORD wi; WORD wj; // 交錯方式存儲時每次增加的行數 WORD wIncTable[5] = { 8,8,4,2,0 }; // 交錯方式存儲時起始行數 WORD wBgnTable[5] = { 0,4,2,1,0 }; BOOL bStart; BYTE bySuffix; BYTE bySubBlock[256]; BYTE byCurrentBits; BYTE byMask; BYTE byChar; BYTE byPass; // 臨時字節變量 BYTE byTemp; // 給字串表分配內存 hTableNdx = GlobalAlloc(GHND,(DWORD)(MAX_HASH_SIZE<<1)); hPrefix = GlobalAlloc(GHND,(DWORD)(MAX_HASH_SIZE<<1)); hSuffix = GlobalAlloc(GHND,(DWORD)MAX_HASH_SIZE); // 鎖定內存 lpwTableNdx = (LPWORD)GlobalLock(hTableNdx); lpwPrefix = (LPWORD)GlobalLock(hPrefix); lpbySuffix = (LPBYTE)GlobalLock(hSuffix); // 計算LZW_MinCodeLen byLZW_MinCodeLen = (BYTE)((lpGIFCVar->wBits>1) ? lpGIFCVar->wBits : 0x02); // 寫GIF LZW最小代碼大小 file.Write((LPSTR)&byLZW_MinCodeLen,1); wRowNum = 0; bStart = TRUE; byPass = 0x00; // 計算LZW_CLEAR wLZW_CLEAR = 1 << byLZW_MinCodeLen; // 計算LZW_EOI wLZW_EOI = wLZW_CLEAR + 1; // 初始化字串表 byCurrentBits = byLZW_MinCodeLen + (BYTE)0x01; wNowTableNdx = wLZW_CLEAR + 2; wTopTableNdx = 1 << byCurrentBits; for(wi=0; wi<MAX_HASH_SIZE; wi++) { // 初始化為0xFFFF *(lpwTableNdx+wi) = 0xFFFF; } // 輸出LZW_CLEAR GIF_LZW_WriteCode(file, wLZW_CLEAR, (LPSTR)bySubBlock, &byCurrentBits, lpGIFCVar); // 逐行編碼 for(wi=0; wi<lpGIFCVar->wDepth; wi++) { // 計算當前偏移量 dwDataNdx = (DWORD)(lpGIFCVar->wDepth - 1 - wRowNum) * (DWORD)wWidthBytes; // 指向當前行圖像的指針 lpImage = (LPSTR) (((BYTE*)lpDIBBits) + dwDataNdx); wWidthCnt = 0; wShiftBits = 8 - lpGIFCVar->wBits; byMask = (BYTE)((lpGIFCVar->wBits==1) ? 0x80 : 0xF0); if (bStart) { // 判斷是否是256色位圖(一個像素一字節) if (lpGIFCVar->wBits==8) { // 256色,直接賦值即可 byTemp = *lpImage++; } else { // 非256色,需要移位獲取像素值 wShiftBits = 8 - lpGIFCVar->wBits; byMask = (BYTE)((lpGIFCVar->wBits==1) ? 0x80 : 0xF0); byTemp = (BYTE)((*lpImage & byMask) >> wShiftBits); byMask >>= lpGIFCVar->wBits; wShiftBits -= lpGIFCVar->wBits; } wPrefix = (WORD)byTemp; bStart = FALSE; wWidthCnt ++; } // 每行編碼 while(wWidthCnt < lpGIFCVar->wWidth) { // 判斷是否是256色位圖(一個像素一字節) if (lpGIFCVar->wBits==8) { // 256色,直接賦值即可 byTemp = *lpImage++; } else { // 非256色,需要移位獲取像素值 byChar = *lpImage; byTemp = (BYTE)((byChar & byMask) >> wShiftBits); if (wShiftBits) { byMask >>= lpGIFCVar->wBits; wShiftBits -= lpGIFCVar->wBits; } else { wShiftBits = 8 - lpGIFCVar->wBits; byMask = (BYTE)((lpGIFCVar->wBits==1) ? 0x80 : 0xF0); lpImage ++; } } bySuffix = byTemp; wWidthCnt ++; // 查找當前字符串是否存在于字串表中 wHashNdx = wPrefix ^ ((WORD)bySuffix << 4); wHashGap = (wHashNdx ? (MAX_HASH_SIZE - wHashNdx) : 1); // 判斷當前字符串是否在字串表中 while(TRUE) { // 當前字符串不在字串表中 if (*(lpwTableNdx + wHashNdx) == 0xFFFF) { // 新字符串,退出循環 break; } // 判斷是否找到該字符串 if ((*(lpwPrefix+wHashNdx) == wPrefix) && (*(lpbySuffix+wHashNdx) == bySuffix)) { // 找到,退出循環 break; } // 第二哈希表 if (wHashNdx < wHashGap) { wHashNdx += MAX_HASH_SIZE; } wHashNdx -= wHashGap; } // 判斷是否是新字符串 if (*(lpwTableNdx+wHashNdx) != 0xFFFF) { // 不是新字符串 wPrefix = *(lpwTableNdx + wHashNdx); } else { // 新字符串 // 輸出該編碼 GIF_LZW_WriteCode(file,wPrefix,(LPSTR)bySubBlock, &byCurrentBits,lpGIFCVar); // 將該新字符串添加到字串表中 wPreTableNdx = wNowTableNdx; // 判斷是否達到最大字串表大小 if (wNowTableNdx < MAX_TABLE_SIZE) { *(lpwTableNdx+wHashNdx) = wNowTableNdx++; *(lpwPrefix+wHashNdx) = wPrefix; *(lpbySuffix+wHashNdx) = bySuffix; } if (wPreTableNdx == wTopTableNdx) { if (byCurrentBits<12) { byCurrentBits ++; wTopTableNdx <<= 1; } else { // 字串表到達最大長度 // 輸出LZW_CLEAR GIF_LZW_WriteCode(file, wLZW_CLEAR, (LPSTR)bySubBlock, &byCurrentBits,lpGIFCVar); // 重新初始化字串表 byCurrentBits = byLZW_MinCodeLen + (BYTE)0x01; wLZW_CLEAR = 1 << byLZW_MinCodeLen; wLZW_EOI = wLZW_CLEAR + 1; wNowTableNdx = wLZW_CLEAR + 2; wTopTableNdx = 1 << byCurrentBits; for(wj=0;wj<MAX_HASH_SIZE;wj++) { // 初始化為0xFFFF *(lpwTableNdx+wj) = 0xFFFF; } } } wPrefix = (WORD)bySuffix; } } // 判斷是否是交錯方式 if (bInterlace) { // 交錯方式,計算下一行位置 wRowNum += wIncTable[byPass]; if (wRowNum>=lpGIFCVar->wDepth) { byPass ++; wRowNum = wBgnTable[byPass]; } } else { // 非交錯方式,直接將行數加一即可 wRowNum ++; } } // 輸出當前編碼 GIF_LZW_WriteCode(file, wPrefix, (LPSTR)bySubBlock, &byCurrentBits,lpGIFCVar); // 輸出LZW_EOI GIF_LZW_WriteCode(file,wLZW_EOI,(LPSTR)bySubBlock, &byCurrentBits,lpGIFCVar); if (lpGIFCVar->byLeftBits) { // 加入該字符 bySubBlock[lpGIFCVar->wBlockNdx++] = (BYTE)lpGIFCVar->dwTempCode; // 判斷是否超出MAX_SUBBLOCK_SIZE if (lpGIFCVar->wBlockNdx > MAX_SUBBLOCK_SIZE) { // 判斷wByteCnt + 256是否超過MAX_BUFF_SIZE if ((lpGIFCVar->wByteCnt + 256) >= MAX_BUFF_SIZE) { // 輸出 file.Write(lpGIFCVar->lpDataBuff, lpGIFCVar->wByteCnt); lpGIFCVar->lpEndBuff = lpGIFCVar->lpDataBuff; lpGIFCVar->wByteCnt = 0; } bySubBlock[0] = (BYTE)(lpGIFCVar->wBlockNdx - 1); memcpy(lpGIFCVar->lpEndBuff,(LPSTR)bySubBlock,lpGIFCVar->wBlockNdx); lpGIFCVar->lpEndBuff += lpGIFCVar->wBlockNdx; lpGIFCVar->wByteCnt += lpGIFCVar->wBlockNdx; lpGIFCVar->wBlockNdx = 1; } lpGIFCVar->dwTempCode = 0UL; lpGIFCVar->byLeftBits = 0x00; }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -