イメージリスト


イメージの集合

イメージリストは、同一サイズのイメージを集めた画像のパッケージオブジェクトで
高度な画像の操作や透過処理等に用いることができます
ゲームや、高度な画像表現を使ったコントロールなどには必須の機能と言えます

イメージリストは、ビットマップ、アイコン、カーソルを含ませることができ
これらのイメージを複数保有し、インデックスで特定のイメージを描画できます
イメージリストを作成するには ImageList_Create() 関数を使います
HIMAGELIST ImageList_Create(
	int cx , int cy ,
	UINT flags, 	
	int cInitial , int cGrow	
);
cx には画像の幅を、cy には画像の高さを指定します
flags には、作成するイメージリストのタイプを表すフラグを指定します
この引数には、次の定数を組み合わせて指定することができます

定数解説
ILC_COLOR デフォルトの動作を示す
通常は ILC_COLOR4 が用いられる
ILC_COLOR4 4ビットDIBセクションを使用する
ILC_COLOR8 8ビットDIBセクションを使用する
ILC_COLOR16 16ビットDIBセクションを使用する
ILC_COLOR24 24ビットDIBセクションを使用する
ILC_COLOR32 32ビットDIBセクションを使用する
ILC_COLORDDB DDBを使用する
ILC_MASK マスクを使用する
イメージリストには、通常のビットマップと
マスクビットマップがセットで扱われる

cInitial には、イメージリスト内の初期イメージ数を指定します
イメージリストは複数のイメージを管理することが可能であり
この引数に、抱合するであろうイメージの数を指定します

cGrow には、拡張可能なイメージ数を指定します
これは、イメージリストのサイズを変更しなければならなくなった時に使用されます

関数が成功すればイメージリストのハンドルが、失敗すれば NULL が返ります
イメージリストのハンドルは HIMAGELIST 型のハンドルです
不用になったイメージリストは ImageList_Destroy() で破棄します

BOOL ImageList_Destroy(HIMAGELIST himl);

himl には、破棄するイメージリストのハンドルを指定します
成功すれば 0 以外、失敗すれば 0 が返ります

次に、イメージリストを使うには、まずイメージを追加する必要があります
イメージリストに画像を追加するには、いくつかの方法がありますが
ここでは、アイコン、またはカーソルを追加する ImageList_AddIcon() を使います

int ImageList_AddIcon(HIMAGELIST himl , HICON hicon);

himl には、イメージリストのハンドルを指定します
hicon は、追加するアイコン、またはカーソルのハンドルを指定します
成功すれば新しいイメージのインデックスが、失敗すれば -1 が返ります

イメージリストにイメージが追加されたなら、あとは必要な時に描画するだけです
イメージリスト内のイメージを描画するには ImageList_Draw() を使います
BOOL ImageList_Draw(
	HIMAGELIST himl , int i ,
	HDC hdcDst,
	int x , int y ,
	UINT fStyle
);
himl には、描画するイメージリストのハンドルを
i は、イメージリスト中の描画するイメージのインデックスを指定します

hdcDst は描画先にデバイスコンテキストのハンドルを指定します
x には描画する位置の X 座標、y には Y 座標をそれぞれ指定します

fStyle には、描画スタイルを指定します
この引数には、以下の定数のいずれかを指定できます

定数解説
ILD_BLEND25 ILD_FOCUS と同じ
ILD_FOCUS システムハイライトカラーと25%混合して描画する
マスクが含まれていない場合は無視される
ILD_BLEND50 ILD_BLEND と同じ
ILD_SELECTED ILD_BLEND と同じ
ILD_BLEND システムハイライトカラーと50%混合して描画する
マスクが含まれていない場合は無視される
ILD_MASK マスクを描画する
ILD_NORMAL イメージリストの背景色を使って描画する
背景色が CLR_NONE であれば、マスクを使って透過的に描画する
ILD_TRANSPARENT 背景色に関係なく、マスクを使って透過的に描画する
マスクが含まれていない場合は無視される

関数が成功すれば 0 以外、失敗すれば 0 が返ります

より詳しい描画を行いたければ ImageList_DrawEx() という関数があります
これは、描画するイメージのオフセットや、背景色なども同時に指定できます
BOOL ImageList_DrawEx(
	HIMAGELIST himl , int i,
	HDC hdcDst ,
	int x , int y ,
	int dx , int dy ,
	COLORREF rgbBk , COLORREF rgbFg ,
	UINT fStyle
);
第4引数までの引数と、最後の fStyle 引数、及び戻り値は ImageList_Draw() と同じです

dx には、描画するイメージの左上からの水平オフセットを
dy には、垂直オフセットを指定します

rgbBk は、イメージの背景色を、rgbFg には前景色を指定します
背景色はマスクを使用した時に、前景色はシステムハイライトカラーと混合して描画した時に
それぞれ指定した色が、イメージの描画に反映されます
#define OEMRESOURCE
#include <windows.h>
#include <commctrl.h>
#define TITLE TEXT("Kitty on your lap")

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	HDC hdc;
	PAINTSTRUCT ps;
	static int iImageIndex = 0;
	static HIMAGELIST hImg;

	switch (msg) {
	case WM_DESTROY:
		ImageList_Destroy(hImg);
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		InitCommonControls();
		hImg = ImageList_Create(32 , 32 , ILC_COLOR4 |ILC_MASK , 2 , 1);
		ImageList_AddIcon(hImg , LoadIcon(NULL , IDI_QUESTION));
		ImageList_AddIcon(hImg , LoadIcon(NULL , IDI_ASTERISK));
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hWnd , &ps);
		ImageList_Draw(hImg , iImageIndex , hdc , 10 , 10 , ILD_NORMAL);
		EndPaint(hWnd , &ps);
		return 0;
	case WM_LBUTTONUP:
		iImageIndex = iImageIndex ? 0 : 1;
		InvalidateRect(hWnd , NULL , TRUE);
		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") , TITLE ,
			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;
}


これは、イメージリストに二つの標準アイコンを埋めこんだプログラムです
イメージリストには、疑問符とアスタリスクアイコンの二つのイメージを追加しています
クライアント領域を左クリックするたびに、それらのアイコンが切りかえられます

一度イメージリストに追加した画像のハンドルは、削除しても問題はありません
そのため、明示的に作成した独自のビットマップの場合は追加後に削除するべきですが
イメージリストは、標準のアイコンやビットマップであれば、自動的に破棄してくれます
ビットマップを追加するには ImageList_Add() を用います
これは、アイコンと異なり非マスクビットマップとマスクビットマップを指定します
マスク処理を望まなければ、マスクビットマップは無視することができます
int ImageList_Add(
	HIMAGELIST himl,
	HBITMAP hbmImage , HBITMAP hbmMask
);
himl にはイメージリストのハンドルを指定します
hbmImage は、追加するイメージが含まれているビットマップのハンドルを
hbmMask は、イメージのマスクが含まれているビットマップのハンドルを指定します
イメージリストがマスクを使わないのであれば、この引数は無視されます
成功すれば新しいイメージのインデックスが、失敗すれば -1 が返ります

上のプログラムで示した様に、単純に画像を表示したいのであれば
マスクを用いずに、単純に画像データを追加するだけで、上と同じ扱いができます

今回は、以下のような二つのビットマップを用意してみました
左は、画面に表示させたいキャラクタの画像で、右はマスクデータです
これらの画像を用いることで、キャラクタの背景を透過させたいと思います

ビットマップデータ マスクデータ

