メモリからバイナリデータの取得、ファイル書き込みについてその2

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
マッハ

メモリからバイナリデータの取得、ファイル書き込みについてその2

#1

投稿記事 by マッハ » 7年前

昨日同様のトピックスで質問した者です。
自分なりにいろいろ調査しそれらしきBMPイメージを取得できたのですが、ビューアーで「ファイルが破損しているか、大きすぎる可能性があります」と表示されファイルが開けません。そこで再度質問をさせて頂きたいと思います。


【現象】
BMPファイルは生成できたもののファイルが開けません。また、ファイルのプロパティを確認するとサイズ自体は5,769,844バイトが得られました。


【ソース、メモリ情報】
○メモリ情報
?BMPInfo
0x03130020 {biSize=40 biWidth=1078 biHeight=1783 ...}
biSize: 40
biWidth: 1078
biHeight: 1783
biPlanes: 1
biBitCount: 24
biCompression: 0
biSizeImage: 5769788
biXPelsPerMeter: 15748
biYPelsPerMeter: 15748
biClrUsed: 0
biClrImportant: 0

○処理の概要
上記BMPInfoの情報を元にBITMAPFILEHEADERやBITMAPINFOHEADERに値を格納し、ビットマップイメージを生成

○ソースコード

コード:

        BITMAPFILEHEADER BmpFileHeader;	// ビットマップファイルヘッダ
	BITMAPINFOHEADER BmpInfoHeader;	// ビットマップ情報ヘッダ
	//unsigned long ImageSize = (BMPInfo->biWidth) * (BMPInfo->biHeight) * 3;		// データサイズ
	unsigned long ImageSize = BMPInfo->biSizeImage;		// データサイズ
	unsigned char *b;

	//BITMAP用メモリを確保
	b = (unsigned char*) malloc(ImageSize);
	if (b == NULL) {
		return -1;
	}

	// BITMAPFILEHEADERを設定
	memset(&BmpFileHeader, 0x00, sizeof(BmpFileHeader));
	BmpFileHeader.bfType = 0x4D42;	//ビットマップのファイルタイプ
	BmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + ImageSize;
	BmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

	// BITMAPINFOHEADERを設定
	memset(&BmpInfoHeader, 0x00, sizeof(BmpInfoHeader));
	BmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
	BmpInfoHeader.biWidth = BMPInfo->biWidth;
	BmpInfoHeader.biHeight = BMPInfo->biHeight;
	BmpInfoHeader.biPlanes = BMPInfo->biPlanes;
	BmpInfoHeader.biBitCount = BMPInfo->biBitCount;
	BmpInfoHeader.biCompression = BMPInfo->biCompression;
	BmpInfoHeader.biSizeImage = ImageSize;

	// 出力ファイルオープン
	FILE *fp = NULL;
	if (fopen_s(&fp, "sample.bmp", "wb") != 0){
		return -1;
	}

	// BITMAPFILEHEADERを書き込む。
	if (fwrite(&BmpFileHeader, sizeof(BmpFileHeader), 1, fp) != 1){
		fclose(fp);
		return -1;
	}

	// BITMAPINFOHEADERを書き込む。
	if (fwrite(&BmpInfoHeader, sizeof(BmpInfoHeader), 1, fp) != 1){
		fclose(fp);
		return -1;
	}

	// 画像データを書き込む。
	if (fwrite( b,sizeof(unsigned char) ,ImageSize, fp) != (size_t)ImageSize){
		fclose(fp);
		return -1;
	}

	// 出力ファイルを閉じる。
        free(b);
	fclose(fp);
もう一歩のところまで来ているような気がするのですが。もしアドバイス等ありましたらお願いします。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: メモリからバイナリデータの取得、ファイル書き込みについてその2

#2

投稿記事 by みけCAT » 7年前

マッハ さんが書きました:biWidth: 1078
マッハ さんが書きました:

コード:

	//unsigned long ImageSize = (BMPInfo->biWidth) * (BMPInfo->biHeight) * 3;		// データサイズ
	unsigned long ImageSize = BMPInfo->biSizeImage;		// データサイズ
BMPファイルの各行のデータサイズは4[バイト]の倍数でなければなりません。(各行で余った部分はパディングが入ります)
1078*3は4で割り切れませんが、データサイズは正しいですか?

【追記】
biSizeImage(5769788)をbiHeight(1783)で割ると3236となり、4で割り切れ、3*1078+2なので正しそうですね。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: メモリからバイナリデータの取得、ファイル書き込みについてその2

#3

投稿記事 by みけCAT » 7年前

マッハ さんが書きました:また、ファイルのプロパティを確認するとサイズ自体は5,769,844バイトが得られました。
biSizeImage(5769788)+biSize(40)+ヘッダのサイズ(14) = 5769842 なので、計算が合いませんね。
計算を速くするための構造体のパディングがファイルに混ざってしまっている可能性があります。
TSXBINなどのバイナリエディタかodコマンドなどで、ファイルに書き込まれたデータを確認してみてください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

マッハ

Re: メモリからバイナリデータの取得、ファイル書き込みについてその2

#4

投稿記事 by マッハ » 7年前

>みけCATさん
返信が遅くなりました。申し訳ありません!
頂いたアドバイスを元に、生成したBMPファイルをTSXBINにダンプし、中身を確認しながら実装をすすめました。
ダンプ結果を元にヘッダファイル構造体の型を見直し、適切な値をメンバに格納することで意図したBMPファイルを得ることができました。
ご助言ありがとうございました。
逐一正常なBMPファイルと生成したBMPファイルをバイトごとに比較することが大事だということを痛感しました。


同じような悩みを持つ方にも役に立つかもしれないので
備忘録として僕の実施した検証を書いておきます。
・正しく動作するBMPファイル生成処理が書かれたソースコードを得る
・その正しいソースから得られたBMPファイルと自身が生成したBMPファイルをバイナリエディタで比較する
→比較する場合は、記載された情報の位置、値が重要
→TSXBINは使い勝手の良いバイナリエディタでした。今後愛用しようと思います。
・ソースの検討では、構造体のメンバの型に注意(構造体のsizeofの数字にも注意)

とにかくヘッダの構造体の理解が重要です。
混乱してきた場合は構造体の定義に戻り落ち着いて入るべき値と検討しましょう。

以上です。ありがとうございました。

返信

“C言語何でも質問掲示板” へ戻る