ピクチャボックスに表示された画像を保存するには?


素人  2004-07-18 14:23:32  No: 54029

ピクチャボックスに表示した画像を処理した後、その画像を保存したいのです。
ピクチャボックスに表示はできるのですが、その画像を処理したのち、保存しようとすると、元の画像が保存されてしまうのです。どなたか教えていただけないでしょうか。


ゆう  2004-07-19 04:02:51  No: 54030

ピクチャボックスの画像を処理するのではなく、元の画像に処理を行った後、
再描画させるのが一般的です。
でなければ当然元の画像で保存されます。


素人  2004-07-19 05:29:25  No: 54031

書き込みありがとうございます。
元の画像に処理とはどういうことなのでしょうか。また再描画させるとは?ピクチャボックスに表示させた画像を処理したものをまたピクチャボックスに表示させているのですが、これでは再描画されているということにはならないのでしょうか。
処理されたように見えているだけということでしょうか。よくわからなくて申し訳ありません。


ゆう  2004-07-19 11:12:29  No: 54032

>ピクチャボックスに表示はできるのですが、その画像を処理したのち、保存しよう
>とすると、元の画像が保存されてしまうのです。
元の画像が変更されていないのですから、変更しなければならないのです。

環境(VerやMFCの使用など)やどの様に実現しているのかを詳しく書いた方がいいです。

まずどうやって元の画像を読み込んでいるのでしょう。
LoadImageを使うとか、独自にファイルを読み込んでDIBSectionを作っている
とか、ライブラリを使っているとか...
いずれにしても、その読み込んだ画像に変更を加えなければ、そのまま保存しても
元のままです。

次に変更とはどのような事をしているのでしょう。
hDCを取得して直接描画しているのですか?
(A)ならばもうひとつhDC(memDC)を作ってBitBltを使ってコピーを作成し、
そこからSelectObjectでHBITMAPを取り出す事は可能です。

(B) でも前もってmemDCにて変更画像を作成してから、実際に見えている
hDCにBitBltやStretchBltするのが普通に思えます。

MFCを使って、CStaticにSetBitmapしているなら、GetDCで取得したCDCに対して、
何らかの変更を加えてもCStaticは(B)のような転送した後、変更を加えて
いますから、GetBitmapしても元の画像しか戻ってきません。
この場合、GetDCで取得したCDCから(A)の方法で、HBITMAPを取り出します。

まああまりいい方法とは思えませんが。

http://www.sm.rim.or.jp/~shishido/
http://homepage3.nifty.com/ishidate/vcpp.htm
こことか参考にして、DIBに対して直接画像を加工する方法を覚える事をお勧めします。


素人  2004-07-21 08:37:47  No: 54033

書き込みありがとうございます。
とりあえず現在のプログラムを書かしていただきます。
void CMatchingDlg::OnButton1() 
{
  // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
  int x0=0,y0=0,x1=350,Matrix[350][255];
  int i, j,c,b,b1,d,e;
  int v,w,x,y,z,A,B,C,D;
  CDC* pDC1=m_pict1.GetDC();
           for(j=1;j<255;j++){
    for(i=1;i<349;i++){
    d = GetRValue(pDC1->GetPixel(i,j));
    pDC1->SetPixel(i,j,RGB(0,0,d));
         }
}
}

このような感じでGetpixelでR値を得てSetpixelでB値に変換するというものです。真っ赤の画像が全て青の画像になるのですが、保存するときには赤の画像が保存されてしますのです。この場合(A)の方法になるのでしょうか?SelectObjectでHBITMAPを取り出すのはプログラムの最後に挿入すればよいのでしょうか?たびたび申し訳ありません。よろしくお願いします。


ゆう  2004-07-22 00:34:25  No: 54034

見えているウィンドウに関連づけされたデバイスコンテキスト(DC)
はSelectObjectでBitmapを選択することはできません。
だからBitmapを表示させたい場合は、ウィンドウに関連付けされていない
DC(いわゆる裏画面)を作成して、そこにBitmapを選択させ、BitBlt、StretchBltで
表DCに転送(コピー)します。(裏DCは自由にBitmapを選択できる)

その後、表DCにいくら描画処理を行った所で元のBitmapは何も変わりません。
裏DCをメンバとして持っておいて、そこに描画処理を行いましょう。

例えば CDC m_memDC をメンバにして、そこにBitmapを選択させます。
CStaticの派生クラスを作り、その派生クラスにCDC* m_pDCをメンバを作り、
親クラスのm_memDCを渡しておきます。
void CMatchingDlg::OnButton1()
{
    // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
    int x0=0,y0=0,x1=350,Matrix[350][255];
    int i, j,c,b,b1,d,e;
    int v,w,x,y,z,A,B,C,D;
    for(j=1;j<255;j++)
    {
      for(i=1;i<349;i++)
      {
         d = GetRValue(memDC.GetPixel(i,j));
         memDC.SetPixel(i,j,RGB(0,0,d));
      }
    }
    m_pict1.Invalidate() ;//派生クラスを再描画させる。
}
派生クラスのOnPaintで、
{
   CPaintDC dc(this) ;
   //数値は適当ですから直してください。
   dc.BitBlt(0,0,100,100,m_pDC,0,0,SRCCOPY) ;//親クラスの裏画面を表画面に転送。
}
とかすれば、描画できます。

ピクチャボックスの正体は、CStaticというコントロールクラスです。
コントロールクラスの目的は、自分に対するメッセージ(マウスが自分の上にきた
とか、クリックされたとか)を親に通知する事、わずらわしい表示処理を
デフォルトでやってくれる事で、それ以上の機能はありません。
(CButtonやCEditもコントロールクラスです。)

ですからそれ以上の事を行う場合は、自分で処理しなければならないし、
場合によってはデフォルトの処理が、自分の実現したい機能の邪魔に
なることもあります。

ビクチャボックスの場合は、SetBitmapでBitmapを管理する事がまさにそれです。
このBitmapに対して加工する事はできませんから。(差し替える事はできます。)
だから自分で描画する必要があるんです。

普通はCWndの派生クラスを作るのですが、CStaticもCWnd派生ですから
CStaticを派生クラスを作ればCWndのすべての機能が実現できます。
でも前述の様に邪魔になる機能も含まれてしまいます。


素人  2004-07-27 11:03:14  No: 54035

書き込みありがとうございます。
少しずつ質問させていただきたいのですがよろしいでしょうか。
表DC、裏DCと出てきているのですが、表DCのメンバ変数はm_pict1なのですが裏DCのメンバの定義や裏DC自体の存在がよくわからないのですが…。

例えば CDC m_memDC をメンバにして、そこにBitmapを選択させます。
CStaticの派生クラスを作り、その派生クラスにCDC* m_pDCをメンバを作り、
親クラスのm_memDCを渡しておきます。

この部分がよくわからないのですが・・・。
あと
CPaintDC dc(this) ;
dc.BitBlt(0,0,100,100,m_pDC,0,0,SRCCOPY) ;
の部分はonbuttonの中に組み込みたいのですがm_pict1.Invalidate() ;の前に挿入しておけばよいのでしょうか。いろいろ聞いて申し訳ありません。よろしくお願いします。


ゆう  2004-07-29 06:37:15  No: 54036

>書き込みありがとうございます。
>少しずつ質問させていただきたいのですがよろしいでしょうか。
>表DC、裏DCと出てきているのですが、表DCのメンバ変数はm_pict1なのですが>裏DCのメンバの定義や裏DC自体の存在がよくわからないのですが…。
>
では少しずつ。
表DCは一時的なものです。例えば他のウィンドウに隠されてしまうと隠れた
部分は消滅します。
再度表示される時にはOnPaintが実行され、OnButton1()の内容は
なくなってしまいます。(試しにやってみてください。)

OnButton1()で表DCに描画した内容を再度描画されるようにする為には
どうしたらいいでしょう。

表DCからどこかにその内容を転送して保持しておき、その保存した物を
OnPaintの中で、再度表DCに転送する必要があります。

また、変更した物をファイルに保存する事を考えれば、当然そうしておく必要が
ありますよね。

そこで裏DCというものが出てきます。

変更させるたびに表DCから裏DCへ転送するのでもかまいません。
が、ファイルから読み込んだHBITMAPは持っているのですからそこに直接描画する
方が効率的ではありませんか?その方法が前回の内容です。

>例えば CDC m_memDC をメンバにして、そこにBitmapを選択させます。
>CStaticの派生クラスを作り、その派生クラスにCDC* m_pDCをメンバを作り、
>親クラスのm_memDCを渡しておきます。
>
>この部分がよくわからないのですが・・・。
この部分が分らないと"クラスとは..."から説明しなければならないですね。

>あと
>CPaintDC dc(this) ;
>dc.BitBlt(0,0,100,100,m_pDC,0,0,SRCCOPY) ;
>の部分はonbuttonの中に組み込みたいのですがm_pict1.Invalidate() ;の前に挿入し>ておけばよいのでしょうか。いろいろ聞いて申し訳ありません。よろしくお願いしま>す。
OnPaint内に書かないと上記の理由できちんと表示されません。


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

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






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