DIB の拡大/縮小


DIB のサイズ変更

DDB では、StretchBlt() 関数でビットマップサイズを変更できました
DIB を拡大縮小したい場合、方法の一つとしては
メモリデバイスコンテキストに DIB をコピーして、StretchBlt() を用いるアプローチがありますが
それよりも、StretchBlt() の DIB 版 StretchDIBits() を用いた方が
描画のみを目的とする場合などには、直感的で有効でしょう
int StretchDIBits(
	HDC hdc,
	int XDest , int YDest ,
	int nDestWidth , int nDestHeight ,
	int XSrc , int YSrc ,
	int nSrcWidth , int nSrcHeight ,
	CONST VOID *lpBits,
	CONST BITMAPINFO *lpBitsInfo,
	UINT iUsage , DWORD dwRop
);
hdc にデバイスコンテキストを
XDest と YDest にはコピー先矩形の左上隅の X 座標と Y 座標をそれぞれ指定します

nDestWidth はコピー先の幅、nDestHeight は高さを指定します
ソースイメージは、この矩形のサイズに合わせて拡大縮小されます

XSrc と YSrc はコピー元 DIB の X 座標と Y 座標を
nSrcWidth と nSrcHeight はそれぞれ幅と高さを指定します
lpBits はピクセルビットへのポインタ、lpBitsInfo は情報ヘッダへのポインタです
iUsage はカラー情報フラグ、dwRop にはラスタオペレーションを指定します

カラー情報フラグは SetDIBitsToDevice() 関数を
ラスタオペレーションのフラグは BitBlt() 関数を参照してください
関数が成功するとコピーされた走査線の数が、失敗すると GDI_ERROR が返ります
#include <windows.h>

BITMAPFILEHEADER bmpFileHeader;
BITMAPINFO * bmpInfo;
BYTE * bPixelBits;

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

	switch (msg) {
	case WM_DESTROY:
		free(bPixelBits);
		free(bmpInfo);
		PostQuitMessage(0);
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hWnd , &ps);
		GetClientRect(hWnd , &rect);
		SetStretchBltMode(hdc , COLORONCOLOR);
		StretchDIBits(
			hdc , 0 , 0 , rect.right , rect.bottom , 0 , 0 ,
			bmpInfo->bmiHeader.biWidth , bmpInfo->bmiHeader.biHeight ,
			bPixelBits , bmpInfo , DIB_RGB_COLORS , 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;
	HANDLE hFile;
	DWORD dwBytes;

	hFile = CreateFile(lpCmdLine , GENERIC_READ , 0 , NULL ,
		OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL);
	if (hFile == INVALID_HANDLE_VALUE) return 1;

	ReadFile(hFile , &bmpFileHeader , sizeof (BITMAPFILEHEADER) , &dwBytes , NULL);
	if (bmpFileHeader.bfType != 0x4D42) {
		MessageBox(NULL , TEXT("This is not a bitmap file") , NULL , MB_OK);
		return 1;
	}

	bmpInfo = (BITMAPINFO *) malloc (bmpFileHeader.bfOffBits - dwBytes);
	ReadFile(hFile , bmpInfo , bmpFileHeader.bfOffBits - dwBytes , &dwBytes , NULL);
	bPixelBits = (BYTE *) malloc (bmpFileHeader.bfSize - bmpFileHeader.bfOffBits);
	ReadFile(hFile ,bPixelBits ,
		bmpFileHeader.bfSize - bmpFileHeader.bfOffBits , &dwBytes , NULL);
	CloseHandle(hFile);

	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;
}


コマンドライン引数で指定されたビットマップファイルを読み込み
ウィンドウのクライアント領域のサイズに合わせて描画するプログラムです


StretchDIBits()

int StretchDIBits(
	HDC hdc,
	int XDest , int YDest ,
	int nDestWidth , int nDestHeight ,
	int XSrc , int YSrc ,
	int nSrcWidth , int nSrcHeight ,
	CONST VOID *lpBits,
	CONST BITMAPINFO *lpBitsInfo,
	UINT iUsage , DWORD dwRop
);
hdc - コピー先のデバイスコンテキストを指定します
XDest - コピー先矩形の左上隅の X 座標を指定します
YDest - コピー先矩形の左上隅の Y 座標を指定します
nDestWidth - コピー先の幅を指定します
nDestHeight - コピー先の高さを指定します
XSrc - コピー元 DIB の X 座標を指定します
YSrc - コピー元 DIB の Y 座標を指定します
nSrcWidth - コピー元の幅を指定します
nSrcHeight - コピー元の高さを指定します
lpBits - ピクセルビットへのポインタを指定します
lpBitsInfo 情報ヘッダへのポインタを指定します
iUsage - カラー情報フラグを指定します
dwRop - ラスタオペレーションを指定します

戻り値 - 走査線の数。失敗すると GDI_ERROR

iUsage には次の定数のいずれかを指定します

定数解説
DIB_PAL_COLORS カラーテーブルに論理パレットに対する
16 ビットインデックスが格納されている
DIB_RGB_COLORS カラーテーブルに RGB 値が格納されている

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 に対応する色 (デフォルトは白) で
コピー先の長方形を塗りつぶします



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