拡大と縮小


イメージのサイズ変更

先ほどのビットブロックの転送は、基本的には矩形の原点移動でした
//同じデバイスコンテキストのハンドルを指定した場合

しかし、ビットマップを拡大したり縮小したいこともあるでしょう
また、BitBlt() はコピー元の幅をしていしないので、それが問題になることもあります
コピー元とコピー先の 物理サイズが異なる 場合です

このような場合に備え、転送前と転送後のイメージのサイズを指定できると便利ですね
それには StretchBlt() 関数を使用します
BOOL StretchBlt(
	HDC hdcDest, 
	int nXOriginDest , int nYOriginDest ,
	int nWidthDest , int nHeightDest ,
	HDC hdcSrc ,
	int nXOriginSrc , int nYOriginSrc ,
	int nWidthSrc , int nHeightSrc,
	DWORD dwRop 
);
hdcDest はコピー先のデバイスコンテキストのハンドルを
nXOriginDest はコピー先の長方形の左上隅の X 座標、nYOriginDest は Y 座標
nWidthDest はコピー先の幅、nHeightDest は高さを指定します

hdcSrc はコピー元のデバイスコンテキストのハンドル
nXOriginSrc はコピー元の長方形の左上隅の X 座標、nYOriginSrc は Y 座標
nWidthSrc と nHeightSrc はコピー元の幅と高さを指定します
dwRop は、ラスタオペレーションコードを指定します

戻り値は、成功すれば 0 以外、失敗すれば 0 です
この引数からわかるように、概念的には
BitBlt() に nWidthSrc と nHeightSrc が付加されただけと思って構いません


グラフィックシステムを扱ったことのある多くのプログラマは
イメージの拡大と縮小時に発生するイメージの歪みに直面したことがあるでしょう
これは、拡大や縮小がピクセルの複製や削除で行われるため、整数倍できない時に発生します

この時、色の伸縮方法をいくつか指定することができます
色の伸縮方法を ストレッチモード と呼びます
これを変更するには SetStretchBltMode() 関数を使用します

int SetStretchBltMode(HDC hdc , int iStretchMode);

hdc は、設定するデバイスコンテキストのハンドル
iStretchMode には、ストレッチモードを表す定数を指定します
成功すると以前設定されていたストレッチモード、失敗すれば 0 が返ります

各定数は下のリファレンスに示します
COLORONCOLOR を指定すると、比較的カラービットマップに適しています
デフォルトで、BLACKONWHITE が設定されています
#include <windows.h>

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

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_PAINT:
		GetClientRect(hwnd , &rect);
		hdc = BeginPaint(hwnd , &ps);
		DrawIcon(hdc , 0 , 0 , LoadIcon(NULL , IDI_WINLOGO));

		SetStretchBltMode(hdc , COLORONCOLOR);
		StretchBlt(
			hdc , 0 , 0 , rect.right , rect.bottom ,
			hdc , 0 , 0 , 32 , 32 , 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;
}


このプログラムでは、まず DrawIcon() 関数でアイコンを描画し
それをクライアント領域のサイズに拡大する形でビットブロックを転送しています

因みに、現在設定されているストレッチングモードを取得するには
GetStretchBltMode() を使います

int GetStretchBltMode(HDC hdc);

hdc には、デバイスコンテキストのハンドルを指定します
成功すれば現在のストレッチングモード、失敗すれば 0 が返ります

また、StretchBlt() 関数は回転や反転も可能です
長方形の始点となる X , Y 座標と終点となる幅と高さを(負数を用いて)反転させます
これを用いれば、ビット列を反転、または回転させられます
#include <windows.h>

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

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_PAINT:
		GetClientRect(hwnd , &rect);
		hdc = BeginPaint(hwnd , &ps);
		DrawIcon(hdc , 0 , 0 , LoadIcon(NULL , IDI_WINLOGO));

		StretchBlt(
			hdc , rect.right , rect.bottom ,
			-rect.right , -rect.bottom ,
			hdc , 0 , 0 , 32 , 32 , 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;
}


ウィンドウズアイコンが反転しているのがわかりますね
描画する長方形の終点から、始点に向かって描画しています


StretchBlt()

BOOL StretchBlt(
	HDC hdcDest, 
	int nXOriginDest , int nYOriginDest ,
	int nWidthDest , int nHeightDest ,
	HDC hdcSrc ,
	int nXOriginSrc , int nYOriginSrc ,
	int nWidthSrc , int nHeightSrc,
	DWORD dwRop 
);
コピー元の長方形からコピー先の長方形にビットマップをコピーします

hdcDest - コピー先のデバイスコンテキストのハンドルを指定します
nXOriginDest - コピー先の長方形の左上隅の x 座標を、論理単位で指定します
nYOriginDest - コピー先の長方形の左上隅の y 座標を、論理単位で指定します
nWidthDest - コピー先の長方形の幅を、論理単位で指定します
nHeightDest - コピー先の長方形の高さを、論理単位で指定します
hdcSrc - コピー元のデバイスコンテキストのハンドルを指定します
nXOriginSrc - コピー元の長方形の左上隅の x 座標を、論理単位で指定します
nYOriginSrc - コピー元の長方形の左上隅の y 座標を、論理単位で指定します
nWidthSrc - コピー元の長方形の幅を、論理単位で指定します
nHeightSrc - コピー元の長方形の高さを、論理単位で指定します
dwRop - ラスタオペレーションコードを指定します

戻り値 - 成功すると 0 以外、失敗すると 0

dwRop に指定する定数は、BitBlt() 関数を参照してください

SetStretchBltMode()

int SetStretchBltMode(HDC hdc , int iStretchMode);

指定されたデバイスコンテキストのビットマップ伸縮モードを設定します

hdc - デバイスコンテキストのハンドルを指定します
iStretchMode - ストレッチングモードを表す定数を指定します

戻り値 - 成功すれば以前のストレッチングモード、失敗すれば 0

iStretchMode には、以下の定数のいずれかを指定できます

定数解説
BLACKONWHITE 残す点の色と、取り除く点の色を、論理 AND 演算子で結合します
ビットマップがモノクロビットマップの場合
白のピクセルが消され、黒のピクセルが残ります
COLORONCOLOR ピクセルを削除します
取り除く点の情報を保存することなく、削除します
HALFTONE コピー元のピクセルをコピー先のピクセルブロックに対応づけます
コピー先のブロックの平均的な色が、コピー元のピクセルの色に近い色になります

HALFTONEモードを設定した場合は、ブラシのずれを防ぐため
SetBrushOrgEx() 関数を呼び出してください
STRETCH_ANDSCANS BLACKONWHITE と同じです
STRETCH_DELETESCANS COLORONCOLOR と同じです
STRETCH_HALFTONE HALFTONE と同じです
STRETCH_ORSCANS WHITEONBLACK と同じです
WHITEONBLACK 残す点の色と、取り除く点の色を、論理 OR 演算子で結合します
ビットマップがモノクロビットマップの場合
黒のピクセルが消され、白のピクセルが残ります

GetStretchBltMode()

int GetStretchBltMode(HDC hdc);

現在のビットマップ伸縮モードを取得します

hdc - デバイスコンテキストのハンドルを指定します

戻り値 - ストレッチングモードを表す定数。失敗すれば 0



前のページへ戻る次のページへ