• ベストアンサー

C言語でBMPファイルの内容を表示 その2(Unix使用)

こんにちは。私は30代の男性です。 以前、コマンドラインで指定したBMPファイルの中身をバイナリ形式で読み込むということにチャレンジして、とりあえずBITMAPFILEHEADER構造体の中の情報を引き出すことには成功しました。 ※以前の質問とご回答 → http://okwave.jp/qa2837931.html fread関数を使ってoffsetという情報(ファイル先頭から画像データまでのバイト数)を取り出すことができたので、あとはBMPファイルの先頭アドレスからoffsetのバイト数分だけ進んだ箇所からデータを取り出して出力すれば、数値として格納されている画像データが引き出せると思ったのですが、うまくいきません。 どのようにアドレスを指定すれば、バイナリ形式の画像データを表示できるのでしょうか?宜しくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.3

★頑張っているようですね。 ・でもビットマップの構造体『BITMAPFILEHEADER』をよく理解していないかもしれませんね。  ビットマップには色数によってたくさんのバリエーションがあります。  また、カラーテーブルを使うタイプと使わないフルカラーのタイプに分かれます。  正しく処理するには、構造体よりカラーテーブルの有無をチェックして存在する場合は、  その部分を読み込むか、スキップ処理(fseek)などします。 ・さらに構造体のメンバのパディング処理はなしにコンパイラ・オプションを設定しないと  正しく処理できません。構造体メンバとメンバの隙間が 4 バイトになるようにアライメント  されていしまうとオフセット値がずれます。→結果、おかしな表示になります。 ・ほかにもファイルのデータを上から順に読み込んでいくと、画像部分の下部ラインから順番に  読み込むという動作になります。描画するときは、ここに注意して下さい。分かりますか?  ビットマップ・ファイルは、画像データの下部から順番に1ラインずつ上方向に向かって  記録されていくという構造なのです。面白い構造(まぎわらしい構造)です。注意! ・読み込む処理は、  (1)『bfType』メンバで『BM』文字をチェックします。→違えばビットマップではないと判定。  (2)『bfOffBits』メンバがビットマップのベタ・データまでのオフセット値になります。   『fseek』関数などで移動して『fread』関数で1ラインずつ読み込めば出来ますよ。  (3)『BITMAPINFOHEADER』構造体から画像の横・縦ドットを取得します。   『biWidth』、『biHeight』がピクセル数ですが、横ピクセルは 4 ピクセル単位(倍数)で   記録されます。『biWidth』メンバには実際のピクセル数ですので『差』が生じた場合には   無駄なバイトデータが存在することになります。→『biWidth=1234』では1234÷4=308余り2で   割り切れないため1ラインにつき2ピクセル分の無駄なデータが存在することになります。   このずれをきちんと理解していないと読み込みや描画時に画像がずれます。注意!  (4)『biBitCount』メンバからカラービット数を取得します。   前回の質問から『白黒』画像なので『biBitCount=1』のモノクローム・ビットマップになります。   『白黒』の場合はカラーテーブルを必ず2つ持ちます。注意して下さい。  (5)『RGBQUAD』構造体でカラーテーブルを読み込む。→白黒なので2つの要素です。   (4)の『biBitCount』が 1(白黒2色)、4(16色)、8(256色) の場合は必ずカラーテーブルを含みます。注意!  (6)上記の情報から画像データの位置、色数、ピクセル数、カラーテーブルの有無で読み込み処理を   行っていきます。読み込むときに1ラインは 4 の倍数でピクセル情報が記録されています。注意。   『白黒』ですので 1 バイトが 8 ピクセルを一度に表します。バイトオーダーは『リトルエンディアン』   になります。つまり、上位ビットから下位ビットが左ドットから右ドットへの順になるのです。 ・横方向の走査線の計算がややこしいので構造体の意味をきちんと理解してからプログラミングしないと  バグが多発します。参考文献を多数紹介します。→下の『参考URL』が詳しいので今後の参考にして下さい。 ・もう一度、新規ファイルとして順番に作成することをお勧めします。 ・以上。おわり。→頑張って下さい。 猫でもわかるプログラミング: ・http://www.kumei.ne.jp/c_lang/sdk2/sdk_169.htm→『第169章 ビットマップの構造』 ・http://www.kumei.ne.jp/c_lang/sdk2/sdk_170.htm→『第170章 とりあえずビットマップを表示してみる』 構造資料: ・http://www5d.biglobe.ne.jp/~noocyte/Programming/Windows/BmpFileFormat.html→『BMPファイルのフォーマット』 ・http://hp.vector.co.jp/authors/VA023539/tips/bitmap/001.htm→『ビットマップファイルの構造』 ・http://homepage2.nifty.com/himagination/bmp.html→『間違っているBMP解析講座』 読み込み資料: ・http://www14.big.or.jp/~ken1/tech/tech12.html→『ファイルからビットマップを読み込む16,256色(1)』 ・http://www.alpha-net.ne.jp/users2/uk413/vc/VCT_DIB.html→『ディスク上のBMPファイルを表示する』 ・http://hp.vector.co.jp/authors/VA023539/tips/bitmap/002.htm→『ビットマップファイルを読み込む』

