2009年7月31日金曜日

DCからDIBを生成する

デバイス・コンテキストからDIB(デバイス非依存ビットマップ)を取得するには,必要なメモリを確保した上でヘッダを設定し,GetDIBits関数を呼び出す. (実際には,デバイス・コンテキストから直接ではなく,BITMAPオブジェクトから取得する)

ここでは,24bitカラーのDIBを取得する方法を示す.

GetDIBits関数に渡すヘッダは,BITMAPINFO構造体であるが,カラー・マスクを使用しない場合にはBITMAPINFOHEADER構造体で代用できる.(型キャストが必要)

LPBITMAPINFOHEADER lpdibh;

lpdibh->biSize           = sizeof(BITMAPINFOHEADER);
lpdibh->biWidth          = WIDTH;     //幅(px)
lpdibh->biHeight         = HEIGHT;    //高さ(px)
lpdibh->biPlanes         = 1;         //必ず1
lpdibh->biBitCount       = 24;        //1ピクセル当たりのビット数
lpdibh->biCompression    = BI_RGB;    //非圧縮であることを示す
lpdibh->biSizeImage      = IMG_SIZE;  //ビットマップ(点の配列)の大きさ(バイト)
lpdibh->biClrUsed        = 0;         //カラー・マスクの数
lpdibh->biClrImportant   = 0;

ここで,IMG_SIZE(ビットマップのサイズ)を,HEIGHT×WIDTH×24とできないことに注意が必要. 32bit環境では,一行毎に4バイト(32ビット)の境界に揃える必要があるので,以下のような式でサイズを計算する.

HEIGHT * ( ( WIDTH * 3 + 3 ) & ~3 )

また,データを参照・変更する際には,DIBが(標準では)ボトム・アップで,BGRBGR・・・と並んでいることにも注意が必要.

最後にGetDIBits関数を呼び出す前後の手順の一例を示す.

HDC                hdc_src; //コピー元DCのハンドル
LPBITMAPINFOHEADER lpdibh;  //必要な情報を格納したヘッダ
LPBYTE             lpdata;  //ビットマップ(点の配列)へのアドレス
/* 以上は取得・初期化済みであるとする(開放もしない) */

/// メモリ・デバイスコンテキストの作成
HDC hdcMem = ::CreateCompatibleDC( hdc_src );
/// ビットマップの作成
HBITMAP hbmp = ::CreateCompatibleBitmap( hdc_src , WIDTH , HEIGHT );
/// ビットマップとメモリ・デバイスコンテキストを関連付ける
HBITMAP hbmptmp = ::SelectObject( hdcMem , hbmp );
/// 画像をコピーする
::BitBlt( hdcMem , 0 , 0 , WIDTH , HEIGHT , hdc_src , X , Y , SRCCOPY );
/// DIBを取得する
::SelectObject( hdcMem , hbmptmp );
::GetDIBits( hdcMem , hbmp , 0 , HEIGHT , lpbmp , reinterpret_cast( lpdibh ) , DIB_RGB_COLORS );
/// リソースの開放
::DeleteObject( hbmp );
::DeleteDC( hdcMem );

参考:How To Convert Between Device-Dependent Bitmaps and DIBsトップダウン DIB とボトムアップ DIB

0 件のコメント:

コメントを投稿