Graphics Programming in Visual Basic - Part 1
"Visual Basic Pixel Routines"
By: Tanner "DemonSpectre" Helland
Despite what many programmers will tell you, Visual Basic is an excellent programming language for high-end graphic applications - with or without DirectX and OpenGL. Many VB programmers seem to believe that the only way to get fast 2D graphics is with DirectDraw…and they are completely wrong! Using some creativity and efficient coding, you can get the API to do anything that DirectDraw does - and nearly as fast (and in some cases faster!). But this is not to say that only the DirectX-paranoid can benefit from this tutorial, because even the best DX experts could use a good explanation of how Windows handles graphics routines. This series of articles will explain not only how to do fast graphics but how fast graphics work. You will first learn about pure VB routines for graphics processing; next comes the basic API routines of GetPixel and SetPixel/V; third comes the more advanced GetBitmapBits, SetBitmapBits, and DIB sections; the last tutorial will cover additional optimizations for the real speed demons out there. By the end of this series of tutorials, you will be able to effectively write any graphics application you can dream up using nothing but Visual Basic and the Windows API.
So if you're ready, here's part one of how to become a professional graphics programmer using good ol' VB.
-THE PURPOSE OF THIS TUTORIAL-
This tutorial will discuss the basics of per-pixel graphics programming using only built-in Visual Basic routines. I recommend that even hardened VB veterans at least glance through this document, as it provides the foundation for the advanced graphics principles discussed in the more advanced tutorials. We will discuss the only VB per-pixel graphics routines (Point and Pset), and after this is done you'll know a lot more than you ever wanted to about VB graphics, heh heh heh. :)
-PURE VISUAL BASIC PER-PIXEL GRAPHICS ROUTINES-
Most of you have probably heard of the "horrible twins of Pset and Point" (Matt Hart). This is the easiest possible way to do VB GP, but - of course - it's also the slowest. Unless you have an extremely fast machine you will most definitely want to avoid ever using these routines again. I include them here only for completeness; I have never used them in an actual program simply because they are so extremely slow. Why are they so slow? I'll discuss that later, after we've looked at their syntax.
PART I - GETTING THE COLOR OF A PIXEL
You can use the Point event in VB to get the color of a specified pixel. The format is as follows:
________________________________________________________
Dim Color as Long
Color = PictureBox.Point(x,y)
________________________________________________________
PictureBox is the name of the picture box or form you want to retrieve the pixel from, and (x,y) are the pixels coordinates. So, if you wanted to get a color from spot 35, 42 of picture box "Picture1", you would use the following:
________________________________________________________
Color = Picture1.Point(35,42)
________________________________________________________
It doesn't get much simpler than that, folks.
So now the question becomes, "what do we do once we've gotten the color?" After all, it's of Long type, which is some strange number from -2 billion to +2 billion...and that really doesn't lend itself to adjusting the color of that pixel. So, we have to figure out how to change one 4-bit number into three 1-bit numbers (red, green, and blue).
While this may sound easy, the theory behind doing this requires some knowledge of binary encoding…which I find extremely boring and don't want to write about, lol :). So instead, I'll give you the next best thing: functions that will automatically do the extraction for you.
________________________________________________________
Public Function ExtractR(ByVal CurrentColor As Long) As Byte
ExtractR = CurrentColor And 255
End Function
________________________________________________________
Public Function ExtractG(ByVal CurrentColor As Long) As Byte
ExtractG = (CurrentColor \ 256) And 255
End Function
________________________________________________________
Public Function ExtractB(ByVal CurrentColor As Long) As Byte
ExtractB = (CurrentColor \ 65536) And 255
End Function
________________________________________________________
To utilize these functions, use the following syntax:
________________________________________________________
Dim R as Byte, G as Byte, B as Byte
Dim Color as Long
Color = PictureBox.Point(0, 0)
R = ExtractR(Color)
G = ExtractG(Color)
B = ExtractB(Color)
________________________________________________________
Pretty neat, eh? On a brief side note: while you may find these very handy, I would still highly recommend reading up on binary encoding since it provides pretty much the entire foundation of the digital age. If you don't understand how binary data works, you're probably not going to get very far in the programming world - and besides, it's really pretty easy stuff provided that you can find a good teaching source. Consult your local library for best results.
Anyway, there you have it: how to get a pixel's data and break it down into its red, green, and blue components. Now let's quickly mention how to set that data back into a picture box.
PART 2 - SETTING THE COLOR OF A PIXEL
Setting a pixel's color is almost identical to getting its color. You use the VB event "Pset," which stands for "Pixel Set."
________________________________________________________
PictureBox.PSet (x,y), Color
________________________________________________________
Again, PictureBox is the name of the picture box or form you want to retrieve the pixel from and (x,y) are the pixel's coordinates. The only difference here is that we also include the color that we want to set. So, using the example above, if you wanted to set a color to spot 35, 42 of picture box "Picture1" you would use the following:
________________________________________________________
Picture1.PSet (35,42), Color
________________________________________________________
It is worth noting that Color is of type Long, which creates the same problem we discussed above - how to change the red/green/blue values into a single number. Fortunately, VB has a built-in command called RGB() that does this conversion for us. To illustrate it's use, let's use the same example saying that you want to change the color of the pixel at (35,42) to pure red:
________________________________________________________
Picture1.PSet (35,42), RGB(255, 0, 0)
________________________________________________________
The first RGB parameter is red, then green, then blue, so RGB(255,0,0) will set the color of pure red. Easy, isn't it?
PART 3 - USING THESE COMMANDS TO EDIT AN IMAGE'S DATA
First, a little disclaimer: entire books have been written on the theories behind GP and there are entire sub-disciplines whose job is nothing but optimizing graphics routines. So while what I'm showing you is a nice method, be advised that GP is an extremely complicated field, and to truly succeed in it you must be willing to do a little research. I have chosen a well-optimized and very standard method because it is easy to understand while still offering good results. But, for this first tutorial, don't be disappointed if the results aren't particularly incredible or lightning-fast. That's what the next three tutorials are for! :)
DOWNLOAD THE PSET/POINT EXAMPLE PROGRAM
The included .zip file will demonstrate how to change the brightness of an image using a standard linear brightness algorithm. The code is simple, and it pretty much speaks for itself. Read through the comments and make sure that you understand how everything works.
PART 4 - WHY ARE PSET AND POINT SO SLOW?
If you've tried out the sample code, you're probably not impressed…and rightfully so. PSet and Point - though easy to use - are extremely, extremely slow. Can you imagine trying to work with images 4 or 5 times the size of the demo one? You'd be dead and buried by the time it finished!
So why is this? To illustrate it, let's follow the path your computer takes for changing the color of a single pixel using Point and PSet, as done in the sample program. (Author's Note: I base these conclusions on general programming knowledge, not known facts; so, while I'm pretty sure that I'm right, I could be wrong on some of the details)
So there you have it: steps 1, 2, 5, 7, and 9 are what's slowing down your PSet/Point-based graphics program. Visual Basic is very nice in that it does almost all of your error checking for you, but there is a definite speed trade-off. In languages like C/C++, those error checking steps are removed - which is why C/C++ is generally faster but more dangerous to use. In the next three tutorials we will discuss alternate methods of doing graphics that cut out some of these "speed killer" steps.
So there is your basic graphics lesson for the day. You can now program any graphics routine using nothing but VB! Yay for you!
Actually, to be totally honest, I hope that you completely forget that Pset and Point even exist after reading the next three tutorials. Both are extremely slow and, well, just bad programming. Visual Basic is good for a lot of things but its pixel interfacing is a total joke. So, thankfully, there are three more tutorials that will show you better, faster ways to do graphics programming - but at least you now know how to use PSet and Point if the need ever arises.
Copyright 2002 by Tanner "DemonSpectre" Helland. This article may not be reproduced in any form (printed or electronic) without prior written consent from the author. This site may, however, be hyperlinked on the world wide web without permission from the author.
This programming source code is provided "as is". In no event shall the author or any of his affiliates be liable for any consequential, special, incidental or indirect damages of any kind arising out of the delivery, performance or use of this source code, to the maximum extent permitted by applicable law. While the source code has been developed with great care, it is not possible to warrant that it is error free. This source code is not designed or intended to be used in any activity that may cause personal injury, death or any other severe damage or loss.
Please contact
tannerhelland@hotmail.com with feedback and questions regarding this tutorial.