Quantcast
Channel: VBForums - CodeBank - Visual Basic 6 and earlier
Viewing all articles
Browse latest Browse all 1450

Memory Blt

$
0
0
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.

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.

Viewing all articles
Browse latest Browse all 1450

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>