Introduction
As most of you already know, the .NET environment offers us to Frameworks to do all kinds of cool stuff, including the Drawing classes and objects. BUT?
When we want to use the graphics on a high frame rate, the DrawImage method
just won't do, it's too slow (I am not sure why but it is :] ). So as very well introduced by Matthew Hazlett, the BitBlt
comes to our aid by doing stuff VERY fast. (His article which is very informative and was the foundation for this article and code is located here.)
What I will try to do here is to take it just one step further, give out some guidelines and pointers. Plus - this sample code will provide a very clean and well commented class you can use to learn or even implement in your projects.
In the demo project, I have created a class which copies to memory, and from memory using BitBlt
, it's well documented and easy to understand.
A Quick Run Through The Basics
Just to get things stated, in order to use the BitBlt
function we have to declare it, as it is not a part of the Frameworks, but a part of the Window's API. The function is located at the "GDI32.dll" library, and that's about it. The declaration goes like this:
Private Declare Auto Function BitBlt Lib "GDI32.DLL" _
( ByVal hdcDest As IntPtr, ByVal nXDest As Integer, _
ByVal nYDest As Integer, ByVal nWidth As Integer, _
ByVal nHeight As Integer, ByVal hdcSrc As IntPtr, _
ByVal nXSrc As Integer, ByVal nYSrc As Integer, _
ByVal dwRop As Int32) As Boolean
Now what we do is to copy Bitmaps from one location in the memory to another, these locations are called a Device Context, as they are directly connected to a Graphical Device on the system, for instance - a Picture Box or a Form.
What are all the other parameters? There are the X, Y, Width, Height which tell BitBlt
what is the area we wish to copy, and X and Y parameters to Where to copy at the target Device Context (which is used as our canvas).
Creating a Device Context is Not That Complicated
So for us to be able to use BitBlt
, we need 2 Device Contexts (hard to pronounce isn't it?) To create those, we first need a Graphics
object, we create that one from (almost) any object we want, for example, we can use a picture box:
PictureBox1.CreateGraphics
Dim GrpObj as Graphics = PictureBox1.CreateGraphics
Now we have GrpObj
as a Graphics
object, which we can use to create the Device Context:
Dim MyDeviceContext as IntPtr MyDeviceContext = GrpObj.GetHdc()
(Note: Hdc = Handle of Device Context)
Now what did we just do? We created an Object in Memory which represents the Graphical Object GrpObj
. Now we can use the Device Context to BitBlt
.
RULE NUMBER 1
While we have a Device Context in use, the Parent
Object (in this case GrpObj
) cannot be accessed directly, an attempts to draw to it (like using the .DrawArc
method) will result in an exception! We DO NOT want that.
So - right after creating and using a Device Context, we make sure to Release it:
GrpObj.ReleaseHdc (MyDeviceContext)
Note that the Parent of GrpObj
is also locked until the Device Context is released. AND we have to dispose of it too, to keep our memory leaks to the minimum. ;)
GrpObj.Dispose()
Now we need another Device Context to copy to. To do so, we will create an invisible Device Context in the memory very easily.
Dim srcBmp As New Bitmap(Size.Width, Size.Height, GrpObj)
MemoryGrpObj = Graphics.FromImage(srcBmp)
MemoryHdc = MemoryGrpObj.GetHdc
BitBliting the Images
Now we can copy anything we want to or from this Device Context. Providing
RULE NUMBER 2
After Blitting to memory, we have to keep the Device Context in scope, because when we Blit to memory, the changes will reset after we release the device context. THUS- we either keep the MemoryHDC
as a Global variable or use it in the same procedure.
Still we mustn't forget to release the Device Context so we also have to make sure to keep the Graphics object MemotyGrpObj
reference as well, ok?
Now we can Actually Blit
BitBlt(MemoryHDC, 0, 0, width, Height, MyDeviceContext, 0, 0, SRCCOPY)
^ Target ^ ^ Source ^
This will copy From MyDeviceContext
To MemoryHdc
.
A quick side note: The 'SRCCOPY'
is one of the many raster operations BitBlt can do for us, this (the most commonly used) operation copies an exact copy of the bitmap, I have declared SRCCOPY
as a Const, this is the value.
Dim SRCCOPY as Integer = &HCC0020 or
Dim SRCCOPY as Integer = 13369376
We can also use BitBlt to create masks, transparency and some more cool stuff (FYI).
All we need to do now is to create our target Device Context, and BitBlt
to it from the memory, we can keep an array of Device Contexts, just remember to follow the rules!
To finish up, note that if you want to draw on a specific location, here is the syntax:
BitBlt(TargetHdc, Xpos, Ypos, width, Height, MemoryHDC, 0, 0, SRCCOPY)
^ ^
The sample project will demonstrate it all and maybe save you the trouble. Good luck.