みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

WinAPIのGetDIBitsでディスプレイのビットを...

CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL)
で、ディスプレイのHDCを収得したのですが、その後ある一定範囲のビットを調べたいです。
しかし、GetPixelだと処理が遅くなり、困っています。

GetDIBitsはあまり解説しているサイトが少なく、よくわかりません・・・。
また、第一パラメータはHDCを指定すればいいようですが、そのあとのビットマップハンドルをなぜ指定する必要があるのでしょうか。
それと、ディスプレイのビットマップハンドルを収得できますか?

投稿日時 - 2007-04-05 00:01:43

QNo.2895002

すぐに回答ほしいです

質問者が選んだベストアンサー

★『CreateDIBSection』関数を利用すると良い。
・ディスプレイのデバイス・コンテキスト(HDC)などを 1 ピクセル 32 ビットの DWORD 型配列で
 管理して扱う方法があります。この方法を使えば直接ピクセル値をアクセスするため GDI の
 GetPixel() 関数よりは早くデータを取得(設定)できます。
・下にそのサンプルを載せます。

サンプル:
BITMAPINFO BmpInfo;
HBITMAP hBMP, hBMPOLD;
LPDWORD lpRGB;
HDC hdcBMP;

// ヘッダ情報の設定
ZeroMemory( &BmpInfo, sizeof(BITMAPINFO) );
BmpInfo.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
BmpInfo.bmiHeader.biWidth = XDOT;
BmpInfo.bmiHeader.biHeight = YDOT;
BmpInfo.bmiHeader.biPlanes = 1;
BmpInfo.bmiHeader.biBitCount = 32;
BmpInfo.bmiHeader.biCompression = BI_RGB;

hBMP = CreateDIBSection( hDC, &BmpInfo, DIB_RGB_COLORS, (LPVOID*)(&lpRGB), NULL, 0 );
hdcBMP = CreateCompatibleDC( hDC );
hBMPOLD = SelectObject( hdcBMP, hBMP );

// GDIでアクセスする方法
SetPixel( hdcBMP, x, y, RGB(0xFF,0xCC,0x33) ); ←オレンジ色をセット
GetPixel( hdcBMP, x, y ); ←座標(x,y)の点を取得

// DIBでアクセスする方法
lpRGB[ XDOT * y + x ] = 0xFFCC33; ←座標(x,y)にRGB(0xFF,0xCC,0x33)のオレンジ色を書き込む
printf( "RGB=%d,%d,%d\n",
 (BYTE)(lpRGB[XDOT * y + x] >> 8*2),
 (BYTE)(lpRGB[XDOT * y + x] >> 8*1),
 (BYTE)(lpRGB[XDOT * y + x] >> 8*0) );

// 後始末
SelectObject( hdcBMP, hBMPOLD );
DeleteObject( hdcBMP );
DeleteObject( hBMP );

その他:
・『hDC』がディスプレイのデバイス・コンテキストです。
 あと XDOT、YDOT は横と縦のピクセル数を表した定数です。
 サンプルを利用する際には、ピクセル数を記号定数や変数などで指定して下さい。
・上記の方法ならば GetPixel() 関数を使わずに DWORD のピクセル配列で操作(取得)しますので、
 アクセスが早くなります。ただし、注意点が1つあります。
 それは GDI の GetPixel() 関数とは、座標指定が上下で逆転します。
 つまり、GetPixel(hDC,0,0) は左上隅ですが、lpRGB[XDOT * 0 + 0] は左下隅になります。
 この仕組みは、BMPファイルの構造と同じです。→むしろ、この構造にBMPファイルをあわせたのか?
・取得も設定も DWORD 型の lpRGB[] 配列でアクセスできます。
 DWORD の構造は、下位から 8 ビット単位で B、G、R、未使用の順に並んでいます。
 この構造のため、1 ピクセルを DWORD 変数1つで扱えてとっても便利です。
 マクロ関数を作ってアクセスすれば分かり易いかもしれません。
 『#define MacroGetPixel(x,y)  (lpRGB[XDOT * (y) + (x)])』
 『#define MacroSetPixel(x,y,c) (lpRGB[XDOT * (y) + (x)]=(c))』
 の2つです。変数名(lpRGB)、記号定数名(XDOT)を変える場合は注意して下さい。
・以上。おわり。→参考にどうぞ。

投稿日時 - 2007-04-05 14:11:58

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(2)

ANo.2

>ある一定範囲のビットを調べたい
一般的には、BitBltやStretchBltを使用してディスプレイのDCから自分で作成したDCへ範囲指定でコピーし、そのコピーしたビットマップイメージを参照する事になります。
ディスプレイのDCにはビットマップ相当の何か(VRAMそのもの?)がSelectObjectされている状態になっています。自分で作成したDCには自分で作成したビットマップをSelectObjectしなければなりません。それぞれコピー元とコピー先に指定してBitBltなどを実行すると、デスクトップのビットマップイメージが自分で作成したビットマップにコピーされます。
DIB(デバイスに依存しないビットマップ)がSelectObjectされているDCをコピー先にすると、デスクトップの色数に関係なくDIBで指定した形式に変換しながらコピーされます。ハイカラーやフルカラーはもちろん、特殊なビデオカードの特殊な形式であっても意識する必要がなくなります。

DCやDIBの作成方法は#1さんが解説されている通りだと思います。
付け加えるなら、BITMAPINFOのbmiHeader.biHeightに負数を指定する(100ピクセルなら-100を指定する)と、上下が逆になったトップダウンビットマップが作成されるので、アドレスの計算が少し簡単になります。

投稿日時 - 2007-04-06 01:19:30

あなたにオススメの質問