アドベンチャーゲームなどではメッセージウィンドウが半透明になっていて 下の絵が透けているという画面が良く見られます。Direct X を使えば 簡単に出来そうですが(と言っていも Direct X は良く知らないので 出来るかどうかしりませんが)、GDI の場合はそんな API は無いので 自分でルーチンを書かなければなりません。
半透明処理の基本的な考え方は、元の絵とマスクしたい色を足して平均を 取るということです。つまり、元の絵のある座標(x,y) の点の色が RGB(r,g,b) で、マスクしたい色が RGB(R,G,B) だとしたら、半透明処理を した後の点(x,y) の色は RGB((r+R)/2,(g+G)/2,(b+B)/2) となります。
まあ、詳しくは下のソースをみて下さい。 CreateSemiTransBmp() が実際に半透明処理を行っている関数で、元の ビットマップ(hSrcBitmap) の矩形範囲(x,y)-(x+FWIDTH,y+FHEIGHT) に 対して半透明処理をして 24bitDIB(hDib)に保存しています。結果は こんなふうになります。
// 半透明処理サンプル 99/2/17 // (C) tokai@fides.dti.ne.jp #include < windows.h> #define WINWIDTH 480 // ウィンドウの幅 #define WINHEIGHT 180 // ウィンドウの高さ #define FWIDTH 100 // 枠の幅 #define FHEIGHT 50 // 枠の高さ LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); VOID CreateSemiTransBmp(HDC,HBITMAP,HBITMAP,LPBYTE,LONG,LONG,RGBQUAD); char szClassName[] = "HANTOMEI"; int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPreInst, LPSTR lpszCmdLine,int nCmdShow) { HWND hWnd; MSG lpMsg; WNDCLASS wndClass; // ウィンドウ登録 if (!hPreInst) { wndClass.style=CS_HREDRAW|CS_VREDRAW; wndClass.lpfnWndProc=WndProc; wndClass.cbClsExtra=0; wndClass.cbWndExtra=0; wndClass.hInstance=hInst; wndClass.hIcon= NULL; wndClass.hCursor=LoadCursor(NULL, IDC_ARROW); wndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); wndClass.lpszMenuName=NULL; wndClass.lpszClassName=szClassName; if (!RegisterClass(&wndClass)) return FALSE; } // ウィンドウ作成 hWnd = CreateWindow(szClassName, "半透明",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT, WINWIDTH,WINHEIGHT,NULL,NULL,hInst,NULL); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // メッセージループ while (GetMessage(&lpMsg, NULL, 0, 0)) { TranslateMessage(&lpMsg); DispatchMessage(&lpMsg); } return (lpMsg.wParam); } // プロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { static HINSTANCE hInst; HDC hDC,hMemDC; RECT rt; static HDC hBufDC; static HBITMAP hBufBit,hBgBitmap,hDib; static LPBYTE lpDibBuf,lpDibData; static LPBITMAPINFO lpBitInfo; static RGBQUAD rgbMask; CHAR szStr[256]; switch (msg) { case WM_CREATE: // 初期化 // インスタンス取得 hInst = (HINSTANCE)GetWindowLong(hWnd,GWL_HINSTANCE); // ビットマップロード(test.bmp) hBgBitmap = (HBITMAP)LoadImage(hInst,"test.bmp", IMAGE_BITMAP,0,0,LR_LOADFROMFILE); // 裏画面の作成 GetClientRect(hWnd,&rt); hDC = GetDC(hWnd); hBufBit = CreateCompatibleBitmap(hDC,rt.right - rt.left, rt.bottom - rt.top); hBufDC = CreateCompatibleDC(hDC); SelectObject(hBufDC,hBufBit); ReleaseDC(hWnd,hDC); // ビットマップ貼り付け hMemDC = CreateCompatibleDC(hBufDC); SelectObject(hMemDC,hBgBitmap); BitBlt(hBufDC,0,0,rt.right - rt.left,rt.bottom - rt.top, hMemDC,0,0,SRCCOPY); DeleteDC(hMemDC); // 24bit DIB 作成 // ビットマップインフォ構造体設定 lpBitInfo = (LPBITMAPINFO)GlobalAlloc(GPTR,sizeof(BITMAPINFO)); lpBitInfo-> bmiHeader.biSize=sizeof(BITMAPINFOHEADER); lpBitInfo-> bmiHeader.biWidth=FWIDTH; lpBitInfo-> bmiHeader.biHeight=FHEIGHT; lpBitInfo-> bmiHeader.biPlanes=1; lpBitInfo-> bmiHeader.biBitCount=24; // 24 bit lpBitInfo-> bmiHeader.biCompression=BI_RGB; // 非圧縮 hDC = GetDC(hWnd); hDib = CreateDIBSection(hDC,lpBitInfo,0,(VOID**)&lpDibData, NULL, 0); ReleaseDC(hWnd,hDC); // マスクの色設定 rgbMask.rgbBlue=0; rgbMask.rgbGreen=0; rgbMask.rgbRed=0; break; case WM_PAINT: // 描画(再描画のみ) PAINTSTRUCT ps; hDC = BeginPaint(hWnd,&ps); BitBlt(hDC,ps.rcPaint.left,ps.rcPaint.top, ps.rcPaint.right-ps.rcPaint.left, ps.rcPaint.bottom-ps.rcPaint.top, hBufDC,ps.rcPaint.left,ps.rcPaint.top,SRCCOPY); ReleaseDC(hWnd,hDC); break; case WM_LBUTTONDOWN: // 左ボタン押した GetClientRect(hWnd,&rt); // 半透明処理 CreateSemiTransBmp(hBufDC,hBgBitmap,hDib,lpDibData, LOWORD(lp),HIWORD(lp),rgbMask); hMemDC = CreateCompatibleDC(hBufDC); // ビットマップ貼り付け SelectObject(hMemDC,hBgBitmap); BitBlt(hBufDC,0,0,rt.right - rt.left,rt.bottom - rt.top, hMemDC,0,0,SRCCOPY); // DIB 貼り付け SelectObject(hMemDC,hDib); BitBlt(hBufDC,LOWORD(lp),HIWORD(lp),FWIDTH,FHEIGHT, hMemDC,0,0,SRCCOPY); DeleteDC(hMemDC); // 文字描画 SetBkMode(hBufDC,TRANSPARENT); SetTextColor(hBufDC,RGB(255,255,0)) ; rt.left = LOWORD(lp); rt.top = HIWORD(lp); rt.right = rt.left + FWIDTH; rt.bottom = rt.top + FHEIGHT; wsprintf(szStr,"半透明っす"); DrawText(hBufDC,szStr,strlen(szStr),&rt, DT_CENTER|DT_SINGLELINE|DT_VCENTER); InvalidateRect(hWnd,NULL,FALSE); break; case WM_CLOSE: // クローズ // 裏画面開放 DeleteDC(hBufDC); DeleteObject(hBufBit); // ビットマップ開放 DeleteObject(hBgBitmap); DeleteObject(hDib); GlobalFree(lpBitInfo); DestroyWindow(hWnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return(DefWindowProc(hWnd, msg, wp, lp)); } return (0L); } // hSrcBitmap の一部分を半透明処理して hDib にセットする関数 VOID CreateSemiTransBmp(HDC hDC, HBITMAP hSrcBitmap, // 元のビットマップ HBITMAP hDib, // DIB のハンドル LPBYTE lpDibData, // DIB のデータ配列 LONG x, LONG y, // 座標 RGBQUAD rgbMask // マスク ){ HDC hSrcDC,hDestDC; LONG dx,dy; WORD r,g,b; // 画像コピー hSrcDC = CreateCompatibleDC(hDC); hDestDC = CreateCompatibleDC(hDC); SelectObject(hSrcDC,hSrcBitmap); SelectObject(hDestDC,hDib); BitBlt(hDestDC,0,0,FWIDTH,FHEIGHT,hSrcDC,x,y,SRCCOPY); DeleteDC(hSrcDC); DeleteDC(hDestDC); // 半透明処理 for(dy = 0;dy< FHEIGHT;dy++) for(dx = 0;dx< FWIDTH;dx++) { b = (WORD)lpDibData[(dy*FWIDTH+dx)*3]; g = (WORD)lpDibData[(dy*FWIDTH+dx)*3+1]; r = (WORD)lpDibData[(dy*FWIDTH+dx)*3+2]; lpDibData[(dy*FWIDTH+dx)*3] = (BYTE)((b+(WORD)rgbMask.rgbBlue)>> 1); lpDibData[(dy*FWIDTH+dx)*3+1] = (BYTE)((g+(WORD)rgbMask.rgbGreen)>> 1); lpDibData[(dy*FWIDTH+dx)*3+2] = (BYTE)((r+(WORD)rgbMask.rgbRed)>> 1); } }