[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ピクセルのビットマップファイルのピクセルデータは以下のようになる.
