VC++のMFC、ダイアログベースで画像処理のソフトを作っています。
処理した画像を保存したいのですが、「描画できませんでした」というメッセージのでるファイルになってしまい、うまく保存できません。
プログラムは以下のようになっていてピクチャーコントロールの変数をm_pict8にしています。また、画像は24ビットで240×320のものを保存します。
static LONG CalcScanLineByte(const LONG w, const WORD bpp)
{
return (((bpp * w) + 31) / 32) * 4;
}
//-----------------------------------------------------------
void Cstart2Dlg::OnBnClickedButton10() //保存ボタン
{
CFileDialog myDLG(FALSE,"BMP","*.BMP",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"画像(*.BMP)|*.BMP||");
if(myDLG.DoModal() == IDOK){
CStdioFile fout(myDLG.GetPathName(),CFile::modeCreate | CFile::modeWrite|CFile::typeBinary);
//ピクチャボックスからビットマップを取り出す
HBITMAP hBitmap = m_pict8.GetBitmap();
//無いので処理できない
if(hBitmap == NULL)return;
//ビットマップの情報を取る
BITMAP bitmap = {0};
::GetObject(hBitmap, sizeof(bitmap), &bitmap);
//4バイト調整したスキャンラインのサイズ
const int iScanLineByte = ::CalcScanLineByte(240, bitmap.bmBitsPixel);
//const int iScanLineByte = ::CalcScanLineByte(bitmap.bmWidth, bitmap.bmBitsPixel);
//ファイルヘッダとビットマップヘッダ
BITMAPFILEHEADER bmfh = {sizeof(bmfh)};
BITMAPINFOHEADER bmif = {sizeof(bmif)};
//ビットマップである事を示す名称
bmfh.bfType = ('M' << 8) | 'B';
//イメージデータへのオフセットはファイルヘッダ+ビットマップヘッダ
bmfh.bfOffBits = sizeof(bmfh) + sizeof(bmif);
//見ての通り
bmif.biBitCount = 24;
//24ビットの時はBI_RGBで固定
bmif.biCompression = BI_RGB;
//常に1で固定
bmif.biPlanes = 1;
//見ての通り
bmif.biWidth = 240;
bmif.biHeight= 320;
//bmif.biWidth = bitmap.bmWidth;
//bmif.biHeight= bitmap.bmHeight;
//4バイト調整も含めた正確な合計バイトサイズが必要
bmif.biSizeImage = iScanLineByte * bmif.biHeight;
//ファイルヘッダ→ビットマップヘッダの順番に書き出す
fout.Write(&bmfh, sizeof(bmfh));
fout.Write(&bmif, sizeof(bmif));
//イメージデータをセーブする
HDC hMemDC = ::CreateCompatibleDC(NULL);
::SelectObject(hMemDC, hBitmap);
//yを縦幅-1から回転させないと上下逆転してしまう
for(int y = bmif.biHeight - 1; y >= 0; --y)
{
//3バイトずつステップする
for(int x = 0; x < iScanLineByte; x += 3)
{
const COLORREF cref = ::GetPixel(hMemDC, x / 3, y);
//色素の位置関係をBGRにしないと赤と青の関係が逆転してしまう
const BYTE arrBy[3] = {GetBValue(cref), GetGValue(cref), GetRValue(cref)};
//1ピクセル分(3バイト)書き出す
fout.Write(arrBy, sizeof(arrBy));
}
}
::DeleteDC(hMemDC);
}
どこか改善点などありましたら、よろしくお願いいたします。
A 回答 (4件)
- 最新から表示
- 回答順に表示
No.4
- 回答日時:
こんばんは。
補足頂きました。はい。当方の方では、其のコードで書き込めています。
一応、環境を出して置きます。win2000sp4 vc6.0sp5です。
読み込み確認に使用したのは、御馴染みのMSペイントブラシとMSOfficeピクチャーマネージャーです。
う~む。では確認です。以下は通過出来ていますか。hBitmapの中がNULLではないでしょうか。
//無いので処理できない
if(hBitmap == NULL)return;
其の他、デバッガでステップトレースして、怪しいと思う部分はありませんでしょうか。
>>あとピクチャーコントロールの変数m_pict8はCStatic型でよろしかったでしょうか。
Cstart2Dlgのヘッダでm_pict8が何型で宣言されていますでしょうか。CStaticの派生クラス辺りでしょうか。
MFCですから、CStaticコントロールでタイプがビットマップになったものがピクチャーボックスではないでしょうか。
http://msdn.microsoft.com/ja-jp/library/b7w5x74z …
一応クラス階層図中にもCPictureBoxなるものは無い見たいです。
http://msdn.microsoft.com/ja-jp/library/ws8s10w4 …
No.3
- 回答日時:
こんばんは。
補足頂きました。はい、ありません。
と、言うのも、
//ビットマップの情報を取る
BITMAP bitmap = {0};
::GetObject(hBitmap, sizeof(bitmap), &bitmap);
bitmap.bmWidth//横幅が入っている
bitmap.bmHeight//縦幅が入っている
bitmap.bmBitsPixel//ビット数が入っている
仮にビットマップが240x320x24であろうと1440x900x32であろうとGetObject()で情報を検出出来るからです(実際に前半で情報を検出しています)。
更に、度々すんません、「イメージデータをセーブする」の所を、以下に訂正して下さい。其のままですと縦横が奇数の時(241x319x24で確認)、正常にイメージデータが書けません。
//イメージデータをセーブする
LPBYTE pBuf = (LPBYTE)::calloc(bmif.biSizeImage, 1);
HDC hMemDC = ::CreateCompatibleDC(NULL);
::SelectObject(hMemDC, hBitmap);
for(int y = bmif.biHeight - 1; y >= 0; --y)
{
for(int x = 0; x < bmif.biWidth; ++x)
{
const int pos = (x * 3) + (iScanLineByte * y);
const COLORREF cref = ::GetPixel(hMemDC, x, bmif.biHeight - 1 - y);
pBuf[pos + 0] = GetBValue(cref);
pBuf[pos + 1] = GetGValue(cref);
pBuf[pos + 2] = GetRValue(cref);
}
}
::DeleteDC(hMemDC);
fout.Write(pBuf, bmif.biSizeImage);
::free(pBuf);
この回答への補足
ご回答ありがとうございます。
変更点を直したのですが、やはりまだうまくいかないようです。すみません。
下が修正したプログラムです。
static LONG CalcScanLineByte(const LONG w, const WORD bpp)
{
return (((bpp * w) + 31) / 32) * 4;
}
//-----------------------------------------------------------
void Cstart2Dlg::OnBnClickedButton10()
{
CFileDialog myDLG(FALSE,"BMP","*.BMP",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"画像(*.BMP)|*.BMP||");
if(myDLG.DoModal() == IDOK){
CStdioFile fout(myDLG.GetPathName(),CFile::modeCreate | CFile::modeWrite|CFile::typeBinary);
//ピクチャボックスからビットマップを取り出す
HBITMAP hBitmap = m_pict8.GetBitmap();
//無いので処理できない
if(hBitmap == NULL)return;
//ビットマップの情報を取る
BITMAP bitmap = {0};
::GetObject(hBitmap, sizeof(bitmap), &bitmap);
//4バイト調整したスキャンラインのサイズ
const int iScanLineByte = ::CalcScanLineByte(bitmap.bmWidth, bitmap.bmBitsPixel);
//ファイルヘッダとビットマップヘッダ
BITMAPFILEHEADER bmfh = {(0)};
BITMAPINFOHEADER bmif = {sizeof(bmif)};
//ビットマップである事を示す名称
bmfh.bfType = ('M' << 8) | 'B';
//イメージデータへのオフセットはファイルヘッダ+ビットマップヘッダ
bmfh.bfOffBits = sizeof(bmfh) + sizeof(bmif);
//このイメージファイルのサイズ(コレを追加)
bmfh.bfSize = bmfh.bfOffBits + (iScanLineByte * bitmap.bmHeight);
//見ての通り
bmif.biBitCount = 24;
//24ビットの時はBI_RGBで固定
bmif.biCompression = BI_RGB;
//常に1で固定
bmif.biPlanes = 1;
//見ての通り
bmif.biWidth = bitmap.bmWidth;
bmif.biHeight= bitmap.bmHeight;
//4バイト調整も含めた正確な合計バイトサイズが必要
bmif.biSizeImage = iScanLineByte * bmif.biHeight;
//ファイルヘッダ→ビットマップヘッダの順番に書き出す
fout.Write(&bmfh, sizeof(bmfh));
fout.Write(&bmif, sizeof(bmif));
//イメージデータをセーブする
LPBYTE pBuf = (LPBYTE)::calloc(bmif.biSizeImage, 1);
HDC hMemDC = ::CreateCompatibleDC(NULL);
::SelectObject(hMemDC, hBitmap);
for(int y = bmif.biHeight - 1; y >= 0; --y)
{
for(int x = 0; x < bmif.biWidth; ++x)
{
const int pos = (x * 3) + (iScanLineByte * y);
const COLORREF cref = ::GetPixel(hMemDC, x, bmif.biHeight - 1 - y);
pBuf[pos + 0] = GetBValue(cref);
pBuf[pos + 1] = GetGValue(cref);
pBuf[pos + 2] = GetRValue(cref);
}
}
::DeleteDC(hMemDC);
fout.Write(pBuf, bmif.biSizeImage);
::free(pBuf);
}
ファイルは出来るのですが、0×0のファイルが出来てしまいます。ビットの深さは24ビットになっているようですが…。
あとピクチャーコントロールの変数m_pict8はCStatic型でよろしかったでしょうか。
たびたび本当に申し訳ないのですが、ご指導よろしくお願いいたします。
No.2
- 回答日時:
こんにちは。
すんません、どうやらファイルサイズの設定が疎かになっていた様です。コレで如何にか成りませんか。
//以上同じ
//ファイルヘッダとビットマップヘッダ
BITMAPFILEHEADER bmfh = {0};//ココを変更
BITMAPINFOHEADER bmif = {sizeof(bmif)};
//ビットマップである事を示す名称
bmfh.bfType = ('M' << 8) | 'B';
//イメージデータへのオフセットはファイルヘッダ+ビットマップヘッダ
bmfh.bfOffBits = sizeof(bmfh) + sizeof(bmif);
//このイメージファイルのサイズ(コレを追加)
bmfh.bfSize = bmfh.bfOffBits + (iScanLineByte * bitmap.bmHeight);
//以下同じ
この回答への補足
早速のご回答ありがとうございます。
変更してやってみたのですがうまくいきませんでした。
自分なりに考えてみたのですが、
bitmap.bmWidthとbitmap.bmHeightを今回保存したい画像のサイズ240×320なので、
それぞれ240と320に変える必要はありませんでしょうか?
No.1
- 回答日時:
CalcScanLineByte( )関数が変じゃないですか
画像1行分のバイト数を求めるんですよね
bppを8で割って1ピクセルのバイト数を求めそれと横幅のwをかけて1行分のバイト数を求める。
それを4バイト境界に調整。
でいいのでは。
static LONG CalcScanLineByte(const LONG w, const WORD bpp)
{
LONG line = w * ( bpp / 8 ); // 1行のバイト数
while (line & 3) line++; // 4バイト境界にそろえる
return line;
}
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
許せない心理テスト
私は「あなたの目の前にケーキがあります。ろうそくは何本刺さっていますか」と言われ「12本」と答えたら…
-
フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
あなたが普段思っている「これまだ誰も言ってなかったけど共感されるだろうな」というあるあるを教えてください
-
映画のエンドロール観る派?観ない派?
映画が終わった後、すぐに席を立って帰る方もちらほら見かけます。皆さんはエンドロールの最後まで観ていきますか?
-
海外旅行から帰ってきたら、まず何を食べる?
帰国して1番食べたくなるもの、食べたくなるだろうなと思うもの、皆さんはありますか?
-
天使と悪魔選手権
悪魔がこんなささやきをしていたら、天使のあなたはなんと言って止めますか?
-
RGBのバイナリデータをCImageにコピー
C言語・C++・C#
-
画像の保存方法。
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
バッファとは何ですか
-
EOF
-
バイナリーデータの一部データ...
-
機器とRS232Cクロスケーブルで...
-
【MFC】CFileでSeekした位置か...
-
テキストデータをバイナリデー...
-
フルパスから最後のディレクト...
-
コマンド(例えばls)の出力結果...
-
Acccess レポートをグループ別...
-
新規作成ファイルパスが有効か...
-
ExcelVBAでカレントディレクト...
-
どんなプログラムを書いても指...
-
ファイル名の先頭にアンダース...
-
OLE又はDDEを使うVISUAL BESIC...
-
csvファイルを開かずに文字を検...
-
C++ BuilderでPDF出力
-
WScript.Echo と msgbox
-
VBAでEXEファイルを動かす方法...
-
VBSでファイルを開く
-
VBAで他のプログラムが起動して...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
バッファとは何ですか
-
Microsoft VBAで2GBを超えるフ...
-
ページ読み込み時に自動的にsub...
-
EOF
-
EXCEL VBAでテキストファイルの...
-
エクセルVBA 2千万行のCSVファ...
-
【python】Excelファイルを読み...
-
VBA バイナリ―から文字列にす...
-
入力ファイルをバイナリにする利点
-
バイナリエディタのつかいかた
-
エラー:ストリームの終わりを...
-
24ビットのWaveデータの中身に...
-
C言語とシリアル通信の送受信...
-
テキストデータをSQLServerに取...
-
バイナリーデータの一部データ...
-
削除したファイルの復旧、およ...
-
テキストデータをバイナリデー...
-
バイナリファイルの検索について
-
【Teraterm】filewritelnについて
-
PHPのfgetcsvの処理容量について
おすすめ情報