bitmap画像の保存がうまくいきません。
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);
}
どこか改善点などありましたら、よろしくお願いいたします。
お礼
Dll側からはポインタだけでなく、ビットマップのバイト数も知らせるようにし、UnmanagedMemoryStreamオブジェクトでいけました。 ヒントになる情報ありがとうございました!