因みに、マスクデータは正確にキャラクタを黒色で塗りつぶした
モノクロのビットマップでなければならなりません
この JPEG データは圧縮による画像の劣化で、マスクデータが壊れています
プログラムの実験を行う時は、各自、描画部分を黒で塗りつぶしたビットマップを用意してください
/*リソーススクリプト*/
KITTY BITMAP "kitty.bmp"
MASK BITMAP "mask.bmp"
#include <windows.h>
#include <commctrl.h>
#define TITLE TEXT("Kitty on your lap")

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	HDC hdc;
	PAINTSTRUCT ps;
	HBITMAP hKitty , hMask;
	static HIMAGELIST hImg;

	switch (msg) {
	case WM_DESTROY:
		ImageList_Destroy(hImg);
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		InitCommonControls();
		hImg = ImageList_Create(185 , 300 , ILC_COLOR16 |ILC_MASK , 1 , 1);
		hKitty = LoadBitmap(((LPCREATESTRUCT)lp)->hInstance , TEXT("KITTY"));
		hMask = LoadBitmap(((LPCREATESTRUCT)lp)->hInstance  , TEXT("MASK"));
		ImageList_Add(hImg , hKitty , hMask);

		DeleteObject(hKitty);
		DeleteObject(hMask);
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hWnd , &ps);
		ImageList_Draw(hImg , 0 , hdc , 10 , 10 , ILD_NORMAL);
		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(GRAY_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

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

	hWnd = CreateWindow(
			TEXT("KITTY") , TITLE ,
			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;
}


このプログラムを実行すると、上の図のように表示されます
キャラクタの背景部分が透過していることを確認できますね
透過を確認できるようにするため、クライアント領域の背景色をグレーにしています

Win32 API でゲームを作る時、背景とキャラクタの画像を分けて
これを合成するテクニックとして、このような方法をとることができるでしょう
背景の透過は、ラスタオペレーションとリージョンを駆使したり
ビットマップのピクセルに直接アクセスすれば可能ですが
イメージリストを使えば、こうして一貫したオブジェクトとして扱うことができるようになります


ImageList_Create()

HIMAGELIST ImageList_Create(
	int cx , int cy ,
	UINT flags, 	
	int cInitial , int cGrow	
);
イメージリストを作成します

cx - 画像の幅を指定します
cy - 画像の高さを指定します
flags - 作成するイメージリストのタイプを表すフラグを指定します
cInitial - イメージリスト内の初期イメージ数を指定します cGrow - 拡張可能なイメージ数を指定します

戻り値 - 成功すればイメージリストのハンドルが、失敗すれば NULL

flags には以下の定数を組み合わせて指定することができます

定数解説
ILC_COLOR デフォルトの動作を示す
通常は ILC_COLOR4 が用いられる
ILC_COLOR4 4ビットDIBセクションを使用する
ILC_COLOR8 8ビットDIBセクションを使用する
ILC_COLOR16 16ビットDIBセクションを使用する
ILC_COLOR24 24ビットDIBセクションを使用する
ILC_COLOR32 32ビットDIBセクションを使用する
ILC_COLORDDB DDBを使用する
ILC_MASK マスクを使用する
イメージリストには、通常のビットマップと
マスクビットマップがセットで扱われる

ImageList_Destroy()

BOOL ImageList_Destroy(HIMAGELIST himl);

イメージリストのハンドルを破棄します

himl - 破棄するイメージリストのハンドルを指定します

戻り値 - 成功すれば 0 以外、失敗すれば 0

ImageList_AddIcon()

int ImageList_AddIcon(HIMAGELIST himl , HICON hicon);

イメージリストに、アイコン、またはカーソルのイメージを追加します

himl - イメージリストのハンドルを指定します
hicon - 追加するアイコン、またはカーソルのハンドルを指定します

戻り値 - 新しいイメージのインデックス、失敗すれば -1

ImageList_Draw()

BOOL ImageList_Draw(
	HIMAGELIST himl , int i ,
	HDC hdcDst,
	int x , int y ,
	UINT fStyle
);
イメージリストの指定イメージを、デバイスコンテキストに描画します

himl - 描画するイメージリストのハンドルを指定します
i - イメージリスト中の描画するイメージのインデックスを指定します
hdcDst - 描画先にデバイスコンテキストのハンドルを指定します
x - 描画する位置の X 座標を指定します
y - 描画する位置の Y 座標を指定します
fStyle - 描画スタイルを指定します

戻り値 - 成功すれば 0 以外、失敗すれば

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

定数解説
ILD_BLEND25 ILD_FOCUS と同じ
ILD_FOCUS システムハイライトカラーと25%混合して描画する
マスクが含まれていない場合は無視される
ILD_BLEND50 ILD_BLEND と同じ
ILD_SELECTED ILD_BLEND と同じ
ILD_BLEND システムハイライトカラーと50%混合して描画する
マスクが含まれていない場合は無視される
ILD_MASK マスクを描画する
ILD_NORMAL イメージリストの背景色を使って描画する
背景色が CLR_NONE であれば、マスクを使って透過的に描画する
ILD_TRANSPARENT 背景色に関係なく、マスクを使って透過的に描画する
マスクが含まれていない場合は無視される

ImageList_DrawEx()

BOOL ImageList_DrawEx(
	HIMAGELIST himl , int i,
	HDC hdcDst ,
	int x , int y ,
	int dx , int dy ,
	COLORREF rgbBk , COLORREF rgbFg ,
	UINT fStyle
);
イメージリストの指定イメージを、デバイスコンテキストに描画します

himl - 描画するイメージリストのハンドルを指定します
i - イメージリスト中の描画するイメージのインデックスを指定します
hdcDst - 描画先にデバイスコンテキストのハンドルを指定します
x - 描画する位置の X 座標を指定します
y - 描画する位置の Y 座標を指定します
dx - 描画するイメージの左上からの水平オフセットを指定します
dy - 描画するイメージの左上からの垂直オフセットを指定します
rgbBk - イメージの背景色を指定します
rgbFg - イメージの前景色を指定します
fStyle - 描画スタイルを指定します

戻り値 - 成功すれば 0 以外、失敗すれば

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

定数解説
ILD_BLEND25 ILD_FOCUS と同じ
ILD_FOCUS システムハイライトカラーと25%混合して描画する
マスクが含まれていない場合は無視される
ILD_BLEND50 ILD_BLEND と同じ
ILD_SELECTED ILD_BLEND と同じ
ILD_BLEND システムハイライトカラーと50%混合して描画する
マスクが含まれていない場合は無視される
ILD_MASK マスクを描画する
ILD_NORMAL イメージリストの背景色を使って描画する
背景色が CLR_NONE であれば、マスクを使って透過的に描画する
ILD_TRANSPARENT 背景色に関係なく、マスクを使って透過的に描画する
マスクが含まれていない場合は無視される




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