● 対策−−ブロック転送テクを使おう
そこで、画像印刷処理で使っていた BilBlt によるブロック転送技術を逆用し、画面からメモリ内に Bitmap イメージでブロック転送してから、RGB 情報にばらして取り出す方法をコーディングしました。
インターネットで調べてもこれで悩んでいる人が多いようですのでソースを公開しておきます。
●
VC サンプルソース
長方形ゾーンを指定し、ドット数*3バイトのRGB バッファを用意して呼び出すと RGB 順、べたづめでバッファに格納して返します。
[ ソース ]
当方のソフトから直接切り出しましたのと、< が html 文で正しく理解してくれず、わざとスペースをいれたりして、多少みにくいところもあるかと思います。
でもまあコンバートは難しくないでしょう。
Win10 でも同じ関数を使っていますが、なんら問題を生じていませんので有効です。
メモリ上に互換ビットマップを確保し、そこに画面から指定ゾーンのビットマップ情報を一括転送後、RGB 順に並べ替えています。
なお、画面の表示タイプ(ドットあたりビット数)による場合分けが必要です。注意ください。
//================================================================
// モニタの指定ゾーンのRGBデータを取得
// 時間はかからないはずなので途中経過表示はしない
// 0 - 正常
// -1 - 画像取得失敗
//================================================================
int CNoSrch::MonitRGBGet(
unsigned char *pRGB, // 上流で dx*dy*3 バイトの領域を確保のこと
// RGB 順
int xsd, // 左端
int ysd, // 上端
int dxd, // 幅
int dyd) // 高さ
{
int x,y;
// モニタ全域をカバーする DC を作る
CDC dcMonit;
dcMonit.CreateDC("DISPLAY",NULL,NULL,NULL);
// メモリ上に互換性のある DC を作る
CDC dcMem;
dcMem.CreateCompatibleDC(&dcMonit);
// モニタDC に指定サイズのコンパチビットマップを作る
CBitmap GBmp;
BITMAP bm;
if(FALSE==GBmp.CreateCompatibleBitmap(
&dcMonit,
dxd,
dyd) )
{
MessageBox("Compatible Bitmap 作成に失敗しました","確認",0);
return -1;
}
// このビットマップオブジェクトでバッファを確保する
GBmp.GetObject(sizeof(BITMAP),&bm);
// メモリ上の互換DCを選択する
CBitmap* pOldBmp=dcMem.SelectObject(&GBmp);
//--------------------------------------------------------------------
// メモリDC へ指定ゾーンのモニタ画像を一括転送する
if(!dcMem.BitBlt(
// 転送先
0, // xs
0, // ys
dxd, // Δx
dyd, // Δy
// 転送元
&dcMonit, // DC
xsd, // xs
ysd, // ys
SRCCOPY))
{
MessageBox("Bitmap 転送に失敗しました","確認",0);
dcMem.SelectObject(pOldBmp);
return -1;
}
//----------------------------------------------------------------------
int LineBytes;
int jpad; // パッディングバイト数 24ビットのときのみ必要
// 横1列を偶数バイトにするため
int NBbuf; // バッファサイズ
int NBGet;
unsigned char *pbmpc;
unsigned char Hi,Lo;
int kk;
unsigned char R,G,B;
int Sr=0; // 格納バイトシリアル
// ビットあたりのピクセル数
int crtBitPxl = dcMonit.GetDeviceCaps(BITSPIXEL);
switch(crtBitPxl)
{
case 32: // 32ビット=4バイトタイプ
// 変換用バッファを確保する
NBbuf=dxd*4*dyd; // 必ず偶数になる
pbmpc=new unsigned char [NBbuf];
// ビットマップパターンをCBitmap から変換用バッファへ転送する
// 指定バイト数のデータをバッファへ転送
NBGet=GBmp.GetBitmapBits(NBbuf,&pbmpc[0]);
kk=0;
for(y=0; y < dyd; y++)
{
for(x=0; x< dxd; x++)
{
B=pbmpc[kk++]; // B
G=pbmpc[kk++]; // G
R=pbmpc[kk++]; // R
kk++; // 4バイト目はダミー
pRGB[Sr++]=R; // RGBバッファへ格納
pRGB[Sr++]=G;
pRGB[Sr++]=B;
} // for x
// パッディング不要
} // for y
break;
case 24: // 24ビット=3バイトタイプ
// 24 ビットはパッディングが必要かも
// 横ドット数*3を偶数にする必要がある
LineBytes=dxd*3;
if(LineBytes % 2 !=0)
{
LineBytes++;
jpad=1;
}
else jpad=0;
NBbuf=LineBytes*dyd;
pbmpc=new unsigned char [NBbuf];
// ビットマップパターンをCBitmap から変換用バッファへ転送する
// 指定バイト数のデータをバッファへ転送
NBGet=GBmp.GetBitmapBits(NBbuf,&pbmpc[0]);
kk=0;
for(y=0; y < dyd; y++)
{
for(x=0; x < dxd; x++)
{
B=pbmpc[kk++]; // B
G=pbmpc[kk++]; // G
R=pbmpc[kk++]; // R
pRGB[Sr++]=R; // RGBバッファへ格納
pRGB[Sr++]=G;
pRGB[Sr++]=B;
} // for x
if(jpad!=0) kk++; // バッディング かならず1バイトだけ
} // for y
break;
case 16: // 16ビット=2バイトタイプ
LineBytes=dxd*2;
NBbuf=LineBytes*dyd; // 必ず偶数になる
// 変換用バッファを確保
pbmpc=new unsigned char [NBbuf];
// ビットマップパターンをCBitmap から変換用バッファへ転送する
// 指定バイト数のデータをバッファへ転送
NBGet=GBmp.GetBitmapBits(NBbuf,&pbmpc[0]);
kk=0;
for(y=0; y< dyd; y++)
{
for(x=0; x< dxd; x++)
{ // 2バイトを取り出す
Lo=pbmpc[kk++];
Hi=pbmpc[kk++];
R=Hi & 0xf8; // 上位バイトの上位5ビットがR 下位3ビットをクリアしておく
// 上位バイトの下位3ビットと下位バイトの上位3ビットがG
G=( Hi << 5 ) | ( ( Lo & 0xe0 ) >> 3 );
B= Lo << 3; // 下位バイトの下位5ビットがB 上位ヅメで0が下位3ビットに入る
pRGB[Sr++]=R; // RGBバッファへ格納
pRGB[Sr++]=G;
pRGB[Sr++]=B;
} // for x
// パッディング不要
} // for y
break;
default:
MessageBox("モニタに 32,24,16 ビットタイプ以外が指定されました","確認",0);
dcMem.SelectObject(pOldBmp);
return -1;
}
// バッファはもう不要
delete [] pbmpc;
dcMem.SelectObject(pOldBmp);
return 0; // 正常
}
トップ >
Win7でのソフトの推奨使用法 >
頁トップ