none
Can I create an integer array from an internal memory location (like you can a bitmap) RRS feed

  • Question

  • Using GCHandle, it is possible to generate a new bitmap directly off internal memory that has been temporarily pinned. See 'UIntToBitmapExample()

    But surely there is a way to do the reverse. Lock an existing bitmap into memory and then create a new integer array to share the same memory temporarily while it is pinned.

    Appreciate any insights on how to achieve this. Maybe there is another forum more suitable for unmanaged questions, but hoping that this is achievable with VB

    Imports System.Runtime.InteropServices
    Public Class Form4
        Private bmp As New Bitmap(16, 16)
        Private gcH As GCHandle
        Private ntgr() As UInteger
    
        Private Sub Form7_Load(sender As Object, e As EventArgs) Handles Me.Load
            ClientSize = New Size(1000, 1100)
            CenterToScreen()
        End Sub
    
        Private Sub Form4_Click(sender As Object, e As EventArgs) Handles Me.Click
            BitmapToUintExample()
            'UIntToBitmapExample()
            Invalidate()
        End Sub
    
        Private Sub BitmapToUintExample()
            bmp = New Bitmap("e:\LTemp2017\WLH01.png") ' << Change this to your chosen picture file
            Dim rect As New Rectangle(0, 0, bmp.Width, bmp.Height)
            Dim bmpData As Imaging.BitmapData = bmp.LockBits(rect,
            Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat)
            Dim I As Integer = bmp.Width * bmp.Height - 1
            gcH = GCHandle.Alloc(bmpData, GCHandleType.Pinned)
            'ReDim ntgr(I, gcH.AddrOfPinnedObject) ' << this is pseudo code << 
            'how to declare a new array upon gcH.AddrOfPinnedObject ? ? ?  <<
            gcH.Free()
        End Sub
    
        Private Sub UIntToBitmapExample()
            Dim I As Integer
            ReDim ntgr(404999) ' = W * H - 1    for a 1800 X 900 bitmap 32bpp
            For I = 0 To 404999
                ntgr(I) = 4294967040 ' yellow fill
            Next
            For I = 5400 To 7199 ' draw black line
                ntgr(I) = 4278190080
            Next
            gcH = GCHandle.Alloc(ntgr, GCHandleType.Pinned)
            bmp = New Bitmap(900, 450, 3600, Imaging.PixelFormat.Format32bppPArgb, gcH.AddrOfPinnedObject)
            gcH.Free()
        End Sub
    
        Private Sub Form4_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
            e.Graphics.DrawImage(bmp, 0, 0)
        End Sub


    Pride is the most destructive force in the universe


    • Edited by LeonCS Monday, October 2, 2017 2:21 AM
    Monday, October 2, 2017 2:15 AM

