今まで公開してきたビットマップファイルの読み出し・書き出しのプログラムがバグだらけなので,
ソースコード,および記事を修正して,ここにアップロードしていく.
ここでは,特に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;

あぁ,マンドクセ.


newBitmapLecture001.png

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

newBitmapLecture002.png

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

newBitmapLecture003.png