動的に作成したCBitmapファイルをBMPファイルとして保存するには

[戻る]
kaneko 2007/10/14(日) 23:28:30
はじめまして。
初心者ですが、よろしくお願いします。

環境 [WinXP、VS2003、MFC]

動的に作成したCBitmapファイルをBMPファイルへ保存したいと考えています。

http://www.sm.rim.or.jp/~shishido/wincap.html
を参考に描画したアクティブウィンドウの内容をファイルに落とすことは出来たのです
が、どうしても出力結果が粗くなってしまいます。
(縮小化してCBitmapを表示しているため)

動的に作成したCBitmapファイルの内容をそのままBMPファイルとして
保存するよい方法がありましたら、ご教授下さい。
よろしくお願いします。

しま 2007/10/15(月) 01:43:37
>動的に作成したCBitmapファイルをBMPファイルへ保存したいと考えています。

の意味が分かりません
動的に作成したCBitmapファイルとは何を指していて
そのファイルを(BMP)ファイルへ保存ということはどうしたいのでしょうか??
二つのファイルの関係は何でしょうか???
CBitmap ファイルとういう言葉は初耳です CBitmap はDDBを扱い、DIBとは違うことは
ご存知とは思いますが(ご存じなければDDB、DIB の違いは過去ログか別のサイトで
調べてください)--普通、Windows で BMPファイルというときは DIB 形式のことを
指すと思います--画像をファイルにするときに DDB (Device Dependent Bitmap)で
ファイルにすることは現在ではほとんどしないと思います
そして、参考になさったというサイトが今アクセス出来ないので細かいことが
分かりません

>どうしても出力結果が粗くなってしまいます。
>(縮小化してCBitmapを表示しているため)

縮小していることが荒くなっている原因なら、縮小する前のビットマップをファイルに
保存すればいいだけではないのかと思うのですがそうしない訳は何でしょうか?

+ 2007/10/15(月) 09:29:43
biXPelsPerMeter , biYPelsPerMeter に変な値入れてる?とか・・・

PATIO 2007/10/15(月) 10:55:45
参考にしたと言うサイトが確かに見えないですね。
なのでどういうことをして保存しようとしているのかまったくわかりませんが、
CBitmapクラスにファイルへ出力する機能は有りませんから
ビットマップファイルの構造を理解した上で自前で書き出すか、
GDI+を使って保存するか、そんな所でしょうか。
自前でビットマップファイルヘッダーやらビットマップヘッダーを作成して
順番に出力して、最後にビットマップの画素情報を書き出すようにするなら
ビットマップファイルのフォーマットをちゃんと理解して書き出さないと
おかしい所を見つけられないと思うのでフォーマットの勉強をした方がよろしいかと。

画像が荒いと言うのも他の表示ソフトで表示すると荒いのか
自分で表示すると荒いのかによっても突っ込みどころが変わってくるので
今の話だけだとどうも良く分からないですね。
画像を表示するほかのソフトで見ると荒いと言うのであれば、
ヘッダー部の情報の内容に問題があるのかもしれませんね。
自前でファイルに書き出している場合の話ですけれど。

2007/10/15(月) 19:43:10
参考にされたというサイトは私のほうでは確認できました。
参考にしたという元サイトはWin32APIで対象ウィンドウのクライアント領域でBMP
ファイルを作成していて、その時点では縮小などの処理は入っていないようです。

kanekoさんがどのようなものを作ろうとして、どのようなものを作ったのかが見えて
こないので返答のしようがありません。

勘で返答しておくと、縮小する前後のHDC又はCDCでSetStretchBltModeを
HALFTONEに片っ端から設定すれば多少は見えるものが吐き出される可能性
があります。…が、デバイス依存機能です。
が、これを実行する前に以下の質問に答えてもらいたいです。

とりあえず、
・「CBitmapファイル」というのは何か。「CBitmap」の間違いなのか。
・「縮小化」したのはどの段階か。「BMPファイル」作成の、前か、後か。
・最終的にどうしたいのか。縮小したくないのか、綺麗に縮小したいのか。
・縮小する場合、どの程度の品質を期待しているのか。
線形補間などの単純なものでいいのか、色々なアルゴリズムを使って品質をギリ
ギリまで高めたいのか。
・そもそも、処理の流れとそこに関わるオブジェクトの正確な名前は何なのか。

あたりを返答してもらえると回答者は非常に助かります。

kaneko 2007/10/15(月) 22:50:30
親切な回答ありがとうございます。
質問のあった内容について回答します。

・「CBitmapファイル」というのは何か。「CBitmap」の間違いなのか。
[誤] CBitmapファイル
[正] CBitmap

・「縮小化」したのはどの段階か。「BMPファイル」作成の、前か、後か。
BMPファイル作成前です。
BMP表示用DCに描画後、StretchBltをして画面へ縮小表示しました。

・最終的にどうしたいのか。縮小したくないのか、綺麗に縮小したいのか。
縮小はしたくありません。
マルチウィンドウで他にも複数ウィンドウを立ち上げているため、
画面表示時はStretchBltをしています。

説明不足でご迷惑をおかけしていますが、行いたい作業は以下の通りです。
1.既存の固定bmpファイルを読込む。(LoadBitmap)
2.読み込んだbmpファイルの特定領域へ文字列やラインを出力。
3.「2.」の内容をbmpファイルへ保存。

●3.のbmpファイルへの保存の方法がよく分からず、
記述したURL(参照出来ない方が多いようですが)
のように画面へ表示後、ファイルへ保存しました。

PATIO>
> CBitmapクラスにファイルへ出力する機能は有りませんから
> ビットマップファイルの構造を理解した上で自前で書き出すか、
> GDI+を使って保存するか、そんな所でしょうか。
勉強してきます。

rikizo 2007/10/16(火) 16:32:31
あまり詳しくないんですが、
VS2003のMFCってCImageクラスって使えないんでしたっけ?
CImage::Saveが便利そうなんで、
CImage::AttachとかCBitmap::FromHandleを使って何とか出来ませんかね?

MSDNを見ながら無責任なことを書いてるんで、外してたら申し訳ないです。

PATIO 2007/10/16(火) 17:16:33
> VS2003のMFCってCImageクラスって使えないんでしたっけ?
これってGDI+を内部では使っているみたいですね。
GDI+を直接使っても同じような事はできたと思いますけれど、
ATLみたいなのでCBitmapとかとはちょっと違う分類になりますね。

rikizo 2007/10/16(火) 22:03:59
>ATLみたいなのでCBitmapとかとはちょっと違う分類になりますね。

恥ずかしながらATLとかGDI+とかよく知らないんですけど、
CImageはATL/MFC共有クラスとMSDNに書いてあるので
CBitmapと一緒に使えるんだったら1つの手段としてアリかな〜と。
もちろんBITMAPファイルの構造を理解して自前で書き出してみる経験も有益だと思いま
すけど。

> スレ主様
上でCBitmap::FromHandleとか書いたのは忘れて下さいませm(_ _)m
本当はCBitmap::operator HBITMAPと書きたかった…。

CImage img;
img.Attach(bmp);      // bmpはCBitmap
img.Save(pszName, ImageFormatBMP); // こんな感じじゃダメかな?

例によって適当です。コンパイルもしてません。
さらにCImageを使ったことも無いです(汗

2007/10/16(火) 22:22:22
>1.既存の固定bmpファイルを読込む。(LoadBitmap)
>2.読み込んだbmpファイルの特定領域へ文字列やラインを出力。
>3.「2.」の内容をbmpファイルへ保存。

つまり、既存BMPをGDIで編集して保存する、という事ですね。
その場合、参考サイトでも使われているCreateCompatibleDCを使う事で読み
込んだBitmapオブジェクトを直接編集できるはずです。
 //SelectObjectするまでにTargetBMPへ対象BMPを読み込んでおく。
 CBitmap TargetBMP();
 CDC EditDC();
 
 //ここに描画に使うデバイスを指定する。まぁ、NULLでもクライアント領域でも
良い。
 if(EditDC.CreateCompatibleDC(NULL)){
   CBitmap *pOldBmp=EditDC.SelectObject(&TargetBMP);
   //EditDCに描画。表示したければこれをクライアント領域とかに転送する。
   EditDC.SelectObject(pOldBmp);

   BITMAP BMPInfo;
   if(TargetBMP.GetBitmap(&BMPInfo)){
     HBITMAP hTargetBMP=(HBITMAP)TargetBMP;
     if(hTargetBMP){
       //参考サイトと同様の手順でhTargetBMPを保存する。
       //画像サイズとかはBMPInfoに入っているはずです。
     }
   }
 }
こんな具合で多分いけるかと。
実際に画面に描画してそれをキャプチャする方式ですと、最前面ウィンドウとかで
嫌な事になりかねないのでお勧めしません。

kaneko 2007/10/16(火) 22:43:53
[[解決]]
アドバイスして頂いた方々ありがとうございました。
解決しました。

自分はウィンドウハンドルの取り方&タイミングが間違っていました。
HWND hwnd = ::GetForegroundWindow();
hwnd = ::GetWindow(hwnd, GW_CHILD);
という手順でウィンドウハンドルを取得していたところを
HWND hwnd = CreateDC("DISPLAY", NULL, NULL, NULL);
とすることで目的は達成できました。

現在は、WinProc関数を使用してウィンドウハンドルを取るよう
ソースを変更しています。

よく調べもせずに曖昧に質問をしてしまい、すみませんでした。
回答居頂いた方々、本当にありがとうございました。

古いスレッドには追加発言できません。