音視頻入門文章目錄 html
GIF 包含的數據塊:git
今天的目標是作出一張尺寸 700x700、7 個顏色畫面切換的 GIF 動畫。 github
GIF 的前 6 個字節內容是 GIF 的署名和版本號。有兩個版本 GIF87a
GIF89a
,GIF89a
版本纔有多幀動畫,全部這裏使用 89a
版本。算法
示例代碼:瀏覽器
// GIF 文件頭,6 個字節內容是 GIF 的署名和版本號 uint8_t gif_header[] = {0x47, 0x49, 0x46, 0x38, 0x39, 0x61}; fwrite(gif_header, 6, 1, gif_file);
從上一篇 音視頻入門-17-GIF文件格式詳解 咱們知道:app
邏輯屏幕標識符(7 個字節):ide
打包值,大小爲 1 字節post
示例代碼:動畫
// 邏輯屏幕標識符 uint16_t gif_width = 700; uint16_t gif_height = 700; // 0xF2 = 1 1 1 1 0 0 1 0 uint8_t gif_logical_screen_pack_byte = 0xF2; uint8_t gif_bg_color_index = 0; uint8_t gif_pixel_aspect = 0; fputc(gif_width >> 0, gif_file); // width low 8 fputc(gif_width >> 8, gif_file); // width high 8 fputc(gif_height >> 0, gif_file); // height low 8 fputc(gif_height >> 8, gif_file); // height high 8 fputc(gif_logical_screen_pack_byte, gif_file); fputc(gif_bg_color_index, gif_file); fputc(gif_pixel_aspect, gif_file);
每一個顏色索引由三字節組成,按 RGB 順序排列。ui
由 【邏輯屏幕標識符】可知,顏色的索引數(2^(pixel+1))是 2 的倍數,若是圖片顏色數目不夠要補足。
好比,咱們的圖片用了 7 個顏色,顏色索引數是 8,因此最後再加一個顏色(佔位,不使用)。
示例代碼:
// 顏色表 uint32_t rainbowColors[] = { 0XFF0000, // 赤 0XFFA500, // 橙 0XFFFF00, // 黃 0X00FF00, // 綠 0X007FFF, // 青 0X0000FF, // 藍 0X8B00FF, // 紫 0X000000 // 黑 }; // 全局顏色表、 for(int i = 0; i < 8; i++) { // 根據顏色索引取出顏色表中的顏色 uint32_t color_rgb = rainbowColors[i]; // 當前顏色 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_file); fputc(G, gif_file); fputc(B, gif_file); }
Application Extension 這 19 個字節基本上 GIF 都同樣。
0x21, 0xFF, 0x0B, 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0x00, 0x00, 0x00
表明的內容是 NETSCAPE2.0
示例代碼:
// Application Extension uint8_t gif_application_extension[] = {0x21, 0xFF, 0x0B, 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0x00, 0x00, 0x00}; fwrite(gif_application_extension, 19, 1, gif_file);
這裏容許你將 ASCII 文本嵌入到 GIF 文件,有時被用來圖像描述、圖像信貸或其餘人類可讀的元數據,如圖像捕獲的 GPS 定位。
0x21, 0xFE, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x65, 0x7A, 0x67, 0x69, 0x66, 0x2E, 0x63, 0x6F, 0x6D, 0x20, 0x47, 0x49, 0x46, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x72, 0x00
表明的內容是 Created with ezgif.com GIF maker
示例代碼:
// Comment Extension // Created with ezgif.com GIF maker uint8_t gif_comment_extension[] = {0x21, 0xFE, 0x20, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x65, 0x7A, 0x67, 0x69, 0x66, 0x2E, 0x63, 0x6F, 0x6D, 0x20, 0x47, 0x49, 0x46, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x72, 0x00}; fwrite(gif_comment_extension, 36, 1, gif_file);
咱們的 GIF 不使用處置方法
不使用透明色
圖像延遲 50
。
因此,這裏就是 0x21, 0xF9, 0x04, 0x00, 0x32, 0x00, 0xFF, 0x00
。
示例代碼:
// 圖形控制擴展 uint8_t gif_graphic_control_extension[] = {0x21, 0xF9, 0x04, 0x00, 0x32, 0x00, 0xFF, 0x00}; fwrite(gif_graphic_control_extension, 8, 1, gif_file);
咱們的 GIF 沒有局部顏色表
順序排列
局部顏色表大小爲 0
。
因此,這裏就是 0x2C, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x02, 0xBC, 0x02, 0x00
。
示例代碼:
// 圖像標識符 uint8_t gif_image_descriptor[] = {0x2C, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x02, 0xBC, 0x02, 0x00}; fwrite(gif_image_descriptor, 10, 1, gif_file);
若是有局部顏色表,則跟 全局顏色表(Global Color Table) 同樣的格式。
這裏是最關鍵的圖像數據,生成步驟以下:
咱們要生成的 GIF 尺寸 700x700,有 7 張圖像,每張圖像一個顏色 赤
橙
黃
綠
青
藍
紫
;
顏色已經寫入全局顏色表中;
每一個顏色索引 1 字節;
示例代碼:
// 基於顏色表的圖像數據 uint8_t *gif_one_frame_raw = malloc(700 * 700); memset(gif_one_frame_raw, i, 700*700);
LZW 壓縮算法不在本次研究範圍,直接用便可。
// GIF 一幀圖像的數據壓縮後大小 unsigned long compressed_size; // GIF 一幀圖像的數據解壓後的數據 unsigned char *img; lzw_compress_gif( 3, 700*700, gif_one_frame_raw, &compressed_size, &img );
第一個字節表示 LZW 編碼初始表大小的位數,用於使用 LZW 算法解壓數據。
後面的是圖像數據塊:
每一個數據塊第一個字節表示數據塊大小(不包括這個字節)
數據塊後面的一個字節表示後續數據塊大小
當數據塊後面的一個字節是 0 ,表示數據結束了
示例代碼:
fputc(0x03, gif_file); unsigned long current_index = 0; while (current_index < compressed_size) { if((current_index + 0xFF) >= compressed_size) { unsigned long diff = compressed_size - current_index; fputc(diff, gif_file); fwrite(img+current_index, diff, 1, gif_file); fputc(0x00, gif_file); current_index += diff; } else { fputc(0xFF, gif_file); fwrite(img+current_index, 0xFF, 1, gif_file); current_index += 0xFF; } }
這個特性不起做用; 瀏覽器和圖片處理應用程序,如 Photoshop 忽略它, GIFLIB 並不試圖解釋它。
因此直接忽略。
標識 GIF 文件結束,固定值 0x3B。
當解析程序讀到 0x3B 時,文件終結。
示例代碼:
// GIF 文件結束: 0x3B fputc(0x3B, gif_file);
以上完整代碼在 binglingziyu/audio-video-blog-demos 能夠獲取。
運行代碼,生成 GIF 圖片:
參考資料: