# GIFデコード処理を作る際に、注意しなければいけないポイント

## 2. 画像を展開した後、余ったデータを読み飛ばさなければいけない

前のページで説明したように、GIFデコーダのプログラムは、終了コードを読み込む前に、画像の展開終了を判断します。
画像が一枚だけ入ったGIFファイルならば、それで処理終了としてしまってOKなのですが、アニメーションGIFファイルの場合は問題があります。
一つ目の画像データの後に、次のアニメーションフレームの画像データが続いているので、処理を継続して、次の画像データをデコードする必要があるからです。
プログラムは、終了コードを読み込む前に展開終了を判断したので、まだ、一つ目の画像データの終了コードが読み込まれずに残っています。
そこで、次のアニメーションフレームの画像データを読み込み始める前に、一つ目の画像データの終了コードを読み飛ばさなければなりません。
終了コードを読み飛ばすためには、データブロックの残りのビットを捨ててしまえばよいのです。
前のページのGIFファイルを例に挙げると、プログラムは、6バイトのデータブロックのうち、青色で囲んだ範囲まで読み込んで、展開終了と判断します。

終了コードの4ビット分が、まだ読み込まれずに残っています。
プログラムは、残っている終了コードのことは気にせずに、6バイトのデータブロックの末尾まで、読み込みポインタを進めてしまえば良いのです。
変数pBlockBaseにデータブロックの先頭アドレス、変数BlockSizeにデータブロックのバイト数が入っているとすれば、

    	　　　　　・
    	　　　　　・
    	　　　　　・
    	一つ目の画像の展開終了

    	pBlockBase += BlockSize;　　// 終了コードを読み飛ばして、現在のデータブロックの末尾まで進める。
    	pBlockBase += 1;　　　　　　// 画像データ終了を表す「00」を読み飛ばす。

    	二つ目の画像の展開開始
    	　　　　　・
    	　　　　　・
    	　　　　　・

たいていは上述の方法でOKなのですが、稀に、2フレーム目の画像がデコードエラーになってしまうGIFファイルがありました。
たとえば、このようなGIFファイルです。
15×15ピクセル・2フレームのアニメーションGIFファイルで、1フレーム目は全ピクセルが違う色、2フレーム目は白一色で塗りつぶしてあります。
GIFファイルの内容の一部を、HEXエディタでダンプしてみました。
緑色の部分が、一つ目の画像データです。

画像データの部分だけを抜き出して、説明を加えてみました。
ちょっと長いですが・・・

上図の右下あたりに注目してください。
GIFのデータブロックは、各々が最大255バイトまでという制限があります。
画像全体のピクセルに相当するコードは、最初のデータブロックに収まっているのですが、終了コードだけが収まりきらず、次のデータブロックに分割されてしまっています。
プログラムは、最初のデータブロックの末尾にある、終了コードを読み込む前に、展開終了を判断します。
一つ目の画像データの終了コードを読み飛ばすために、最初のデータブロックの末尾まで読み込みポインタを進め、引き続き、次のアニメーションフレームのデコードを開始しようとします。
ところが実際には、読み込みポインタは、まだ、一つ目の画像データの、二つ目のデータブロックを指しています。
プログラムは、一つ目の画像データの終了コードの残り3ビットの部分を、次のアニメーションフレームの画像データと見なしてデコード処理を開始してしまって、デコードエラーになるのです。
エラーを避けるためには、一つ目の画像データの終了コードを読み飛ばす際、終了コードの一部のビットが、次のデータブロックにも分割されて格納されていないかを調べます。
もし、終了コードの一部のビットが、次のデータブロックにも分割されて格納されていたら、次のデータブロックも読み飛ばせば良いのです。

    	　　　　　・
    	　　　　　・
    	　　　　　・
    	一つ目の画像の展開終了

    	pBlockBase += BlockSize;　　　　　　// 終了コードを読み飛ばして、現在のデータブロックの末尾まで進める。
    	BlockSize = *pBlockBase++;　　　　　// 画像データ終了を表す「00」、または、次のデータブロックのバイト数を読み込む。
    	if(BlockSize != 0x00) { 　　　　　　// 終了コードの一部のビットが、次のデータブロックに分割されて格納されていたら・・・
    	　　　　pBlockBase += BlockSize;　　// 次のデータブロックも読み飛ばす。
    	　　　　pBlockBase += 1;　　　　　　// 画像データ終了を表す「00」を読み飛ばす。
    	}

    	二つ目の画像の展開開始
    	　　　　　・
    	　　　　　・
    	　　　　　・