任意指定透明色的繪圖方法

透明位圖繪製方法在網上見得很多,多數是採用事先做好一個Mask圖,這方法優點是速度快,但就是太麻煩,靈活性差。
任意指定透明色,當然經常也要用到,爲此,API提供了一個函數TransparentBlt,可這個函數,非常讓人遺憾,VB的API瀏覽器中不帶它是有道理的,因爲,它在Win98下有嚴重內存漏洞,你若有98系統,可試一下:
for i=1 to 20000
TransparentBlt ....
next
同樣的圖片,在我的XP下16毫秒可完成,但在98下用了14秒,而且,提示系統資源不足,當機了!

下面我寫了一個函數就是可以代替TransparentBlt的一種方法,速度當然會慢些,但在任何系統下都可放心使用。

Private Type BITMAP
    bmType As Long
    bmWidth As Long
    bmHeight As Long
    bmWidthBytes As Long
    bmPlanes As Integer
    bmBitsPixel As Integer
    bmBits As Long
End Type
Private Declare Function GetCurrentObject Lib "gdi32" (ByVal hdc As Long, ByVal uObjectType As Long) As Long
Private Declare Function GetObj Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Declare Function SetBkColor Lib "gdi32" (ByVal hdc As Long, ByVal crColor As Long) As Long

Private Declare Function CreateBitmap Lib "gdi32" (ByVal nWidth As Long, ByVal nHeight As Long, ByVal nPlanes As Long, ByVal nBitCount As Long, lpBits As Any) As Long
Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal y As Long) As Long
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal X As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare Function StretchBlt Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long

Public Function TranBlt(DestHdc As Long, X As Long, y As Long, w As Long, h As Long, srcHdcOrBmp As Long, Optional srcX As Long, Optional srcY As Long, Optional srcW As Long, Optional srcH As Long, Optional tc As Long = -1, Optional IsBmp As Boolean) As Long
    'srcHdcOrBmp參數 傳入的可以是hdc也可以是Bmp對象的Handle,
    'IsBmp參數 爲真時srcHdcOrBmp代表Bmp對象的Handle,爲假時代表hdc
    '返回值 成功時返回透明色,不成功時返回-1
    Dim tHdc(3) As MemHdc
    Dim j As Long, oc As Long, i As Long, Bm As BITMAP, cc As Long, NewDc As Long
    Dim sw As Long, sh As Long, sBmp As Long, sHdc As Long, obm As Long, NewX As Long, NewY As Long
    If DestHdc = 0 Or srcHdcOrBmp = 0 Or w = 1 And h = 1 Then GoTo fail
    If IsBmp Then   '若傳入的是Bmp句柄,需爲其創建一個臨時DC
        sBmp = srcHdcOrBmp
        tHdc(3) = NewMyHdc(DestHdc, 0, 0, srcHdcOrBmp)
        sHdc = tHdc(3).hdc
    Else
        sHdc = srcHdcOrBmp
        If srcW = 0 Then sBmp = GetCurrentObject(sHdc, 7)
    End If
    If sHdc = 0 Or sBmp = 0 Then GoTo fail
    If srcW = 0 Then    '若沒有提供源圖大小,需取得整個源圖大小
        GetObj sBmp, Len(Bm), Bm
        sw = Bm.bmWidth - srcX
        sh = Bm.bmHeight - srcY
    Else
        sw = srcW
        sh = srcH
    End If
    If sw < 1 Or sh < 1 Then GoTo fail
    If tc = -1 Then
        cc = GetPixel(sHdc, srcX, srcY)       '將左上角第一個像素作爲源圖背景色,用於透明
    Else
        cc = tc
    End If
    If w <> sw Or h <> sh Then
        tHdc(2) = NewMyHdc(DestHdc, w, h)
        StretchBlt tHdc(2).hdc, 0, 0, w, h, sHdc, srcX, srcY, sw, sh, vbSrcCopy
        '先將源圖縮放,下面步驟就一樣了。
        NewDc = tHdc(2).hdc
    Else
        NewDc = sHdc
        NewX = srcX
        NewY = srcY
    End If
    BitBlt DestHdc, X, y, w, h, NewDc, NewX, NewY, vbSrcInvert
    '將源圖先反色(XOR)繪入目標圖,若源圖背景爲黑色,此步可省
       
    '下面是製作Mask圖的方法
    i = CreateBitmap(w, h, 1, 1, ByVal 0&)  '建立單色位圖
    tHdc(0) = NewMyHdc(DestHdc, 0, 0, i)       '爲單色圖建立新DC,並選入
    tHdc(1) = NewMyHdc(DestHdc, w, h)          '另建一個彩色圖及DC,用於存放Mask圖
    oc = SetBkColor(NewDc, cc)              '將源圖背景色改爲透明色
    BitBlt tHdc(0).hdc, 0, 0, w, h, NewDc, NewX, NewY, vbSrcCopy
    '先將源圖繪入單色DC,由此產生只有正反的Mask圖,背景色(透明色)爲黑,其它爲白
    SetBkColor NewDc, oc                    '恢復源圖背景色,不是必須的,但這是個好習慣。
    BitBlt tHdc(1).hdc, 0, 0, w, h, tHdc(0).hdc, 0, 0, vbSrcCopy
    '單色DC必須複製進彩色DC才能進行後面的的AND運算
    'Mask圖完成,並已放入彩色DC
       
    BitBlt DestHdc, X, y, w, h, tHdc(1).hdc, 0, 0, vbSrcAnd    '標準透明繪圖:選將Mask圖用And運算繪入,
    BitBlt DestHdc, X, y, w, h, NewDc, NewX, NewY, vbSrcInvert '再將源圖以反色(XOR)繪入一次
   
    DelMyHdc tHdc(0)
    DelMyHdc tHdc(1)
   
    If tHdc(2).hdc <> 0 Then DelMyHdc tHdc(2)
    If tHdc(3).hdc <> 0 Then DelMyHdc tHdc(3)
    TranBlt = cc
    Exit Function
fail:
    If tHdc(3).hdc <> 0 Then DelMyHdc tHdc(3)
    TranBlt = -1
End Function

Private Function NewMyHdc(dHdc As Long, w As Long, h As Long, Optional Bm As Long) As MemHdc
    With NewMyHdc
        .hdc = CreateCompatibleDC(dHdc)
        If Bm = 0 Then
            .Bmp = CreateCompatibleBitmap(dHdc, w, h)
        Else
            .Bmp = Bm
        End If
        .obm = SelectObject(.hdc, .Bmp)
    End With
End Function
Private Function DelMyHdc(MyHdc As MemHdc, Optional nobmp As Boolean) As MemHdc
    With MyHdc
        If .hdc <> 0 And .obm <> 0 Then SelectObject .hdc, .obm
        If nobmp = False And .Bmp <> 0 Then DeleteObject .Bmp
        If .hdc <> 0 Then DeleteDC .hdc
    End With
End Function

Private Sub Command1_Click()
    TranBlt Picture1.hdc, 0, 0, Image1.Width, Image1.Height, Image1.Picture.handle, , , , , , True
End Sub

Private Sub Form_Load()
    Me.ScaleMode = 3
End Sub

本篇中的公用函數NewMyHdc、DelMyHdc及相關結構與API聲明,可在以下文章中找到
http://blog.csdn.net/homezj/archive/2005/04/14/348001.aspx

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