TIFFのフォーマット(その1)

 TIFFは画像を記述するためのファイル形式です。TIFFは「付加情報+画素データ」よりなります。TIFFは複数の画像データを取り扱ったりすることができたいへん便利なファイル形式です。そのため、画像処理プログラミングをする際にTIFFのフォーマットを知っていると、ライブラリを使わなくてもTIFFを読み込めて便利です。ここでは、TIFFのファイル形式がどのようになっているのかについて解説していきます。

画像データの基礎

 はじめに画像を数値で表す方法について簡単に解説します。画像は小さい点の集合によって構成されます。例えば、

jprogramer.png

の画像も拡大していくと

拡大

と四角い点の集合になっています(左上を拡大)。この点のことをピクセルと呼びます。

 ピクセルの色は基本的に3つの数値により決定されます。この3つの数値は「赤・緑・青」であり英語の頭文字をとってRGB(Red,Green,Blue)とよびます。そして、この3つの数値のデータサイズのことを色の深さと呼びます。よく使用される色の深さは8ビットであり、0から2^{8}-1=255の間でRGBを指定します。例えば、赤なら(R,G,B)=(255,0,0)となります。

TIFFの解説の前にファイルの基礎を理解しよう

 TIFFのデータについて説明する前にファイルの基本について簡単に解説します。わたしたちが使用しているファイルは0と1から構成されています。そして、この0と1の情報量をビットといいます。そして、ビットを8つまとめたものをバイトといいます。例えば、

00101100

が1バイトとなります。1バイトを16進数で表すと2桁で表すことができます。例えば先程の1バイトは16進数で

2C

となります。TIFFファイルはバイトを単位として構成されています。このバイトの並びをみることでTIFFの内容を知ることができるのです。

TIFFの必要性

 TIFFの起源を理解するために、画像をファイルに保存することを考えます。まず単純に画素データを順番にファイルに書いていけばよさそうです。しかし、よくよく考えてみると、画素データだけ並べられても、画素データをどのように並べたらいいかわかりません。また、画素データが何bitなのかや色の数も知りたいところです。よって、画素データだけでなく他の情報も付加する必要があることがわかります。

 そこで考えだされた画像ファイル形式がTIFF(Tag Image Format: 拡張子.TIF, .TIFF)なのです。画素データに加えて付加情報(タグ)がついたのがTIFFという画像フォーマットということになります。

TIFFの全体像

 ではTIFFファイルの記述方法(フォーマット)について解説します。さっそくですが、TIFFファイルを覗いてみます。以下のTIFFファイルをバイナリエディタで開いてみてください。

>>ファイルへのリンク

すると

4D 4D 00 2A 00 00 00 08 …

となっています。この2桁の16進数を解析することでTIFFファイルが意味する画像を読み解いていくのです。

 まずはざっくりTIFFのファイル構造を俯瞰します。TIFFは

  1. ヘッダ
  2. IFD (Image File Directory)
  3. 画素データ

からなります。ヘッダにはTIFFファイル情報の読み方のルールが書かれています。そして、IFDには画像の幅や高さといった付加情報が書かれています。そして、画素データがあります。

 TIFFにはマルチページTIFFという画像が何枚にも連なった形式があります。このマルチページTIFFの場合は

  1. ヘッダ
  2. IFD1+画素データ1
  3. IFD2+画素データ2

のような順にファイルが構成されています。IFDの最後に次のIFDの開始位置が書かれており読み取ることが可能になっています。

 以上がTIFFの全体構造です。ヘッダがはじめにあって、IFDと画素データが続くだけです。あとはヘッダやIFD、画素データの記述方法について学べばTIFFは理解できます。では、順番に解説します。

TIFFのヘッダ

 TIFFファイルのはじめの8バイトがヘッダにあたります。先にあげたTIFFファイルなら

4D 4D 00 2A 00 00 00 08

がヘッダです。はじめの2つの数字「4D 4D」はバイトを読む方向を指定します。

「4D 4D」なら上位から下位バイトへ読み、「49 49」なら下位から上位バイトで読みます。

これだけだとわかりにくいので、次の「00 2A」を解説しながら説明します。今回のファイルは「4D 4D」なので上位から下位バイトを読みます。よって、「00 2A」は「00 2A」と左から右に読みます。ですから、10進数で42と読み取れます。もしも、「49 49」なら「00 2A」は下位から読むので「2A 00」となり10進数で10752となります。この説明で「4D 4D」と「49 49」の違いがわかっていただけたかと思います。

 さて、「00 2A」の意味ですが、

「00 2A」はこのファイルがTIFFであることを示します。

