透明顯示原理及其實現

  圖標顯示原理
  其實,Windows中隨處可見的圖標就是一個透明位圖的典型實例。
  圖標是由兩個單獨的位圖組成的。第一個位圖是由黑色(顏色位全爲0)背景與彩色圖標圖案組成的,該位圖將與當前屏幕顯示通過異或(XOR)操作結合起來,故稱其爲XOR位圖。第二個位圖是由白色(顏色位全爲1)背景與黑色(顏色位全爲0)圖標圖案組成的,該位圖將與當前屏幕顯示通過與(AND)操作結合起來,故稱其爲AND位圖。圖標的顯示是通過兩個步驟完成的:

  當前屏幕顯示與AND位圖通過AND操作結合起來;
  當前屏幕顯示與XOR位圖通過XOR操作結合起來。

  大家知道,1與任何數值AND操作的結果將維持原數值,而0與任何數值AND操作的結果則是0,因此在步驟1中,AND位圖中白色(1)與屏幕顯示經過AND操作後被原色彩屏蔽,而黑色(0)則將原色彩屏蔽。步驟1結束後,屏幕上將留下一個黑色的圖標圖案。在隨後的步驟2中,由於0與任何數值異或的結果都將是原數值,因此,XOR位圖與屏幕顯示經過異或操作後,位圖和屏幕中的黑色部分都將被各自對應的彩色部分屏蔽。步驟2結束後,一個形狀不規則的圖標圖案就出現在屏幕上了。這就是圖標顯示的原理。

       實現代碼(VC)

        畫透明位圖通常的方法是使用遮罩。所謂遮罩就是一張黑白雙色的位圖,他和要透明的位圖是對應的,遮罩描述了位圖中需要透明的部分,透明的部分是黑色的,而不透明的是白色的,白色的部分就是透明的部分。
        假設圖A是要畫的透明位圖,圖B是遮罩,圖A上是一個大寫字母A,字母是紅色的,背景是黑色的,圖B背景是白色的,上面有一個黑色的字母A和圖A的形狀是一樣的。
        比如我們要在一張藍天白雲的背景上透明地畫圖A,就是隻把紅色的字母A畫上去。我們可以先將圖B和背景進行與操作,再把圖B和背景進行或操作就可以了。

BOOL DrawTransparentBmp(HDC hdc, HBITMAP hbmp, RECT &rect, COLORREF colorTrans)
{
 HDC dcImage, dcTrans, dcImage24;
 HBITMAP holdbmp24, hbmp24;
 HBITMAP holdbmp;
 HBITMAP hbmpTrans, holdbmpTrans;

 // 創建內存DC
 dcImage = CreateCompatibleDC(hdc);
 dcTrans = CreateCompatibleDC(hdc);
 dcImage24 = CreateCompatibleDC(hdc);

 if (dcImage == NULL || dcTrans == NULL || dcImage24 == NULL)
 // Error: can't create compatible dc
 return FALSE;
 // 獲取圖像屬性
 BITMAP bmp;
 GetObject(hbmp, sizeof(bmp), &bmp);

 // 選擇圖片到目標DC中
 holdbmp = (HBITMAP)SelectObject(dcImage, hbmp);

 // 創建24位圖
PBITMAPINFO lpBmpInfo;

 lpBmpInfo = (BITMAPINFO*) new BYTE[sizeof(BITMAPINFOHEADER)];

 lpBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 lpBmpInfo->bmiHeader.biPlanes = 1;
 lpBmpInfo->bmiHeader.biBitCount = 24;//nBitCount;
 lpBmpInfo->bmiHeader.biCompression = BI_RGB;
 lpBmpInfo->bmiHeader.biSizeImage = 0;
 lpBmpInfo->bmiHeader.biClrUsed = 0;

 lpBmpInfo->bmiHeader.biWidth = bmp.bmWidth;
 lpBmpInfo->bmiHeader.biHeight = bmp.bmHeight;

 HDC dc = CreateCompatibleDC(NULL);

 // 生成新圖片
 LPVOID lpBits;
 hbmp24 =::CreateDIBSection(dc,lpBmpInfo,DIB_RGB_COLORS,
 &lpBits,NULL,0);

 DeleteDC(dc);
 delete lpBmpInfo;

 if (hbmp24 == NULL)
  // Error
  return FALSE;

 //將24位圖片選擇到位圖DC

ldbmp24 = (HBITMAP)SelectObject(dcImage24, hbmp24);

 // 將原圖繪製到24位圖中
itBlt(dcImage24, 0, 0, bmp.bmWidth, bmp.bmHeight, dcImage, 0, 0, SRCCOPY);

 // 創建Mask圖
 hbmpTrans = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
 if (hbmpTrans == NULL)
  // Error
  return FALSE;

 // 選擇Mask圖到dcTrans中
 holdbmpTrans = (HBITMAP)SelectObject(dcTrans, hbmpTrans);

 // 創建掩碼圖像(基於指定的顏色),即AND Mask圖
ORREF oldbkcolor = SetBkColor(dcImage24, colorTrans);
 BitBlt(dcTrans, 0, 0, bmp.bmWidth, bmp.bmHeight, dcImage24, 0, 0, SRCCOPY);

 SetBkColor(dcImage24, RGB(0,0,0));
 COLORREF oldtextcolor = SetTextColor(dcImage24, RGB(255,255,255));
 BitBlt(dcImage24, 0, 0, bmp.bmWidth, bmp.bmHeight, dcTrans, 0, 0, SRCAND);

 // 去除指定顏色
 COLORREF crOldBack, crOldText;
crOldBack = SetBkColor(hdc, RGB(255,255,255));
crOldText = SetTextColor(hdc, RGB(0,0,0));

 // 顯示透明圖
 StretchBlt(hdc, rect.left, rect.top, rect.right - rect.left,rect.bottom - rect.top,
 dcTrans, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCAND);
 StretchBlt(hdc, rect.left, rect.top, rect.right - rect.left,rect.bottom - rect.top,
 dcImage24, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCPAINT);

 // 恢復設置及其釋放資源
 SelectObject(dcImage, holdbmp);

 SelectObject(dcImage24, holdbmp24);
 SelectObject(dcTrans, holdbmpTrans);

 DeleteObject(hbmp24);
 DeleteObject(hbmpTrans);

 SetBkColor(hdc, crOldBack);
 SetTextColor(hdc, crOldText);

 SetBkColor(dcImage24, oldbkcolor);
 SetTextColor(dcImage24, oldtextcolor);

 DeleteDC(dcImage);
 DeleteDC(dcImage24);
 DeleteDC(dcTrans);

 return TRUE;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章