不知不覺又半個月沒有更新部落格了,今天終於抽出點時間,來分享一下前段時間的成果。
在網上,我們經常看到各種各樣的圖片,尤其是GIF圖片的動態效果,讓整個網站更加富有表現力!有時候,我們看到一些比較好看的GIF圖片或者一些奇特的Gif圖片,我們想要停留在某一幀看的清楚一點或者瞭解這個Gif動畫到底是怎麼實現的,懷著這種好奇的心理,我們來看一下,今天的開源專案,用WPF來實現GIF圖片的預覽和分離和儲存。
1、GIF簡介
GIF(Graphics Interchange Format)是CompuServe公司開發的影像檔案儲存格式,1987年開發的GIF檔案格式版本號是GIF87a,1989年進行了擴充,擴充後的版本號定義為GIF89a。 GIF影像檔案以資料塊(block)為單位來儲存影像的相關資訊。一個GIF檔案由表示圖形/影像的資料塊、資料子塊以及顯示圖形/影像的控制資訊塊組成,稱為GIF資料流(Data Stream)。資料流中的所有控制資訊塊和資料塊都必須在檔案頭(Header)和檔案結束塊(Trailer)之間。
GIF檔案格式採用了LZW(Lempel-Ziv Walch)壓縮演算法來儲存影像資料,定義了允許使用者為影像設定背景的透明(transparency)屬性。此外,GIF檔案格式可在一個檔案中存放多幅彩色圖形/影像。如果在GIF檔案中存放有多幅圖,它們可以像演幻燈片那樣顯示或者像動畫那樣演示。
2、GIF檔案結構
GIF檔案結構的典型結構如圖6-01所示。為下文說明方便,在構件左邊加了編號。
資料塊可分成3類:
控制塊(Control Block),圖形描繪塊(Graphic-Rendering Block)和專用塊(Special Purpose Block)。
(1) 控制塊:
控制塊包含有用來控制資料流(Data Stream)或者設定硬體引數的資訊,其成員包括:
GIF檔案頭(Header)
邏輯螢幕描述塊(Logical Screen Descriptor)
圖形控制擴充套件塊(Graphic Control Extension)
檔案結束塊(Trailer)
(2) 圖形描繪塊:
包含有用來描繪在顯示裝置上顯示圖形的資訊和資料,其成員包括:
影像描述塊(Image Descriptor)
無格式文字擴充套件塊(Plain Text Extension)
全域性調色盤、區域性調色盤、影像壓縮資料和影像說明擴充塊。
(3) 特殊用途資料塊:
包含有與影像處理無關的資訊,其成員包括:
註釋擴充套件塊(Comment Extension)
應用擴充套件塊(Application Extension)
除了在控制塊中的邏輯螢幕描述塊(Logical Screen Descriptor)和全域性彩色表(Global Color Table)的作用範圍是整個資料流(Data Stream)之外, 所有其他控制塊僅跟在它們後面的圖形描繪塊。
3、GIF結構詳解
由於GIF結構比較複雜,我們就簡單講解一下GIF的檔案頭吧,因為我們要用到,更多的資料請參看百度文庫:http://wenku.baidu.com/view/2c0feaa6f524ccbff121841d.html。
(1)檔案頭描述塊(Header)定義GIF資料流(GIF Data Stream),它的結構如圖6-02所示。檔案頭描述塊(Header)由GIF標記域(Signature)和版本號(Version)域組成,是一個由6個固定位元組組成的資料塊,它們用來說明使用的檔案格式是GIF格式及當前所用的版本號。GIF標記域(Signature)存放的是“GIF”,版本號域存放的是1987年5月釋出的“87a”或者1989年7月釋出的“89a”,或者更加新的版本號。
這裡我們識別一個圖片是不是GIF檔案,就是判斷檔案的前三個位元組是不是GIF,就算是圖片唄重新命名為jpg或者其他的,只要用瀏覽器開啟,都是可以正常顯示的,這也就是為什麼有些jpg圖片也會動的原因。同理PNG圖片的前三個圖片是PNG.
(2)邏輯螢幕描述塊(Logical Screen Descriptor)包含定義影像顯示區域的引數,包括背景顏色資訊。這個資料塊中的座標相對於虛擬螢幕的左上角,不一定是指螢幕的絕對座標,這就意味可以參照視窗軟體環境下的視窗座標或者印表機座標來設計影像顯示程式。邏輯螢幕描述塊的結構如圖6-03所示:
這裡我們看到GIF的欄位,可以讀取GIF圖片的實際高度和寬度,到這裡就差不多了,其他的大家看百度文庫的文件吧,我就不再說了。
上面給大家講了那麼多的GIF檔案的東西,可能大家看的有點不耐煩,目的主要是為了讓大家瞭解GIF的結構,這樣才能更好的讀懂專案裡面的程式碼。下面來看一段讀取GIF檔案資訊的程式碼,體會一下:
private void ShowGifInfo(byte[] buffer, string imgPath) { string type = ASCIIEncoding.ASCII.GetString(buffer, 0, 3); //前3個位元組,標識"GIF" string version = ASCIIEncoding.ASCII.GetString(buffer, 3, 3);//3~6個位元組,版本號 int logicalWidth = BitConverter.ToUInt16(buffer, 6);//第7,8兩個位元組,寬度 int logicalHeight = BitConverter.ToUInt16(buffer, 8); //第9,10兩個位元組,高度 txtFileName.Text = "圖片路徑: " + imgPath; txtTotalFrames.Text = "總幀數: " + bd.Frames.Count.ToString(); txtRealHeight.Text = "實際高度: " + logicalHeight.ToString() + "px"; txtRealWidth.Text = "實際寬度: " + logicalWidth.ToString() + "px"; txtVersion.Text = "Gif版本: " + version; }
這段程式碼讀取和顯示GIF的標識、版本號、寬度和高度資訊。可以看到,都是讀取檔案的特定的幾個位元組。
下面來看看這個開源專案的介面吧,首先GIF圖片,如下:
看起來很炫,是吧,然後我們來看看到底都有哪些幀組成的,如圖:
我們可以看到GIF的版本號和幀數,一共是8幀,也就是八張圖片,我們點選另存為,輸入圖片名稱,如Img,儲存每一幀圖片,如圖:
我們看到,八張圖片都分離出來了,看起來好漂亮啊,圖片的名字就是我們剛才輸入的名稱後面加上編號。
下面我們來看幾個比較神祕的GIF,如下圖:
這幾張圖片看起來是無限迴圈的,沒有停頓,那麼他們到底有多少幀呢?這個就留給大家去探索吧!
叫你看完不點推薦,見你看完不點推薦……
Github開源地址:https://github.com/yunfeifei/GifSeparator/
專案中有不足的地方,大家可以留言指出,我會第一時間修改更正!同時歡迎大家一起進QQ群學習交流~
作者:雲霏霏
QQ交流群:243633526
部落格地址:http://www.cnblogs.com/yunfeifei/
宣告:本部落格原創文字只代表本人工作中在某一時間內總結的觀點或結論,與本人所在單位沒有直接利益關係。非商業,未授權,貼子請以現狀保留,轉載時必須保留此段宣告,且在文章頁面明顯位置給出原文連線。
如果大家感覺我的博文對大家有幫助,請推薦支援一把,給我寫作的動力。