- Master's Toolbox
- Caller ID with Visual Basic
- Building a Screen Saver in Visual Basic
- SQL Server to Access Database Table Export Program
- Using the Windows API to Create Transparent Images
- From Here...
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
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.