?? 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 + -