1. 程式人生 > 其它 >詳解用BitBlt實現透明貼圖

詳解用BitBlt實現透明貼圖

效果:

程式碼:

struct BitmapInDC {
  HDC m_hdc;
  HBITMAP m_hbmp;
  HGDIOBJ m_hbmpOld;
  BitmapInDC(HDC hdc, HBITMAP bmp) {
    m_hdc = CreateCompatibleDC(hdc);
    m_hbmp = bmp;
    m_hbmpOld = SelectObject(m_hdc, m_hbmp);
  }
  ~BitmapInDC() {
    SelectObject(m_hdc, m_hbmpOld);
    DeleteObject(m_hbmp);
    DeleteDC(m_hdc);
  }
  
operator HDC () { return m_hdc; } }; void TransparentBlt2(HDC hdc, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, UINT crTransparent) { BitmapInDC image(hdc, CreateCompatibleBitmap(hdc, nWidthDest, nHeightDest));
// HBITMAP CreateBitmap(nWidth, nHeight, nPlanes, nBitCount, lpBits); BitmapInDC mask(hdc, CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL)); // 把hdcSrc中的圖片複製到到image if (nWidthDest == nWidthSrc && nHeightDest == nHeightSrc) { BitBlt(image, 0, 0, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY); }
else { StretchBlt(image, 0, 0, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, SRCCOPY); } // 單色點陣圖每個畫素都是0或1。 // DWORD real_color[2] = { BkColor, TextColor }; // i = (color == BkColor ? 1 : 0); // 把image複製到mask. The transparent region as white (all 1), the non-transparent area Black (all 0). SetBkColor(image, crTransparent); BitBlt(mask, 0, 0, nWidthDest, nHeightDest, image, 0, 0, SRCCOPY); // This way, the background color (black) area of the mask bitmap is reserved in, and the foreground color (white) // part becomes black. SetBkColor(image, RGB(0,0,0)); SetTextColor(image, RGB(255,255,255)); BitBlt(image, 0, 0, nWidthDest, nHeightDest, mask, 0, 0, SRCAND); // SRCAND後,背景不變,主體成為黑洞 SetBkColor(hdc, RGB(255,255,255)); SetTextColor(hdc, RGB(0,0,0)); BitBlt(hdc, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, mask, 0, 0, SRCAND); // SRCPAINT combines the colors of the source and destination rectangles by using the Boolean OR operator. BitBlt(hdc, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, image, 0, 0, SRCPAINT); }
View Code

如果一張圖片只有兩種顏色,那麼每個畫素都可以用1個bit表示。這是bitmap這個名字的來歷。早期記憶體非常貴,有圖就不錯了。這種二值影象,可以把0顯示為黑色RGB(0, 0, 0),1顯示為白色RGB(255, 255, 255),也可以0顯示為RGB(0, 255, 0)等等。即先用0或1查顏色表(或者叫palette)。顏色“豐富”的圖片,可以每個畫素用4位表示,能顯示16種顏色,具體啥顏色還是查表。到了24位,就可以不用查表了,RGB各用8位表示。

灰度影象與二值影象不同。灰度影象可以有各種亮度的灰色,與“五彩斑斕的黑”不同,這個沒毛病。

BitBlt是Bit Block Transfer的縮寫,就是把一個矩形內的圖片資料複製到另外一個矩形。我有破電腦後遺症,傾向於苦思冥想如何優化,其實BitBlt的軟體實現可能就是for迴圈裡賦值和if. 高速一點點是memcpy,which用rep movsb (repeat move string byte), 最快還是硬體,這個雖然我不會,但對會者來說很簡單。

DC是device context(裝置上下文)的縮寫。裝置就是顯示卡。VGA是640x480, 每個畫素16種顏色,如何把一張8位顏色深度(color depth)的圖片顯示出來?24位的呢?這個我懶得想,只知道CreateBitmap和CreateCompatibleBitmap()都返回HBITMAP, 後者和DC相容(格式一樣),BitBlt時不用轉換,速度快。H代表Handle.

這個洋網站引用的是CSDN,哈哈。

CreateBitmap function (wingdi.h) - Win32 apps | Microsoft Learn說:The CreateBitmap function creates a device-dependent bitmap. After a bitmap is created, it can be selected into a device context by calling the SelectObject function. However, the bitmap can only be selected into a device context if the bitmap and the DC have the same format. [CreateBitmp()根本就沒有HDC這個引數,咋個device-dependent?]

CreateCompatibleBitmap function (wingdi.h) - Win32 apps | Microsoft Learn說:The CreateCompatibleBitmap function creates a bitmap compatible with the device that is associated with the specified device context. [這個有HDC引數。]

還有BitBlt的引數,有了SRCAND,再有SRCOR天經地義,結果來了個SRCPAINT不知所云。

如何檢視顏色的RGB值?啥軟體都沒有的話,可以用系統自帶的畫圖。用吸管工具在點上點一下,再點“編輯顏色”。