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で質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# C言語の質問です。バイナリ形式で保存されたWindows Bitmap形式の画像ファイルを読み込み、 3 2023/07/19 14:58
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# #include <stdio.h>int main(void) { int buf[100] = 6 2022/11/01 22:45
- Excel(エクセル) エクセル VBA For Next 繰り返しの書き方を教えてください 6 2022/09/01 14:11
- C言語・C++・C# leetcode 155 minstack 1 2022/05/07 16:43
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- JavaScript clear機能を失わずにファイルアップロード機能を作成したい 3 2023/06/10 16:12
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
バッファとは何ですか
-
エラー:ストリームの終わりを...
-
EXCEL VBAでテキストファイルの...
-
ページ読み込み時に自動的にsub...
-
VBA バイナリ―から文字列にす...
-
機器とRS232Cクロスケーブルで...
-
C++ Builderにおける画像データ...
-
c言語についての質問です
-
入力ファイルをバイナリにする利点
-
24ビットのWaveデータの中身に...
-
FTPでエクセルをPUTするとファ...
-
Microsoft VBAで2GBを超えるフ...
-
エクセルVBA 2千万行のCSVファ...
-
PHPのfgetcsvの処理容量について
-
= (イコール)で始まるセルの値...
-
EOF
-
バイナリエディタのつかいかた
-
C言語で、ファイルを読み込んで...
-
ダンプツール作成… 行き詰まり...
-
VBでCSVファイルを読み込む方法...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
バッファとは何ですか
-
Microsoft VBAで2GBを超えるフ...
-
EXCEL VBAでテキストファイルの...
-
バイナリエディタのつかいかた
-
ページ読み込み時に自動的にsub...
-
VBA バイナリ―から文字列にす...
-
エクセルVBA 2千万行のCSVファ...
-
エラー:ストリームの終わりを...
-
EOF
-
【python】Excelファイルを読み...
-
EXCEL VBAで、バイナリデータの...
-
入力ファイルをバイナリにする利点
-
DXFファイル用クラスライブラリ...
-
バイナリーデータの一部データ...
-
C言語とシリアル通信の送受信...
-
C言語の質問です。バイナリ形...
-
Javaでのエンディアン変換
-
24ビットのWaveデータの中身に...
-
bitmap画像の保存がうまくいき...
-
PHPのfgetcsvの処理容量について
おすすめ情報