GIFファイル形式

(この文書は2001年8月頃作成・編集されたものです)

「GIF(Graphics Interchange Format)」の概要
圧縮アルゴリズム「LZW」を利用した可搬性に優れた画像ファイル形式
GIFは米CompuServeによって設計された画像ファイル形式です。世界規模のネットワークであるインターネットでもJPEGと同様に標準的に活用されています。改良された年度により 87a, 89a のバージョンが存在していますが現在流通しているのは特定色透過,インターレース表示,アニメーションに対応した新しい 89a がほとんどとなっています。特徴としては次のようなものがあります。
  • LZW(Lempel-Ziv and Welch)というデータ圧縮アルゴリズム(可逆圧縮)を利用している
  • 扱える色数は最大256色で、それ以下なら 2,4,8,16,32,64,128 から選ぶことができる
  • 複数のデータ(画像)を含めることができる。かつ、それは早期の段階から考えられていた
87aの段階では圧縮率の高いファイル形式に過ぎませんでしたが、89aでユーザの要望に応える拡張がなされたこと、また Netscape Navigator や Internet Explorer などの主要なブラウザがそれに対応したことでGIFは一気に広まり、標準的な形式となりました。
GIFに適した画像タイプ
GIFは扱える最大の色数が256色(=1バイト以下で参照できる数)に限定されています。これはデータ圧縮に利用するアルゴリズムであるLZWの性質を最大限に活かすためで、色数を限定することで単純になった色指標配列を効率的に圧縮することができます。

・GIFとJPEG
写真などの階調の激しいタイプの画像は最低でも256色まで減色する必要があり、GIFには適しません。変わりにそのような画像はJPEGと呼ばれる形式を利用することが望ましいことが多々あります。このようにGIFとJPEGはそれぞれの得意分野を持っていて場合に応じて使い分けされます。ただし、小さい(例えば50px×50pxのような)写真の場合はJPEGよりもGIFで保存した方が良いでしょう。なぜならそのような小さなデータでは減色しても目立たない上、JPEGを利用した場合はブロックノイズ(圧縮率にもよる)が画像が小さいだけに目立ってしまうことがあるからです。

うに”ゃ〜、な子猫 7.51KB
PhotoshopでJPEG品質:高画質で保存した例。このような小さなイメージの場合、これ以上品質を低くしても画質がひどく悪くなる割にはサイズは小さくならない。
同じくうに”ゃ〜な子猫 4.58KB
GIF形式で64色まで減色した場合。ほとんど肉眼では見劣りは感じられないがサイズは軽くなっている。
3.58KB
GIF形式で32色まで減色した場合。やはりディスプレイ上では劣化はあまり感じられない。Photoshopの性能によるところも大きい。
透過GIF
トランスペアレントGIFとも言われます。これは使用する配色表の中の特定の一色を復号器(この呼名は仕様書邦訳の真似です)に対して透明色として扱うよう指定するものです。この拡張は 89a でなされました。従って 89a に準拠した復号器では指定した色がまるでもともと無かったかのように透過して表示されます。透過色に指定する色は配色表の中から任意で選べます。
しま
緑色を透過色に指定すると
右のようになる。
しま
インターレースGIF
言い忘れていましたがGIFの特徴として、ネットワークからのダウンロード時など、すべてのデータが揃っていなくても得られたデータを順次表示させることができる、という点があります。サイズの大きなデータの場合(またはGIFを選ぶべきでないタイプの画像であった場合)は画像の上から下までちょっとずつ表示されるのを待機させられる羽目になります。インターレースGIFはこのユーザの精神的な負担を軽減させるものです。この機能の拡張は 89a でなされました。従って 89a に準拠した復号器ではインターレース配置されたGIFを上からちょっとずつ表示するのではなく、モザイク処理されたような大まかなイメージが徐々に本来の画像に変化していくような表示方法で処理されます。
アニメーションGIF
単独のファイルにアニメーションに必要なデータを格納してしまえるこの形式は大きな反響を得ました。それまではWeb上のアニメーションといえばCGIを利用したとても実用的ではないような方法しか存在しなかったのです。という訳でアニメーションGIFは現在ではそれを作成する専用のアプリケーションも豊富に揃い、マニアックにアニメーションGIFに専念している人もいます。

GIFは 87a の古いバージョンからもともと複数の画像データを含めることができましたが、これは特に、アニメのため、というわけではありませんでした(それも出来る、とは考えてはいたかもしれない)。単独のファイルに複数のデータを含めることでサイズの縮小や、やり取りの効率化を目的にしていたのでしょう。89a の拡張ではこの点を生かし、Graphic Control Extension block という新たなブロックを含めることで 89a に準拠した復号器では、ファイルに含まれる複数のデータに延滞時間を設定し、連続的に表示することができるようになりました。これで最初のデータから最後のデータまでの一回きりのアニメーションを行うことができます。

どちらかというと最後のデータを表示し終えたら最初のデータに戻る繰り返しのアニメーションの方が一般的ですが、実はこれにはやはり 89a で拡張がなされた他の機関が定義する Application Extension block を含める必要があります。最後のデータを表示し終えたら最初のデータに戻るという拡張は Netscape社 が定義しました。というわけで繰り返しのアニメーションがなされるGIFにはすべて Application Extension block が含まれており、かつその中には“Netscape2.0”という文字列が含まれています。

参考のアニメを用意しましたが、このページに表示させるとブラウザに負荷がかかってしまうのでリンクにしました。
参考アニメGIF → あせるしま

ファイル・フォーマット
GIFのファイル構造
GIFは複数の固定長の、あるいは可変長の論理的なブロックから成っています。拡張として追加されたブロックには“拡張ブロックである”という印が最初に立っていて、その次に何の拡張であるかを示すラベルがあります。Image Data block や拡張ブロックのいくつかにはさらに複数のサブ・ブロックが含まれることがあります。ブロックの中には特定の位置に一回しか登場が許されないもの(Header などの基本的なブロック)や、許された場所になら何回でも登場し得るもの(画像データや Extension系ブロック)、また存在してもしなくても良いもの(配色表データブロックなど)などがあります。以下はGIF89aで定義されているブロックすべてを簡潔な表にまとめています。それぞれのブロック名はこの次の節からの詳細な説明へのリンクになっています。

基本ブロック
ブロック名Version説明
Header87aGIFデータの始まりであることと、復号器に要求する処理能力を示すバージョン番号が記述される。
Logical Screen Descriptor87a(89a)データを絵画する論理的な領域のサイズ、その他すべてのデータの扱いの際に必要なパラメータが記述される。
Trailer87aGIFデータの終わりであることを示す。
Image Descriptor87a(89a)この後の画像データの位置や大きさ、その他のパラメータが記述される。
Image Data87a画像データとその圧縮されたデータの復元に使用されるLZW最小符号寸法が記述される。
Global Color Table87aすべての画像データから参照可能な配色表が記述される。
Local Color Table87a単一の画像データからのみ参照可能な配色表が記述される。
Sub block87a可変長のデータを格納するブロック中のブロック。
拡張ブロック
Graphic Control Extension89a透過色の指定、次のデータに移る延滞時間などが記述される。
Plain Text Extension89a画像として絵画されるテキストデータの情報などが記述される。
Comment Extension89a画像の情報や作成者の署名などのテキストデータを含めることができる。
Application Extension89aアプリケーション固有の情報が含まれている。

※バージョンの括弧は89aで若干の変更があったことを示す。

ここからは各ブロックの詳細に移ります。整形済みテキストを利用したブロックの図形表現は仕様書からの受け売りです。これ以上に見やすい方法を検討してみましたが、扱いやすさ、視覚的な分かりやすさを考えたところ、結局これ以上の方法は無い、と落ちつきました。ちなみにほとんど同じですが仕様書からのコピーではありません。内容についても十分な理解が得られない部分については仕様書の受け売りになっています。

Header block
このブロックはGIFファイルの先頭に必ず一回だけ現れます。復号器にGIFであることを示す署名と要求する処理能力を示すバージョンの情報を含みます。
  8 7 6 5 4 3 2 1
 +---------------+
1|      "G"      |
 +               +
2|      "I"      |
 +               +
3|      "F"      |
 +---------------+
4|               |
 +               +
5|               |
 +               +
6|               |
 +---------------+

・1 〜 3byte: 署名
GIFデータであることを示す文字列で“GIF”の固定値。

・4 〜 6byte: バージョン
復号器に要求する処理能力を示すバージョン番号。87a か 89a のどちらかの文字列。

Logical Screen Descriptor block
このブロックは Header block の後に必ず一回だけ現れます。このブロックはすべてのデータの処理において必要な環境変数のような情報を含みます。
  8 7 6 5 4 3 2 1
 +---------------+
1|               |
 +               +
2|               |
 +---------------+
3|               |
 +               +
4|               |
 +---------------+
5| |     | |     |
 +---------------+
6|               |
 +---------------+
7|               |
 +---------------+

・1, 2byte: 論理画面横幅
含まれるすべてのデータを絵画するのに十分な横幅の値。最大65536の2バイトで表せる数値。

・3, 4byte: 論理画面縦幅
含まれるすべてのデータを絵画するのに十分な縦幅。最大65536の2バイトで表せる数値。

・5byte: 下記ビット情報含む

8:Global Color Table フラグ
Global Color Table block の有無。このビットが立っている場合はこのブロックの直後に Global Color Table block が存在することを意味する。
7 〜 5:色解像度
このビット列の値 + 1 がオリジナルの画像の色解像度を示す。
4:カラーテーブル整列フラグ
Global Color Table が整列されているかの真偽。値が1の場合にはカラーテーブルは重要度が高い色から順番に整列されている。これは先頭近くに並ぶ色だけで画像全体の大まかな表現が可能であることを意味する。
3 〜 1:Global Color Table サイズ
この値 + 1 を 2 の累乗した数がカラーテーブルの大きさになる。RGB各色1バイトで一つの色を表すため、実際にはさらに 3 を掛けた数がカラーテーブルのバイトサイズになる。

・6byte: 背景色指標
論理画面の背景色を指定する Global Color Table への色指標。背景色は絵画される画像に覆われない部分を塗りつぶすのに使われる。

・7byte: 画素縦横比 原画中の画素の縦横比の近似の計算に使用される係数。
※このバイトは 87a の段階では予約領域だったが 89a で上記の割り当てがなされた。

Trailer block
このブロックはGIFファイルの末尾に一回だけ現れます。GIFストリームの終了を意味する単純な1バイトの値です。
  8 7 6 5 4 3 2 1
 +---------------+
1|    0x3B(;)    |
 +---------------+

・1byte: GIF終了符号
16進数では 0x3B,文字ではセミコロン(;)のGIFストリームの終わりを示す符号。

Image Descriptor block
このブロックは Header, Logical Screen Descriptor, Global Color Table(あるなら)の後、Trailer の前になら何回でも現れ得ます。そしてこの後にはこのブロックのパラメータにより随意で Local Color Table が現れ、その後に必ず Image Data が現れます。要すると、大抵の場合において Image Descriptor, Image Data という順にブロックが並びます。これらをまとめて「グラフィック絵画ブロック」と考えることができます。また、このブロックの直前にはこのグラフィックに対してある種の特殊な修飾(つまりは透過GIFやアニメーションのような)を意味付ける Graphic Control Extension ブロックが存在する可能性があります。
   8 7 6 5 4 3 2 1
  +---------------+
 1|    0x2C(,)    |
  +---------------+
 2|               |
  +               +
 3|               |
  +---------------+
 4|               |
  +               +
 5|               |
  +---------------+
 6|               |
  +               +
 7|               |
  +---------------+
 8|               |
  +               +
 9|               |
  +---------------+
10| | | |   |     |
  +---------------+
 

・1byte: 画像分離符号
コンマ,区切りを意味する 0x2C という値。

・2, 3byte: 画像表示レフト・オフセット
論理画面の左端を基点とする画像表示のオフセット。

・4, 5byte: 画像表示トップ・オフセット
論理画面の上端を基点とする画像表示のオフセット。

・6, 7byte: 画像横幅
画像の横幅の大きさ。

・8, 9byte: 画像縦幅
画像の縦幅の大きさ。

・10byte: 下記のビット情報含む

8:Local Color Table フラグ
Local Color Table block の有無。このビットが立っている場合はこのブロックの直後に Local Color Table block が存在することを意味する。
7:インターレース・フラグ
この値が1である場合、画像データがインターレース配置されていることを示す。対応した復号器はインターレース表示を行う。
6:カラーテーブル整列フラグ
Local Color Table が整列されているかの真偽。値が1の場合にはカラーテーブルは重要度が高い色から順番に整列されている。これは先頭近くに並ぶ色だけで画像全体の大まかな表現が可能であることを意味する。
5, 4:予約領域
現在は使われない領域。将来に割り当てが行われるかもしれない、0をセットしておくべき。
3 〜 1:Local Color Table サイズ
この値 + 1 を 2 の累乗した数がカラーテーブルの大きさになる。RGB各色1バイトで一つの色を表すため、実際にはさらに 3 を掛けた数がカラーテーブルのバイトサイズになる。
Image Data block
このブロックは Image Descriptor,もしくは存在するなら Local Color Table ブロックの後に必ず現れます。同ブロックが存在するならセットとして一回ずつ、何回でも現れ得ます。このブロックはデータの復元に利用されるLZW最小符号寸法とLZW圧縮された配色表式画像データを格納する複数のサブ・ブロックを含みます。
  8 7 6 5 4 3 2 1
 +---------------+
1|               |
 +---------------+
     Sub block
 +---------------+
2|               |
     〜 〜 〜

・1byte: LZW最小符号寸法

・2byte 〜: 画像データ・サブ・ブロック郡
配色表式の画像データを格納するサブ・ブロックが続く。データはLZW圧縮されている。

Global Color Table block
このブロック出現は Logical Screen Descriptor の Global Color Table Flag によって制御されますが、大抵の場合において同ブロックの後に一回だけ(に限る)現れます。同じく同ブロックの Global Color Tabel Size によってその大きさを特定されます。このブロックはこのGIFストリーム中のすべての画像データから参照できるカラーパレットの集合を含みます。また、このGIFストリームにおいての使用に限らず、GIFを扱うアプリケーションはのちに参照される可能性のあるカラーパレットとして、このカラーテーブルを保持することもできます。
  8 7 6 5 4 3 2 1
 +---------------+
1|   Red光度     |
 +               +
2|   Green光度   |
 +               +
3|   Blue光度    |
 +---------------+
4|   Red光度     |
     〜 〜 〜

・1 〜 3byte: インデクス 0 のカラー,1 のカラー・・・と続く
一つの色を光の三原色 RGB 各色を 1Byte 合計 3Byte で表す。インデクス 0 から Logical Screen Descriptor で指定されたカラーテーブルのサイズ分繰り返す。例えば同ブロックの Global Color Table Size が 7 であった場合、2 ** (7 + 1) の 256 がカラーテーブルのサイズになる。一色3バイトなのでさらに 3 を掛けた 768 がバイト数になる。

Local Color Table block
このブロックは Image Descriptor の Local Color Table Flag によって随意で同ブロックの後に一回だけ現れます。多くの場合、このブロックは存在せず同ブロックの後には Image Data が続きます。このブロックの大きさは同ブロックの Local Color Table Size によって特定されます。Global Color Tabel はすべてのデータに対しスコープがありますが、このブロックは直後に続くデータのみに限られます。
  8 7 6 5 4 3 2 1
 +---------------+
1|   Red光度     |
 +               +
2|   Green光度   |
 +               +
3|   Blue光度    |
 +---------------+
4|   Red光度     |
     〜 〜 〜

・1 〜 3byte: インデクス 0 のカラー,1 のカラー・・・と続く
一つの色を光の三原色 RGB 各色を 1Byte 合計 3Byte で表す。インデクス 0 から Image Descriptor で指定されたカラーテーブルのサイズ分繰り返す。例えば同ブロックの Local Color Table Size が 7 であった場合、2 ** (7 + 1) の 256 がカラーテーブルのサイズになる。一色3バイトなのでさらに 3 を掛けた 768 がバイト数になる。

Graphic Control Extension block
このブロックは Image Descriptor の前に一回だけ現れることがあり、その場合はそのグラフィックに対し透過色や延滞時間の指定などの特殊な修飾を施します。結果的に 89a に準拠したGIFを扱うアプリケーションではそのような特殊な画像を表示することが可能です。アニメーション設定されたGIFファイルは Image Descriptor の前に必ずこのブロックが先行します。このブロックはサブ・ブロックを一つだけ含みます。
  8 7 6 5 4 3 2 1
 +---------------+
1|     0x21(!)   |
 +---------------+
2|     0xF9      |
 +---------------+
     Sub block
 +---------------+
3|     0x04      |
 +---------------+
4|     |     | | |
 +---------------+
5|               |
 +               +
6|               |
 +---------------+
7|               |
 +---------------+
    Terminator
 +---------------+
8|      0x00     |
 +---------------+

・1byte: 拡張導入符号
拡張ブロックであることを示す固定値 0x21(!)。続いてその種類を示すラベルが登場することはすべての拡張ブロックにおいて共通。

・2byte: Graphic Control Extension Label
Graphic Control Extension block であることを示す固定値 0xF9。

・3byte: ブロック寸法
サブ・ブロックのバイトサイズを表す固定値 0x04。このバイトは含めない。

・4byte: 下記ビット情報含む

8 〜 6:予約領域
現在は使われない領域。将来に割り当てが行われるかもしれない、0をセットしておくべき。
5 〜 3:処分方法
表示後の画像の処分方法を 0 〜 7 までの数で指定する。大抵は、0: 指定しない(まかせる)、か、1: 処分せずそのまま残す、のどちらかが利用される。
2:ユーザ入力フラグ
次のデータ表示への移行にユーザの入力をスイッチとするかの真偽。0 であれば受け付けず、1 であれば入力を期待する。
1:透過色フラグ
このビットが立っている場合には透過色インデクスで指定された色を透過色とし、透過GIFとして処理する。

・5, 6byte: 延滞時間
次のデータの表示に移るまでの延滞時間。100分の1秒単位の値。

・7byte: 透過色インデクス
透過色とする色を Global Color Table あるいは Local Color Table からインデクスで指定する。透過色フラグが立っていない場合には無意味となる。

・8byet: サブ・ブロック終了符
サブ・ブロックの終了を示す。

Comment Extension block
このブロックは Header, Logical Screen Descriptor, Global Color Table(あるなら)の後、Trailer の前になら何回でも現れ得ますが、グラフィック絵画ブロック(Image Descriptor 〜 Image Data)の間には入れるべきではありません。グラフィック絵画ブロックの直前に、そのグラフィックに関連付けられたコメントとして登場することが期待されます。このブロックはコメントデータを含む複数のサブ・ブロックを持ちます。
  8 7 6 5 4 3 2 1
 +---------------+
1|     0x21(!)   |
 +---------------+
2|     0xFE      |
 +---------------+
     Sub block
 +---------------+
3|               |
     〜 〜 〜

・1byte: 拡張導入符号
拡張ブロックであることを示す固定値 0x21(!)。続いてその種類を示すラベルが登場することはすべての拡張ブロックにおいて共通。

・2byte: Comment Extension Label
Comment Extension block であることを示す固定値 0xFE。

・3byte 〜: コメントデータ・サブ・ブロック郡
コメントデータ(文字列)を含む複数のサブ・ブロック。

Application Extension block
このブロックの出現性は前節の Comment Extension block と同じです。このブロックもまた次に現れるグラフィックに何らかの修飾を施す可能性がありますが、特定のグラフィックに限らない修飾であることもあります。このブロックはこのブロックの情報を格納する一つの特別なサブ・ブロックと、アプリケーション固有のデータを格納するための複数のサブ・ブロックを含みます。
   8 7 6 5 4 3 2 1
  +---------------+
 1|     0x21(!)   |
  +---------------+
 2|     0xFF      |
  +---------------+
      Sub block
  +---------------+
 3|     0x0B      |
  +---------------+
 4|               |
  +               +
 5|               |
  +               +
 6|               |
  +               +
 7|               |
  +               +
 8|               |
  +               +
 9|               |
  +               +
10|               |
  +               +
11|               |
  +---------------+
12|               |
  +               +
13|               |
  +               +
14|               |
  +---------------+
      Sub block
  +---------------+
15|               |
      〜 〜 〜

・1byte: 拡張導入符号
拡張ブロックであることを示す固定値 0x21(!)。続いてその種類を示すラベルが登場することはすべての拡張ブロックにおいて共通。

・2byte: Application Extension Label
Application Extension block であることを示す固定値 0xFF。

・3byte: ブロック寸法
サブ・ブロックのバイトサイズを表す固定値 0x0B。このバイトは含めない。

・4 〜 11byte: アプリケーション識別名
この拡張を所有するアプリケーションの識別名。例えばアニメーションGIFで使用される拡張はNetscape社が所有しているので、“NETSCAPE”という文字列が格納される。

・12 〜 14byte: アプリケーション確証符号
アプリケーション識別名を確証するための符号が格納される。Netscape社の所有するアニメーションGIFで使用される拡張では単に“2.0”という文字列が記述されている。

・15byte 〜: アプリケーション・データ・サブ・ブロック郡
アプリケーション固有の情報が格納される複数のサブ・ブロック郡。

Plain Text Extension block
このブロックの出現性は Image Descriptor と同じです。なぜならこのブロックはグラフィック絵画ブロックに種別されるからです。そのことは同時に Graphic Control Extension に修飾され得ることを意味しています。このブロックはこのブロックの情報を格納する一つの特別なサブ・ブロックと、テキストデータを格納するための複数のサブ・ブロックを含みます。

付け加えると、このブロックは定義されてはいるものの、利用しているアプリケーションは見かけられません。

   8 7 6 5 4 3 2 1
  +---------------+
 1|     0x21(!)   |
  +---------------+
 2|     0x01      |
  +---------------+
      Sub block
  +---------------+
 3|     0x0C      |
  +---------------+
 4|               |
  +               +
 5|               |
  +---------------+
 6|               |
  +               +
 7|               |
  +---------------+
 8|               |
  +               +
 9|               |
  +---------------+
10|               |
  +               +
11|               |
  +---------------+
12|               |
  +---------------+
13|               |
  +---------------+
14|               |
  +---------------+
15|               |
  +---------------+

      Sub block
  +---------------+
16|               |
      〜 〜 〜

・1byte: 拡張導入符号
拡張ブロックであることを示す固定値 0x21(!)。続いてその種類を示すラベルが登場することはすべての拡張ブロックにおいて共通。

・2byte: Plain Text Extension Label
Plain Text Extension block であることを示す固定値 0x01。

・3byte: ブロック寸法
サブ・ブロックのバイトサイズを表す固定値 0x0C。このバイトは含めない。

・4, 5byte: テキスト格子レフト・オフセット
論理画面の左端を基点とするテキスト格子のオフセット。

・6, 7byte: テキスト格子トップ・オフセット
論理画面の上端を基点とするテキスト格子のオフセット。

・8, 9byte: テキスト格子横幅
テキスト格子の横幅の大きさ。

・10, 11byte: テキスト格子縦幅
テキスト格子の縦幅の大きさ。

・12byte: 文字区画横幅
テキスト格子中の各文字区画の横幅。

・13byte: 文字区画縦幅
テキスト格子中の各文字区画の縦幅。

・14byte: テキスト前景色インデクス
テキストの前景色を決定する Global Color Table への色指標。

・15byte: テキスト背景色インデクス
テキストの背景色を決定する Global Color Table への色指標。

・16byte 〜: テキストデータ・サブ・ブロック郡
グラフィック絵画に使用されるテキストデータが格納される複数のサブ・ブロック。

Sub block
このブロックはブロックの中に含まれる特別なブロックです。複数のサブ・ブロックを含むことができるブロックならいくつでも含むことができます。サブ・ブロックは、それ単体では単なる何らかのデータでしかありません。このブロックは必ずそれに意味を与える関連付けられたブロックの中に登場します。

ブロック寸法が 0x00 の値を持つサブ・ブロックは、サブ・ブロックの連続のターミネーターとして機能します。

  8 7 6 5 4 3 2 1
 +---------------+
1|               |
 +---------------+
2|               |
     〜 〜 〜

・1byte: ブロック寸法
このサブ・ブロックの寸法を表す。このバイトは含めない。

・2byte 〜: データ
ブロック寸法分のバイト数のデータが続く。

一般的なGIFファイルの構造
GIFストリームの流れ,GIF Analyzer,バイナリエディタ
この節では一般的によく作成されるであろうGIFファイルを例にそのファイル構造をみていきますが、その前にGIFファイルの構造の流れを簡単に説明してみます。まず Header が必ず登場します。これに反するものは復号器によって“GIFファイルではない”とはじかれるでしょう。そして Logical Screen Descriptor,そしてほとんどの場合 Global Color Table が登場します。この後に Image Descriptor, 無いことの多い Local Color Table, Image Data の三つ(大抵は Local Color Table を除いた二つ)のブロックの0回以上の連続が続きますが、その前にあるいはその途中に Graphic Control Extension, その他の拡張ブロックが挟まれることがあります(透過GIF,アニメーションGIFの場合は必ず。インターレースGIFに関しては Image Descriptor で指定する)。そして多くの場合、最後の Image Data のサブ・ブロックの連続がブロック終了符である 0x00 により終了し、次のバイトで Trailer が登場してGIFストリームの閉幕となります。

それではこのGIF画像を例にGIFファイルがどのような構造を成しているかを説明していきます。ここでは僕がGIFのファイル構造を理解するために作成したツール「GIF Analyzer」を併用していきます。これは単純にGIFファイルが持つブロック構造を標準出力にプリントするPerlで書かれたプログラムです。ここからダウンロードできますが、Perlインタプリタがインストールされていないと動かないですし、バグが潜んでいる可能性も多いにあり得ますし僕の環境(Win98)と異なる場合はおかしな挙動を見せるかもしれません。使用方法は単純です。以下のようにコマンドラインに入力してください。[ ] の中はファイルに出力したい場合は入力します。

perl gif_analyzer.pl GIF File Name [ > Output File Name ]
そしてもう一つ、僕が使用しているバイナリエディタを紹介しておきます。軽く、扱いやすくGIFファイルのバイナリデータを閲覧/編集する際にとても便利です。

Stirling(スターリング):DDS2のページ

例を用いたGIFファイル構造の詳細
さきほどのGIF画像を GIF Analyzer を通して解析結果をテキストファイルに出力しました。これをブロックごとにバイナリデータと見比べていきましょう。この画像は単純なもので、拡張ブロックは一切使用されていず、含まれる画像データも一つだけのもっとも一般的にあり得るタイプのGIFファイルといえます。
GIF Analyzer の出力バイナリデータ
Header block
[Header block]
Signature: GIF
Version: 89a
47 49 46 38 39 61
Logical Screen Descriptor block
[Logical Screen Descriptor block]
Logical Screen Width: 36
Logical Screen Height: 36
Packed Fields Bits: 11000100
Global Color Table Flag: 1
Color Resolution: 5
Sort Flag: 0
Global Color Table Size: 5
Background Color Index: 0x00
Pixel Aspect Ratio: 0
24 00 24 00 C4 00 00
Global Color Table block
[Global Color Table block]
[00]000000 [01]FFFFFF [02]242C4D [03]616F89
[04]7F91AA [05]3B5C79 [06]A4BDD2 [07]BDD4D8
[08]39B9B5 [09]B9C1BA [0A]D5DDD5 [0B]E7EFE7
[0C]CBD1CA [0D]DDE7DB [0E]7E857C [0F]E6ECDE
[10]B5B5AB [11]A9A596 [12]C9C7C0 [13]B1ACA0
[14]9B8E75 [15]989389 [16]85765D [17]A79B8A
[18]70614C [19]453727 [1A]C3BCB4 [1B]594839
[1C]2D2118 [1D]3C291D [1E]231410 [1F]170A09
00 00 00 FF FF FF 24 2C 4D 61 6F 89 7F 91 AA 3B 5C 79 A4 BD D2 BD D4 D8 39 B9 B5 B9 C1 BA D5 DD D5 E7 EF E7 CB D1 CA DD E7 DB 7E 85 7C E6 EC DE B5 B5 AB A9 A5 96 C9 C7 C0 B1 AC A0 9B 8E 75 98 93 89 85 76 5D A7 9B 8A 70 61 4C 45 37 27 C3 BC B4 59 48 39 2D 21 18 3C 29 1D 23 14 10 17 0A 09
Image Descriptor block
[Image Descriptor block]
Image Separator: 0x2C(,)
Image Left Position: 0
Image Top Position: 0
Image Width: 36
Image Height: 36
Packed Fields Bits: 00000000
Local Color Table Flag: 0
Interlace Flag: 0
Sort Flag: 0
Reserved: 0
Local Color Table Size: 0
2C 00 00 00 00 24 00 24 00 00
Image Data block
[Image Data block]
LZW Minimum Code Size: 5
Total Sub Blocks Number: 3
05 FF ... FF ... DC ... 00
Trailer block
[Trailer block]
GIF Trailer: 0x3B(;)
3B
Header
基本ブロックだけしか存在しないのでバージョンは 87a でもよさそうな気がしますが 87a では予約領域であった Logical Screen Descriptor と Image Descriptor のビットが 89a では機能の割り当てが行われたからでしょうか。

Logical Screen Descriptor
最初の4バイトが論理画面の大きさを表しています。次の1バイトはビット単位で情報が表されています。MSB(最上位ビット)が1で Global Color Table が存在することを、次の3ビットの値 + 1 が色解像度、次の1ビットがカラーテーブルの整列の真偽、次の3ビットの値 + 1 を2の累乗にした数がカラーテーブルのサイズである32を表しています。

Global Color Table
Logical Screen Descriptor の Global Color Table Flag が立っているのでこのブロックは存在しました。0x00 〜 0x1F までの32のカラーテーブルが並んでいます。最初の2つはバイナリデータを見ても“黒”と“白”であることが分かります。

Image Descriptor
最初のバイトは固定値 0x2C(,)、次の4バイトで画像の位置を、次の4バイトで画像の大きさを表しています。最後のバイトはビット情報ですがすべて 0 で Local Color Table は存在せず、インターレースでもなく、整列されていず(MSBが立ってないので意味がない)、予約領域は当然 0 で、カラーテーブルのサイズは 0(同様に意味がない)だということが分かります。

Image Data
最初のバイトはLZW最小符号寸法です。この意味はまだ分からないのですが Logical Screen Descriptor の色解像度の値と同じになるみたいですね。この後はサブ・ブロックが続きます。長いので省略していますが、ブロック寸法のバイトだけ示しています。0xFF が255バイトのデータを、続いて 0xFF が255バイトのデータを、続いて 0xDC が220バイトのデータを、そしてブロック終了符として機能する 0x00 で終わり、トータル3のサブ・ブロックが存在することが分かります。

Trailer
文字ではセミコロンになる 0x3B の値がGIFストリームの終了を意味します。GIFファイルの中には Trailer の直前に拡張ブロックが登場する場合があります。

以上、一般的なGIFファイルの構造をざっと見てきました。ここまで説明したことが理解できたならバイナリエディタで直接GIFファイルの内容を編集することも出来るようになるはずです。

