Visual Basic Explorer
Visual Basic Explorer
 Navigation
 Home


 Coding
 Source Code

 FAQ Center

 VB Tips

 Downloads

 ToolBox

 Tutorials

 VB Games

 VB News

 VB Award

 VB Forums



 Affiliates
 Planet Source Code

 Rent a Coder

 DirectX4VB


 Misc
 Search

 Feedback

 Advertise

 About


Need to hire
a VB coder?

Please support our sponsor:

 Home 
 Site Map 
 Forums 
 News 
 Feedback 

The BitBlt API
Author : Michael Lambino
Created : 11 May, 1998
Modified : 17 October, 1998
Skill Level :
Beginner - Casual

This tutorial is a revised version of the original BitBlt API primer/tutorial I originally wrote in May, 1998. Most of the content remains the same, it's just that I've (hopefully) made it a little easier to read. You can also download the associated demo project here.

It appears that want of information for this popular API never seems to cease. The BitBlt API call was the first API I learned how to implement, as I suspect may be the case with many who may come across this tutorial. It is for this reason why the tutorial is geared mainly towards newbies but hopefully there's something in it for everybody.

If you read and re-read parts of this tutorial and find that parts are a little over your head, skip the paragraph and try out the code. Come back to it in your own time (days, weeks, months) and things will get clearer. Like most things dealing with programming, practice makes perfect. There are improvements that can be applied to the method of bltting that I show here, let me make that perfectly clear :o), so treat this material as a starting point and then write some code, and then write some more.

One thing not to forget though is to Enjoy :o) -- Catch you all later!


So, what is this BitBlt I've been hearing so much about?

BitBlt is an acronym for Bit Block Transfer. It is an API function exposed by the GDI32.dll that performs a transfer of a rectangular area of an image to another rectangular area of equal size. This includes copying, combining or merging images and displaying the result.

An important point to keep in mind is like most API calls, Visual Basic knows not when you invoke the function. If you use the BitBlt function to perform a bltting operation to an object with it's AutoRedraw property set to True, you must call the object's Refresh method to update the screen with the image in memory... But more about this later.

 

Enough talk, show me the code!

The following listing (Listing 1.1) is the source code for a reusable .bas module that provides enumerated Raster Operation constants and the declaration for the BitBlt API function. A member of the enumerated raster operation type is used in the last parameter of a BitBlt function call.

The Bitblt API is a function exposed by the GDI32.dll, which is made available for use within your Visual Basic projects with the below (or similar) declaration. It is declared below to be used in a .bas module, in a global scope, making it accessable to all forms and modules you may be using in your project. You use the function as you would any other custom function you write in Visual Basic.

Listing 1.1 BitBlt.bas - Generic BitBlt API Declaration and Constants for use in a .bas module.

' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

' Project
' Filename
' Description
' Created
' Modified

:
:
:
:
:

BitBltPrimer.vbp
BitBlt.bas
BitBlt API primer tutorial project
11.15 PM GMT + 10.00, February 23, 1998
12:26 AM GMT + 10.00, October 17, 1998

' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

' Author
' E-mail
' Comments
' License
'
'

:
:
:
:

Michael Lambino
ProSoft@the18th.com
Copyright ©, 23 February, 1998 - Michael Lambino
Freeware - Freely distributable unmodified. No costs may be charged whatsoever for the distribution of this tutorial, in any form of media, without expressed permission from the author.

' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

' Require all variables be declared.  Option Explicit   ' Enumerated raster operation constants Public Enum RasterOps ' Copies the source bitmap to destination bitmap SRCCOPY = &HCC0020 ' ' Combines pixels of the destination with source bitmap using the Boolean AND operator. SRCAND = &H8800C6 ' ' Combines pixels of the destination with source bitmap using the Boolean XOR operator. SRCINVERT = &H660046 ' ' Combines pixels of the destination with source bitmap using the Boolean OR operator. SRCPAINT = &HEE0086 ' ' Inverts the destination bitmap and then combines the results with the source bitmap ' using the Boolean AND operator. SRCERASE = &H4400328 ' ' Turns all output white. WHITENESS = &HFF0062 ' ' Turn output black. BLACKNESS = &H42 End Enum   ' BitBlt API Public Declaration 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 RasterOps _ ) As Long  

.. so, what does it all mean?

For now, skip the enumerated constants (that's the code between Public Enum RasterOps and End Enum), and we'll focus on the actual BitBlt Declaration, which, for the purpose of this tutorial we'll call the BitBlt function. Lets take a look at the parameters of the function and delve into them a little deeper than the more sane members of our communities ever would - Take a look at Listing 1.2

Listing 1.2 BitBlt.bas - A snippet of the BitBlt API declaration


ByVal
hDestDC As Long, _
..
ByVal
hSrcDC As Long, _

The values you pass here are the Destination Object's hDC (hence hDestDC) and the Source Object's hDC (hSrcDC). In saying that BitBlt transfers an image from one area of memory to another, the operating system needs to know where to find the image to transfer and where to send them too. Both the Source image and Destination object need to have a handle for Windows to find where the source pixels are and where the pixels should be painted too at any given time. This is where the hDC comes into play.

In the accompanying project, we use a PictureBox Object to contain the source image and use another PictureBox to contain the resulting image which is transferred, both of which support the hDC property. The hDC property of an object returns the handle in which your OS can find a device context ... huh? I hear you say ... In times of huh? we first turn to traditional resources of information (start with the VB Help file) -- it states that:

Borrowed from MS VB5 Help File

this property is a Windows operating environment device context handle. The Windows operating environment manages the system display by assigning a device context for ..... each form and PictureBox control in your application. You can use the hDC property to refer to the handle for an object's device context. This provides a value to pass to Windows API calls.

This API function needs to know where in the system memory the source pixels which you want transferred are located (as well as the destination you want them transferred too). You cannot simply say BitBlt PictureBox2 (Destination) from PictureBox1 (Source) and expect windows to understand or find what you've just asked it to. Instead we pass the handle to the Device Context, by calling BitBlt PictureBox2.hDC from PictureBox2.hDC .. nothing really hard! ;o) in fact, windows does all the hard work behind the scenes for you .. it actually creates a link between your application, a device driver, and an output device; such as the screen or a printer.

Now one more thing about hDC before we move on to the next parameters ... We've established that the hDC property provides a method of finding the location of an object in memory ... well another relevant question which you should ask yourself is -- Does the value that the hDC property return remain the same, and if so, for how long? -- well I'm glad you asked. In short, the answer is NO - the hDC may not remain the same during the lifetime of a running application. As the VB Help File suggests (lookup: hDC Property), do not hardcode the value returned by the hDC property in any API calls ... simply refer to the property whenever you need it. Experiment with this though as caching the hDC property can sometimes improve performance.

Whilst we're talking about memory and fun stuff like that, I might take a short timeout to look into the AutoRedraw property of an object. I said above that BitBlt transfers image data from a rectangular source image to a destination picture-container. When the AutoRedraw property of an object is set to True, then the system stores an image, contained by the object, in memory (persistant bitmap). Whilst this property is set to True, any changes done to the image will only be done to the image held in memory, NOT the image you see on the screen. When the AutoRedraw property of a destination object is set to true you must tell the OS to Refresh the on-screen image and update it with the image being held in memory. You do this by calling the Refresh method of the destination object (PictureBox2.Refresh).

Ok, I can hear someone saying, why bother - what's the advantage of that? Well an answer could be that theoretically, if you do all your changes to an image "off-screen" and then simply display the image when changes are completed, this will cause less "flicker" as opposed to displaying an image as changes are taking place. You can theorize, it is faster not to update the screen as you do the changes, as your application needs to pass thru a display driver which in turn instructs your monitor to update the changes, as opposed to doing all the work behind the scenes (in memory) and updating the screen once. This will definately be faster! Now, an important thing to remember is that you must use this technique wisely as memory is not infinate ... I'm sure I don't have to go into this :o) ...

Now, that's the end of one of the hardest concepts of this API call and a little background into the AutoRedraw property. As a reward here's a quick lookup table of all the parameters of the function. Don't bother copying and pasting the table as it comes in the BitBlt.bas module with the accompanying project download.

Listing 1.3 BitBlt.bas - Quick lookup table for the parameters of the BitBlt API Declaration

' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
' Parameter descriptions
' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

'

ByVal hDestDC As Long

:

hDC of object (Destination PictureBox hDC) in which resulting
Blt operation will performed.

'

ByVal x As Long

:

Leftmost coordinate (upper-left) of the destination rectangle.

'

ByVal y As Long

:

Topmost coordinate (upper-left) of the destination rectangle.

'

ByVal nWidth As Long

:

width of the rectangle of the destination image to be bltted. 

'

ByVal nHeight As Long

:

height of the rectangle of the destination image to be bltted.  

'

ByVal hSrcDC As Long

:

hDC of object (Source PictureBox hDC) in which resulting Blt
operation will be performed from.

'

ByVal xSrc As Long

:

Leftmost coordinate (upper-left) of the source rectangle.

'

ByVal ySrc As Long

:

Topmost coordinate (upper-left) of the source rectangle.

'

ByVal dwRop As Long

:

specifies the raster operation to be performed as above.

Let's push on to the following parameters -- x, and y: Listing 1.4 BitBlt.bas

Listing 1.4 BitBlt.bas - A snippet of the BitBlt API declaration


ByVal
x As Long, _
..
ByVal
y As Long, _

The BitBlt API as stated numerous times above, transfers a rectangular portion of a source image onto a destination ... the X and Y parameters allow you to specify the exact whereabouts, on the destination, the rectangular source image should be transferred to. Just like positioning an object within a container (eg, a picturebox within a form), x and y are very similar to the object's .left and .top properties -- easy ;o) .. but wait for it!

  • x sets the distance between the internal left edge of the destination object and the leftmost coordinate at which the source image will be transferred, and
  • y sets the distance between the internal top edge of an destination object and the topmost coordinate at which the source image will be transferred.

There's really only one thing to bear in mind when passing values to the x, and y parameters of the function call. The unit of measurement used in setting x, and y, is PIXELS. This is different to the top and left properties of an object as they can use twips or any other user-defined unit of measurement.

X and Y allows you great control in the positioning of the transferred image. You can use the X and Y values to create tiled background effects or illusions of animation - but BitBlt doesn't stop there. It also allows you to specify whereabouts it should start transferring pixels from the source image. Take a look at :

Listing 1.5 BitBlt.bas - A snippet of the BitBlt API declaration


ByVal
xSrc As Long, _
..
ByVal
ySrc As Long, _

The BitBlt API allows you to specify whereabouts from a source image to start transferring pixels. This allows you to keep a number of different images (Sprites or tiles) in one image file (usually a grid of many images) and specify which sprite to transfer. As you can imagine, by keeping many frames or a sequence of images (used in animation) in one image file; this will allow for faster animation (as the system doesn't have to go through the process of accessing them from the harddrive) usually producing smoother animation. But with all good things come the bad - always keep in mind that the single (large) image may be held in memory.

Values for the xSrc and ySrc parameters are passed in the same way as x and y, as stated above.

  • xSrc sets the distance between the internal left edge of the source container and the leftmost coordinate you want to start tranferring the source image, and
  • ySrc sets the distance between the internal top edge of the source container and the topmost coordinate you want to start transferring the source image.

Also remember that xSrc and ySrc are measured in PIXELS!!

Now, the next two parameters of the function that we should look at is nWidth and nHeight. Take a look at the following :

Listing 1.6 BitBlt.bas - A snippet of the BitBlt API declaration


ByVal
nWidth As Long, _
..
ByVal
nHeight As Long, _

As said many times earlier, BitBlt transfers a rectangular source image to a destination. The height and width of the rectangle is set with these two parameters. The values that you pass to these parameters should be measured in pixels, again ;o) ... As you may now have figured out, pixels is the unit of measurement used with BitBlt, and generally speaking the unit of measurement used in API functions. To play it safe, set your source and destination object's ScaleMode properties to 3 - Pixels, but often this may end up confusing (or not possible) and may not be desired. A common question is how do I convert a value measured in twips to it's value measured in pixels? ... Maybe we should once again, take a timeout and look at the Screen object and it's properties!

In the last paragraph, I stated that it may not be possible to change the ScaleMode property of an object -- I was refering to the Screen object. Consider this - say you wanted to copy a portion of the desktop image and apply some cool affects to it using BitBlt -- for example, you wanted to grab the portion of the desktop's image (specifically; the area around a form in a project you are running) and paint it to your current form to make it appear transparent (see Source Code examples) or better yet apply some animation so it looks like it explodes!! }:o) -- you cannot use the form's .top and .left properties alone (to findout it's dynamic position) as their values are returned measured in twips! .... You must convert their values to pixels to attain the desired result.

The Screen object has properties that can be used to convert values measured in twips to their equivalent pixel value. The two properties in question are Screen.TwipsPerPixelX and Screen.TwipsPerPixelY. These properties return the number of Twips that can fit into one pixel horizontally and vertically, respectively, taking into account the current resolution. To convert a value measured in twips into pixels - divide the twips value by the value returned by Screen.TwipsPerPixel_ or to convert a value measured in pixels to twips simply multiply that value by TwipsPerPixel_ . Here's an example of converting a form's Leftmost coordinate from twips to pixel using integer division:

Dim lngLeft As Long

LngLeft = Form1.Left \ Screen.TwipsPerPixelsX

Ok! -- You should be able to know how to define a rectangular portion of a source image and know whereabout's on a destination object you want it transferred (whether you're using Twips or Pixels as the ScaleMode). Further, you should be able to understand how to let the Operating System know where to find both the source and destination objects!

Throughout this tutorial so far I've said that BitBlt transfers pixels from a source image to a destination. BitBlt allows you to transfer those pixels to your destination in a number of different ways. You have control over this by choosing which Raster Operation should be applied when transfer (or merging the source image with existing images in the destination) and this is done by passing a value into the last parameter in the function. Take a look at the following parameter :

Listing 1.7 BitBlt.bas - A snippet of the BitBlt API declaration


ByVal
dwRop As RasterOps _

The first thing to take for granted here is that the information that is stored in a pixel (the colour of it) is stored as a numerical value (let's not get too technical to start off here). The BitBlt operation under Windows is not limited to a simple copying of an image to a destination, it also allows you to perform mathematical and logical operations on a source image and it's destination. The effects you can create (transparency, inverted colours) can be calculated if you understand the Raster Operations that are supported by BitBlt. But in understanding the raster operations it is a good idea to understand what OR, AND, NOT and XOR operations do to binary data. Before going any further into RasterOps, maybe a short lesson / recap in Boolean Algebra!??

Boolean what!?!

Boolean Algebra ;o) - Some background in it's uses may be in order first of all! -- It's pretty much common knowledge that computers, in it's most basic form, used to / still run on information transfered in Binary Language ... When you think of this mechanically we talk of switches ... The most basic switch has two states, On and Off, this in Binary language this is 1 and 0. Some machines which use this logic to perform tasks, can perform a wide number of operations - some of which may be as simple as: if a user hits either the Escape key (a Switch) or the F10 key (another Switch) perform the Quitting sequence ... In VB this is written like this :

Dim bEscapeKey As Boolean
Dim
bF10Key As Boolean

'Esc Key Flag
'F10 Key Flag

If bEscapeKey = True OR bF10Key = True then

'Either Esc key or F10 key was depressed
Unload Object

End If

Linking it back to boolean algebra this translates as the following :


bEscapeKey + bF10Key = Result (either 0 or 1)

The above boolean expression has the following possibilities (expressed using binary values) :

bEscapeKey

+

bF10Key

=

Result

0

+

0

=

0

(Do not run sequence as No key was depressed)

1

+

0

=

1

(Run Quit sequence as ESC Key was depressed)

0

+

1

=

1

(Run Quit sequence as F10 Key was depressed)

1

+

1

=

1

(Run Quit sequence as Both Keys were depressed)

.... as you can see the plus symbol is a little misleading and that's why OR is often used in it's place

That was just an example of the OR operator -- it speaks for itself really ... if Switch1 OR Switch2 is True then the Result will be True.

Another commonly used operation in boolean algebra is the AND operation. This operation also speaks for itself. Take the following scenario for instance ... if the CTRL Key AND the ALT Key AND the DELETE Key is pressed at the same time Quit! -- In Visual Basic this is written like this :

 
dim bCtrlKey As Boolean     'CTRL Key Flag
dim bAltKey As Boolean      'ALT Key Flag
dim bDelKey As Boolean      'DELETE Key Flag
 
      if bCtrlKey = True AND _
         bAltKey = True  AND _
         bDelKey = True then
           'CTRL & ALT & DEL keys were depressed
           unload object
      end if

Linking it back to boolean algebra this translates as the following :


bCtrlKey . bAltKey . bDelKey = Result (either 0 or 1)

The above boolean expression has the following possibilities (expressed using binary values) :

bCtrlKey

.

bAltKey

.

bDelKey

=

Result

0

.

0

.

0

=

0

(Do not run sequence as No key was depressed)

1

.

0

.

0

=

0

(Do not run Quit sequence as only one key was depressed)

0

.

1

.

0

=

0

0

.

0

.

1

=

0

1

.

1

.

0

=

0

(Do not run Quit sequence as only two Keys were depressed)

1

.

0

.

1

=

0

0

.

1

.

1

=

0

1

.

1

.

1

=

1

(Run Quit sequence as all three Keys were depressed)

.... as you can see the multiplication symbol (.) is a little misleading and that's why AND is often used in it's place

To keep it simple -- the AND operation only returns true if all it's variables are true, ie, Switch1 AND Switch2 AND .. SwitchN = True.

The NOT operation is alot simpler ... it basically inverts the value of a bit. Take this example for instance : As the result of another operation you want to invert the status of an indicator light from on to off, or off to on - inverting the current status of the light. In VB you may write something like this:

Dim bLight As Boolean

' Status light flag.

bLight = Not(bLight)

Linking it back to boolean algebra this translates as the following. Read it from right to left as in the above equations, ie, the result is a consequence of the logic to the left of the equal sign:

_____
bLight = bLight

The above boolean expression has the following possibilities (expressed using binary values) :

_____
bLight

=

Result

1

=

0

(Variable results as being inverted - in binary)

0

=

1

(Variable results as being inverted - in binary)

.... as you can see the overline symbol is weird! and that's why NOT is often used in it's place

 

The last of the Boolean Operations that you will probably need to understand will be the XOR operation (Exclusive OR operation) -- This one will be alittle tricky as it is a combination of NOT, AND, and OR operations all wrapped up into one!! The way it works is pretty much best left unexplained, it sooo much easier to remember the results than explain how the results are achieved. But! if you're curious send me an e-mail and I'll explain it as best I can, warning though, I'll explain it using circuit diagrams! ;o) .... The only important thing to remember will be that it requires two variables to give a result .. For now I'll just provide the lookup table:

The following boolean expression has the following possibilities (expressed using binary values) :

Switch1

Å

Switch2

=

Result

0

Å

0

=

0

(Result is false)

1

Å

0

=

1

(Result is true)

0

Å

1

=

1

(Result is true)

1

Å

1

=

0

(Result is false)

.... as you can see the EX-OR symbol is a little misleading and that's why XOR is often used in it's place

Basically this operation only returns true if only one of the switches are on ... Remember this and that's all it is to it! Now, if you've gotten through the Boolean Algebra unscaved then let's go back to the Raster Operations of the BitBlt API.

RasterOps!!

BitBlt allows you to transfer (merge, combine) source pixels to a destination .. more accurately, it performs this task by transferring the image data from one location to another. The Raster Operation parameter allows you to manipulate how the data is transferred. Lets take a look at the common raster operations and see what the results yield (incorporating what we've seen with Boolean Algebra expressions) ...

' SRCCOPY ........ Copies the source bmp to the destination .bmp
'
SRCAND ......... Combines source bmp and dest. bmp using AND operator
'
SRCINVERT ...... Combines source bmp and dest. bmp using XOR operator
'
SRCPAINT ....... Combines source bmp and dest. bmp using OR operator

SRCCopy is simple. It doesn't use boolean operations on the image data. It transfers a copy of the image data to the destination. It's the others we really want to look at.

Now, consider this example: that the value of the colour WHITE is 1,1,1 (RGB: 11111111, 11111111, 11111111) and the value of colour BLACK is 0,0,0 (RGB: 00000000, 00000000, 00000000).

If a source pixel's colour is WHITE (1) and the destination pixel already has a value of 0 - BLACK performing the following Raster Operations will give you the following results :

  • SRCCOPY: Destination Pixel will be WHITE.
  • SRCAND: Destination Pixel will be BLACK.
  • SRCINVERT: Destination Pixel will be WHITE.
  • SRCPAINT: Destination Pixel will be WHITE.
  • and so on, and so on, check out the tables above!

Interesting eh? ;o) .... Now, what good is all this? Checkout some of my other tuts, including Transparency using Bitblt :o), they're too long to get into for this primer. On your own, try creating something like a progress bar out of two PictureBoxes. Start with something simple like, inverting the existing colour in the destination PictureBox, or something groovy like that!

Let's sum it up!

To use BitBlt API to copy from a picSource to picDestination:

  • You can set both PictureBoxes AutoRedraw properties set to True, and
  • the portion of picSource you want to Blt should be equal to or smaller than picDestination
Remember that if you set both PictureBoxe's Scalemode properties to Twips you should convert the appropriate values. Here's an example:

Call BitBlt(picDestination.hdc, _
                0, _
                0, _
                picSource.ScaleWidth \ Screen.TwipsPerPixelX, _
                picSource.ScaleHeight \ Screen.TwipsPerPixelY, _
                picSource.hDC, _
                0, _
                0, _
                SRCCOPY)

Now by calling the API function like this we're ignoring the return value of the function. The function will return zero if it fails. That should finish it up!

Simple as that! -- But now you know what it all means :o) If you want more information in the Tutorial, feel free to send comments or suggestions to me!

Michael Lambino
ProSoft@the18th.com

Copyright ©, 23 February, 1998 - Michael Lambino
Freeware - Freely distributable unmodified. No costs may be charged whatsoever for the distribution of this tutorial, in any form of media, without expressed permission from the author.




Home | About | What's New | Source Code | FAQ | Tips & Tricks | Downloads | ToolBox | Tutorials | Game Programming | VB Award | Search | VB Forums | Feedback | VBNews | Copyright & Disclaimer | Advertise | Privacy Policy |

Quick searches: Site Search | Advanced Site Search 

Copyright 2002 by Exhedra Solutions, Inc.
By using this site you agree to its terms and conditions
VB Explorer and VBExplorer.com are trademarks of Exhedra Solutions, Inc.