音視頻入門文章目錄 html
圖像互換格式主要分爲兩個版本,即圖像互換格式 87a 和圖像互換格式 89a。
圖像互換格式 87a:是在 1987 年制定的版本。
圖像互換格式 89a:是在 1989 年制定的版本。在這個版本中,爲圖像互換格式文檔擴充了圖形控制區塊、備註、說明、應用程序接口等四個區塊,並提供了對透明色和多幀動畫的支持。git
如今咱們通常所說的 GIF 動畫都是指 89a 的格式。github
GIF 包含的數據塊:算法
本文全部分析,都是基於下面這張 GIF 圖片。
用來分析的樣例圖片瀏覽器
十六進制編輯器app
GIF 的前 6 個字節內容是 GIF 的署名和版本號。
咱們能夠經過前 3 個字節判斷文件是否爲 GIF 格式,後 3 個字節判斷 GIF 格式的版本:編輯器
邏輯屏幕標識符配置了 GIF 一些全局屬性,咱們經過讀取解析它,獲取 GIF 全局的一些配置。ide
邏輯屏幕標識符(7 個字節):工具
打包值,大小爲 1 字節oop
從圖中能夠看出,這張 GIF 圖片:
PS: Glide 中在讀取了全局的寬高以後,忽略了顏色深度和分類標誌,像素寬高比也只是讀取,後續並無使用到。
全局顏色表,在邏輯屏幕標識以後,每一個顏色索引由三字節組成,按 RGB 順序排列。
在 (2) 邏輯屏幕標識符(Logical Screen Descriptor)
中獲得,全局顏色表大小是 8 個顏色,每一個顏色佔 3 字節(R、G、B)。
接下來出現的是 21
FF
,特定於應用程序的信息,這個並無太大用處。惟一已知的公共文件是 Netscape 2.0 擴展(以下所述),用於循環動畫GIF文件。
Netscape 2.0 循環塊擴展必須當即出如今邏輯屏幕描述符的全局顏色表以後。它有19個字節長。
byte 1 : 33 (hex 0x21) GIF Extension code byte 2 : 255 (hex 0xFF) Application Extension Label byte 3 : 11 (hex 0x0B) Length of Application Block (eleven bytes of data to follow) bytes 4 to 11 : "NETSCAPE" bytes 12 to 14 : "2.0" byte 15 : 3 (hex 0x03) Length of Data Sub-Block (three bytes of data to follow) byte 16 : 1 (hex 0x01) bytes 17 to 18 : 0 to 65535, an unsigned integer in little-endian byte format. This specifies the number of times the loop should be executed. byte 19 : 0 (hex 0x00) a Data Sub-Block Terminator.
Application Extension 這 19 個字節基本上目前全部 GIF 都同樣。
在 89a 版本,GIF 添加了圖形控制擴展塊。放在一個圖象塊(圖象標識符)的前面,用來控制它後面的第一個圖象的顯示。
處置方法(Disposal Method):指出處置圖形的方法:
用戶輸入能夠是按回車鍵、鼠標點擊等,能夠和延遲時間一塊兒使用,在設置的延遲時間內用戶有輸入則立刻繼續進行,或者沒有輸入直到延遲時間到達而繼續。
透明顏色標誌(Transparent Color Flag):置位表示使用透明顏色。
從圖中能夠看出,這張 GIF 圖片:
接下來出現的是 21
FE
,這容許你將 ASCII 文本嵌入到 GIF 文件,有時被用來圖像描述、圖像信貸或其餘人類可讀的元數據,如圖像捕獲的 GPS 定位。
下面是這張圖片的 Comment Extension:
一個 GIF 文件中能夠有多個圖像塊,每一個圖像塊就會有圖像標識符,描述了當前幀的一些屬性。下面咱們來看看圖像標識符中包含的一些信息。
圖像標識符以 ',' (0x2c) 做爲開始標誌。接着定義了當前幀的偏移量和寬高。
最後 5 個標誌的意義分別爲:
置位時標識緊接在圖象標識符以後有一個局部顏色列表,供緊跟在它以後的一幅圖象使用;值否時使用全局顏色列表,忽略 pixel 值。
從圖中能夠看出,這張 GIF 圖片:
若是有局部顏色表,則跟 (3) 全局顏色表(Global Color Table)
同樣的格式。
接下來就是圖像數據(已使用 LZW 算法壓縮,解壓後纔是真正的 基於顏色表的圖像數據
)。
數據的第一個字節表示 LZW 編碼初始表大小的位數,用於使用 LZW 算法解壓數據。
後面的是圖像數據塊:
0
,表示數據結束了
如上圖所示:
最後一步,咱們將使用 LZW 算法解壓圖像數據塊,並根據顏色表還原出整張圖像(GIF 的一幀)的 RGB 文件。
須要刪除標藍色之外的全部字節,保存爲rainbow-compressed.gif.frame
。
這個特性不起做用; 瀏覽器和圖片處理應用程序,如 Photoshop 忽略它, GIFLIB 並不試圖解釋它。
標識 GIF 文件結束,固定值 0x3B。
當解析程序讀到 0x3B 時,文件終結。
根據 (9) 基於顏色表的圖像數據(Image Data)
,能夠獲得 GIF 一幀圖像的數據(已使用 LZW 算法壓縮)。
文 件 名:rainbow-compressed.gif.frame
文件大小:3428字節
這裏直接使用 github.com/jefftime/lzw 這個庫。
#include "stdio.h" #include "stdlib.h" #include "lzw/src/lzw.h" int main () { // LZW 編碼初始表大小的位數:3 unsigned char code_size = 3; // GIF 一幀圖像的數據壓縮文件(rainbow-compressed.gif.frame)大小 long total_bytes; // GIF 一幀圖像的數據壓縮數據 unsigned char *img_compressed; // GIF 一幀圖像的數據解壓後的數據 unsigned char *img; // GIF 一幀圖像的數據解壓後大小 unsigned long decompressed_size; FILE *gif_compressed_frame = fopen("/Users/staff/Desktop/rainbow-compressed.gif.frame", "rb+"); fseek(gif_compressed_frame, 0L, SEEK_END); total_bytes = ftell(gif_compressed_frame); fseek(gif_compressed_frame, 0L, SEEK_SET); printf("Gif 一幀壓縮文件大小:%li\n", total_bytes); img_compressed = malloc((unsigned long) total_bytes); fread(img_compressed, total_bytes, 1, gif_compressed_frame); // 進行 LZW 解壓 lzw_decompress( code_size, total_bytes, img_compressed, &decompressed_size, &img ); printf("Gif 一幀解壓文件大小:%li\n", decompressed_size); FILE *gif_decompressed_frame = fopen("/Users/staff/Desktop/rainbow-decompressed.gif.frame", "wb+"); fwrite(img, decompressed_size, 1, gif_decompressed_frame); fflush(gif_decompressed_frame); free(img_compressed); free(img); fclose(gif_compressed_frame); fclose(gif_decompressed_frame); return 0; }
解壓後獲得解壓文件:rainbow-decompressed.gif.frame
解壓後文件大小:490000字節 (700x700x1)
解壓後文件中每個字節表明顏色表的一個顏色索引
#include "stdio.h" #include "stdlib.h" #include "lzw/src/lzw.h" // 顏色表 uint32_t rainbowColors[] = { 0XFF0000, // 赤 0X00FF00, // 綠 0XFFA500, // 橙 0XFFFF00, // 黃 0X0000FF, // 藍 0X007FFF, // 青 0X8B00FF, // 紫 0X000000 // 黑 }; int main () { ...... FILE *gif_frame_rgb = fopen("/Users/staff/Desktop/rainbow-decompressed.gif.frame.rgb", "wb+"); for(int i = 0; i < decompressed_size; i++) { // 顏色索引值 unsigned char color_index = img[i]; // 根據顏色索引取出顏色表中的顏色 uint32_t color_rgb = rainbowColors[color_index]; // 當前顏色 R 份量 uint8_t R = (color_rgb & 0xFF0000) >> 16; // 當前顏色 G 份量 uint8_t G = (color_rgb & 0x00FF00) >> 8; // 當前顏色 B 份量 uint8_t B = color_rgb & 0x0000FF; fputc(R, gif_frame_rgb); fputc(G, gif_frame_rgb); fputc(B, gif_frame_rgb); } fflush(gif_frame_rgb); ...... }
這一步,獲得了 GIF 一幀圖像的 RGB 文件:rainbow-decompressed.gif.frame.rgb
GIF 一幀圖像的 RGB 文件大小爲:1470000 字節(700x700x3)
ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-decompressed.gif.frame.rgb
參考資料:
內容有誤?聯繫做者: