ウィンドウのビットマップ保存(範囲選択し、縮小してさらにモノクロ変換) – 固定ページ 2 – プログラミング – Home

ウィンドウのビットマップ保存(範囲選択...
 
通知
すべてクリア

ウィンドウのビットマップ保存(範囲選択し、縮小してさらにモノクロ変換)

固定ページ 2 / 2

bun
 bun
(@bun)
ゲスト
結合: 24年前
投稿: 761
 

こんな感じかな。

CLSID EncorderClsId;
EncoderParameters EncoderParams;
:
Bitmap Bmp(hBMP, NULL);
Bmp.Save([保存先パス], &EncorderClsId, &EncoderParams);


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

もしかしてC++の文法に関しても知識が足りない?

MFC(CScrollViewとかはMFCのクラスです)を使っているのなら
少なくともC++言語の文法に関する知識は必須ですよ。
文法を知らずにC++のプログラムは書けません。
コピペで組み立てることはできるかもしれませんが、
それでは実際に行われている処理が理解出来ませんし、
メンテナンスが出来ないソースになってしまいます。


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

事情は分かりませんけれど、
もしC++言語の文法自体を良く知らないのであれば、
一度きちんとC++言語の文法を勉強した方が良いです。
C++言語は文法とクラスの概念に関する知識が必要になるので
この辺が分かっていないとMFCを使いこなす事は難しいです。

できれば、MFCを使わない状況でまずC++言語の勉強を
純粋にした方が良いです。逆にC++言語の知識があれば、
MFCがやっている事もある程度理解出来ますし、
使い方も理解しやすくなります。


返信引用
トト
 トト
(@トト)
ゲスト
結合: 20年前
投稿: 11
Topic starter  

PATIOさん

そうです。知識は乏しいです・・・。
でも勉強する時間が無いので、とりあえず動くモノを、と思っております。

【質問】
試行錯誤しながらコーディングしている最中なんですが、
StretchBltを使用して、縮小しようと思っております。

試しに、ピクチャーコントロールを2つ作成し、1つめに表示している画像を2つめの
ピクチャーコントロールに縮小・拡大して表示させることは出来ました。

この時、コピー元のDCとコピー先DCは異なったものでなければならないと思うのです
が、「CClientDC dc(this);」で取得したDCを縮小したいといった場合、どのように処理
するものなのでしょうか?

「ダミーのデバイスコンテキストハンドルを生成してそこにコピーする」
といった方法は可能なのでしょうか?
また、可能な場合は単純に
HDC hDC2;
のようにインスタンスだけ生成すれば良いのでしょうか?


返信引用
みい
 みい
(@みい)
ゲスト
結合: 22年前
投稿: 65
 

「CreateCompatibleDC」を使って仮想描画領域を作ります。

CDC dcBuffer;
CBitmap bmpBuffer;
CRect rcRect;

CClientDC dc(this); //コピー元
// rcRectにコピー先の領域をセット
...
//

// 仮想描画領域
dcBuffer.CreateCompatibleDC(&dc);
bmpBuffer.CreateCompatibleBitmap(&dc, rcRect.Width(), rcRect.Height());
dcBuffer.SelectObject(&bmpBuffer);

// 処理
...

// 使い終わったら削除
dcBuffer.DeleteDC();
bmpBuffer.DeleteObject();


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

HDC hdc2;としてもデバイスコンテキストのインスタンスにはなりません。
この辺の話はやっぱりちゃんと理解していないと厳しいような気もしますけれど。
HDCはあくまでもデバイスコンテキストを特定する為のハンドルに過ぎません。
ハンドル自体がデバイスコンテキストの実体(インスタンス)ではないと言う事は
理解されていますか?

ビットマップを転送したり、画面から複写する為に
メモリ上にコンパチブルなデバイスコンテキストを作成して
そこに画像を受け取る為のbitmapを選択しておくと言う方法は
C++に限らずWindowsではポピュラーな方法なので
メモリ上のDCに選択したbitmapに貼り付ける時に縮小すれば、
いいはずです。ただし、GDIのStretchBltの縮小は縮小できれば良い
というレベルなので縮小された画像の出来に関してはある程度あきらめるしか
ないかなと思います。
知識がないながらも動くものをと言うのはわかるのですが、
C++言語の知識がどの程度足りないのかも結構重要ですよ。
クラスの概念等殆ど知りませんと言う話なら、
このまま続けるとドハマリする可能性も否定できません。
実際の話、C++言語の知識に関しては最低限必要な物なので。
その上でWindowsの仕組みとかMFCのクラスの使い方とかの
知識が必要になるわけで、これらの一番土台になる部分なので
継ぎ接ぎでプログラミングをするとしてもかなり困難なのではないかなぁ。
と思うのです。
せめてC++言語の勉強だけでもされた方が良いと思います。


返信引用
gak
 gak
(@gak)
ゲスト
結合: 21年前
投稿: 132
 

> 「CClientDC dc(this);」
CClientDC だと今其の時画面に見えているイメージ(CScrollViewをスクロールして見え
るようになる部分は無理)しか取得できないよ。(そういう仕様なら問題は無いけど)

> とりあえず動くモノを
GDI+を使わないサンプル。自動改行入ってボロボロになるだろうけどソース載せる。

void CScrollView::****() {
// イメージのCRect(100, 100, 200, 200)を白黒2色、CSize(300, 300)で保存
SaveImage(CRect(100, 100, 200, 200), 1, 300, 300, _T(output.bmp));
}
void CScrollView::SaveImage(const CRect& rect, int bitdepth, int cx, int cy,
LPCTSTR output) {
const int colors = ((1 << bitdepth) & 0x1ff);
const int headerLen = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * colors;
BITMAPINFO* bi = reinterpret_cast<BITMAPINFO*>(new BYTE[headerLen]);
memset(bi, 0, sizeof(BITMAPINFOHEADER));
bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi->bmiHeader.biWidth = cx;
bi->bmiHeader.biHeight = cy;
bi->bmiHeader.biPlanes = 1;
bi->bmiHeader.biBitCount = bitdepth;
bi->bmiHeader.biSizeImage = (((bi->bmiHeader.biBitCount *
bi->bmiHeader.biWidth + 31) / 32) * 4) * bi->bmiHeader.biHeight;
// grayscaleパレット構築
for (int i=0; i < colors; ++i) {
bi->bmiColors[i].rgbBlue = bi->bmiColors[i].rgbGreen =
bi->bmiColors[i].rgbRed = ::MulDiv(255, i, (colors - 1));
bi->bmiColors[i].rgbReserved = 0;
}
CDC dc;
dc.Attach(::CreateCompatibleDC(NULL));
void* bits;
CBitmap bitmap;
bitmap.Attach(::CreateDIBSection(NULL, bi, DIB_RGB_COLORS, &bits, NULL, 0));
CBitmap* oldbmp = dc.SelectObject(&bitmap);
dc.FillSolidRect(0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight,
RGB(0xff, 0xff, 0xff));
dc.SetMapMode(MM_ANISOTROPIC);
dc.SetWindowOrg(0, 0);
dc.SetViewportOrg(::MulDiv(-rect.left, cx, rect.Width()),
(::MulDiv(-rect.top, cy, rect.Height())));
dc.SetWindowExt(rect.Size());
dc.SetViewportExt(cx, cy);
dc.SetStretchBltMode(HALFTONE);
CScrollView::OnDraw(&dc); // イメージ描画処理
dc.SelectObject(oldbmp);
// bmp保存
BITMAPFILEHEADER bfh = { 0 };
bfh.bfType = 0x4d42;
bfh.bfSize = sizeof(BITMAPFILEHEADER) + headerLen + bi->bmiHeader.biSizeImage;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + headerLen;
CFile file(output, CFile::modeCreate | CFile::modeWrite);
file.Write(&bfh, sizeof(BITMAPFILEHEADER));
file.Write(bi, headerLen);
file.Write(bits, bi->bmiHeader.biSizeImage);
delete []reinterpret_cast<BYTE*>(bi);
}

問題点
・減色をシステムに丸投げしている(パレットから近似色取ってるだけ)為質が良くな
い。ディザも掛からない
・CScrollView::OnDraw() 内でマッピングモード関連を弄っている場合は調整が要る


返信引用
ryo
 ryo
(@ryo)
ゲスト
結合: 23年前
投稿: 252
 

時間がないなら、CImageが一番楽。

1:保存したいサイズのCImageをつくる(100*100など)
#このときモノクロでつくれば、モノクロ化も一発で可能(*1)

2:表示しているDCから、CImageへ、StrecthBltする。

3:CImageを保存。(CImageの破棄)

おわり

*1:ある色は白、別の色は黒・・・といった変換をいろいろ設定したいのなら
この方法ではできない


返信引用
トト
 トト
(@トト)
ゲスト
結合: 20年前
投稿: 11
Topic starter  

gakさんに記載していただいているソースで試してみたのですが、
真っ白なビットマップが出力されてしまいます・・・。

これからryoさんに提案いただいた方法で試させていただきます。


返信引用
トト
 トト
(@トト)
ゲスト
結合: 20年前
投稿: 11
Topic starter  

gakさんに記載していただいているソースについて質問させてください。

1.CreateDIBSectionの第一引数は「dc」でなくても良い?

2.biSizeImageの計算で、Y方向はバイト換算しなくても良い?

デバイスコンテキストとビットマップの結びつけが出来ていないのか、デバイスコンテ
キストに描画して出力しても何も表示されません・・・。


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

HDCにNULLを指定すると多分デスクトップウインドウのハンドル扱いになったと思います。

あと、X方向のバウンダリ合わせの事を言っているのなら既にX方向でバウンダリはあって
いるのでY方向は必要ないです。メモリ上にどのように配置されるのかを考えるとその辺
はわかると思います。


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

あと、ちょっと確認を。

ファイルに出力した結果を画像表示ソフトで表示しても何も表示されない
と言う事で良いのですか?
ファイルに出力する時は、DCに選択されたままの状態にしているとうまく行かないと思い
ます。
gakさんのソースでは出力前に非選択状態にしてますよ。


返信引用
固定ページ 2 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました