2006 年 1 月 19 日 23 時 29 分

ヘッダ情報+α


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


今日は BMP のヘッダについて書く。
詳細は Web を参照すれば出てくるので、
今回は BMP を生成するための最低限を紹介する。

ファイルの最初には、
BITMAPFILEHEADER と呼ばれる 14 バイトが入る。

pack("a2Vx4V", "BM", $file_size, $offset);

a2 は、ASCII 2 文字。
V は、リトルエンディアンの 4 バイト整数。
x4 は、NUL 4 文字。つまり、0 のバイトが 4 つ。

BITMAPFILEHEADER の最初の 2 バイトは
"BM" という文字が入る。これは決まりごとだ。

次の 4 バイトには、ファイル全体のサイズが入る。
つまり、ファイルを作成する際には、
先に計算しておかないといけない。

次の 4 バイトには 0 が入る。これも決まりごと。

最後の 4 バイトにはデータ部の開始オフセットが入る。
通常、ヘッダ部直後にデータ部がくるので、
この値はヘッダ部全体のサイズになる。
BITMAPFILEHEADER の 14 に、後述する
BITMAPINFOHEADER の 40 を足した 54 が入る事が多い。
(ヘッダ情報が他にもある場合は、値が変わる)

BITMAPFILEHEADER の次には、
BITMAPINFOHEADER と呼ばれる 40 バイトが入る。
ここには、画像に関する情報が含まれる。

pack("VVVvvVVx16", 40, $width, $height,
1, $bit_count, $compression, $data_size);

v は、リトルエンディアンの 2 バイト整数。
x16 は、NUL 16 文字。つまり、0 のバイトが 16 個。

BITMAPINFOHEADER の最初の 4 バイトは
BITMAPINFOHEADER 自体のサイズが入る。通常は 40 だ。

次の 4 バイトは画像の横幅、次の 4 バイトは画像の高さ。
次の 2 バイトは 1 固定。そして次の 2 バイトには、
ピクセルあたりのビット数が入る。前の例では 24 だ。
他に、16 や 32 などもある。

次の 4 バイトは圧縮手法だが、0 で良い。(非圧縮)
圧縮形式はあまり使われない。
次の 4 バイトは、画像データ部のサイズだが、
圧縮手法が 0 の場合は 0 で構わない。
最後の 16 バイトは、とりあえず 0 で構わない。

16, 24, 32 ビットの BMP の場合、
必要なヘッダはこの 2 つだけで、54 バイトのサイズとなる。

欄が余ったので、それぞれの BMP の差について書こう。

16, 24, 32 ビットの BMP の差は、ピクセルデータの表現。
24, 32 は、RGB それぞれ 8 ビットで 0 ~ 255 の範囲だが、
16 の場合、RGB それぞれ 5 ビットで 0 ~ 31 となる。

ビット単位で書くと、
16 ビットの場合、gggbbbbb 0rrrrrgg
24 ビットの場合、bbbbbbbb gggggggg rrrrrrrr
32 ビットの場合、bbbbbbbb gggggggg rrrrrrrr 00000000

16 ビットの並びに違和感を持たないだろうか。

BMP はリトルエンディアンである。
gggbbbbb 0rrrrrgg というバイトの並びを、
リトルエンディアンの 2 バイト整数として読み込んだ場合、
0rrrrrgggggbbbbb という値になるのだ

32 ビットの場合も、同様に 4 バイト整数として読み込むと、
00000000rrrrrrrrggggggggbbbbbbbb となる。
どうだろう。仕組みがみえてこないだろうか。

BMP を扱う上で避けられないのが、エンディアンである。
BMP の場合、各画素値は、RGB がパックされた整数値であり、
決められたビット幅の中に、右詰で RGB の順に格納される。

16 ビットの BMP の場合、16 ビット長の整数の中に、
R, G, B の順に 5 ビットづつ格納されている。
右詰なので、左端にはビットが 1 つ余りそこには 0 が入る。

32 ビットの場合は、32 ビット長の整数の中に、
R, G, B の順に 8 ビットづつ格納されている。
右詰なので、左端にはビットが 8 つ余りそこには 0 が入る。

24 ビットの場合は、24 ビット長の整数の中に、
R, G, B の順に 8 ビットづつ格納されている。
これは丁度埋まるので、ビットは余らない。

あくまでも、~ビット長の整数であり、
バイトで区切って考えてはいけない。

これら整数値をリトルエンディアンでファイル化するため、
24 ビットや 32 ビットの場合、
丁度 B, G, R の順に格納されているように見えるのだ。

今日はかなりややこしくなった。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.