BMP形式について、改めて書き直しています。以下を参照ください。
- BMPファイルフォーマット(簡易版)
- BMP画像の読み込み(簡易版)
- BMP画像の書き出し(簡易版)
- BMPファイルフォーマット(Windows)
- BMPファイルフォーマット(OS/2)
- BMPファイルフォーマット(Windows拡張)
- BMPファイルフォーマット(画像データ)
- BMP画像の読み込み(ヘッダ)
- BMP画像の読み込み(画像データ)
- BMP画像の書き出し(ヘッダ)
- BMP画像の書き出し(画像データ)
- PNG画像の入出力
画像ファイルの扱い方 (7) -BMP(DIB)形式 (3)
BMP形式出力関数
さて、入力ができたら次は出力関数です。
ところが、ここで重大なことが判明、
今扱っている Picture 構造体では完全にフルカラーの画像データしか扱えず、インデックスカラーを扱えないということです。
まあ、後に画像処理演算を行うことが目的なのでこれは致し方ないこと、
適当な減色をして処理しようかなとも思いましたが、そんなアルゴリズム知りませんし、
このような関数にそんなアルゴリズムを組み込むべきではありません。
ついでに、インデックスカラーを扱うには Picuture 構造体に手を加えるか、
新たな構造体を導入するか、 C++ とかでならクラスを作るか・・・ってとこですか?(別の関数で扱った方がスマートかも・・・)
インデックスカラー形式の出力についても、入力よりも楽にできると思いますのでそれほどサンプルソースを示す必要もないでしょう。
(データの整列がややこしいといえばややこしいけど)
というわけで、単純にフルカラーで出力するだけの関数を作ることにしました。
出力する形式を絞ってしまうと、作業は非常に単純、楽に作れました。(前半はさぼりのいいわけではない)
まいどのことですが、100%の自信はありませんので、ご注意を。
バグ等気が付かれた方は報告お願いします。
なお、前回と同様の移植性問題を抱えていることを追記しておきます。
/***********************************************************************/
/*** BMPファイル出力関数 ***/
/*** Windows Bit Map 24bitカラー形式で出力(固定) ***/
/*** ファイルポインタ、画像データを引数に与える。 ***/
/*** 成功した場合出力したデータのポインタを返し、 ***/
/*** 何らかのエラーが発生した場合NULLを返す。 ***/
/***********************************************************************/
Picture* putBmp(FILE* fp,Picture* pPic){
int i,j; /* ループ用変数 */
int x,y; /* x軸、y軸方向の画素数 */
int pad; /* 32bit境界のためのパディング */
int imgsize; /* イメージのサイズ */
unsigned char *buf,*buf_top; /* 画像データとその先頭ポインタ */
BMPFILEHEADER bf; /* ファイルヘッダ */
BMPINFOHEADER bi; /* ファイルヘッダ */
if(fp == NULL || pPic == NULL) /* 引数異常 */
return NULL;
/* ------------------------- ヘッダ作成 ---------------------------- */
x = pPic->x;
y = pPic->y;
pad = (x * 3 + 3) / 4 * 4 - x * 3; /* 32bit境界条件によるパディング */
imgsize = (x * 3 + pad) * y; /* 出力される場増データサイズ */
bf.bfType = *(WORD*)"BM";
bf.bfSize = imgsize
+ sizeof(BMPFILEHEADER)
+ sizeof(BMPINFOHEADER);
bf.bfReserved1 = 0;
bf.bfReserved2 = 0;
bf.bfOffBits = sizeof(BMPFILEHEADER)
+ sizeof(BMPINFOHEADER);
bi.biSize = sizeof(BMPINFOHEADER);
bi.biWidth = x;
bi.biHeight = y;
bi.biPlanes = 1;
bi.biBitCount = 24;
bi.biCompression = 0;
bi.biSizeImage = imgsize;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
/* ------------------------- ヘッダ出力 ---------------------------- */
if(fwrite((void*)&bf,sizeof(BMPFILEHEADER),1,fp) != 1)
return NULL; /* 書き込み失敗 */
if(fwrite((void*)&bi,sizeof(BMPINFOHEADER),1,fp) != 1)
return NULL; /* 書き込み失敗 */
/* ------------------------- 出力バッファ確保 ---------------------- */
buf_top = buf = (unsigned char*)malloc(imgsize);
if(buf_top == NULL)
return NULL; /* メモリ確保失敗 */
/* ------------------------- データ整列 ---------------------------- */
for(i = y - 1 ; i >= 0 ; i--){
for(j = 0 ; j < x ; j++){
*(buf++) = pPic->b[j + i * x];
*(buf++) = pPic->g[j + i * x];
*(buf++) = pPic->r[j + i * x];
}
for(j = 0;j < pad;j++)
*(buf++) = 0;
}
/* ------------------------- 画像データ出力 ------------------------ */
if(fwrite((void*)buf_top,1,imgsize,fp) != imgsize){
free(buf_top);
return NULL; /* 書き込み失敗 */
}
/* ------------------------- すべて成功 ---------------------------- */
free(buf_top);
return pPic;
}
っと、以上でとりあえずは BMP 形式のファイルフォーマットについての解説はおしまいです。
とりあえず、これまで解説したPPM形式とBMP形式が分かっていれば、画像処理ソフトなどの変換機能を利用することで、
ほとんどの形式で保存された画像ファイルをプログラム内で扱えるようになると思います。
まあ、画像処理ソフトのようなものを作りたいとか、画像形式変換プログラムを作りたいというのなら、
もっと様々なファイルフォーマットを知らないといけませんけど・・・
この場合は、ひとりで解決するのは難しいので、あらかじめ用意されたライブラリなどを利用するのが現実的でしょう。
例えば Windows なら Susie Plug-in を利用すれば、ほぼ全てのファイルフォーマットへの対応ができます。
(私はプラグインの利用法については勉強中です、どうやら正体は DLL のようですが、 DLL についても全く知らないので・・・)