効果的なファイルサイズの減少
色数を適切に減らす
GIFは色数を減らすことでファイルサイズを軽く出来ることで知られています。これは色数を少なくするに比例して配色表式の画像データがより単純な指標の並びになり、LZW(Lempel-Ziv and Welch)法で圧縮する際に好都合だからです。

色数の減らし方について、知っておくとよいことがあります。色数は最大256までの2の累乗の数 2, 4, 8, 16, 32, 64, 128, 256 の中からしか選べません。グラフィック・ソフトによってはこれ以外の数を選ぶことが出来る場合がありますが、結局のところ前述の数の中から一番近く、かつ小さくない数のパレットが作成されます。例えば 129色 を選んだとしてもパレットは 256色分作成されます。付加された 127色については使用されない無駄なパレットになってしまいます。このことから色数は前述の数の中から選ぶのが無駄のないGIFファイルを作る一つのコツだということが分かります。

画質を保ちながら効果的に色数を減らすには優れた減色ルーチンを搭載するソフトが必要です。やはり Photoshop がお勧めですが、GIFを扱う程度ならばこのような高価なソフトでなくとも十分な機能を持つソフトはたくさん存在します。PaintShop Pro などはなかなか使えると思います。

錯覚で擬似色を作り出すディザ
画像の種類や寸法にもよりますが色数を極端に減らすと、いくら性能の良い減色ルーチンでも画質の保ちようがなくなり階調が少ない潰れたような画像になってしまいます。ディザはこれを最小限に押えるための技法で、パレットに存在する濃い色と薄い色を使用してその中間色を擬似的に表現します。例えば白と黒の小さな画素が交互に繰り返されて塗りつぶされた四角を遠めから見ると、その四角は灰色に見えるといった感じです。ディザは存在しない色を人間の目の錯覚を利用して擬似的に作り出し、少ない色数でも画像の不自然さを抑えることが可能ですが、その変わりにデータはLZW法にとっては不都合な並びになってしまい、結果的にファイルサイズは色数が少ないにも関わらず期待に応えかねるものになってしまうことがあります。効果的にファイルサイズを減少させるには色数と、ディザの適用量の適切な判断が必要になります。

と、述べてきましたが実際にはここまで気を配らなくても基本的なこと(GIF/JPEGどちらでフォーマットすべきか適切に判断できる,イラスト系はかなりの色数が削れる,など)が分かっているのなら、そうそうおかしなデータが出来あがることはありません。大抵の場合ソフトに任せてしまえば問題の無いデータになります。これからはブロードバンド化も進みそうなので PNG のような多少サイズが大きくなりやすい形式も普及して行くと思います。

その他
参考サイト
  • GIF Info
    GIF仕様書の邦訳を配布されている。GIFのフォーマットに関してはここだけ参照すれば十分な情報が得られる。ありがたい。
  • Hey! Java Programming!
    C++によるGIF解析プログラムを含めたGIFの詳しい解説がある。他にもJava/プログラミングに関する各種情報。
  • HP2! -HiroPon's HomePage-
    「貧乏人のためのCG講座」に個人的に研究したらしいGIFやJPEGに関する情報を掲載されている。
  • うらうらホームページ
    開発者向けのGIFフォーマット情報,GIFアニメ作成の具体的な手順。
  • GIF Animation on the WWW JAPAN
    テクニカルな視点からみたGIFアニメーションの情報。
あとがき
さて、随分長くなったようです。これもバイナリ・レベルでGIFのファイル構造を理解しようとした結果です。ファイル構造というもの自体、ここまで本格的に調べるのは初めてのことだったので苦労もしましたが大変勉強になりました。GIFファイルの構造を解析,出力するプログラムなども慣れないPerlでやっとこさ作ったりして、ちょっぴりプログラマの気持ちになったりもしました。

最初の予定では LZW についても調べるつもりだったのですがその余裕がなくなってしまいました。これについては時期をみてまた取り組むつもりです。最後にいくつか言わなくてはならないことを。このページの情報についてはそのほとんどを「参考サイト」から得ました。特にGIF仕様書の邦訳が存在したことはありがたかったです。マイナーな形式ではこうはスムーズにいかないでしょう・・。情報の正確性については気を付けてはいるつもりですが、いくつかの点については独自の解釈をしたところなどもありますので過信はしないでください。金銭に関わる業務などに利用する場合は必ず仕様書をご覧になることをお勧めします。

Copyright (C) 2004-2008 Nekopps all rights reserved.
http://uketama.nekopps.com/