参考URL:
http://www5d.biglobe.ne.jp/~noocyte/Programming/Windows/BmpFileFormat.html
DT50
質問者

お礼

Oh-Orange様 いつもご回答頂きありがとうございます。詳しい手順をお教え頂き、とても参考になります。今はfseek関数を使って、画像データが格納されている最初の行(らしきもの)を読み込むことができましたが、下の行には移動できず悪戦苦闘中です・・・(-.-;)。 実際は下の行から読み込めなくてはならないのですね? まずは、画像データの最初の行から下の行まで全行を読み込めるようにして、それができてから下の行から読んでいこうと思います。

その他の回答 (2)

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.2

解1: C言語のファイルポインタ制御はfseekという関数を使います。 第三引数の指定に注意してください。 解2: freadの度にポインタは移動しますから、FILE*を引き回す手もあります。 # 念のため、先頭のBMくらいはチェックした方がいいのでは? > fread関数を使ってoffsetという情報(ファイル先頭から画像データまでのバイト数)を -- snip -- > うまくいきません。 以前の回答をきちんと調べましたか?BMPにはいろいろな形式があり、 実際のデータの読み方は、BITMAPINFOの内容に依存して変わるので、 固定/決めうちでなければ、これをキチンと解析するコード書く必要があります。 -- 以下、ソースの話 -- > if (argc != 2){ err_str = strerror(errno); この時点では、errnoをstrerrorしてもダメです。 int f_size = sizeof(fp); FILE*のサイズ(通常は唯のポインタなので4byte程度)が必要とは思えないので、 多分、何か勘違いされていそうな気がします。 > free(file_image); 突然解放してますが、これは省略された部分で確保されたものですか。 (仮にそうだとしても、このような確保と解放が非対称な用法はお勧めしません) # fopen失敗時にも同じ1が返るが、freeされてない。 # ⇒呼び元ではメモリが解放されたか否かも判断できない argc,argvをむやみに引き回すのもあまりお勧めしません。

DT50
質問者

お礼

ご回答ありがとうございました。 fseek関数は、昨日調べていて使わなければいけないものだということに気付き始めていました(^-^;)。どうもありがとうございました。

noname#26650
noname#26650
回答No.1

どんなコードを書いて、どううまくいかないか、 具体的に提示する必要がありそうです。 「できると思ったけど、うまくいかない」だけでは、 誰も何もわかりません。

DT50
質問者

お礼

ご回答ありがとうございます。字数の関係で、BITMAPFILEHEADERを記したヘッダファイル部分は省かせてもらいます。 #include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>int read_file(char *file_name, unsigned char **file_image, size_t *file_size, int argc, char *argv[]);   int file_header(struct BITMAPFILEHEADER bmh, int argc, char *argv[] );  int main(int argc, char *argv[]){ char *err_str; char *file_name = argv[1]; size_t file_size; unsigned char **file_image; file_size = sizeof *argv[1]; if (argc != 2) { err_str = strerror(errno); fprintf(stderr, "ERROR: %s(%d): %s:失敗(%s)\n", __FILE__, __LINE__, file_name, err_str); return 1; } read_file(file_name, file_image, &file_size, argc, argv); return 0;} int read_file(char *file_name, unsigned char **file_image, size_t *file_size, int argc, char *argv[]){ char *err_str; int sts; size_t read_size_bmh; FILE *fp; int f_size = sizeof(fp); fp = fopen(file_name, "rb"); if (fp == NULL) { err_str = strerror(errno); fprintf(stderr, "ERROR: %s(%d): %s:失敗(%s)\n", __FILE__, __LINE__, file_name, err_str); return 1; } read_size_bmh = fread(&bmh, sizeof(bmh), 1, fp); if (read_size_bmh != 1) { err_str = strerror(errno); fprintf(stderr, "ERROR: %s(%d): %s:読み込み失敗(%s)\n", __FILE__, __LINE__, file_name, err_str); sts = fclose(fp); free(file_image); return 1; } file_header(bmh, argc, argv); sts = fclose(fp); if (sts != 0) { err_str = strerror(errno); fprintf(stderr, "ERROR: %s(%d): %s:クローズに失敗(%s)\n", __FILE__, __LINE__, file_name, err_str); } return 0;} int file_header(struct BITMAPFILEHEADER bmh, int argc, char *argv[]) { printf("offset = %ld\n\n", bmh.offset); struct tagBITMAPFILEHEADER *p; p = &bmh; printf("%ld\n", p->offset); return 0;}

関連するQ&A