Home > Articles > Programming > Visual Basic

  • Print
  • + Share This

Using the Windows API to Create Transparent Images

One of the most complex features in the Win32 API is the Graphics Device Interface (GDI) APIs. Because these APIs are very complicated, tedious, and GPF-prone, Microsoft played it safe and excluded most of them from VB. Although leaving out the APIs shelters you from the complexity and makes your programs more robust, it severely limits your ability to do the "cool" things that many users expect. VB 4.0 helped to relieve this problem to some extent by providing new features such as the PaintPicture function and the ImageList control, but it still fell short. This means that sometime in the near future, you will find yourself calling the GDI APIs from your application. To demonstrate some of the more common GDI APIs, you'll write a cool function called TransparentPaint in this section.

NOTE

The version of the TransparentPaint routine you see in this chapter is a Win32 version of the TransparentBlt code (written by Mike Bond) that originally appeared in the Microsoft KnowledgeBase KB article number Q94961. This version contains many modifications to the code and includes

TransparentPaint, shown in Listing 23.4, is designed to treat a bitmap like an icon when you paint it on a surface. You can designate a part of the icons to be transparent, but you cannot do the same with bitmaps. TransparentPaint overcomes this limitation by allowing you to make all of a single color on a bitmap transparent. To accomplish this difficult feat, you need to create a series of temporary bitmaps and do some painting in memory only. Although this abstract concept can be complicated, the comments in TransparentPaint help explain what is happening at each step.

Listing 23.4  Code for the TransparentPaint Procedure

'*********************************************************************
' Paints a bitmap on a given surface using the surface backcolor
' everywhere lngMaskColor appears on the picSource bitmap
'*********************************************************************
Sub TransparentPaint(objDest As Object, picSource As StdPicture, _
    lngX As Long, lngY As Long, ByVal lngMaskColor As Long)
    '*****************************************************************
    ' This sub uses a bunch of variables, so let's declare and explain
    ' them in advance...
    '*****************************************************************
    Dim lngSrcDC As Long     'Source bitmap
    Dim lngSaveDC As Long    'Copy of Source bitmap
    Dim lngMaskDC As Long    'Monochrome Mask bitmap
    Dim lngInvDC As Long     'Monochrome Inverse of Mask bitmap
    Dim lngNewPicDC As Long  'Combination of Source & Background bmps

    Dim bmpSource As BITMAP  'Description of the Source bitmap

    Dim hResultBmp As Long   'Combination of source & background
    Dim hSaveBmp As Long     'Copy of Source bitmap
    Dim hMaskBmp As Long     'Monochrome Mask bitmap
    Dim hInvBmp As Long      'Monochrome Inverse of Mask bitmap

    Dim hSrcPrevBmp As Long  'Holds prev bitmap in source DC
    Dim hSavePrevBmp As Long 'Holds prev bitmap in saved DC
    Dim hDestPrevBmp As Long 'Holds prev bitmap in destination DC
    Dim hMaskPrevBmp As Long 'Holds prev bitmap in the mask DC
    Dim hInvPrevBmp As Long  'Holds prev bitmap in inverted mask DC

    Dim lngOrigScaleMode&    'Holds the original ScaleMode
    Dim lngOrigColor&        'Holds original backcolor from source DC
    '*****************************************************************
    ' Set ScaleMode to pixels for Windows GDI
    '*****************************************************************
    lngOrigScaleMode = objDest.ScaleMode
    objDest.ScaleMode = vbPixels
    '*****************************************************************
    ' Load the source bitmap to get its width (bmpSource.bmWidth)
    ' and height (bmpSource.bmHeight)
    '*****************************************************************
    GetObject picSource, Len(bmpSource), bmpSource
    '*****************************************************************
    ' Create compatible device contexts (DCs) to hold the temporary
    ' bitmaps used by this sub
    '*****************************************************************
    lngSrcDC = CreateCompatibleDC(objDest.hdc)
    lngSaveDC = CreateCompatibleDC(objDest.hdc)
    lngMaskDC = CreateCompatibleDC(objDest.hdc)
    lngInvDC = CreateCompatibleDC(objDest.hdc)
    lngNewPicDC = CreateCompatibleDC(objDest.hdc)
    '*****************************************************************
    ' Create monochrome bitmaps for the mask-related bitmaps
    '*****************************************************************
    hMaskBmp = CreateBitmap(bmpSource.bmWidth, bmpSource.bmHeight, _
        1, 1, ByVal 0&)
    hInvBmp = CreateBitmap(bmpSource.bmWidth, bmpSource.bmHeight, _
        1, 1, ByVal 0&)
    '*****************************************************************
    ' Create color bitmaps for the final result and the backup copy
    ' of the source bitmap
    '*****************************************************************
    hResultBmp = CreateCompatibleBitmap(objDest.hdc, _
        bmpSource.bmWidth, bmpSource.bmHeight)
    hSaveBmp = CreateCompatibleBitmap(objDest.hdc, _
        bmpSource.bmWidth, bmpSource.bmHeight)
    '*****************************************************************
    ' Select bitmap into the device context (DC)
    '*****************************************************************
    hSrcPrevBmp = SelectObject(lngSrcDC, picSource)
    hSavePrevBmp = SelectObject(lngSaveDC, hSaveBmp)
    hMaskPrevBmp = SelectObject(lngMaskDC, hMaskBmp)
    hInvPrevBmp = SelectObject(lngInvDC, hInvBmp)
    hDestPrevBmp = SelectObject(lngNewPicDC, hResultBmp)
    '*****************************************************************
    ' Make a backup of source bitmap to restore later
    '*****************************************************************
    BitBlt lngSaveDC, 0, 0, bmpSource.bmWidth, bmpSource.bmHeight, _
        lngSrcDC, 0, 0, vbSrcCopy
    '*****************************************************************
    ' Create the mask by setting the background color of source to
    ' transparent color, then BitBlt'ing that bitmap into the mask
    ' device context
    '*****************************************************************
    lngOrigColor = SetBkColor(lngSrcDC, lngMaskColor)
    BitBlt lngMaskDC, 0, 0, bmpSource.bmWidth, bmpSource.bmHeight, _
        lngSrcDC, 0, 0, vbSrcCopy
    '*****************************************************************
    ' Restore the original backcolor in the device context
    '*****************************************************************
    SetBkColor lngSrcDC, lngOrigColor
    '*****************************************************************
    ' Create an inverse of the mask to AND with the source and combine
    ' it with the background
    '*****************************************************************
    BitBlt lngInvDC, 0, 0, bmpSource.bmWidth, bmpSource.bmHeight, _
        lngMaskDC, 0, 0, vbNotSrcCopy
    '*****************************************************************
    ' Copy the background bitmap to the new picture device context
    ' to begin creating the final transparent bitmap
    '*****************************************************************
    BitBlt lngNewPicDC, 0, 0, bmpSource.bmWidth, bmpSource.bmHeight, _
        objDest.hdc, lngX, lngY, vbSrcCopy
    '*****************************************************************
    ' AND the mask bitmap with the result device context to create
    ' a cookie cutter effect in the background by painting the black
    ' area for the non-transparent portion of the source bitmap
    '*****************************************************************
    BitBlt lngNewPicDC, 0, 0, bmpSource.bmWidth, bmpSource.bmHeight, _
        lngMaskDC, 0, 0, vbSrcAnd
    '*****************************************************************
    ' AND the inverse mask with the source bitmap to turn off the bits
    ' associated with transparent area of source bitmap by making it
    ' black
    '*****************************************************************
    BitBlt lngSrcDC, 0, 0, bmpSource.bmWidth, bmpSource.bmHeight, _
        lngInvDC, 0, 0, vbSrcAnd
    '*****************************************************************
    ' XOR the result with the source bitmap to replace the mask color
    ' with the background color
    '*****************************************************************
    BitBlt lngNewPicDC, 0, 0, bmpSource.bmWidth, bmpSource.bmHeight, _
        lngSrcDC, 0, 0, vbSrcPaint
    '*****************************************************************
    ' Paint the transparent bitmap on source surface
    '*****************************************************************
    BitBlt objDest.hdc, lngX, lngY, bmpSource.bmWidth, _
        bmpSource.bmHeight, lngNewPicDC, 0, 0, vbSrcCopy
    '*****************************************************************
    ' Restore backup of bitmap
    '*****************************************************************
    BitBlt lngSrcDC, 0, 0, bmpSource.bmWidth, bmpSource.bmHeight, _
        lngSaveDC, 0, 0, vbSrcCopy
    '*****************************************************************
    ' Restore the original objects by selecting their original values
    '*****************************************************************
    SelectObject lngSrcDC, hSrcPrevBmp
    SelectObject lngSaveDC, hSavePrevBmp
    SelectObject lngNewPicDC, hDestPrevBmp
    SelectObject lngMaskDC, hMaskPrevBmp
    SelectObject lngInvDC, hInvPrevBmp
    '*****************************************************************
    ' Free system resources created by this sub
    '*****************************************************************
    DeleteObject hSaveBmp
    DeleteObject hMaskBmp
    DeleteObject hInvBmp
    DeleteObject hResultBmp
    DeleteDC lngSrcDC
    DeleteDC lngSaveDC
    DeleteDC lngInvDC
    DeleteDC lngMaskDC
    DeleteDC lngNewPicDC
    '*****************************************************************
    ' Restores the ScaleMode to its original value
    '*****************************************************************
    objDest.ScaleMode = lngOrigScaleMode
