EternalWindows
ビットマップ / 透過と半透明

今回は、ビットマップの特定の色を透過して描画する関数と、 ビットマップを半透明にして描画する関数を取り上げます。 次に示すTransparentBltは、指定した色を透過してビットマップを描画します。

BOOL TransparentBlt(
  HDC hdcDest,
  int xoriginDest,
  int yoriginDest,
  int wDest,
  int hDest,
  HDC hdcSrc,
  int xoriginSrc,
  int yoriginSrc,
  int wSrc,
  int hSrc,
  UINT crTransparent
);

hdcDestは、コピー先のデバイスコンテキストのハンドルを指定します。 xoriginDestは、コピー先のx座標を指定します。 yoriginDestは、コピー先のy座標を指定します。 wDestは、コピーする幅を指定します。 hDestは、コピーする高さを指定します。 hdcSrcは、コピー元のデバイスコンテキストのハンドルを指定します。 xoriginSrcは、コピー元の開始位置を示すx座標を指定します。 yoriginSrcは、コピー元の開始位置を示すy座標を指定します。 wSrcは、コピー元の幅を指定します。 hSrcは、コピー元の幅を指定します。 crTransparentは、透過する色を指定します。 この色のピクセルは、コピーされることはありません。

次に示すAlphaBlendは、ビットマップを半透明にして描画します。

BOOL AlphaBlend(
  HDC hdcDest,
  int xoriginDest,
  int yoriginDest,
  int wDest,
  int hDest,
  HDC hdcSrc,
  int xoriginSrc,
  int yoriginSrc,
  int wSrc,
  int hSrc,
  BLENDFUNCTION ftn
);

hdcDestは、コピー先のデバイスコンテキストのハンドルを指定します。 xoriginDestは、コピー先のx座標を指定します。 yoriginDestは、コピー先のy座標を指定します。 wDestは、コピーする幅を指定します。 hDestは、コピーする高さを指定します。 hdcSrcは、コピー元のデバイスコンテキストのハンドルを指定します。 xoriginSrcは、コピー元の開始位置を示すx座標を指定します。 yoriginSrcは、コピー元の開始位置を示すy座標を指定します。 wSrcは、コピー元の幅を指定します。 hSrcは、コピー元の幅を指定します。 ftnは、アルファ値などを格納するBLENDFUNCTION構造体を指定します。 この構造体は、次のように定義されています。

typedef struct _BLENDFUNCTION {
  BYTE BlendOp;
  BYTE BlendFlags;
  BYTE SourceConstantAlpha;
  BYTE AlphaFormat;
} BLENDFUNCTION, *PBLENDFUNCTION, *LPBLENDFUNCTION;

BlendOpは、AC_SRC_OVERを指定します。 BlendFlagsは、0を指定します。 SourceConstantAlphaは、0から255までのアルファ値を指定します。 0なら完全に透明となり、255ならば不透明、128ならば半透明になります。 AlphaFormatは、32ビットマップでない場合は0を指定します。 32ビットマップの場合は、ビットマップに設定されたアルファ値を参照するためにAC_SRC_ALPHAを指定します。

今回のプログラムは、TransparentBltとAlphaBlendの呼び出す例を示しています。

#include <windows.h>

#pragma comment (lib, "msimg32.lib")

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR      szAppName[] = TEXT("sample");
	HWND       hwnd;
	MSG        msg;
	WNDCLASSEX wc;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WindowProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hinst;
	wc.hIcon         = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	wc.hCursor       = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = szAppName;
	wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	
	if (RegisterClassEx(&wc) == 0)
		return 0;

	hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
	if (hwnd == NULL)
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
	
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int)msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static HDC     hdcMem = NULL;
	static HBITMAP hbmpMem = NULL;
	static HBITMAP hbmpMemPrev = NULL;
	
	switch (uMsg) {

	case WM_CREATE: {
		HDC hdc;

		hdc = GetDC(hwnd);
		
		hdcMem = CreateCompatibleDC(hdc);
		hbmpMem = (HBITMAP)LoadImage(NULL, TEXT("sample.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
		if (hbmpMem == NULL) {
			ReleaseDC(hwnd, hdc);
			return -1;
		}

		hbmpMemPrev = (HBITMAP)SelectObject(hdcMem, hbmpMem);

		ReleaseDC(hwnd, hdc);

		return 0;
	}

	case WM_PAINT: {
		int           nWidth;
		int           nHeight;
		HDC           hdc;
		BITMAP        bm;
		PAINTSTRUCT   ps;
		BLENDFUNCTION blendFunction;
		
		GetObject(hbmpMem, sizeof(BITMAP), &bm);
		nWidth = bm.bmWidth;
		nHeight = bm.bmHeight;

		hdc = BeginPaint(hwnd, &ps);

		TransparentBlt(hdc, 0, 0, nWidth, nHeight, hdcMem, 0, 0, nWidth, nHeight, RGB(0, 255, 0));
		
		blendFunction.BlendOp             = AC_SRC_OVER;
		blendFunction.BlendFlags          = 0;
		blendFunction.SourceConstantAlpha = 128;
		blendFunction.AlphaFormat         = 0;
		AlphaBlend(hdc, 0, nHeight + 10, nWidth, nHeight, hdcMem, 0, 0, nWidth, nHeight, blendFunction);

		EndPaint(hwnd, &ps);

		return 0;
	}

	case WM_DESTROY:
		if (hdcMem != NULL) {
			if (hbmpMem != NULL) {
				SelectObject(hdcMem, hbmpMemPrev);
				DeleteObject(hbmpMem);
			}
			DeleteDC(hdcMem);
		}
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

TransparentBltの最後の引数には、RGB(0, 255, 0)を指定しています。 よって、この色のピクセルは描画されないことになります。 AlphaBlendを呼び出すには、事前にBLENDFUNCTION構造体を初期化することになります。 SourceConstantAlphaに128を指定していることから、ビットマップはちょうど半透明に描画されることになります。


戻る