天天看點

MFC GDI繪圖(3) 圖檔透明化

本系列文章由zhmxy555編寫,轉載請注明出處。
 http://blog.csdn.net/zhmxy555/article/details/7338082

透明效果

由于所有的圖檔案都是以矩形來儲存的,我們也許會需要把一張怪獸圖檔貼到視窗的背景圖上,而這種情況下如果直接進行貼圖,結果如下圖:

MFC GDI繪圖(3) 圖檔透明化

這似乎不是我們想要的結果。

為了得到透明效果,我們需要運用到BitBlt()貼圖函數以及其參數Raster的值來将圖檔中不必要的部分去掉(又稱去背),使得圖中的主題可以與背景完美融合。

制作透明效果有很多種方法,但是基本上都是利用貼圖時不同的Raster運算,通過轉換而産生相同的透明效果。在這裡先來介紹一種透明運算的方法。

我們以圖中的恐龍為例子,首先準備一張位圖,如下圖。

MFC GDI繪圖(3) 圖檔透明化

圖中的左邊的圖是要去背并貼到背景上的前景圖。右邊的黑白圖稱為“屏蔽圖”,在透明的過程中會用到它。要把去背的位圖與屏蔽圖合并成同一張圖,透明的時候再按照需要來進行裁切。可以把它分成兩張圖,但是這樣程式必須運作兩次圖檔案加載的操作。

有了屏蔽圖就可以利用貼圖函數來産生透明效果了,所需的貼圖步驟如下:

<1>将屏蔽圖與背景圖做"AND"運算,Raster值為SRCAND,貼到目的地DC中。

<2>将前景圖與背景圖做"OR"運算,Raster值為SRCPAINT,貼到目的地DC中。

為什麼經過上面兩個操作就能産生透明的效果呢?看下圖就了解了:

MFC GDI繪圖(3) 圖檔透明化

下面具體說明上面兩個步驟所産生的圖點色彩的變化。

1.屏蔽圖與背景圖做"AND"運算

<1>屏蔽圖中的黑色部分與背景圖做"AND"運算:

MFC GDI繪圖(3) 圖檔透明化
<2>屏蔽圖中的白色部分與背景圖做"AND"運算:
MFC GDI繪圖(3) 圖檔透明化
進過這一運算所産生的結果如下圖
MFC GDI繪圖(3) 圖檔透明化

2.前景圖與背景圖做"OR"運算

<1>前景圖中的彩色部分與圖第一步得到的“黑色恐龍”圖做"OR"運算:

MFC GDI繪圖(3) 圖檔透明化
<2>前景圖中的黑色部分與第一步得到的“黑色恐龍”圖做"OR"運算:
MFC GDI繪圖(3) 圖檔透明化
經過這一運算後所顯示的畫面就是所需的透明圖了,如下圖所示:
MFC GDI繪圖(3) 圖檔透明化

下面我們來看看實作上述透明貼圖效果的源代碼

[cpp]  view plain copy print ?

MFC GDI繪圖(3) 圖檔透明化
MFC GDI繪圖(3) 圖檔透明化
  1. #include "stdafx.h"  
  2. //全局變量聲明  
  3. HINSTANCE hInst;  
  4. HBITMAP bg,dra;        //聲明兩個位圖對象,分别存儲背景圖與前景恐龍圖  
  5. HDC  mdc;       //聲明一個記憶體DC"mdc",用來暫存位圖  
  6. //全局函數聲明  
  7. ATOM     MyRegisterClass(HINSTANCE hInstance);  
  8. BOOL     InitInstance(HINSTANCE, int);  
  9. LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);  
  10. void     MyPaint(HDC hdc);  
  11. ****Winmain函數,程式入口點函數**************************************  
  12. int APIENTRY WinMain(HINSTANCE hInstance,  
  13.                      HINSTANCE hPrevInstance,  
  14.                      LPSTR     lpCmdLine,  
  15.                      int       nCmdShow)  
  16. {  
  17. MSG msg;  
  18. MyRegisterClass(hInstance);  
  19. if (!InitInstance (hInstance, nCmdShow))   
  20. {  
  21. return FALSE;  
  22. }  
  23. //消息循環  
  24. while (GetMessage(&msg, NULL, 0, 0))   
  25. {  
  26. TranslateMessage(&msg);  
  27. DispatchMessage(&msg);  
  28. }  
  29. return msg.wParam;  
  30. }  
  31. //****設計一個視窗類,類似填空題,使用視窗結構體*************************  
  32. ATOM MyRegisterClass(HINSTANCE hInstance)  
  33. {  
  34. WNDCLASSEX wcex;  
  35. wcex.cbSize = sizeof(WNDCLASSEX);   
  36. wcex.style   = CS_HREDRAW | CS_VREDRAW;  
  37. wcex.lpfnWndProc    = (WNDPROC)WndProc;  
  38. wcex.cbClsExtra  = 0;  
  39. wcex.cbWndExtra  = 0;  
  40. wcex.hInstance   = hInstance;  
  41. wcex.hIcon   = NULL;  
  42. wcex.hCursor     = NULL;  
  43. wcex.hCursor     = LoadCursor(NULL, IDC_ARROW);  
  44. wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);  
  45. wcex.lpszMenuName   = NULL;  
  46. wcex.lpszClassName  = "canvas";  
  47. wcex.hIconSm     = NULL;  
  48. return RegisterClassEx(&wcex);  
  49. }  
  50. //****初始化函數*************************************  
  51. // 1.建立與視窗DC相容的記憶體DC  
  52. // 2.從檔案加載背景圖與恐龍圖  
  53. BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)  
  54. {  
  55. HWND hWnd;  
  56. HDC hdc;  
  57. hInst = hInstance;  
  58. hWnd = CreateWindow("canvas", "繪圖視窗" , WS_OVERLAPPEDWINDOW,  
  59. CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);  
  60. if (!hWnd)  
  61. {  
  62. return FALSE;  
  63. }  
  64. MoveWindow(hWnd,10,10,600,450,true);  
  65. ShowWindow(hWnd, nCmdShow);  
  66. UpdateWindow(hWnd);  
  67. hdc = GetDC(hWnd);                     //獲得視窗DC  
  68. mdc = CreateCompatibleDC(hdc);           //建立與視窗相容的記憶體DC(mdc)  
  69. bg = (HBITMAP)LoadImage(NULL,"bg.bmp",IMAGE_BITMAP,600,450,LR_LOADFROMFILE);   
  70. //J加載背景圖到bg中  
  71. dra = (HBITMAP)LoadImage(NULL,"dra.bmp",IMAGE_BITMAP,170,99,LR_LOADFROMFILE);   
  72. //加載恐龍圖到dra中  
  73. MyPaint(hdc);  
  74. ReleaseDC(hWnd,hdc);  
  75. return TRUE;  
  76. }  
  77. //****自定義繪圖函數*********************************  
  78. //透明貼圖  
  79. void MyPaint(HDC hdc)  
  80. {  
  81. SelectObject(mdc,bg);  
  82. BitBlt(hdc,0,0,600,450,mdc,0,0,SRCCOPY);    //先将背景圖貼到顯示視窗中  
  83. SelectObject(mdc,dra);                      //選用恐龍圖到"mdc"中  
  84. BitBlt(hdc,280,320,85,99,mdc,85,0,SRCAND);//進行制作貼圖的第一步驟,即将屏蔽圖與背景圖做"AND"運算,屏蔽圖在整張恐龍圖中,最左上角起始位置點得坐标為(85,0),BitBlt()函數中最後一個Raster參數值設定為SRCAND。  
  85. BitBlt(hdc,280,320,85,99,mdc,0,0,SRCPAINT);//進行制作透明貼圖的第二步驟,即将前景圖與背景圖做"OR"運算,前景圖在整張恐龍圖中,最左上角起始位置的坐标為(0,0),BitBlt()函數最後一個參數值設定為SRCPAINT。  
  86. }  
  87. //****消息處理函數**********************************  
  88. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  
  89. {  
  90. PAINTSTRUCT ps;  
  91. HDC hdc;  
  92. switch (message)  
  93. {  
  94. case WM_PAINT:   //視窗重繪消息  
  95. hdc = BeginPaint(hWnd, &ps);  
  96. MyPaint(hdc);  
  97. EndPaint(hWnd, &ps);  
  98. break;  
  99. case WM_DESTROY:     //視窗結束消息  
  100. DeleteDC(mdc);  
  101. DeleteObject(bg);  
  102. DeleteObject(dra);  
  103. PostQuitMessage(0);  
  104. break;  
  105. default:     //其他消息  
  106. return DefWindowProc(hWnd, message, wParam, lParam);  
  107.    }  
  108.    return 0;  
  109. }  
最後程式的運作結果為:
MFC GDI繪圖(3) 圖檔透明化

通過BitBlt()貼圖函數及Raster運算值的設定,很簡單地就做出了想要的透明效果,這種方法在設計2D遊戲的一些畫面内容時使用相當頻繁。

最後我說明一個非常關鍵的問題(多謝yao050421103 的提醒),而這點由恰恰依賴于美工設計師們。我們在準備位圖資源的時候,前景圖部分絕對不能包含背景圖的顔色,否則,就不會得到我們預期的結果。

還要指出的一個地方是,前景圖的需要還原為背景色的部分一定要為黑色

繼續閱讀