Results 1 to 2 of 2

Thread: Memory Blt

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,238

    Memory Blt

    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.

  2. #2
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Memory Blt

    Your assumption about LoadImage is wrong. You should read the documentation regarding the various flags; most notably: LR_CREATEDIBSECTION.

    Your assumptions about 32bpp doesn't make a lot of sense either. The only difference between 24 and 32 bpp bitmaps is the alpha channel. Even if BitBlt could some how result in color loss when source & destination both contain same bit depth, then other APIs can be used and are described in the documentation of BitBlt. If the alpha channel should be used in the blit'ing, for blending, then BitBlt is the wrong API anyway.

    Last but not least, your code does not address 24 bit images which are far more common than 32 bit. If your scenarios affect 32 bit, then they also affect 24 bit. Nor does it address another scenario, nearly as important as BitBlt: StretchBlt. Rarely does anyone dealing with graphics only need to simply copy image data, from A to B, always in the same scale.
    Last edited by LaVolpe; Jan 14th, 2018 at 09:23 AM. Reason: typo
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width