GIF是圖像交換格式(Graphics Interchange Format)的簡稱,它是由美國CompuServe公司在1987年所提出的圖像檔案格式,它最初的目的是希望每個BBS的使用者能夠通過GIF圖像 檔案輕易存儲并交換圖像資料,這也就是它為什麼被稱為圖像交換格式的原因了。
GIF檔案格式采用了一種經過改進的LZW壓縮算法,通常我們稱 之為GIF-LZW算法。這是一種無損的壓縮算法,壓縮效率也比較高,并且GIF支援在一幅GIF檔案中存放多幅彩色圖像,并且可以按照一定的順序和時間 間隔将多幅圖像依次讀出并顯示在螢幕上,這樣就可以形成一種簡單的動畫效果。盡管GIF最多隻支援256色,但是由于它具有極佳的壓縮效率并且可以做成動 畫而早已被廣泛接納采用。下面筆者詳細介紹GIF檔案的格式。
GIF圖像檔案是以塊的形式來存儲圖像資訊,其中的塊又稱為區域結構。按照其中 塊的特征又可以将所有的塊分成三大類,分别是控制塊(Control Block)、圖像描述塊(Graphic Rendering Block)和特殊用途塊(Special Purpose Block)。控制塊包含了控制資料流的處理以及硬體參數的設定,其成員主要包括檔案頭資訊、邏輯螢幕描述塊、圖像控制擴充塊和檔案結尾塊。圖像描述塊包 含了在顯示裝置上描述圖像所需的資訊,其成員包括圖像描述塊、全局調色闆、局部調色闆、圖像壓縮資料和圖像說明擴充塊。特殊用途塊包含了與圖像資料處理無 直接關系的資訊,其成員包括圖像注釋擴充塊和應用程式擴充塊。下面詳細介紹每一個塊的詳細結構。
1. 檔案頭資訊
GIF的檔案頭隻有六個位元組,其結構定義如下:
typedef struct gifheader
{
BYTE bySignature[3];
BYTE byVersion[3];
} GIFHEADER;
其中,bySignature為GIF檔案标示碼,其固定值為“GIF”,使用者可以通過該域來判斷一個圖像檔案是否是GIF圖像格式的檔案。 byVersion表明GIF檔案的版本資訊。其取值固定為“87a”和“89a”。分别表示GIF檔案的版本為GIF87a或GIF89a。這兩個版本 有一些不同,GIF87a公布的時間為1987年,該版本不支援動畫和一些擴充屬性。GIF89a是1989年确定的一個版本标準,隻有89a版本才支援 動畫、注釋擴充和文本擴充。
2. 邏輯螢幕描述塊
邏輯螢幕(Logical Screen)是一個虛拟螢幕(Virtual Screen),它相當于畫布,所有的操作都是在它的基礎上進行的,同時它也決定了圖像的長度和寬度。邏輯螢幕描述塊共占有七個位元組,其具體結構定義如下:
typedef struct gifscrdesc
{
WORD wWidth;
WORD wDepth;
struct globalflag
{
BYTE PalBits : 3;
BYTE SortFlag : 1;
BYTE ColorRes : 3;
BYTE GlobalPal : 1;
} GlobalFlag;
BYTE byBackground;
BYTE byAspect;
} GIFSCRDESC;
其中,wWidth用來指定邏輯螢幕的寬度,wDepth用來指定邏輯螢幕的高度,glaobalflag為全域性資料,它的總長度為一個位元組,其中前 三位(第0位到第2位)指定全局調色闆的位數,可以通過該值來計算全局調色闆的大小。第3位表明全局調色闆中的RGB顔色值是否按照使用率進行從高到底的 次序排序的。第4到第6位指定圖像的色彩分辨率。第7位指明GIF檔案中是否具有全局調色闆,其值取1表示有全局調色闆,為0表示沒有全局調色闆。一個 GIF檔案可以有全局調色闆也可以沒有全局調色闆,如果定義了全局調色闆并且沒有定義某一幅圖像的局部調色闆,則本幅圖像采用全局調色闆;如果某一幅圖像 定義的自己的局部調色闆,則該幅圖像使用自己的局部調色闆。如果沒有定義全局調色闆,則GIF檔案中的每一幅圖像都必須定義自己的局部調色闆。全局調色闆 必須緊跟在邏輯螢幕描述塊的後面,其大小由GlobalFlag.PalBits決定,其最大長度為768(3*256)位元組。全局調色闆的資料是按照 RGBRGB…..RGB的方式存儲的。byBackground用來指定邏輯螢幕的背景顔色,也就相當于是畫布的顔色。當圖像長寬小于邏輯螢幕的大小 時,未被圖像覆寫部分的顔色值由該值對應的全局調色闆中的索引顔色值确定。如果沒有全局調色闆,該值無效,預設背景顔色為黑色。byAspect用來指定 邏輯螢幕的像素的長寬比例。
3. 圖像描述塊
一幅GIF圖像檔案中可以存儲多幅圖像,并且這些圖像沒有固定的存放次序。為了區分兩幅 圖像,GIF采用了一個位元組的識别碼(Image Separator)來判斷下面的資料是否是圖像描述塊。圖像描述塊以0x2C開始,定義緊接着它的圖像的性質,包括圖像相對于邏輯螢幕邊界的偏移量、圖 像大小以及有無局部調色闆和調色闆的大小。圖像描述塊由10個位元組組成:
typedef struct gifimage
{
WORD wLeft;
WORD wTop;
WORD wWidth;
WORD wDepth;
struct localflag
{
BYTE PalBits : 3;
BYTE Reserved : 2;
BYTE SortFlag : 1;
BYTE Interlace : 1;
BYTE LocalPal : 1;
} LocalFlag;
} GIFIMAGE;
其中,wLeft用來指定圖像相對邏輯螢幕左上角的X坐标,以象素為機關。wTop用來指定圖像相對邏輯螢幕左上角的Y坐标。wWdith和 wDepth分别用來指定圖像的寬度和高度。LocalFlag用來指定區域性資料,也就是具體一幅圖像的屬性。LocalFlag的總長度為一個位元組, 其中的前三位用來指定局部調色闆的位數,可以根據該值來計算局部調色闆的大小。第4位到第5位為保留位,沒有使用,其值固定為0。第6位指明局部調色闆中 的RGB顔色值是否經過排序,其值為1表示調色闆中的RGB顔色值是按照其使用率從高到底的次序進行排序。第7位表示GIF圖像是否以交錯方式存儲,其取 值為1表示以交錯的方式進行存儲。當圖像是按照交錯方式存儲時,其圖像資料的處理可以分為4個階段:第一階段從第0行開始,每次間隔8行進行處理;第二階 段從第4行開始,每次間隔8行進行處理;第三階段從第2行開始,每次間隔4行進行處理;第四階段從第1行開始,每次間隔2行進行處理,這樣當完成第一階段 時就可以看到圖像的概貌,當處理完第二階段時,圖像會變得清晰一些;當處理完第三階段時,圖像處理完成一半,清晰效果也進一步增強,當完成第四階段,圖像 處理完畢,顯示出完整清晰的整幅圖像。以交錯方式存儲是GIF檔案格式的一個重要的特點,也是GIF檔案格式的一個重要的優點。以交錯方式存儲的圖像的好 處就是無需将整個圖像檔案解壓完成就可以看到圖像的概貌,這樣可以減少使用者的等待時間。第8位指明GIF圖像是否含有局部調色闆,如果含有局部調色闆,則 局部調色闆的内容應當緊跟在圖像描述塊的後面。
4. 圖像壓縮資料
圖像壓縮資料是按照GIF-LZW壓縮編碼後存儲于圖像壓縮資料塊 中的。GIF-LZW編碼是一種經過改良的LZW編碼方式,它是一種無損壓縮的編碼方法。GIF-LZW編碼方法是将原始資料中的重複字元串建立一個字元 串表,然後用該重複字元串在字元串表中的索引來替代原始資料以達到壓縮的目的。由于GIF-LZW壓縮編碼的需要,必須首先存儲GIF-LZW的最小編碼 長度以供解碼程式使用,然後再存儲編碼後的圖像資料。編碼後的圖像資料是一個個資料子塊的方式存儲的,每個資料子塊的最大長度為256位元組。資料子塊的第 一個位元組指定該資料子塊的長度,接下來的資料為資料子塊的内容。如果某個資料子塊的第一個位元組數值為0,即該資料子塊中沒有包含任何有用資料,則該子塊稱 為塊終結符,用來辨別資料子塊到此結束。
5. 圖像控制擴充塊
圖像控制擴充塊是可選的,隻應用于89a版本,它描述了與圖像控制相關 的參數。一般情況下,圖像控制擴充塊位于一個圖像塊(包括圖像辨別符、局部顔色清單和圖像資料)或文本擴充塊的前面,用來控制跟在它後面的第一個圖像(或 文本)的渲染(Render)形式,組成結構如下:
typedef struct gifcontrol
{
BYTE byBlockSize;
struct flag
{
BYTE Transparency : 1;
BYTE UserInput : 1;
BYTE DisposalMethod : 3;
BYTE Reserved : 3;
} Flag;
WORD wDelayTime;
BYTE byTransparencyIndex;
BYTE byTerminator;
} GIFCONTROL;
其中,byBlockSize用來指定該圖像控制擴充塊的長度,其取值固定為4。Flag用來描述圖像控制相關資料,它的長度為1個位元組。它的第0位用 來指定圖像中是否具有透明性的顔色,如果該位為1,這表明圖像中某種顔色具有透明性,該顔色由參數byTransparencyIndex指定。第一位用 來判斷在顯示一幅圖像後,是否需要使用者輸入後再進行下一個動作。如果該位為1,則表示應用程式在進行下一個動作之前需要使用者輸入。第2-4位用來指定圖像 顯示後的處理方式,當該值為0時,表示沒有指定任何處理方式;當該值為1時,表明不進行任何處理動作;當該值為2時,表明圖像顯示後以背景色擦去;當該值 為3時,表明圖像顯示後恢複原先的背景圖像。第5-7位為保留位,沒有任何含義,固定為0。wDelayTime用來指定應用程式進行下一步操作之前延遲 的時間,機關為0.01秒。如果Flag.UserInput和wDelayTime都設定了,則以先發者為主,如果沒有到指定的延遲時間即有使用者輸入, 則應用程式直接進行下一步操作。如果到達延遲時間後還沒有使用者輸入,應用程式也直接進入下一步操作。byTransparenceIndex用來指定圖像 中透明色的顔色索引,指定的透明色将不在顯示裝置上顯示。byTerminator為塊終結符,其值固定為0。
6. 圖像說明擴充塊
圖像說明擴充塊又可以稱為圖像文本擴充塊,它用來繪制一個簡單的文本圖像,這一部分由用來繪制的純文字資料(7位的 ASCII字元)和控制繪制的參數等組成。繪制文本借助于一個文本框(Text Grid)來定義邊界,在文本框中劃分多個單元格,每個字元占用一個單元,繪制時按從左到右、從上到下的順序依次進行,直到最後一個字元或者占滿整個文本 框(之後的字元将被忽略,是以定義文本框的大小時應該注意到是否可以容納整個文本),繪制文本的顔色使用全局顔色清單,沒有則可以使用一個已經儲存的前一 個顔色清單。另外,圖形文本擴充塊也屬于圖形塊(Graphic Rendering Block),可以在它前面定義圖形控制擴充對它的表現形式進一步修改。圖像說明擴充塊的組成:
typedef struct gifplaintext
{
BYTE byBlockSize;
WORD wTextGridLeft;
WORD wTextGridTop;
WORD wTextGridWidth;
WORD wTextGridDepth;
BYTE byCharCellWidth;
BYTE byCharCellDepth;
BYTE byForeColorIndex;
BYTE byBackColorIndex;
} GIFPLAINTEXT;
其中,byBlockSize用來指定該圖像擴充塊的長度,其取值固定為13。wTextGridLeft用來指定文字顯示方格相對于邏輯螢幕左上角的 X坐标(以像素為機關)。wTextGridTop用來指定文字顯示方格相對于邏輯螢幕左上角的Y坐标。wTextGridWidth用來指定文字顯示方 格的寬度。wTextGridDepth用來指定文字顯示方格的高度。byCharCellWidth用來指定字元的寬度, byCharCellDepth用來指定字元的高度。byForeColorIndex用來指定字元的前景色,byBackColorIndex用來指定 字元的背景色。
7. 圖像注釋擴充塊
圖像注釋擴充塊包含了圖像的文字注釋說明,可以用來記錄圖形、版權、描述等任何的非圖形和控制的 純文字資料(7位的ASCII字元),注釋擴充并不影響對圖象資料流的處理,解碼器完全可以忽略它。存放位置可以是資料流的任何地方,最好不要妨礙控制和 資料塊,推薦放在資料流的開始或結尾。在GIF中用識别碼0xFE來判斷一個擴充塊是否為圖像注釋擴充塊。圖像注釋擴充塊中的資料子塊個數不限,必須通過 塊終結符來判斷該擴充塊是否結束。
8. 應用程式擴充塊
應用程式擴充塊包含了制作該GIF圖像檔案的應用程式的資訊,GIF中用識别碼0xFF來判斷一個擴充塊是否為應用程式擴充塊。它的結構定義如下:
typedef struct gifapplication
{
BYTE byBlockSize;
BYTE byIdentifier[8];
BYTE byAuthentication[3];
} GIFAPPLICATION;
其中,byBlockSize用來指定該應用程式擴充塊的長度,其取值固定為12。byIdentifier用來指定應用程式名稱。byAuthentication用來指定應用程式的識别碼。
9. 檔案結尾塊
檔案結尾塊為GIF圖像檔案的最後一個位元組,其取值固定為0x3B