ビットマップ


ビットブロック転送

さて、応用編の最初はビットマップというテーマから始めたいと思います
ビットマップは、ピクセルの情報を2次元配列にまとめたデータです
画像ファイルであるビットマップファイルで、皆さんもご存知でしょう

ビットマップは写真や可愛い猫耳娘のCGを扱う手段の一つです
複雑なイメージを表現し、ラスタデバイスで表すことができます

ビットマップにはいくつかの弱点が指摘されます
一つは、1ピクセルごとのデータを持つためにファイルサイズが大きいということ
しかし、現在の数十、数百GBのハードドライブを持つコンピュータでは大きな問題にはならないだろう

また、ビットマップにはデバイスの発色能力の問題もあります
ビットマップには、モノクロ、16色、256色、high color、true color がある
モノクロビットマップはカーソル、16色はアイコンなどでよく見かける

256色も、90年代後半にPC-98等から移植された古いゲームなどでよく見かけます
近年では 32,768色、または 65,536色 表示可能の high color も一般的です
1ピクセルに 24 ビット用い、16,777,216色使える true color というものもあります
これは、人間が知覚できる色の限界とほぼ同じ数といわれます

今後のサンプルプログラムでは、簡単のために省略しますが
本来は GetDeviceCaps() 関数でビデオアダプタの発色能力を調べるべきです

さて、ビットマップを扱うということは画像ファイルを操作すると思われるかもしれませんが
そもそもディスプレイの画面はビデオアダプタの内蔵メモリが保存している
一つの巨大なビットマップであると考えることができるのです

そこで、まずはこのビデオアダプタのメモリを直接操作することからはじめます
ある矩形のビットブロックを転送するには BitBlt() 関数を使用します
BOOL BitBlt(
	HDC hdcDest,
	int nXDest , int nYDest ,
	int nWidth , int nHeight ,
	HDC hdcSrc, 
	int nXSrc , int nYSrc ,
	DWORD dwRop
);
hdcDest は、ビットブロックのコピー先デバイスコンテキストのハンドルを
nXDest はコピー先の長方形の左上隅の X 座標、nYDest は Y 座標
nWidth と nHeight はそれぞれ幅と高さで、コピー元ビットマップ幅にもなります

hdcSrc は、コピー元のデバイスコンテキストのハンドル
nXSrc と nYSrc はコピー元の X 座標と Y 座標を指定します
dwRop は転送時のラスタオペレーションを指定します
詳しいラスタオペレーションの定数は下記のリファレンスを参照してください
SRCCOPY を指定すれば、コピー元と同じ状態で転送されます

戻り値は、成功すれば 0 以外、失敗すれば 0 です
この関数は、ある矩形を原点のみ変更してコピーする時に非常に便利です
#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
	HDC hdc;
	PAINTSTRUCT ps;
	int x;

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hwnd , &ps);
		for (x = 0 ; x < 100 ; x += 10) {
			MoveToEx(hdc , x , 0 , NULL);
			LineTo(hdc , x , 100);
		}
		BitBlt(hdc , 300 , 0 , 100 , 100 , hdc , 0 , 0 , SRCCOPY);
		EndPaint(hwnd , &ps);
		return 0;
	}
	return DefWindowProc(hwnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow ) {
	HWND hwnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return -1;

	hwnd = CreateWindow(
			TEXT("KITTY") , TEXT("Kitty on your lap") ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL ,
			hInstance , NULL
	);

	if (hwnd == NULL) return -1;

	while(GetMessage(&msg , NULL , 0 , 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}


まず、プログラムはクライアント領域の左上隅に線を描画します
次に、この領域のビットブロックを右側にそのまま転送しています

この動作は一見単純ですが非常に重要です
BitBlt はビデオメモリから直接データを参照して転送しているのです
当然、デバイスコンテキストは異なっていても問題はありません

たとえば、ディスプレイ全体の画面をソフトに取りこむ場合は
ディスプレイのデバイスコンテキストをウィンドウに BitBlt() で転送する方法が考えられますね

ただし、BitBlt() は2つのデバイスコンテキストが互換である必要があります
基本的に、色の形式やビット数が同じであることが望ましいのです


BitBlt()

BOOL BitBlt(
	HDC hdcDest,
	int nXDest , int nYDest ,
	int nWidth , int nHeight ,
	HDC hdcSrc, 
	int nXSrc , int nYSrc ,
	DWORD dwRop
);
ビットブロック転送を行います

hdcDest - コピー先のデバイスコンテキストのハンドルを指定します
nXDest - コピー先の長方形の左上隅の X 座標を、論理単位で指定します
nYDext - コピー先の長方形の左上隅の Y 座標を、論理単位で指定します
nWidth - コピー先の長方形の幅を、論理単位で指定します。コピー元のビットマップの幅でもあります
nHeight - コピー先の長方形の高さを、論理単位で指定します。コピー元のビットマップの幅でもあります
hdcSrc - コピー元のデバイスコンテキストのハンドルを指定します
nXSrc - コピー元の長方形の左上隅の X 座標を、論理単位で指定します
nYSrc - コピー元の長方形の左上隅の Y 座標を、論理単位で指定します
dwRop - ラスタオペレーションコードを指定します

dwRop には以下の定数を指定できます

定数解説
BLACKNESS 物理パレットのインデックス 0 に対応する色 (デフォルトは黒) で
コピー先の長方形を塗りつぶします
DSTINVERT コピー先長方形の色を反転します
MERGECOPY コピー元の色と、コピー先の色を
論理 AND 演算子で結合します
MERGEPAINT コピー元の色を反転した色と
コピー先の色を、論理 OR 演算子で結合します
NOTSRCCOPY コピー元の色を反転して
コピー先にコピーします
NOTSRCERASE コピー元の色と、コピー先の色を
論理 OR 演算子で結合し、さらに反転します
PATCOPY 指定したパターンをコピー先にコピーします
PATINVERT 指定したパターンの色と、コピー先の色を
論理 XOR 演算子で結合します
PATPAINT 指定したパターンの色と、コピー元の色を反転した色を
論理 OR 演算子で結合し、さらにその結果を
コピー先の色と論理 OR 演算子で結合します
SRCAND コピー元の色と、コピー先の色を
論理 AND 演算子で結合します
SRCCOPY コピー元をコピー先にそのままコピーします
SRCERASE コピー先の色を反転した色と、コピー元の色を
論理 AND 演算子で結合します
SRCINVERT コピー元の色と、コピー先の色を
論理 XOR 演算子で結合します
SRCPAINT コピー元の色と、コピー先の色を
論理 OR 演算子で結合します
WHITENESS 物理パレットのインデックス 1 に対応する色 (デフォルトは白) で
コピー先の長方形を塗りつぶします



戻る次のページへ