詳解用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); }View Codeoperator 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); }
如果一張圖片只有兩種顏色,那麼每個畫素都可以用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.
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值?啥軟體都沒有的話,可以用系統自帶的畫圖。用吸管工具在點上點一下,再點“編輯顏色”。