The Bottom Line on PaintPicture


PaintPicture lacks the flexibility for the kinds of masking and blitting operations discussed in the rest of this chapter. It is tied to an unchangeable Picture
object, whereas BitBlt and StretchBlt are tied to device contexts that you can change however you want. But you shouldn’t throw PaintPicture out of your toolbox. It’s certainly the easiest and fastest way to draw a thousand copies of a picture or to draw a picture in a thousand pieces. In other words, you can use it to create great visual effects.


If you’re going to be copying a picture around, it’s best to use an Image control as the picture container because it has lower overhead than a PictureBox. You can make it invisible if you don’t want to show the source. Simply pass its Picture property to PaintPicture or to any of your procedures that take Picture parameters. For example, this procedure draws a spiral pattern of bitmaps, just as you might use PSet to draw a spiral pattern of dots (think of the pictures as big dots):

Sub BmpSpiral(cvsDst As Object, picSrc As Picture)
With cvsDst
‘ Calculate sizes
Dim dxSrc As Long, dySrc As Long, dxDst As Long, dyDst As Long
dxSrc = .ScaleX(picSrc.Width): dySrc = .ScaleY(picSrc.Height)
dxDst = .ScaleWidth: dyDst = .ScaleHeight
‘ Set defaults (play with these numbers for different effects)
Dim xInc As Long, yInc As Long, xSize As Long, ySize As Long
Dim x As Long, y As Long
xInc = CInt(dxSrc * 0.01): yInc = CInt(dySrc * 0.01)
xSize = CInt(dxSrc * 0.1): ySize = CInt(dySrc * 0.1)
Dim radCur As Single, degCur As Integer, angInc As Integer
degCur = 0: angInc = 55
‘ Start in center
x = (dxDst \ 2) - (dxSrc \ 2): y = (dyDst \ 2) - (dySrc \ 2)

‘ Spiral until off destination
Do
‘ Draw at current position
.PaintPicture picSrc, x, y, , , , , , , vbSrcAnd
‘ Calculate angle in radians
radCur = (degCur - 90) * (PI / 180)
‘ Calculate next x and y
x = x + (xSize * Cos(radCur))
y = y + (ySize * Sin(radCur))
‘ Widen spiral
xSize = xSize + xInc: ySize = ySize + yInc + 1
‘ Turn angle
degCur = (degCur + angInc) Mod 360
Loop While (x > 0) And (x + dxSrc < dxDst - dxSrc) And _
(y > 0) And (y + dySrc < dyDst)
End With
End Sub

If you have an Image control with a bitmap picture, draw it on the current form with the statement BmpSpiral Me, imgSmallBmp.Picture.

Although previous versions of Visual Basic didn’t provide a built-in way to blit, they did have a built-in way to stretch. The Stretch property of the Image control provided the moral equivalent of StretchBlt with no ROP mode. If all you want to do with a picture is stretch or compress it, it’s hard to beat using the Image control with its Stretch property set to True. So how do you think Visual Basic implements the Stretch and AutoSize properties? Your guess is as good—and probably the same—as mine: StretchBlt.


Once you get the idea, it’s not hard to devise ways to change the algorithm for inward spirals and other patterns. You can also experiment with different ROP codes for combining the images. Figure 7-9 shows one effect.


Another PaintPicture trick with many variations is to break a large bitmap into small squares and display the squares in some pattern. For example, you can



Figure 7-9. The Bitmap Spiral in Fun ’n Games.


randomize the position of the squares to form a puzzle and then put them back together. Another variation is to draw the squares in their correct places but create a pattern that makes the picture appear to explode, crush, or spiral onto the surface.


Here’s a spiral bitmap effect. To try it, click the Spiral Bitmap button in the Fun ’n Games program. You can load your own digitized pictures or other large bitmaps by clicking the Large button or the picture box adjacent to it.

Sub SpiralBmp(cvsDst As Object, picSrc As Picture, _
ByVal xOff As Long, ByVal yOff As Long)
With cvsDst
Dim xLeft As Long, xRight As Long, yTop As Long, yBottom As Long
Dim dxSrc As Long, dySrc As Long, xSrc As Long, ySrc As Long
Dim xDst As Long, yDst As Long, xInc As Long, yInc As Long
Dim x As Long, y As Long
‘ Initialize
dxSrc = .ScaleX(picSrc.Width): dySrc = .ScaleY(picSrc.Height)
xInc = dxSrc / 20: yInc = dySrc / 20
xLeft = 0: yTop = 0:
xRight = dxSrc - xInc: yBottom = dySrc - yInc

‘ Draw each side
Do While (xLeft <= xRight) And (yTop <= yBottom)
‘ Top
For x = xLeft To xRight Step xInc
.PaintPicture picSrc, x + xOff, y + yOff, xInc, yInc, _
x, y, xInc, yInc, vbSrcCopy
Next
x = x - xInc: yTop = yTop + yInc
‘ Right
For y = yTop To yBottom Step yInc
.PaintPicture picSrc, x + xOff, y + yOff, xInc, yInc, _
x, y, xInc, yInc, vbSrcCopy
Next
y = y - yInc: xRight = x - xInc
‘ Bottom
For x = xRight To xLeft Step -xInc
.PaintPicture picSrc, x + xOff, y + yOff, xInc, yInc, _
x, y, xInc, yInc, vbSrcCopy
Next
x = x + xInc: yBottom = y - yInc
‘ Left
For y = yBottom To yTop Step -yInc
.PaintPicture picSrc, x + xOff, y + yOff, xInc, yInc, _
x, y, xInc, yInc, vbSrcCopy
Next
y = y + yInc: xLeft = xLeft + xInc
Loop
End With
End Sub

I can’t show you this effect on the page because the movement is the point; you’ll have to try it.