ですから、ほとんどの場合、「00 2A」となります。ただ、BigTIFFという大きいサイズのTIFFを扱う形式の場合は「00 2B」となります。「00 2B」がBigTIFFであることを示すのです。

 最後の「00 00 00 08」はImage File Directory(IFD)が開始するバイト番号を示します。今回は8なので8バイトからIFDが始まることになります(今回の場合は、4D 4D 00 2A 00 00 00 08の直後ですね)。IFDには画像の情報が書き込まれているので、「00 00 00 08」を読み取って画像情報の位置を把握することになります。ここが8バイトなので、TIFFのサイズの上限は2^{8\times 4}=4294967296と約4Gバイトとなります(4G以上を扱うにはBigTIFFを使用する必要があります)。

 以下がヘッダのまとめです。確認しておきましょう。

ImageJ=1.46r TIFFのヘッダまとめ

IFD (Image File Directory)

 IFDはImage File Directoryの頭文字をとったものであり、画像の付加情報がのっています。付加情報のことをタグと読んだりします。IFDは

  1. 付加情報(タグ)の数
  2. 付加情報(タグ)
  3. 次のIFDの位置情報

からなります。これらを順番に解説します。

付加情報(タグ)の数

はじめの2バイトにタグの数が記述されています。今回のTIFFファイルでは

00 0A

なので10(=0A)個のタグがあることになります。ちなみにこの領域が2バイトなので、最大のタグの数は65535(2^16-1)個となります。

付加情報(タグ)

 タグの数のあとに、指定された数のタグ情報が記述されます。1つのタグは12バイトより構成されます。そして、12バイトは以下のような割り当てで使用されます。

  1. タグの種類(2バイト)
  2. データの型(2バイト)
  3. データの量(4バイト)
  4. データ(4バイト)

タグの種類に「どのような付加情報なのか」を指定します。例えば、画像の高さなら0100(16進数)や幅なら0101(16進数)といったかんじです。この種類はたくさんあるので次回の記事でまとめて紹介します。データの型はFLOATなのかLONGなのかというプログラミングでお馴染みのデータの型です。以下にデータ型と数値の対応関係をまとめます。

  • 1: BYTE型(1バイト整数)
  • 2: ASCII型(1バイトASCII文字)
  • 3: SHORT型(2バイト短整数)
  • 4: LONG型(4バイト長整数)
  • 5: RATIONAL型(はじめの4バイトが分子で、残り4バイトが分母)
  • 6: SBYTE型(1バイト符号付き整数)
  • 7: UNDEFINED型(1バイトデータ)
  • 8: SSHORT型(2バイト符号付き短整数)
  • 9: SLONG型(4バイト符号付き長整数)
  • 10: SRATIONAL型(8バイト分子、8バイト分母)
  • 11: FLOAT型(4バイト実数)
  • 12: DOUBLE型(8バイト倍精度実数)

次のIFDの位置情報

 画像がひとつでなく複数ある場合はここに次のIFDの開始位置を記述します。4バイトで記述します(4バイトは2の32乗で4,294,967,296となり約4Gです。よって、TIFFは4G以上の画像を扱うことはできません。扱うにはBigTIFFを使用する)。もし、次の画像がない場合は

00 00 00 00

とゼロを記述します。もしここがゼロでない場合は、マルチページTIFFとなります。複数画像を含むTIFFを構成したい場合は、この位置に次のIFDを記載しておきましょう。

例にあげた TIFFファイルのIFDを整理してみる

例にあげたTIFFファイルのIFDを整理すると以下のようになります。

(「タグ名 | データの型 | 個数 | 値」としています。)

  1. 00 FE | 00 04 | 00 00 00 01 | 00 00 00 00 : NewSubfileType
  2. 01 00 | 00 04 | 00 00 00 01 | 00 00 00 96 :画像の幅150(16進数で96)
  3. 01 01 | 00 04 | 00 00 00 01 | 00 00 00 96:画像の高さ150(16進数で96)
  4. 01 02 | 00 03 | 00 00 00 03 | 00 00 00 86:色の深さ、位置86に記載(00 08 00 08 00 08)
  5. 01 06 | 00 03 | 00 00 00 01 | 00 02 00 00 :RGBダイレクトカラー
  6. 01 0E | 00 02 | 00 00 00 0E | 00 00 00 8C :ImageDescripation(位置8Cは49 6D 61 67 65 4A 3D 31 2E 34 36 72 0A 00でASCIIコードでImageJ=1.46rとなる)
  7. 01 11 | 00 04 | 00 00 00 01 | 00 00 00 9A : StripOffsets、画素データ(ストリップ)の開始位置
  8. 01 15 | 00 03 | 00 00 00 01 | 00 03 00 00 : RGB
  9. 01 16 | 00 03 | 00 00 00 01 | 00 96 00 00 : 1ストリップあたりの行数(RowsPerStrip)は150(16進数で96)行
  10. 01 17 | 00 04 | 00 00 00 01 | 00 01 07 AC : StripByteCounts、1ストリップあたりのデータ数

タグ名の意味がわかりませんが、他は理解できるかと思います。次回、タグ名について解説するので、それでスッキリすると思います。

参考サイト

この記事を書くにあたって参考にしたサイトを紹介します。

著者:安井 真人(やすい まさと)