
こんにちは。私は30代の男性です。
以前、コマンドラインで指定したBMPファイルの中身をバイナリ形式で読み込むということにチャレンジして、とりあえずBITMAPFILEHEADER構造体の中の情報を引き出すことには成功しました。
※以前の質問とご回答 → http://okwave.jp/qa2837931.html
fread関数を使ってoffsetという情報(ファイル先頭から画像データまでのバイト数)を取り出すことができたので、あとはBMPファイルの先頭アドレスからoffsetのバイト数分だけ進んだ箇所からデータを取り出して出力すれば、数値として格納されている画像データが引き出せると思ったのですが、うまくいきません。
どのようにアドレスを指定すれば、バイナリ形式の画像データを表示できるのでしょうか?宜しくお願い致します。
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/ …→『BMPファイルのフォーマット』
・http://hp.vector.co.jp/authors/VA023539/tips/bit …→『ビットマップファイルの構造』
・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_D …→『ディスク上のBMPファイルを表示する』
・http://hp.vector.co.jp/authors/VA023539/tips/bit …→『ビットマップファイルを読み込む』
参考URL:http://www5d.biglobe.ne.jp/~noocyte/Programming/ …
Oh-Orange様
いつもご回答頂きありがとうございます。詳しい手順をお教え頂き、とても参考になります。今はfseek関数を使って、画像データが格納されている最初の行(らしきもの)を読み込むことができましたが、下の行には移動できず悪戦苦闘中です・・・(-.-;)。
実際は下の行から読み込めなくてはならないのですね?
まずは、画像データの最初の行から下の行まで全行を読み込めるようにして、それができてから下の行から読んでいこうと思います。
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をむやみに引き回すのもあまりお勧めしません。
ご回答ありがとうございました。
fseek関数は、昨日調べていて使わなければいけないものだということに気付き始めていました(^-^;)。どうもありがとうございました。
No.1
- 回答日時:
どんなコードを書いて、どううまくいかないか、
具体的に提示する必要がありそうです。
「できると思ったけど、うまくいかない」だけでは、
誰も何もわかりません。
ご回答ありがとうございます。字数の関係で、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が見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題です 2 2023/07/21 10:51
- Visual Basic(VBA) 3つのプロシージャをまとめたら実行時エラー発生で対応不能 6 2022/05/17 01:47
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# C言語の質問です。バイナリ形式で保存されたWindows Bitmap形式の画像ファイルを読み込み、 3 2023/07/19 14:58
- その他(OS) Windowsで大量の画像サイズを半自動で変更する方法 6 2023/02/17 08:45
- Visual Basic(VBA) 動かなくなってしまった古いVBAを動くようにしたい 8 2022/09/20 13:57
- C言語・C++・C# C言語初心者 構造体 課題について 1 2023/03/10 19:30
- Windows 10 JPG PNG サポートされていない形式 (JPGファイルで開ける、開けないがある場合) 4 2022/04/23 13:46
- Excel(エクセル) エクセルのマクロについて教えてください。 3 2023/02/07 14:47
- その他(データベース) c言語の問題です。これを踏まえてコーディングしたいのでおしえていただきたいです。 3 2023/08/03 09:27
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
バッファとは何ですか
-
JPGのwidhtとheight
-
C言語とシリアル通信の送受信...
-
ページ読み込み時に自動的にsub...
-
EOF
-
入力ファイルをバイナリにする利点
-
C言語初心者の質問失礼します。
-
stdio.hをオープンできない…
-
どんなプログラムを書いても指...
-
教えてください!vectorworksに...
-
教えてください!vector works...
-
フリーソフトウェアでflaファイ...
-
JARファイルをEclipseを使って...
-
コンパイルするときに、ファイ...
-
jarの開き方を教えてください。
-
VBAでHTMLファイルを扱うにはど...
-
テキストファイルの文字を消す方法
-
VBAでEXEファイルを動かす方法...
-
FTPでputすると空ファイルが出...
-
ファイルアイコンの左下に緑の□...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
バッファとは何ですか
-
Microsoft VBAで2GBを超えるフ...
-
EXCEL VBAでテキストファイルの...
-
VBA バイナリ―から文字列にす...
-
エラー:ストリームの終わりを...
-
ページ読み込み時に自動的にsub...
-
EOF
-
エクセルVBA 2千万行のCSVファ...
-
入力ファイルをバイナリにする利点
-
【Teraterm】filewritelnについて
-
【python】Excelファイルを読み...
-
EXCEL VBAで、バイナリデータの...
-
FTPでエクセルをPUTするとファ...
-
テキストデータをSQLServerに取...
-
C言語とシリアル通信の送受信...
-
ビットマップファイル生成(C言...
-
pcxファイルを開きたい(RGBデ...
-
FTPを使わないファイルアップロ...
-
MacからWinにファイルを添付す...
-
HDDのバイナリイメージの取得方...
おすすめ情報