VC++ 6.0 XP
表示しているクライアント領域の画像データをとりこみたいのですが、
CDC::GetPixel()では、おそいのですが、
なにか、いい手は、ないでしょうか?
CClientDC wDC(this);
CRect wRect;
GetClientRect(&wRect);// クライアント領域の大きさを得る
vector <COLORREF> wBuffer ;
int x,y ;
for(y = wRect.top;y < wRect.bottom;y++) {
for(x = wRect.left;x < wRect.right;x++) {
COLORREF wColor = wDC.GetPixel(x,y) ;
wBuffer.append(1,wColor) ;
}
}
なぜかGetPixel(1,0)のとき-1が返ってきます。
わかりません。SetPixelでかけるのに、GetPixelで読めないです。
CRect wRect;
GetClientRect(&wRect);// クライアント領域の大きさを得る
std::vector <COLORREF> wBuffer ;
int x,y ;
for(y = wRect.top;y < wRect.bottom;y++) {
for(x = wRect.left;x < wRect.right;x++) {
pDC->SetPixel(x,y,RGB(0xff,0,0)) ;
COLORREF wColor = pDC->GetPixel(x,y) ;
wBuffer.push_back(wColor) ;
}
}
とりあえず、BitBlt()転送してからの方が早いかも。
以下、C++Builderのサンプルですが、
VC++が分かる人ならきっと読めると思います。
http://www.ne.jp/asahi/protech/hiroaki/programing/cb.html#Q8
転送できたら、CBitmap::GetBitmapBits() でバッファに取り込めます。
> わかりません。SetPixelでかけるのに、GetPixelで読めないです。
新しいSDIプロジェクトで↓を試すとどうなります?
void CMy0409View::OnLButtonDown(UINT nFlags, CPoint point)
{
CClientDC dc(this);
dc.SetPixel(point.x, point.y, RGB(0, 0, 0xff));
int ret = dc.GetPixel(point.x, point.y);
TRACE((%d, %d) color = %06x\n, point.x, point.y, ret);
CView::OnLButtonDown(nFlags, point);
}
MDSNを読んで見ましょう。
> すべてのデバイスが GetPixel 関数をサポートするわけではありません。
> 詳細については、GetDeviceCaps メンバ関数の RC_BITBLT ラスタ機能に
> 関する解説を参照してください。
> RC_BITBLT Capable of transferring bitmaps.
対象がビットマップになっている必要があるみたいですね。
追記、
ん、SetPixelも一緒だね。
対象はビットマップですね。
SetPixelはうまくいっているのですよね。
GetPixelとSetPixelの組合せでやるとかなり遅いと思います。
一ピクセルずつ処理しないといけない訳でもあれば話は別ですけれど。
一般的に画像を取り込みたいときは、bunさんの方法を使うと思います。
提示されているソースでは画素毎に変換等をやっているわけではなくて
単純に写しているだけのようなのでそれならば、BitBltでやった方が
効率が良いと思います。
GetPixelがうまく行かないわけについてはちゃんと理解した方が良いと
思うのでそれはそれで追求した方が良いとは思いますけれど。
bunさん、たいちうさん、ITOさん、PATIOさん、レスありがとうございます。
どうやら、ビットマップになっていないとだめなようですね。
ソースは、すこし時間が今すこし、UPは、お時間をくださいね。
もう、八方ふさがりになっていたので、すごく助かりました。
まだ、動作するかどうかわかりませんが、きっといい結果につながると思います。
void CMyView::OnDraw(CDC* pDC)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// CClientDC wDC(this);
CDC wDC ; // デバイスコンテキストを実体化
// そのデバイスコンテキストをメモリデバイスコンテキストにコンパチブルにする
wDC.CreateCompatibleDC(pDC) ;
CRect wRect;
GetClientRect(&wRect);// クライアント領域の大きさを得る
std::vector <COLORREF> wBuffer ;
CBitmap wBitmap ;
// ビットマップは、デバイスによって違うので、メモリデバイスコンテキス
ト
// にコンパチブルなビットマップを生成する。
wBitmap.CreateCompatibleBitmap(pDC,wRect.right+1,wRect.bottom+1) ;
wDC.SelectObject(&wBitmap) ;
int x,y ;
for(y = wRect.top;y < wRect.bottom;y++) {
for(x = wRect.left;x < wRect.right;x++) {
//GetPixelのテストなので画面表示はされない
wDC.SetPixel(x,y,RGB(x%256,0,0)) ;
COLORREF wColor = wDC.GetPixel(x,y) ;
wBuffer.push_back(wColor) ;
}
}
}
ひとまず、これで動作しました。みなさん、ありがとうございました。
ただ、OnDraw()の引数になっているpDCをビットマップ化しようとすると、
GetPixel()はうまく動作しませんでした。
pDC->SelectObject(&wBitmap) ;とするとpDC->GetPixel(x,y)は、動作しませんでした。
(なぜだか、 よくわかりません???)
ちょっと気になったのですが、
> std::vector <COLORREF> wBuffer ;
これって有効なんですか?
vectorでCOLORREF等WIN32 API系の型を使った
例って見たことないのですが大丈夫ですか?
long等の型で定義して、キャストでCOLORREF
に変換するほうがいいと思ったのですが。
> std::vector <COLORREF> wBuffer ;
> これって有効なんですか?
特にエラーなく、動作も期待通りに動いたのですが・・・・
あんまり、よくなかったですか?
>vectorとCOLORREF
STLガシガシ使うときにOSベッタリの型を使う事が少ないって程度で、何の問題
も無いと思います。
実際にもCOLORREFはDWORDのtypedefで、DWORDはunsigned longの
typedefなので、全く問題は無い筈です。
というかこんな事で問題が起きる様なAPIだと、そっちの方が大問題では。
統一感の問題ではないかと。
非MFCでWin32 Applicationのプログラムを作る場合、
COLORREFを動的配列で持ちたいならば、
私もstd::vector<COLORREF>を使います。
麩さんの書いてある理由の通りで、キャストが必要とも思いません。
ただ、ガラさんのプログラムはMFCなので、動的配列にはMFCのCUIntArrayが使えます。
統一性を重んじるならば、CUIntArrayを使うほうが良いかもしれません。
# 個人的にはCArray系のクラスは使いなれないので、MFCでもstd::vectorを
# 使う場合があり、テスト用のプログラムなどではその選択が多いです。
# 皆さんはMFCとSTLを混ぜて使いますか?
# 皆さんはMFCとSTLを混ぜて使いますか?
ケースバイケースでは?
取り敢えず…や、急ぎで…ならば、試行錯誤する時間よりも
(自身的に)使用経験の豊富な組み合わせで対処すると思われます。
> 実際にもCOLORREFはDWORDのtypedefで、DWORDはunsigned longの
> typedefなので、全く問題は無い筈です。
> 私もstd::vector<COLORREF>を使います。
ガラさんの問題の助けにならないかと思いました。
問題ないとのことでよかったです。