Tips of VC++ > ビットマップ > ビットマップファイルの構造
★ 前へ戻る ★ 次へ進む


ビットマップファイルの構造

ビットマップファイルのフォーマットは 数多くのサイトでも紹介されているかと思いますが、 あえて、私のサイトでも。 MSDNを見たほうが最新の情報は詳しく載っているでしょう。 つーか、このサイトの情報は古いです。 使えるかもしれませんが、とにかく古いです。(笑

ビットマップファイルの構造
ファイルの情報 BITMAPFILEHEADER構造体
ビットマップの情報 BITMAPINFOHEADER構造体
カラーテーブル RGBQUAD構造体の配列
画像ビット 数字がちゃらちゃら(笑)

まず、最初にBITMAPFILEHEADER構造体があります。 この構造体の値を確かめることにより ファイルがビットマップか他のファイルか確かめることができます。
あと、リソースの場合は存在しません。

typedef struct tagBITMAPFILEHEADER {
  WORD    bfType;
  DWORD   bfSize;
  WORD    bfReserved1;
  WORD    bfReserved2;
  DWORD   bfOffBits;
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
BITMAPFILEHEADER構造体
bfType ファイルタイプを指定します。 ビットマップファイルの場合は"BM"、すなわち0x4D42を そのまま代入してください。
この値が0x4D42でない場合は、ビットマップではない事が分かる。
bfSize ビットマップファイルのサイズを指定する。 ファイルサイズはAPIを使った方が正確であるので、特に使う事はない。
bfReserved1 現在使われていない。0にしなければならない。
bfReserved2 現在使われていない。0にしなければならない。
bfOffBits この構造体から画像ビットまでのバイト数を指定する。 これも使う必要はない。

BITMAPINFOHEADER構造体はBITMAPINFO構造体の一部ですが、 分けて考えた方が楽です。ビットマップの情報(幅・高さ・解像度など)が 入ってるので、重要です。

typedef struct tagBITMAPINFOHEADER{
  DWORD  biSize;
  LONG   biWidth;
  LONG   biHeight;
  WORD   biPlanes;
  WORD   biBitCount;
  DWORD  biCompression;
  DWORD  biSizeImage;
  LONG   biXPelsPerMeter;
  LONG   biYPelsPerMeter;
  DWORD  biClrUsed;
  DWORD  biClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
BITMAPINFOHEADER構造体
biSize 構造体のバイト数を指定する。 sizeof(BITMAPINFOHEADER)でよい。
biWidth ビットマップの幅をピクセルで指定する。 biCompressionの値がBI_JPEGかBI_PNGだった場合は、 展開したときの幅である。ただし、圧縮に尽いては触れないことにする。
biHeight ビットマップの高さをピクセルで指定する。
この値が正のとき、ビットマップは"bottom-up DIB"。すなわち、 画像ビットが左下隅から上に向かって並べられていることを示す。
この値が負のときは"top-down DIB"。すなわち、 画像ビットは左上隅から下に向かって並べられていることを示す。
もし後者の場合、biCompressionはBI_RGBかBI_BITFIELDSの どちらかでなければならない。 "top-down DIB"は圧縮することができない。
さらに、biCompressionの値がBI_JPEGかBI_PNGだった場合は、 展開したときの幅である。ただし、圧縮に尽いては触れないことにする。
biPlanes ターゲットデバイスのためのプレーン数を指定する。 この値は1でなければならない。
biBitCount 1ピクセルあたりのビット数を指定する。 この値は0,1,4,8,16,24,32のいずれかの値を取る。 詳細に尽いては後で述べることにする。
biCompression このメンバはBI_RGB,BI_RLE4,BI_RLE8, BI_BITFIELDS,BI_JPEG,BI_PNG のいずれかを取る。 詳細に尽いては後で述べることにする。
biSizeImage 画像のサイズを指定する。 biCompressionがBI_RGB、つまり無圧縮の場合は 0でもよい。そのときは自分で計算する必要がある。
bi_CompressionがBI_JPEGかBI_PNGのときは このメンバはJPEG画像、PNG画像それぞれの イメージバッファのサイズが入る。
biXPelsPerMeter ビットマップのターゲットデバイスの水平方向の解像度を 1メートルあたりのピクセル数で指定する。 アプリケーションはこの値を、 現在の(current)デバイスから最もよく合うリソースグループから ビットマップを選ぶのに使うことができる。
biYPelsPerMeter ビットマップのターゲットデバイスの水平方向の解像度を 1メートルあたりのピクセル数で指定する。
biClrUsed 実際にビットマップで使われている カラーテーブルのエントリ数を指定する。 この値が0ならば、ビットマップはbiBitCountの値で使用できる 最大のエントリ数を持っている。
biClrImportant ビットマップを表示するのに必要な(required) カラーテーブルのエントリ数を指定する。 この値が0のときは、全ての色が必要である。

BITMAPINFO構造体は次のようになっていて、 前述のBITMAPINFOHEADER構造体とカラーテーブル(配列)が格納されます。

typedef struct tagBITMAPINFO {
  BITMAPINFOHEADER bmiHeader;
  RGBQUAD          bmiColors[1];
} BITMAPINFO, *PBITMAPINFO;

RGBQUADの配列がカラーテーブルです。この構造体は単純です。 RGBそれぞれの明度が入っているわけです。 解説は要りませんね。rgbReservedは使われていません。

typedef struct tagRGBQUAD {
  BYTE    rgbBlue;
  BYTE    rgbGreen;
  BYTE    rgbRed;
  BYTE    rgbReserved;
} RGBQUAD;

画像ビットはBITMAPINFOHEADER::biHeightの符号によって 変わってくるのですが、基本的には下から上に向かって並んでいます。 しかし順番が逆なわけではなく、ラインの並べる方向が逆なのです。 並べられた状態を図にしてみるとこんな感じ。

それだけでなく、ラインはlong境界に合わせる。 すなわち、1ラインのバイト数を4の倍数にしなければならないので、 それに満たない場合は0で埋められている。 例えば、幅が99ピクセルの8bpp画像は1ラインは99バイトにならずに 100バイトになる。つまり、幅が99ピクセルでも100ピクセルでも 画像のサイズは同じなのである。

ビットマップがカラーテーブルを持っている場合、 画像ビットはもちろんカラーテーブルのインデックス値を示す。 そうでないフルカラービットマップの場合は、BGR順の3バイトで 1ピクセルを表すことになる。RGB順ではない点に注意して欲しい。

次に、BITMAOINFOHEADERのbiBitCountについて詳細を述べる。 またMSDNからの転用であるが…。

Value Meaning
0 1ピクセルあたりのビット数はJPEGフォーマットか、 PNGフォーマットによって指定されている。
1 白黒ビットマップである。 BITMAPINFO::bmiColorsは2つのエントリを保持している。 ビットマップ配列の互いのビットがピクセルで表現される。 もし、ビットがクリア(clear)ならば(おそらくOFFのときだろう)、 ピクセルはBITMAPINFO::bmiColorsの最初のエントリで表現される。 もし、ビットがセット(set)ならば(おそらくONのときだろう)、 ピクセルはBITMAPINFO::bmiColorsの2番目のエントリで表現される。
4 ビットマップは最大で16色持つことができる。 BITMAPINFO::bmiColorsは16のエントリを保持している。 ビットマップの互いのピクセルは カラーテーブルへの4ビットのインデックスで表現される。 例えば、画像の最初のバイトが0x1fの場合は二つのピクセルを示しており、 最初のピクセルは2番目のカラーテーブル、二つ目のピクセルは 16番目のカラーテーブルのエントリを示している。
8 ビットマップは最大で256色を保持できる。 BITMAPINFO::bmiColorsは256のエントリを持っている。 この場合、画像のそれぞれの1バイトは一つのピクセルを表している。
16 ビットマップは最大で2^16(65536)色を持っている。
もしbiCompressionがBI_RGBならばBITMAPINFO::bmiColorsはNULLである。 画像ビットのそれぞれ2バイト(WORD)が一つのピクセルを示す。 そして、5ビットでそれぞれ赤・緑・青の明度(intensity)を示す。 青の値は緑と赤の後に来て、末尾の5ビットで表される。 カラーテーブルはbiClrUsedによって指定されたエントリ数を 保持していなければならない。
もしbiCompressionがBI_BITFIELDSならば、 BITMAPINFO::bmiColorsは3つのDWORDでそれぞれ、赤・緑・青を構成している カラーマスク(color mask)を保持している。 しかし、システムは次に示す二つの16bppカラーマスクしか サポートしていない。すなわち、青のマスクが0x001Fで緑のマスクが0x03E0、 赤が0x7C00の"5-6-5 16-bit image"と青のマスクが0x001Fで 緑のマスクが0x07E0、赤が0xF800の"5-5-5 16-bit imageで"ある。
画像ビットの2バイト(WORD)で1ピクセルを表す。
24 ビットマップは最大で2^24(16777216)色を保持できる。 BITMAPINFO::bmiColorsはNULLで、画像ビットのそれぞれ3バイトが 青・緑・赤の順番でそれぞれ明度(intensity)を示す。
32 4294967296 ビットマップは最大で2^32(4294967296)色を保持できる。
もし、biCompressionがBI_RGBならば、 BITMAPINFO::bmiColorsはNULLで、画像ビットのそれぞれ4バイト(DWORD)が 青・緑・赤の順番でそれぞれ明度(intensity)を示す。 DWORDの最上位バイト(high byte)は使われていない。
もしbiCompressionがBI_BITFIELDSならば、 BITMAPINFO::bmiColorsは3つのDWORDでそれぞれ、赤・緑・青を構成している カラーマスク(color mask)を保持している。 しかし、システムは次に示す32bppカラーマスクしか サポートしていない。すなわち、青のマスクが0x000000FFで 緑のマスクが0x0000FF00、赤が0x00FF0000 緑のマスクが0x07E0、赤が0xF800の"5-5-5 16-bit imageで"ある。
画像ビットの4バイト(DWORD)で1ピクセルを表す。

以上のことを分析すると、 カラーテーブルを持っているのは1,4,8bppのビットマップまでで、 他の16,24,32bppはフルカラービットマップである。 さらに、0,16,32bppのビットマップはbiCompressionの値が深く関ってきそうだ。

Value Description
BI_RGB 非圧縮ビットマップである。
BI_RLE4 4bppビットマップのためのランレングス(RLE)形式である。 ビットマップ圧縮についてはここでは述べない。
BI_RLE8 8bppビットマップのためのランレングス(RLE)形式である。 ビットマップ圧縮に尽いてはここでは述べない。
BI_BITFIELDS ビットマップが非圧縮で、BITMAPINFO::bmiColorsが 三つのDWORD値から成立しているとき指定する。 これは16,32bppのとき使われる、
BI_JPEG 画像ビットがJPEGであることを示す。
BI_PNG 画像ビットがPNGであることを示す。

圧縮されたビットマップがあまり蔓延していないことを理由に ランレングス形式の解説は端折らせていただきます。ごめんなさい。m(_ _)m
JPEG,PNGフォーマットも知りたいんですが、難しそう…。 他のサイトを見てくださいな。でも、リクエストがあれば調べますよ〜。

May 9, 2002