dポイントプレゼントキャンペーン実施中!

VC++のMFC、ダイアログベースで画像処理のソフトを開発している者です。

ピクチャーコントロールに画像を表示させて、その画像を保存したいと思っています。
保存用のダイアログを開き、名前を付けて保存したいのですがうまくいきません。
下が今作っているプログラムです。

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);

UpdateData(TRUE);
fout.WriteString(m_pict8);
fout.WriteString("\xla");
filename = myDLG.GetPathName();
SetWindowText("start2"+filename);
}

ピクチャーコントロールの変数をm_pict8にしています。テキストファイルを保存するプログラムを参考にして作っているので間違っているのだと思います。
画像の保存方法が分かる方がいらっしゃいましたらよろしくお願いいたします。

A 回答 (2件)

 こんにちは。



 ビットマップファイルの場合、セーブする為の手順は

 BITMAPFILEHEADER → BITMAPINFOHEADER → RGBQUADテーブル → イメージデータ

 と言った具合です。RGBQUADテーブル(パレットテーブル)は、何ビットイメージでセーブするかによって、テーブル長が変化します。
 さて、何ビットイメージでセーブをお望みでしょうか。

この回答への補足

machongolaさん。早速のご回答ありがとうございます。
カラー画像なので24ビットで保存したいと思っています。

補足日時:2009/02/12 18:23
    • good
    • 0

 こんばんは。

補足頂きました。
 24bitフォーマットならば、特に難しい事は有りません。
 イメージ全体のサイズが4の倍数に満たない場合、ダミーバイトを付け加えてサイズの調整しないといけません。此れを怠ると、別のソフトで開いた時にほぼ間違いなく可笑しくなります。
 また、パレットイメージを所有していない為、RGBQUADテーブル(パレットテーブル)の作成も必要有りません。
 改善の余地もあるとは思いますが、以下参考程度に。

//1スキャンライン辺りの4バイト調整をした数字を求める
static LONG CalcScanLineByte(const LONG w, const WORD bpp)
{
return (((bpp * w) + 31) / 32) * 4;
}

+---------------------------------------------------------------------------------------
 セーブする時

//ファイルを開く
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 = {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 = 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);

この回答への補足

2度もご回答本当にありがとうございます。もう少しでうまくいきそうなのですが、

CFileDialog myDLG(FALSE,"BMP","*.BMP",
OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,
"画像(*.BMP)|*.BMP||");

の部分に、「2 番目の引数を 'const char [4]' から 'LPCTSTR' に変換できません。」というエラーが出てしまいす。どうしたら解決できるのか、ご指導お願いいたします。

補足日時:2009/02/13 15:00
    • good
    • 1
この回答へのお礼

先ほどの問題はなんとか解決することができました。

またまたお手数なのですが、32ビットの保存方法も教えていただけないでしょうか。
よろしくお願いいたします。

お礼日時:2009/02/13 15:56

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています