- ベストアンサー
画像の保存方法
- VC++のMFC、ダイアログベースで画像処理のソフトを開発している者です。ピクチャーコントロールに画像を表示させて、その画像を保存したいと思っています。
- 保存用のダイアログを開き、名前を付けて保存したいのですがうまくいきません。
- ピクチャーコントロールの変数をm_pict8にしています。画像の保存方法が分かる方がいらっしゃいましたらよろしくお願いいたします。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
こんにちは。 ビットマップファイルの場合、セーブする為の手順は BITMAPFILEHEADER → BITMAPINFOHEADER → RGBQUADテーブル → イメージデータ と言った具合です。RGBQUADテーブル(パレットテーブル)は、何ビットイメージでセーブするかによって、テーブル長が変化します。 さて、何ビットイメージでセーブをお望みでしょうか。
その他の回答 (1)
- machongola
- ベストアンサー率60% (434/720)
こんばんは。補足頂きました。 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);
お礼
先ほどの問題はなんとか解決することができました。 またまたお手数なのですが、32ビットの保存方法も教えていただけないでしょうか。 よろしくお願いいたします。
補足
2度もご回答本当にありがとうございます。もう少しでうまくいきそうなのですが、 CFileDialog myDLG(FALSE,"BMP","*.BMP", OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, "画像(*.BMP)|*.BMP||"); の部分に、「2 番目の引数を 'const char [4]' から 'LPCTSTR' に変換できません。」というエラーが出てしまいす。どうしたら解決できるのか、ご指導お願いいたします。
補足
machongolaさん。早速のご回答ありがとうございます。 カラー画像なので24ビットで保存したいと思っています。