End Sub

For simplicity's sake, I omitted the API declarations from Listing 23.4. I could go on for pages explaining exactly what is happening during each step of TransparentPaint, but I won't because this sub contains the same comments I've made in this listing. Also, following this listing would be more difficult if it were broken into several smaller blocks. After you read the comments for this sub, I encourage you to single-step through the TRANSPARENT.VBP project, which you can get from Macmillan's Web site at www.mcp.com/info. Reading this project will help you to visualize what is happening at each step.

Although TransparentPaint is a difficult procedure to follow, using it is easy. Listing 23.5 loads a bitmap from a resource and paints it on the upper-left corner of the form using TransparentPaint. Next, it paints the picture using PaintPicture. The last parameter, vbGreen, tells TransparentPaint to replace any bits in the bitmap that are green, with the background color of the form. The result is shown in Figure 23.5.

Listing 23.5  Using the TransparentPaint Procedure

'*********************************************************************
' Transparent.frm - Demonstrates how to use basTransparent's
'   TransparentPaint using a bitmap from a resource file.
'*********************************************************************
Option Explicit
'*********************************************************************
' Gets a StdPicture handle by loading a bitmap from a resource file
' and paints it transparently on the form by using Gray as the mask
' color.
'*********************************************************************
Private Sub cmdPaintTransBmp_Click()
    TransparentPaint Me, LoadResPicture(103, 0), 0, 0, QBColor(7)

End Sub

Figure 23.5

TransparentPaint is a must for your multimedia applications.

Try replacing the resource file in this project with your own resource file to see how TransparentPaint works. Also, try using different mask colors as well as the images from picture boxes. Now, you never have to write an application that appears to be of inferior quality because it doesn't use transparent bitmaps.

  • + Share This
  • 🔖 Save To Your Account

Related Resources

There are currently no related titles. Please check back later.