In order to copy graphics, you typically use BitBlt which works on DCs containing Bitmap objects. But the problem with that is that you have to keep track of all your DCs and Bitmaps (and dispose of them when done, to prevent memory leaks), and color conversions can happen behind the scenes. For example, if I use LoadImage API on an older machine with 8bit graphics, it will automaticlally convert any bitmap (even a 32bit bitmap file) into either an 8bit bitmap, or a 32bit bitmap who's color values correspond to the colors of the default 8bit system palette. This causes significant loss in color depth, so any images saved after that, will be permanently lowered in color depth, and look very ugly.
So I need to avoid using the Windows APIs altogether for loading 32bit bitmaps (only using the API functions to display bitmaps to the screen after any processing is done) if I want my program to be compatible on nearly all computers (both new and very old). I will need to write my own code for loading the image data from 32bit BMP files into RGBQuad arrays. But then when I do that, I have the other problem of losing all of the API functions like BitBlt that work with bitmaps and DCs. Those don't work with arrays. So that is why I have written my own Memory Blt functions. These copy images (or parts of images) from one RGBQuad array to another. I have 2 such functions. Below is the code for these, that you can put in any VB6 Module.
The two Memory Blt subs are MemBlt and MemBlt2.
MemBlt does all required bounds checking, and changes as necessary the size of the copied region so that it fits within both of the RGBQuad arrays. If the copied region is completely outside of either the source or the destination, then it exits immediately. It uses __vbaCopyBytes instead of RtlMoveMemory (aka CopyMemory), because __vbaCopyBytes is faster (no memory region overlap compensating), and also because the overlap compensating done by RtlMoveMemory only works in a 1D memory region. It fails to prevent the problems produced by overlap of source and destination when working in a 2D memory region. So why slow it down when the slower function isn't even effective in the situation it's being used in?
Of course the overlap problem does need a solution. While MemBlt is fine for use as-is when the source array and destination array are different, or when they are the same but the regions are different (and in fact MemBlt is better in these cases, because it's faster), there is still the problem of what to do when the source and destination arrays are the same and the regions overlap. To fix that, I created MemBlt2. It creates a temporary RGBQuad array, and performs 2 calls to MemBlt. First call to MemBlt copies a region from the source array to the temporary array, and the second call to MemBlt copies from the temporary array to the destination array. This is slower, but effective at preventing the problems that can occur when the source and destination arrays are the same, and source and destination regions overlap. This is the 2D equivalent to RtlMoveMemory.
So I need to avoid using the Windows APIs altogether for loading 32bit bitmaps (only using the API functions to display bitmaps to the screen after any processing is done) if I want my program to be compatible on nearly all computers (both new and very old). I will need to write my own code for loading the image data from 32bit BMP files into RGBQuad arrays. But then when I do that, I have the other problem of losing all of the API functions like BitBlt that work with bitmaps and DCs. Those don't work with arrays. So that is why I have written my own Memory Blt functions. These copy images (or parts of images) from one RGBQuad array to another. I have 2 such functions. Below is the code for these, that you can put in any VB6 Module.
Code:
Public Declare Sub CopyBytes Lib "msvbvm60.dll" Alias "__vbaCopyBytes" (ByVal ByteCount As Long, ByRef Dest As Any, ByRef Src As Any)
Public Type RGBQuad
B As Byte
G As Byte
R As Byte
unused As Byte
End Type
Public Sub MemBlt( _
ByVal Width As Long, _
ByVal Height As Long, _
ByVal SrcX As Long, _
ByVal SrcY As Long, _
ByVal DestX As Long, _
ByVal DestY As Long, _
ByRef Src() As RGBQuad, _
ByRef Dest() As RGBQuad)
Dim UBXSrc As Long
Dim UBYSrc As Long
Dim UBXDest As Long
Dim UBYDest As Long
Dim y As Long
Dim y1 As Long
Dim y2 As Long
Dim ByteWidth As Long
UBXSrc = UBound(Src, 1)
UBYSrc = UBound(Src, 2)
UBXDest = UBound(Dest, 1)
UBYDest = UBound(Dest, 2)
If SrcX < 0 Then
Width = Width + SrcX
SrcX = 0
ElseIf SrcX > UBXSrc Then
Exit Sub
End If
If SrcX + Width - 1 < 0 Then
Exit Sub
ElseIf SrcX + Width - 1 > UBXSrc Then
Width = (UBXSrc - SrcX) + 1
End If
If SrcY < 0 Then
Height = Height + SrcY
SrcY = 0
ElseIf SrcY > UBYSrc Then
Exit Sub
End If
If SrcY + Height - 1 < 0 Then
Exit Sub
ElseIf SrcY + Height - 1 > UBYSrc Then
Height = (UBYSrc - SrcY) + 1
End If
If DestX < 0 Then
Width = Width + DestX
DestX = 0
ElseIf DestX > UBXDest Then
Exit Sub
End If
If DestX + Width - 1 < 0 Then
Exit Sub
ElseIf DestX + Width - 1 > UBXDest Then
Width = (UBXDest - DestX) + 1
End If
If DestY < 0 Then
Height = Height + DestY
DestY = 0
ElseIf DestY > UBYDest Then
Exit Sub
End If
If DestY + Height - 1 < 0 Then
Exit Sub
ElseIf DestY + Height - 1 > UBYDest Then
Height = (UBYDest - DestY) + 1
End If
ByteWidth = Width * 4
For y = 0 To Height - 1
y1 = SrcY + y
y2 = DestY + y
CopyBytes ByteWidth, Dest(DestX, y2), Src(SrcX, y1)
Next y
End Sub
Public Sub MemBlt2( _
ByVal Width As Long, _
ByVal Height As Long, _
ByVal SrcX As Long, _
ByVal SrcY As Long, _
ByVal DestX As Long, _
ByVal DestY As Long, _
ByRef Src() As RGBQuad, _
ByRef Dest() As RGBQuad)
Dim temppix() As RGBQuad
ReDim temppix(Width - 1, Height - 1)
MemBlt Width, Height, SrcX, SrcY, 0, 0, Src(), temppix()
MemBlt Width, Height, 0, 0, DestX, DestY, temppix(), Dest()
End Sub
The two Memory Blt subs are MemBlt and MemBlt2.
MemBlt does all required bounds checking, and changes as necessary the size of the copied region so that it fits within both of the RGBQuad arrays. If the copied region is completely outside of either the source or the destination, then it exits immediately. It uses __vbaCopyBytes instead of RtlMoveMemory (aka CopyMemory), because __vbaCopyBytes is faster (no memory region overlap compensating), and also because the overlap compensating done by RtlMoveMemory only works in a 1D memory region. It fails to prevent the problems produced by overlap of source and destination when working in a 2D memory region. So why slow it down when the slower function isn't even effective in the situation it's being used in?
Of course the overlap problem does need a solution. While MemBlt is fine for use as-is when the source array and destination array are different, or when they are the same but the regions are different (and in fact MemBlt is better in these cases, because it's faster), there is still the problem of what to do when the source and destination arrays are the same and the regions overlap. To fix that, I created MemBlt2. It creates a temporary RGBQuad array, and performs 2 calls to MemBlt. First call to MemBlt copies a region from the source array to the temporary array, and the second call to MemBlt copies from the temporary array to the destination array. This is slower, but effective at preventing the problems that can occur when the source and destination arrays are the same, and source and destination regions overlap. This is the 2D equivalent to RtlMoveMemory.