保存について

解決


ヨシ  2004-07-18 16:24:53  No: 54037

このサイトやほかのサイトの過去ログを見てもわからないので
質問させていただきます。

ピクチャーボックス内に画像を表示し保存をすることはできているのですが、
保存を行うと保存した画像が、アプリケーションの画面ごと保存されてしまいます。
ピクチャーボックスが約473*315の大きさで、
表示している画像は3072*2048のBMP画像になります。
ピクチャーボックスからその写真ははみ出さないように表示させており、
スクロールバーの移動によって表示していない部分は見れるようになっています。
ピクチャーボックス内に表示されていないスクロールバーの移動により
見える残りの部分を保存するようにしたいのですが、
どのようにプログラムを書けばよろしいでしょうか?

保存する際には表示させた画像のみを保存するようにもしたいです。
保存する画像の大きさは3072*2048のBMPでもともとの大きさで保存を行いたいです
アプリケーションの画面は保存しないで、ピクチャボックス内の画像のみ保存する方法も
同時におねがいします。


ゆう  2004-07-19 03:58:21  No: 54038

どうやって読み込みしてどうやって保存しているのですか?

読み込んだDIBなりをとっておいてそれを保存するだけです。

アプリケーションの画面がなぜついてくるのでしょう。
デバイスコンテキストが持っているDIBを保存しているのかな。


ヨシ  2004-07-19 22:27:24  No: 54039

int ret;
CString ext_filter = "BMP|*.bmp|";
CFileDialog savefile(FALSE,"BMP",
NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT , ext_filter);
ret = savefile.DoModal();
if(ret == IDOK){
  char filename[128];
  sprintf(filename,"%s",savefile.GetPathName());
  CWnd *wnd = GetDlgItem(IDC_PICT1);  
    CRect rt;
    wnd -> GetClientRect(&rt);
    CDC * pDC = wnd->GetDC( );

    CFile file;
    CFileException fx;
    if( !file.Open(filename, CFile::modeCreate|CFile::modeReadWrite, &fx) )
  {
  }
    else{
    char *wkmem = new char[3072 * 2048 * 2];

    CDC  dcMm ;
    BITMAPINFO*  pbminfo ;
    HBITMAP  hBITMAP ;
    HGLOBAL hMem = GlobalAlloc( GMEM_MOVEABLE |                         GMEM_ZEROINIT,sizeof( BITMAPINFO ) ) ;
    pbminfo = (BITMAPINFO*) GlobalLock( hMem ) ;
    pbminfo->bmiHeader.biSize = sizeof(                                       BITMAPINFOHEADER ) ;
    pbminfo->bmiHeader.biWidth = 3072 ;
    pbminfo->bmiHeader.biHeight = 2048 ;
    pbminfo->bmiHeader.biPlanes = 1 ;
    pbminfo->bmiHeader.biBitCount = 16 ;  //bit color
    pbminfo->bmiHeader.biCompression = BI_RGB;
    pbminfo->bmiHeader.biSizeImage = 0 ;
    pbminfo->bmiHeader.biXPelsPerMeter = 0 ;
    pbminfo->bmiHeader.biYPelsPerMeter = 0 ;
    pbminfo->bmiHeader.biClrUsed = 0 ;
    pbminfo->bmiHeader.biClrImportant = 0 ;
    pbminfo->bmiColors[0].rgbRed = NULL;
    pbminfo->bmiColors[0].rgbGreen = NULL;
    pbminfo->bmiColors[0].rgbBlue = NULL;
    pbminfo->bmiColors[0].rgbReserved = 0 ;

    hBITMAP = CreateDIBitmap( pDC->m_hDC,&(pbminfo-                    >bmiHeader),CBM_INIT,wkmem,pbminfo,DIB_RGB_COLORS ) ;
    dcMm.CreateCompatibleDC( pDC ) ;
    HBITMAP *oldbitmap = (HBITMAP *)dcMm.SelectObject(                   hBITMAP ) ;
    dcMm.SetStretchBltMode( STRETCH_DELETESCANS ) ;
    dcMm.StretchBlt( 0,0, 3072, 2048, pDC, 0,0, 3072,                   2048 ,SRCCOPY );
    GetDIBits(dcMm.m_hDC, hBITMAP, 0, 2048, wkmem,                         pbminfo, DIB_RGB_COLORS ) ;

    BITMAPFILEHEADER bfh;
    bfh.bfType = WORD(0x4d42);  //BM
    bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof                      (BITMAPINFOHEADER) + 3078 * 2048;
    bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof                    (BITMAPINFOHEADER) ;
    bfh.bfReserved1 = bfh.bfReserved2 = 0;
      
    file.Write( &bfh, sizeof(BITMAPFILEHEADER) );
    file.Write( pbminfo, sizeof(BITMAPINFOHEADER));
    file.Write( wkmem, 3078 * 2048*2);
    file.Close();

    dcMm.SelectObject( oldbitmap ) ;
    DeleteObject( hBITMAP ) ;
    DeleteDC( dcMm ) ;
    GlobalUnlock( hMem );
    GlobalFree( hMem ) ;
    delete [] wkmem;
このような感じで保存するソースは作っています。

//ファイルダイアログを表示してファイル指定する
  CFileDialog myDLG                                                    (TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,
    "ビットマップ(*.BMP)|*.BMP||");
  if(myDLG.DoModal()!=IDOK) return;
  
  //取得したファイルをオープンする
  filename = myDLG.GetPathName();
  if(!file.Open(filename,CFile::modeRead|CFile::typeBinary)){
    return;
  }
  
  //ファイルヘッダ部とインフォヘッダ部を読み込む
  file.Read(&m_BmpFileHdr,sizeof(BITMAPFILEHEADER));
  file.Read(&myBmpInfoHdr,sizeof(BITMAPINFOHEADER));
  
  //前回使用していれば、一旦メモリ解放する
  if(m_BmpInfo) delete[] m_BmpInfo;
  
  //色情報を取得する。biBitCountは1ピクセルあたりのカラー表現
  //ビット数1,4,8,16,24,32がある、数字が大きいほ        ど精細表現が可能
  //16ビット以上と未満でカラーデータ格納が異なる
  
  if(myBmpInfoHdr.biBitCount >= 16){
    m_BmpInfo = (LPBITMAPINFO)new char[sizeof                          (BITMAPINFOHEADER)];
  }
  else{
    m_BmpInfo = (LPBITMAPINFO)new char[sizeof                            (BITMAPINFOHEADER)+
      (1<<myBmpInfoHdr.biBitCount)*sizeof                          (RGBQUAD)];
    file.Read(m_BmpInfo->bmiColors,                                      (1<<myBmpInfoHdr.biBitCount)*sizeof(RGBQUAD));
  }
  
  //m_BmpInfo(LPBITMAPINFO型)のmyBmpInfoHdrメンバに設定
  m_BmpInfo->bmiHeader = myBmpInfoHdr;
  
  //ファイル内のビットマップ実データ位置に合わせる
  file.Seek(m_BmpFileHdr.bfOffBits,CFile::begin);
  
  //前回の画像イメージを一旦解放
  if(m_BmpImage) delete[] m_BmpImage;
  
  //実画像データ分のバイト数を確保
  //bfsizeビットマップファイル全サイズ
  //bfOffBits先頭にあるヘッダ情報サイズ
  m_BmpImage = new char[m_BmpFileHdr.bfSize -                           m_BmpFileHdr.bfOffBits];
  
  //ビットマップ実データを読み込み格納
  file.Read(m_BmpImage,m_BmpFileHdr.bfSize -                           m_BmpFileHdr.bfOffBits);
  file.Close();
読み込むソースはこのような感じです。
よろしくお願いします☆


ゆう  2004-07-20 01:23:10  No: 54040

読み込むときのm_BmpInfo(BITMAPINFO?)、m_BmpImage(画像の実データ?)
をとっておいてそれをもとにBITMAPFILEHEADERを作成し、
保存すればいいだけです。

固定サイズしか書き込めない処理なんですね。
MFCを使っているならMSDNにDIBLOOKと言うサンプルソースがあり、
bmpの読み込み、保存をしていますから、それを参考にされてみては
いかがでしょうか。(ちょっと古いけど)


ヨシ  2004-07-20 01:32:26  No: 54041

読み込むときのm_BmpInfo(BITMAPINFO?)、m_BmpImage(画像の実データ?)
をとっておいてそれをもとにBITMAPFILEHEADERを作成し、
保存すればいいだけです。

>これをすれば写真のみ保存ができるようになりますか?

固定サイズしか書き込めない処理なんですね。
>最初はピクチャーボックスのサイズのみの大きさ
rt.right rt.bottomを使っていたのですが
こっちのほうがいいのでしょうか?画像の範囲が
3072*2048だったので値を入れたのです。


ゆう  2004-07-20 02:21:58  No: 54042

bmpの構造は
BITMAPFILEHEADER
BITMAPINFOHEADER
256色以下だった場合パレット
実際の色データ
となります。

   BITMAPFILEHEADER bfh;
   bfh.bfType = WORD(0x4d42);    //BM
   bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof                    
   (BITMAPINFOHEADER) + 3078 * 2048;
    bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof                  
   (BITMAPINFOHEADER) ;
   bfh.bfReserved1 = bfh.bfReserved2 = 0;
            
    file.Write( &bfh, sizeof(BITMAPFILEHEADER) );
    file.Write( m_BmpInfo, sizeof(BITMAPINFOHEADER));
                ~~~~~~~~~
    file.Write( m_BmpImage, 3078 * 2048*2);
                ~~~~~~~~~~
とすればHBITMAPは必要ありません。 
(24ビットカラーの場合のみ。パレットがあるとうまくいきませんが)


ヨシ  2004-07-20 02:38:14  No: 54043

ありがとうございます。
ためしにやってみたのですが内部に書き込んでいないため
保存されたっけかに反映されていませんでした。
あとサイズは問題ないのですが
ピクチャーボックスに表示しているところしか保存ができません。
なぜかBMPで保存をしているのに
フォトショップで開けないのですがなんで開けないのですか?


ゆう  2004-07-20 02:58:15  No: 54044

>ためしにやってみたのですが内部に書き込んでいないため
>保存されたっけかに反映されていませんでした。
>あとサイズは問題ないのですが
>ピクチャーボックスに表示しているところしか保存ができません。
??何をおっしゃっているのか分りません。
ピクチャーボックスは一切関係していないはずですが...

>なぜかBMPで保存をしているのに
>フォトショップで開けないのですがなんで開けないのですか?
"開けません。"ってフォトショップに言われるんですか。
だとしたら
   bfh.bfType = WORD(0x4d42);    //BM
がうまく反映されていないとか、拡張子にbmpがついていないとか
そういう理由でしょう。

開けるけど表示がおかしいなら
BITMAPFILEHEADER,BITMAPINFOHEADERの値がおかしいからでしょう。
 bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof                    
   (BITMAPINFOHEADER) + 3078 * 2048;
                        ~~~~~~~~~~~~~
file.Write( m_BmpImage, 3078 * 2048*2);
                        ~~~~~~~~~~~~~~~
なぜデータのサイズが異なるんでしょう。


よし  2004-07-20 05:31:07  No: 54045

>ためしにやってみたのですが内部に書き込んでいないため
>保存されたっけかに反映されていませんでした。
>あとサイズは問題ないのですが
>ピクチャーボックスに表示しているところしか保存ができません。
勘違いでした。すいません。
>"開けません。"ってフォトショップに言われるんですか。
>だとしたら
>   bfh.bfType = WORD(0x4d42);    //BM
一応その画像のプロパティでみたらBMPになっていたのですが
問題あるのでしょうか?

>開けるけど表示がおかしいなら
>BITMAPFILEHEADER,BITMAPINFOHEADERの値がおかしいからでしょう。
 >bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof                    
  > (BITMAPINFOHEADER) + 3078 * 2048;
                        ~~~~~~~~~~~~~
>file.Write( m_BmpImage, 3078 * 2048*2);
                        ~~~~~~~~~~~~~~~
>なぜデータのサイズが異なるんでしょう

なぜデータのサイズが異なるかわかりません。


まさ  2004-07-20 06:12:56  No: 54046

保存するに当たって私も参考にしているのですが
わかりません。ゆうさんにはお手数ですが
サンプルとかありませんか?
ヨシさんはわかるかもしれませんが私にはさっぱりです。
お願いします。


ゆう  2004-07-20 07:34:56  No: 54047

http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/vcsample/html/_sample_mfc_diblook.asp

DIBLOOKサンプルの中でbmpの読み書きをしています。


まさ  2004-07-20 08:12:39  No: 54048

ありがとうございます。


ヨシ  2004-07-20 09:14:36  No: 54049

実画面に絵を描いて,それを保存するために実画面の内容をStretchBltで
取得して保存するようになっているのですが、
これを、ピクチャーコントロールが内部に保持しているビットマップの内容を取得し、それを保存するにはどのようにしたらよいでしょうか?。
あと、描画を内部のビットマップに対しても行うように
するのもおねがいします。


ゆう  2004-07-20 09:55:29  No: 54050

何故ピクチャーコントロールにこだわるのでしょうか。
多分、ピクチャーコントロールはそんな用途で用意されているものでは
ないと思います。無理やりそんな使い方してると思わぬバグが
入り込みますよ。
StretchBltで取得したHBIAMAPを再度SetBitmapすればよさそうですが、
やったことないんで分りません。


ヨシ  2004-07-20 10:02:57  No: 54051

ピクチャーにこだわらないでやる方法が正直わかりません。
ほかに何かいい方法があるのでしょうか?
何度もすいません。


ゆう  2004-07-20 10:44:30  No: 54052

CDCクラスをメンバに追加します。(例えばm_memDC) ;
ビットマップをファイルから取得して、ここに選択させます。

絵を描く作業はすべてこのm_memDCに対して行います。

OnPaintでダイアログの実画面(dc)にm_memDCからStretchBltします。

保存する時にはmemDCからHBITMAPを取り出して保存します。

ビットマップの管理が一つで済むと思いませんか。


よし  2004-07-20 12:19:35  No: 54053

たしかにそう思います。
>絵を描く作業はすべてこのm_memDCに対して行います。
m_memDC->MoveTo( point );
m_memDC->LineTo( point );
このような感じでいいのですよね??

>OnPaintでダイアログの実画面(dc)にm_memDCからStretchBltします。
>保存する時にはmemDCからHBITMAPを取り出して保存します。
>ビットマップの管理が一つで済むと思いませんか。

これをヘッダーに追加して
CDC* m_memDC;

OnPaint()に
// コントロール全面にDIBを表示する??
dcMm.StretchBlt( 0,0, 3072, 2048, memDC, 0,0, 3072, 2048 ,SRCCOPY );

このようなかんじにした後に
memDCからHBITMAPを取り出して保存をするでよろしいのでしょうか?


Kazuki  2004-07-20 23:50:11  No: 54054

聞く前にやってみようよ
memDCはm_memDCの書き間違いだとしても
> ゆうさん
> ビットマップをファイルから取得して、ここに選択させます。
↑の作業をやってないのでそのコードだけだと駄目っぽいです


ゆう  2004-07-22 00:37:26  No: 54055

http://madia.world.coocan.jp/cgi-bin/Vcbbs/wwwlng.cgi?print+200407/04070029.txt
こっちでも似たような話なんで参考にしてください。


よし  2004-07-26 13:16:36  No: 54056

画像全体を保存することはできたのですが
なぜか元画像の容量と保存画像の容量が違います。
これはなぜなんでしょうか?


masa  2004-08-04 12:08:03  No: 54057

俺はできた★。、::。.::・'゜☆。.::・'゜★。、::。.::・'゜


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加