All replies

  • But surely there is a way to do the reverse. Lock an existing bitmap into memory and then create a new integer array to share the same memory temporarily while it is pinned.

    It depends on whether or not the integer values have a meaning within the context.   Any sequence of bits can be referred to as Integer, but whether that provides the Integer value you expect from that particular set of bytes is a different question.

    Use a Structure and the FieldOffset attribute to map two primitive types to the same memory location.  See: 
    https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.fieldoffsetattribute(v=vs.110).aspx

    Whether or not you can do this for an array would require some experimenting.

    Monday, October 2, 2017 3:55 AM
  • Consider the next way too. It uses the ImageMatrix class, designed to deal with 32-bit pixels as a matrix of integer numbers:

    Public Class ImageMatrix
        Implements IDisposable
    
        Private ReadOnly bmp As Bitmap
        Private ReadOnly bd As BitmapData
    
        Public Sub New(image As Bitmap)
            Me.bmp = image
            Dim rect As New Rectangle(0, 0, image.Width, image.Height)
            Me.bd = image.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
        End Sub
    
    
        Default Public Property Item(x As Integer, y As Integer) As Int32
            Get
                Dim p = GetPtr(x, y)
                Return Marshal.ReadInt32(p)
            End Get
            Set(value As Int32)
                Dim p = GetPtr(x, y)
                Marshal.WriteInt32(p, value)
            End Set
        End Property
    
        Public Sub Dispose() Implements IDisposable.Dispose
            bmp.UnlockBits(bd)
        End Sub
    
        Private Function GetPtr(x As Integer, y As Integer) As IntPtr
    
            If x < 0 OrElse x >= bd.Width Then Throw New ArgumentOutOfRangeException(String.Format("Invalid x: {0}. Width: {1}", x, bd.Width))
            If y < 0 OrElse y >= bd.Height Then Throw New ArgumentOutOfRangeException(String.Format("Invalid y: {0}. Height: {1}", x, bd.Height))
    
            Return New IntPtr(bd.Scan0.ToInt64 + bd.Stride * y + x * Marshal.SizeOf(GetType(UInt32)))
    
        End Function
    
    End Class

    Sample usage:

    bmp = New Bitmap(". . .")
    
    Using m As New ImageMatrix(bmp)
    
       For x = 0 To bmp.Width - 1
          For y = 0 To bmp.Height - 1
             m(x, y) = &HFF_FF_FF_00 ' 4294967040UI -- yellow fill
          Next
       Next
    
       For x = 0 To bmp.Width - 1
          m(x, bmp.Height \ 2) = &HFF_00_00_00 ' 4278190080UI -- black horizontal line
       Next
    
       For y = 0 To bmp.Height - 1
          m(bmp.Width \ 2, y) = &HFF_00_00_00 ' 4278190080UI -- black vertical line
       Next
    
    End Using
    
    PictureBox1.Image = bmp

    The above “( x, y )” operator makes the locked bytes to look like a bi-dimensional array.

    It can be improved and adjusted to specific needs.

    In other languages (C++, C#) you can use pointers, which are more efficient than Marshal class.


    • Edited by Viorel_MVP Monday, October 2, 2017 6:10 AM
    Monday, October 2, 2017 6:07 AM
  • Thanks Viorel

    Following your lead I tested how quickly I could loop through and simply read the values with offset from PTR. Interestingly, the marshal read is 10 times slower than a similar read from a normal integer array.

    But marshal read is still a serious contender when seeking a method to construct color pallets from bitmaps, and access the integer color values from a bitmap.

    My test bitmap is 713 X 1005 in size. The bitmap must load as a 32bit bitmap for the following code to work.

        Private Sub BitmapToIntExample()
            Dim I As Integer
            bmp = New Bitmap("e:\LTemp2017\WLH01.png") ' << Change this to your chosen picture file
            Dim rect As New Rectangle(0, 0, bmp.Width, bmp.Height)
            Dim bmpData As Imaging.BitmapData = bmp.LockBits(rect,
            Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat)
            Dim _length As Integer = CInt(bmpData.Stride * bmp.Height / 4) ' = 716565
            'MsgBox(_length.ToString)
            ReDim ntgr(_length - 1)
            Dim _color As Integer
            sw.Reset()
            sw.Start()
            Dim ptr As IntPtr = bmpData.Scan0
            For I = 0 To _length - 1
                _color = Marshal.ReadInt32(ptr + I * 4)
            Next
            sw.Stop()
            MsgBox(sw.ElapsedMilliseconds.ToString) ' took 10 milliseconds
            'sw.Reset()
            'sw.Start()
            'For I = 0 To _length - 1
            '_color = ntgr(I)
            'Next
            'sw.Stop()
            'MsgBox(sw.ElapsedMilliseconds.ToString) ' this took only 1 millisecond
            bmp.UnlockBits(bmpData)
        End Sub


    Pride is the most destructive force in the universe


    • Edited by LeonCS Monday, October 2, 2017 10:21 AM
    Monday, October 2, 2017 10:19 AM
  • It depends on whether or not the integer values have a meaning within the context.

    Cheers Acamar

    If only I knew how to apply a Structure to the IntPtr ? ? ? It would be interesting to see the total time taken to establish the structure, and read all the values.

    In the operation of listing all the unique colors in a bitmap, there would be no need to access the ARGB component values - - just compare and build a list.

    If I wanted to expose the ARGB values inherent in the Integer, I could use the following : -

            Dim J As Integer
            Dim B(3) As Byte
            J = -1 '-2147483648
            B(0) = CByte(J And 255)
            B(1) = CByte((J And 65280) / 256)
            B(2) = CByte((J And 16711680) / 65536)
            If J > -1 Then
                B(3) = CByte((J And -16777216) / 16777216)
            Else : B(3) = CByte((J And -16777216) / 16777216 + 256)
            End If

    A 32bpp image will have a [B, G, R, A][B, G, R, A]. . . . format, so B(0) is blue, B(1) is green, B(2) is red, B(3) is alpha

    Or given known ARGBs, get the integer by the following

            Dim I As Integer
            Dim B(3) As Byte
            B(0) = 0 : B(1) = 255 : B(2) = 0 : B(3) = 255
            I = B(0) + B(1) * 256 + B(2) * 65536
            If B(3) < 128 Then
                I += B(3) * 16777216
            Else : I += (B(3) - 256) * 16777216
            End If


    Burn all valuable data to CD/DVD disks. EMP proof.



    • Edited by LeonCS Wednesday, October 4, 2017 9:45 AM
    Wednesday, October 4, 2017 9:35 AM
  • Hi leonCS,

    From this article , wen can see that LockBits and UnlockBits methods in the following example are not designed to work correctly with all pixel formats,  so I guess that different images may have different effects.

    https://msdn.microsoft.com/en-us/library/5ey6h79d(v=vs.110).aspx

    Best Regards,

    Cherry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, October 11, 2017 9:25 AM
    Moderator
  • Leon,

    While busy with questions about memory be clear what you mean with that. 

    The .Net developers do not mean by that the hardware memory like others mostly do.

    This has already given many problems for persons who started to buy new hardware memory when they got the message. "It mostly means that the memory is corrupted." (Which is than the by .Net allocated memory).


    Success
    Cor


    • Edited by Cor Ligthert Wednesday, October 11, 2017 1:13 PM
    Wednesday, October 11, 2017 10:02 AM
  • Cherry

    Lockbit/unlockbits method does not share the same pinned (locked) memory with the second object (like GC Handle method). With lock/unlock bits, you have to marshal COPY the memory into a new array object. Or with lock/unlock bits you can marshal read the memory - - but it is 10 times slower than reading a normal integer array. See above posts.

    So no, lock/unlock bits functionality does not offer what I am asking for here.


    Burn all valuable data to CD/DVD disks. EMP proof.

    Thursday, October 12, 2017 9:23 AM
  • Hi Cor

    Am a bringing to view the GC Handle method of pinning (locking) the memory of one given array object, and then overlaying a new bitmap object over that same pinned memory. It is virtually instantaneous.

    And, the point of this thread is to ask why the reverse is not possible - - that is - -  to pin a given bitmap object and then overlay a new array object over that same pinned memory.


    Burn all valuable data to CD/DVD disks. EMP proof.

    Thursday, October 12, 2017 9:29 AM
  • Hi Cor

    Am a bringing to view the GC Handle method of pinning (locking) the memory of one given array object, and then overlaying a new bitmap object over that same pinned memory. It is virtually instantaneous.

    And, the point of this thread is to ask why the reverse is not possible - - that is - -  to pin a given bitmap object and then overlay a new array object over that same pinned memory.


    Burn all valuable data to CD/DVD disks. EMP proof.

    Leon,

    I think (based on knowledge) that it makes no sense to to search for that. 

    Every hacker would be glad if that was so simple to do, and those simple things are closed with endless locks (and if it is not today, it is  tomorrow)


    Success
    Cor


    • Edited by Cor Ligthert Thursday, October 12, 2017 11:19 AM
    Thursday, October 12, 2017 11:18 AM
  • Cor

    No, it has nothing to do with hacking - - otherwise using lock-bits is also hacking.


    Burn all valuable data to CD/DVD disks. EMP proof.

    Saturday, October 14, 2017 9:48 AM