LoginSignup
11
8

More than 5 years have passed since last update.

GIFのバイナリを読んでみた

Last updated at Posted at 2017-01-16

GIFの仕様書を見ながら小さなGIFファイルを読んでみました。調査結果を基に手を加えてアニメーション化を試み、差分を示しました。

シリーズの記事です。

  1. GIFのバイナリを読んでみた ← この記事
  2. GIFのLZW圧縮を調べてみた
  3. GIFのLZWを展開してみた

参考

英語版Wikipediaと、そこからリンクされている仕様書を参照しました。

サンプル

GIMPで16×16の画像を作りました。

gif1.gif

バイナリダンプ
00000000  47 49 46 38 37 61 10 00  10 00 a1 02 00 00 00 00  |GIF87a..........|
00000010  80 80 80 ff ff ff ff ff  ff 2c 00 00 00 00 10 00  |.........,......|
00000020  10 00 00 02 2b 94 8f a9  16 b0 0b 42 78 c8 09 4b  |....+......Bx..K|
00000030  b1 a4 fb 60 f5 5d 4f 28  74 47 03 a4 91 07 22 92  |...`.]O(tG....".|
00000040  14 bd e5 b4 98 62 56 51  f7 ac db fa fe 43 14 00  |.....bVQ.....C..|
00000050  00 3b                                             |.;|

解読

仕様書を見ながらコメントを付けます。仕様書の該当するセクションを記載します。

  • F#で文字の B や数値の uybyte 型を表すサフィックスで、省略できません。
  • Width, Height などの2バイト値はリトルエンディアンです。
GIFTest.fsx
let gif = [|
    // 17. Header.
    'G'B; 'I'B; 'F'B  // Signature
    '8'B; '7'B; 'a'B  // Version

    // 18. Logical Screen Descriptor.
    16uy; 0uy  // Logical Screen Width
    16uy; 0uy  // Logical Screen Height
    0xA1uy     // <Packed Fields>
               //   Global Color Table Flag
               //   | Color Resolution
               //   | |   Sort Flag
               //   | |   | Size of Global Color Table
               //   1 010 0 001
    2uy        // Background Color Index
    0uy        // Pixel Aspect Ratio

    // 19. Global Color Table.
    0x00uy; 0x00uy; 0x00uy  // RGB #0
    0x80uy; 0x80uy; 0x80uy  // RGB #1
    0xFFuy; 0xFFuy; 0xFFuy  // RGB #2
    0xFFuy; 0xFFuy; 0xFFuy  // RGB #3

    // 20. Image Descriptor.
    0x2Cuy     // Image Separator
    0uy ; 0uy  // Image Left Position
    0uy ; 0uy  // Image Top Position
    16uy; 0uy  // Image Width
    16uy; 0uy  // Image Height
    0uy        // <Packed Fields>
               //   Local Color Table Flag
               //   | Interlace Flag
               //   | | Sort Flag
               //   | | | Reserved
               //   | | | |  Size of Local Color Table
               //   0 0 0 00 000

    // 22. Table Based Image Data.
    2uy     // LZW Minimum Code Size
    // F. Variable-Length-Code LZW Compression.
    0x2Buy  // block size
            // data bytes
    0x94uy; 0x8Fuy; 0xA9uy; 0x16uy; 0xB0uy; 0x0Buy; 0x42uy; 0x78uy
    0xC8uy; 0x09uy; 0x4Buy; 0xB1uy; 0xA4uy; 0xFBuy; 0x60uy; 0xF5uy
    0x5Duy; 0x4Fuy; 0x28uy; 0x74uy; 0x47uy; 0x03uy; 0xA4uy; 0x91uy
    0x07uy; 0x22uy; 0x92uy; 0x14uy; 0xBDuy; 0xE5uy; 0xB4uy; 0x98uy
    0x62uy; 0x56uy; 0x51uy; 0xF7uy; 0xACuy; 0xDBuy; 0xFAuy; 0xFEuy
    0x43uy; 0x14uy; 0x00uy
    0uy     // Block Terminator

    // 27. Trailer.
    0x3Buy  // GIF Trailer
|]

表示

先ほどのコードに付け足しで画面表示します。

GIFTest.fsx(続き)
#r "System"
#r "System.Drawing"
#r "System.Windows.Forms"

open System
open System.IO
open System.Drawing
open System.Windows.Forms

[<EntryPoint; STAThread>] do
let w = new Form(Text = "GIF", Size = Size(180, 100))
let p = new PictureBox(Dock = DockStyle.Fill,
                       SizeMode = PictureBoxSizeMode.CenterImage)
try
    p.Image <- Image.FromStream(new MemoryStream(gif))
with _ -> ()
w.Controls.Add p
Application.EnableVisualStyles()
Application.Run w

gif.png

GIFアニメーション化

3ステップでGIFを手動編集してアニメーション化を試みます。

カラーテーブルのローカル化

後で複数のGIFを連結することを想定して、手動でカラーテーブルをローカルに移します。

  • Background Color Index: 情報が消えますが、とりあえず無視します。
  • Color Resolution: 個々の画像を見ないと分かりませんが、簡単のため111に決め打ちします。
GIFTest-L.diff
--- GIFTest.fsx
+++ GIFTest-L.fsx
@@ -6,34 +6,34 @@
     // 18. Logical Screen Descriptor.
     16uy; 0uy  // Logical Screen Width
     16uy; 0uy  // Logical Screen Height
-    0xA1uy     // <Packed Fields>
+    0x70uy     // <Packed Fields>
                //   Global Color Table Flag
                //   | Color Resolution
                //   | |   Sort Flag
                //   | |   | Size of Global Color Table
-               //   1 010 0 001
-    2uy        // Background Color Index
+               //   0 111 0 000
+    0uy        // Background Color Index
     0uy        // Pixel Aspect Ratio

-    // 19. Global Color Table.
-    0x00uy; 0x00uy; 0x00uy  // RGB #0
-    0x80uy; 0x80uy; 0x80uy  // RGB #1
-    0xFFuy; 0xFFuy; 0xFFuy  // RGB #2
-    0xFFuy; 0xFFuy; 0xFFuy  // RGB #3
-
     // 20. Image Descriptor.
     0x2Cuy     // Image Separator
     0uy ; 0uy  // Image Left Position
     0uy ; 0uy  // Image Top Position
     16uy; 0uy  // Image Width
     16uy; 0uy  // Image Height
-    0uy        // <Packed Fields>
+    0x81uy     // <Packed Fields>
                //   Local Color Table Flag
                //   | Interlace Flag
                //   | | Sort Flag
                //   | | | Reserved
                //   | | | |  Size of Local Color Table
-               //   0 0 0 00 000
+               //   1 0 0 00 001
+
+    // 21. Local Color Table.
+    0x00uy; 0x00uy; 0x00uy  // RGB #0
+    0x80uy; 0x80uy; 0x80uy  // RGB #1
+    0xFFuy; 0xFFuy; 0xFFuy  // RGB #2
+    0xFFuy; 0xFFuy; 0xFFuy  // RGB #3

     // 22. Table Based Image Data.
     2uy     // LZW Minimum Code Size

アニメーション化(1フレーム)

ループ回数(0で無限)とフレーム情報を入れてアニメーション化します。1フレームを無限に繰り返すためアニメーションしているようには見えません。

※ ループ回数はNetscapeのアプリケーション拡張として定義します。

GIFTest-A.diff
--- GIFTest-L.fsx
+++ GIFTest-A.fsx
@@ -1,7 +1,7 @@
 let gif = [|
     // 17. Header.
     'G'B; 'I'B; 'F'B  // Signature
-    '8'B; '7'B; 'a'B  // Version
+    '8'B; '9'B; 'a'B  // Version

     // 18. Logical Screen Descriptor.
     16uy; 0uy  // Logical Screen Width
@@ -15,6 +15,32 @@
     0uy        // Background Color Index
     0uy        // Pixel Aspect Ratio

+    // 26. Application Extension.
+    0x21uy            // Extension Introducer
+    0xFFuy            // Extension Label
+    11uy              // Block Size
+                      // Application Identifier
+    'N'B; 'E'B; 'T'B; 'S'B; 'C'B; 'A'B; 'P'B; 'E'B
+    '2'B; '.'B; '0'B  // Appl. Authentication Code
+    3uy               // Application Data Size
+    1uy               // data sub-block index (always 1)
+    0uy; 0uy          // unsigned number of repetitions
+    0uy               // Block Terminator
+
+    // 23. Graphic Control Extension.
+    0x21uy     // Extension Introducer
+    0xF9uy     // Graphic Control Label
+    4uy        // Block Size
+    0uy        // <Packed Fields>
+               //   Reserved
+               //   |   Disposal Method
+               //   |   |   User Input Flag
+               //   |   |   | Transparent Color Flag
+               //   000 000 0 0
+    10uy; 0uy  // Delay Time (10ms * 10 = 0.1s)
+    0uy        // Transparent Color Index
+    0uy        // Block Terminator
+
     // 20. Image Descriptor.
     0x2Cuy          // Image Separator
     0x00uy; 0x00uy  // Image Left Position

アニメーション化(2フレーム)

パレットを変えて赤字にした同じ絵を追加してアニメーションさせます。

GIFTest-A2.diff
--- GIFTest-A.fsx
+++ GIFTest-A2.fsx
@@ -74,6 +74,53 @@
     0x43uy; 0x14uy; 0x00uy
     0uy     // Block Terminator

+    // 23. Graphic Control Extension.
+    0x21uy     // Extension Introducer
+    0xF9uy     // Graphic Control Label
+    4uy        // Block Size
+    0uy        // <Packed Fields>
+               //   Reserved
+               //   |   Disposal Method
+               //   |   |   User Input Flag
+               //   |   |   | Transparent Color Flag
+               //   000 000 0 0
+    10uy; 0uy  // Delay Time (10ms * 10 = 0.1s)
+    0uy        // Transparent Color Index
+    0uy        // Block Terminator
+
+    // 20. Image Descriptor.
+    0x2Cuy     // Image Separator
+    0uy ; 0uy  // Image Left Position
+    0uy ; 0uy  // Image Top Position
+    16uy; 0uy  // Image Width
+    16uy; 0uy  // Image Height
+    0x81uy     // <Packed Fields>
+               //   Local Color Table Flag
+               //   | Interlace Flag
+               //   | | Sort Flag
+               //   | | | Reserved
+               //   | | | |  Size of Local Color Table
+               //   1 0 0 00 001
+
+    // 21. Local Color Table.
+    0xFFuy; 0x00uy; 0x00uy  // RGB #0
+    0xFFuy; 0x80uy; 0x80uy  // RGB #1
+    0xFFuy; 0xFFuy; 0xFFuy  // RGB #2
+    0xFFuy; 0xFFuy; 0xFFuy  // RGB #3
+
+    // 22. Table Based Image Data.
+    2uy     // LZW Minimum Code Size
+    // F. Variable-Length-Code LZW Compression.
+    0x2Buy  // block size
+            // data bytes
+    0x94uy; 0x8Fuy; 0xA9uy; 0x16uy; 0xB0uy; 0x0Buy; 0x42uy; 0x78uy
+    0xC8uy; 0x09uy; 0x4Buy; 0xB1uy; 0xA4uy; 0xFBuy; 0x60uy; 0xF5uy
+    0x5Duy; 0x4Fuy; 0x28uy; 0x74uy; 0x47uy; 0x03uy; 0xA4uy; 0x91uy
+    0x07uy; 0x22uy; 0x92uy; 0x14uy; 0xBDuy; 0xE5uy; 0xB4uy; 0x98uy
+    0x62uy; 0x56uy; 0x51uy; 0xF7uy; 0xACuy; 0xDBuy; 0xFAuy; 0xFEuy
+    0x43uy; 0x14uy; 0x00uy
+    0uy     // Block Terminator
+
     // 27. Trailer.
     0x3Buy  // GIF Trailer
 |]

gif-a2.gif

感想

GIFはシンプルな構造で、バイナリいじりの入門にも良いかもしれないと思いました。結果がアニメーションするので面白いです。

11
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
8