![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?e8efa67)
![](http://oshiete.xgoo.jp/images/v2/common/profile/M/noimageicon_setting_12.png?e8efa67)
C++での画像処理プログラムの研究をしている者です。
文字数制限がありますので簡潔になりますがよろしくお願いします。
担当教官から基本となるプログラムをいただいたのですが実行するとエラーが出てしまいます。
プログラム内容:
void TImg::ImgMemToBmp(Graphics::TBitmap *bmp, BYTE *img)
{
GetBmpHdr(); // ビットマップヘッダー取得
String fileName = StartDir + "\\tmp.bmp";
FILE *fp;if (NULL == (fp = fopen(fileName.c_str(), "wb"))) return;
fwrite(BmpHeader, 54, 1, fp); // ヘッダー
//******** 画像書き込み ********
BYTE *p, *img1 = (BYTE *)malloc(Pixel_X_Max*3);
for (int y=0; y<Pixel_Y_Max; y++) {
p = img + (Pixel_Y_Max-y-1) * Pixel_X_Max;
for (int x=0; x<Pixel_X_Max; x++) {
*(img1+3*x) = *(img1+3*x+1) = *(img1+3*x+2) = *(p+x);
}
fwrite(img1, Pixel_X_Max*3, 1, fp);
}
fclose(fp);
bmp->LoadFromFile(fileName); // BMPファイル読み込み
DeleteFile(fileName); free(img1); // 不要ファイル、メモリ削除
}
問題点:下から3行目の
bmp->LoadFromFile(fileName);
でクラスの例外が発生しました。"ビットマップが不正です"とのエラーが出ます。
私なりにプログラムを解析してみたところ
で、tmp.bmpというファイルを作りそこに白黒画素値を書き込んでいるように思うのですが
途中で止めてtmp.bmpのサイズを確認してみたところ
原画像が640×480の画像でtmp.bmpのサイズは20971840×15728640となっていました。
これが原因でエラーと出たのではないかと考えたのですがいかがでしょうか?
補足要求していただければ、適宜補足いたしますので
どうかご助力をよろしくお願いいたします。
No.1ベストアンサー
- 回答日時:
> 原画像が640×480の画像でtmp.bmpのサイズは20971840×15728640となっていました。
これはどうやって調べたんでしょうか?
信頼できる手段で確認したんでしょうか?
tmp.bmp の16進ダンプを見たんでしょうか?
それとも (バグがあるかもしれない) 自作プログラムですか?
ヘッダがちゃんと書けていないんだったら,
普通の画像表示・編集ソフトで読もうとしてもエラーになるはずですよね?
(1) tmp.bmp が正しく書けていないのか,それとも LoadFromFile() に
問題があるのかを切り分けるため,tmp.bmp が画像表示・編集ソフト
(ペイントなど) でちゃんと表示できるかどうか確認してください.
(2) tmp.bmp がちゃんと書けていないのであれば,GetBmpHdr() に問題が
ありそうなので,そのソースを示してください.それと,できれば
tmp.bmp のヘッダ部 (ファイルの先頭54バイト) の16進ダンプも.
> 白黒画素値を書き込んでいるように思うのですが
元画像は8ビットグレースケールですが,
RGB 24ビットに変換して書き込んでいますね.
画像書き込み部のコードにもバグがあります.
BMP ファイルの1本の走査線は,4バイトの倍数に切り上げなければなりません.
(担当の先生は BMP ファイルのフォーマットを十分理解されていないようです.)
しかし今回は原画像の幅が480ドット (4の倍数) なので,
たまたまうまく動くはずです.したがって今回のエラーの原因ではありません.
↓参考
BMPファイルのフォーマット
http://www5d.biglobe.ne.jp/~noocyte/Programming/ …
この回答への補足
以下、GetBmpHdrのソースです。
void TImg::GetBmpHdr(void)
{
// BitmapHeaderが読みこまれていない場合読み込む
if (BmpHFlag == 0) MakeBmpHeaderFile(Pixel_X_Max, Pixel_Y_Max);
}
//---------------------------------------------------------------------------
// MakeBmpHeaderFile ビットマップヘッダーファイルを作成する
//---------------------------------------------------------------------------
int TImg::MakeBmpHeaderFile(int w, int h)
{
// 画像サイズ設定
if (w == 0) { w = Pixel_X_Max; h = Pixel_Y_Max; }
// ビットマップ画像の作成と保存
String fileHdr = StartDir + "\\BmpHeader.dat";
String fileName = StartDir + "\\template.bmp";
Graphics::TBitmap *bitmap;
bitmap = new Graphics::TBitmap; // ビットマップオブジェクト用のメモリ確保
bitmap->Width = w;
bitmap->Height = h;
bitmap->SaveToFile(fileName);
delete bitmap; // ビットマップの開放
BITMAPFILEHEADER bfHdr; BITMAPINFOHEADER biHdr;
// ビットマップファイルよりヘッダー情報の読み取り
FILE *fp;
if (NULL == (fp = fopen(fileName.c_str(), "rb"))) return NG;
fread(&bfHdr, sizeof(BITMAPFILEHEADER), 1, fp);
fread(&biHdr, sizeof(BITMAPINFOHEADER), 1, fp);
biHdr.biHeight = h;
biHdr.biWidth = w;
biHdr.biBitCount = 24;
biHdr.biCompression = 0;
bfHdr.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + w*h*3;
fclose(fp);
// ヘッダー情報の保存
if (NULL == (fp = fopen(fileHdr.c_str(), "wb"))) return NG;
fwrite(&bfHdr, sizeof(BITMAPFILEHEADER), 1, fp);
fwrite(&biHdr, sizeof(BITMAPINFOHEADER), 1, fp);
fclose(fp);
// ビットマップファイルよりヘッダー情報の読み取り
if (NULL == (fp = fopen(fileHdr.c_str(), "rb"))) return NG;
fread(BmpHeader, 54, 1, fp);
fclose(fp);
BmpHFlag = 1;
// ビットマップファイルの削除
DeleteFile(fileName);
DeleteFile(fileHdr);
return OK;
}
すみません。無知なもので16進ダンプの正確な定義がわからないですが
フリーの16進ダンプリストを表示するソフトにtmp.bmpを入れた結果の先頭64ビットを以下に示します。
もし違いましたらご指摘お願いします。
00000000 42 4D 36 B0 38 84 03 00 00 00 36 00 00 00 28 00
00000010 00 00 40 01 40 01 00 00 F0 00 00 00 20 00 18 00
00000020 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
tmp.bmpは途中でShowMessageを使ってプログラムを止めてエクスプローラで確認した結果です。
tmp.bmpファイルをペインタで開いてみたところ、ペインタでは開けませんでしたので
ソースと16進ダンプを補足させていただきました。
画像書き込み部のコードにもバグがあるようで…
なかなかこのプログラムには苦戦させられそうです。
なにはともあれ回答していただきありがとうございました。
参考URLも参考にさせていただきます。
No.3
- 回答日時:
画像書き込み部の修正版も作ってみました.これもコンパイルは通してません.
//******** 画像書き込み ********
const size_t bitsPerPixel = 24; // 1画素のビット数
const size_t bytesPerPixel = bitsPerPixel / 8; // 1画素のバイト数
// 走査線1本のバイト数 lineSize を計算する.
size_t lineSize = bytesPerPixel * Pixel_X_Max; // 正味のバイト数
// lineSize を4の倍数に切り上げる (BMPファイルの仕様).
lineSize = (lineSize + 3) & ~(size_t)3;
// 走査線1本分のバッファを確保する.
// calloc() を用いるのは,lineBuf の最後の
// 0~3バイトを0クリアするのが目的.
BYTE *lineBuf = (BYTE*)calloc(lineSize, 1);
if(lineBuf == NULL) {
Error:
if(lineBuf != NULL) free(lineBuf);
fclose(fp);
DeleteFile(fileName); // 出来損ないのファイルを削除する.
return; // 本当は NG を返すべき.
}
// 画素データを書く.
const BYTE *srcLine = img + lineSize * Pixel_Y_Max; // img[] の直後を指す.
for(int y = 0; y < Pixel_Y_Max; y++) {
// srcLine, src ← img[] の現在の走査線の先頭
srcLine -= lineSize;
const BYTE *src = srcLine;
BYTE *dest = lineBuf;
for(int x = 0; x < Pixel_X_Max; x++) {
// 元画像の画素 *src (グレースケール8ビット) を
// RGB 24ビットに変換して lineBuf に格納する.
dest[2] = dest[1] = dest[0] = *src++;
dest += bytesPerPixel;
}
if(fwrite(lineBuf, 1, lineSize, fp) != lineSize) goto Error;
}
fclose(fp);
free(lineBuf);
return; // 本当は OK を返すべき.
研究の発表がありお礼が遅くなってしまい申し訳ありません。
ここまで、詳しく回答していただいてお礼のお言葉が思い浮かびません!
まだまだ私には難しいところがありますがこれも見識を広めるいい機会だと思います。
No.1の回答にあるサイトとあわせて勉強させていただきます。
本当に回答ありがとうございました。
No.2
- 回答日時:
#1 です.
> int TImg::MakeBmpHeaderFile(int w, int h)
うわ~,このメンバ関数は意図不明なことをやってますね.
処理の内容はわかりますが,わざわざこういう複雑怪奇な
処理をする意図がさっぱりわかりません.
Graphics::TBitmap は C++ Builder のクラスライブラリが提供している
クラスでしょうか? だとすれば,おそらくこのメソッドの作者
(JulesVerne さんの先生か先輩?) は,ヘッダの各メンバの計算方法が
よくわからなかったかサボりたかったので,出来合いの TBitmap::SaveToFile()
が書き出してくれるヘッダを流用しようとしたのではないでしょうか?
でもいくつかのメンバは簡単なので自分で設定したと….(笑)
でも,できたヘッダの16進ダンプを見ると,ほとんどデタラメですね.
ソースを見る限り,設定内容は悪くなさそうなので,
ファイルの読み書きがちゃんとできていないのかもしれません.
(エラーチェックをほとんどしていないので,そうであっても報告されない.)
もしかしたら StartDir の設定が間違っているのではないでしょうか.
┌複雑怪奇な TImg::MakeBmpHeaderFile() の改良版を作ってみましたので
│ご参考まで.(コンパイルは通していません.またインデントが潰れるのを
│防ぐため,半角空白を全角空白に置き換えています.)
↓
int TImg::MakeBmpHeaderFile(int w, int h)
{
BITMAPFILEHEADER bfHdr;
BITMAPINFOHEADER biHdr;
const size_t bitsPerPixel = 24; // 1画素のビット数
const size_t bytesPerPixel = bitsPerPixel / 8; // 1画素のバイト数
// 画像サイズ設定
if (w == 0) { w = Pixel_X_Max; h = Pixel_Y_Max; }
// 走査線1本のバイト数 lineSize を計算する.
size_t lineSize = bytesPerPixel * w; // 正味のバイト数
// lineSize を4の倍数に切り上げる (BMPファイルの仕様).
lineSize = (lineSize + 3) & ~(size_t)3;
// 画像データ本体のバイト数
size_t imageSize = lineSize * h;
// ヘッダサイズの合計
size_t headerSize = sizeof(bfHdr) + sizeof(biHdr);
// ヘッダの内容を設定する.
bfHdr.bfType = 'B' | ('M' << 8);
bfHdr.bfSize = (DWORD)(headerSize + imageSize);
bfHdr.bfReserved1 = 0;
bfHdr.bfReserved2 = 0;
bfHdr.bfOffBits = (DWORD)headerSize;
biHdr.biSize = sizeof(biHdr);
biHdr.biWidth = (LONG)w;
biHdr.biHeight = (LONG)h;
biHdr.biPlanes = 1;
biHdr.biBitCount = (WORD)bitsPerPixel;
biHdr.biCompression = BI_RGB;
biHdr.biSizeImage = (DWORD)imageSize;
biHdr.biXPelsPerMeter = 0;
biHdr.biYPelsPerMeter = 0;
biHdr.biClrUsed = 0;
biHdr.biClrImportant = 0;
// ヘッダを BmpHeader にコピーする.
memcpy(&BmpHeader, &bfHdr, sizeof(bfHdr));
memcpy((char*)&BmpHeader + sizeof(bfHdr), &biHdr, sizeof(biHdr));
BmpHFlag = 1;
return OK;
}
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・ゆるやかでぃべーと タイムマシンを破壊すべきか。
- ・「I love you」 をかっこよく翻訳してみてください
- ・歩いた自慢大会
- ・許せない心理テスト
- ・字面がカッコいい英単語
- ・昔のあなたへのアドバイス
- ・かっこよく答えてください!!
- ・あなたが好きな本屋さんを教えてください
- ・スタッフと宿泊客が全員斜め上を行くホテルのレビュー
- ・【大喜利】【投稿~8/27】 こんなガソリンスタンド二度と来るか!なぜそう思った?
- ・これ何て呼びますか Part2
- ・人生で一番思い出に残ってる靴
- ・【お題】動物のキャッチフレーズ
- ・【お題】甲子園での思い出の残し方
- ・ゆるやかでぃべーと すべての高校生はアルバイトをするべきだ。
- ・「それ、メッセージ花火でわざわざ伝えること?」
- ・自分用のお土産
- ・人生で一番お金がなかったとき
- ・一番好きなみそ汁の具材は?
- ・泣きながら食べたご飯の思い出
- ・ちょっと先の未来クイズ第1問
- ・ゴリラ向け動画サイト「ウホウホ動画」にありがちなこと
- ・初めて自分の家と他人の家が違う、と意識した時
- ・単二電池
- ・チョコミントアイス
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
バッファとは何ですか
-
24ビットのWaveデータの中身に...
-
EOF
-
VBでCSVファイルを読み込む方法...
-
削除したファイルの復旧、およ...
-
入力ファイルをバイナリにする利点
-
ページ読み込み時に自動的にsub...
-
DXFファイル用クラスライブラリ...
-
HDDのバイナリイメージの取得方...
-
Microsoft VBAで2GBを超えるフ...
-
C言語とシリアル通信の送受信...
-
テキストデータをSQLServerに取...
-
VBA バイナリ―から文字列にす...
-
PHPのfgetcsvの処理容量について
-
【python】Excelファイルを読み...
-
ストリームの意味がいまいちですが
-
VB5.0 SP3にてEXCE...
-
C#(VB.Net)でPhotoshopデータを...
-
MacからWinにファイルを添付す...
-
バイナリエディタのつかいかた
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
バッファとは何ですか
-
EXCEL VBAでテキストファイルの...
-
Microsoft VBAで2GBを超えるフ...
-
入力ファイルをバイナリにする利点
-
ページ読み込み時に自動的にsub...
-
エクセルVBA 2千万行のCSVファ...
-
エラー:ストリームの終わりを...
-
EOF
-
VBA バイナリ―から文字列にす...
-
バイナリエディタのつかいかた
-
テキストデータをSQLServerに取...
-
バイナリファイルの検索について
-
バイナリ形式のXMLファイルを読...
-
画像の保存方法。
-
FTPでエクセルをPUTするとファ...
-
バイナリファイルの比較につい...
-
バイナリーデータの一部データ...
-
MacからWinにファイルを添付す...
-
C言語とシリアル通信の送受信...
-
ROM書き込みデータのファイル形...
おすすめ情報