[Tips] ビットマップファイルのフォーマット
今まで公開してきたビットマップファイルの読み出し・書き出しのプログラムがバグだらけなので,
ソースコード,および記事を修正して,ここにアップロードしていく.
ここでは,特に24ビットのビットマップファイルのみを説明対象とする.
ビットマップファイルの構造
ビットマップファイル自体は,2つのヘッダ情報とピクセル情報から構成される.
2つのヘッダファイルは,BitmapHeaderとBitmapInfoHeaderである.
ひとつめのBitmapHeaderは以下である.
typedef struct _BitmapHeader{
char distinct1; // 'B'
char distinct2; // 'M'
int filesize; // 総ファイルサイズ
short reserve1; // 予約領域・常に0
short reserve2; // 予約領域・常に0
int offset; // ファイルの先頭からデータまでのオフセット
}BitmapHeader;
ふたつめのBitmapInfoHeaderは以下である.
typedef struct _BitmapInfoHeader{
int header; // この構造体のサイズ
int width; // Bitmapのサイズ・横幅
int height; // Bitmapのサイズ・縦幅
short plane; // plane数・常に1
short bits; // Bitmapの色数(bit単位)
int compression; // 圧縮されているか?
int comp_image_size; // 画像全体のサイズ・使わない
int x_resolution; // Bitmapの解像度・使わない
int y_resolution; // 72と設定しておいてもかまわない
int pallet_num; // パレット数・24bitカラー等の場合使わない
int important_pallet_num;
// 重要なパレット数・使わない
// 24bitカラー等の場合使わない
}BitmapInfoHeader;
そして,3つめのデータ,ピクセルデータが並ぶ.
このピクセルデータがくせ者.
ビットマップファイルのピクセルデータ
・1ピクセルずつの色情報
直感的に,1ピクセルずつにRGBの順番にデータが入っているのが普通な気がするが,実はビットマップファイルでは,1ピクセルずつに,BGRの順番でデータが入っている.
このため,RGBの順番でピクセルデータをプログラム上で管理する場合,読み込み,書き込み時に順番を入れ替える必要がある.
・横と縦のピクセルの並び
一般的に画像の座標は,デバイス座標系で表す(とsonsonは考えているのだが).このデバイス座標系では,左上が原点となり,右方向にX軸,下方向にY軸を取る.このため,画像データもデバイス座標系で保存するのが一般的である(とsonsonは考えているのだが).
そうすると,1次元配列でRGB24ビットの画像を保存する場合,例えば,以下のように表すことができる.
unsigned char *pixel = (unsigned char*)malloc(sizeof(unsigned char)*width*height*3); *(pixel+3*(x+y*width) )=red; *(pixel+3*(x+y*width)+1)=blue; *(pixel+3*(x+y*width)+2)=green;
この場合,メモリ上に画像の左上から,1行ずつ並べていくように保存するイメージとなる.
しかし,ビットマップファイルは,画像をデバイス座標系で言うと下から1行ずつ保存する.つまり,上下が逆さまなのだ.このため,デバイス座標系で管理する画像データを書き出す場合は,上下の方向を逆にする必要がある.つまり直感的に言うと下のようなコーディングとなる.
*(pixel+3*(x+(y-(height-1))*width) )=red; *(pixel+3*(x+(y-(height-1))*width)+1)=blue; *(pixel+3*(x+(y-(height-1))*width)+2)=green;
あぁ,マンドクセ.

・バイトマージン
また,ビットマップファイルの横方向にはマージンがある.このマージンは横方向の1行のバイト数は4の倍数にするというものだ.24ビットのビットマップファイルは,1ピクセル当たり3バイトとなる.このとき,横幅が20ピクセルある場合,1行のバイト数は60バイトとなる.このときは,1行が4の倍数のバイト数となっているため,マージンはない.しかし,21ピクセルの場合は,1行のバイト数は,63バイトとなる.この場合は,1バイト分,0が追加される.また,22ピクセルの場合は,66バイトとなり,マージンは,2バイト分であり,2バイト分0が追加されることになる.
あぁ,これもマンドクセ.

・サンプル
例えば,24ビット,横幅22ピクセル,高さ60ピクセルのビットマップファイルのピクセルデータは以下のようになる.
