|
The BitBlt API 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.
.. 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
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:
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.
Let's push on to the following parameters -- x, and y: Listing 1.4 BitBlt.bas
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!
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 :
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.
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 :
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:
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 :
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 :
Linking it back to boolean algebra this translates as the following :
The above boolean expression has the following possibilities (expressed using binary values) :
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 :
Linking it back to boolean algebra this translates as the following :
The above boolean expression has the following possibilities (expressed using binary values) :
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:
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:
The above boolean expression has the following possibilities (expressed using binary values) :
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) :
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 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 :
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:
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!
Michael Lambino |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Quick searches: Site Search | Advanced Site Search |
|
By using this site you agree to its terms and conditions VB Explorer and VBExplorer.com are trademarks of Exhedra Solutions, Inc. |