Solved

Send Byte Array

Posted on 2004-09-21
30
469 Views
Last Modified: 2013-11-13
I need to send a byte array over winsock.
This is what it looks like...

ReDim Bits(0 To 3, 0 To bmWidth - 1, 0 To bmHeight - 1) As Byte

GetBitmapBits Picture1.Image, bmSize, Bits(0, 0, 0)
   
    For Y = 0 To bmHeight - 1
        For X = 0 To bmWidth - 1
            Bits(2, X, Y) = Bits(2, X, Y) 'Red Bits
            Bits(1, X, Y) = Bits(1, X, Y) 'Green Bits
            Bits(0, X, Y) = Bits(0, X, Y) 'Blue Bits
        Next X
    Next Y

...
Now how do I send Bits(0, 0, 0) through winsock??? I'm thinking Bits(0, 0, 0) contains alot of information but when I look to see what it is all it says is 128. I know it contains more than that. So whats the easyest way to send it through winsock? Also can someone please explain how byte arrays work, I see them all the time but I cant figure out how to use them. Thanks.
0
Comment
Question by:Rickyman45
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 17
  • 13
30 Comments
 

Author Comment

by:Rickyman45
ID: 12118667
please someone help me
0
 
LVL 32

Expert Comment

by:Erick37
ID: 12125347
Firstly, I think you want to use the GetDIBits function to read RGB bitmaps.

Second, why are you assigning each value to itself?
Bits(2, X, Y) = Bits(2, X, Y) 'Red Bits
...

Make sure you are using pixel scalemode in your picturebox (not the default twips)

Here is a short sample which uses SetDIBits:
http://www.vb-helper.com/howto_setdibits.html



To send your data you may try:

dim vtdata as Variant

vtdata = Bits

WinSock1.SendData vtdata
0
 
LVL 32

Expert Comment

by:Erick37
ID: 12125464
Here is an example of using GetBitmapBits:

'Create a new project, add a command button and a picture box to the project, load a picture into the picture box.
'Paste this code into Form1
Private Type BITMAP
    bmType As Long
    bmWidth As Long
    bmHeight As Long
    bmWidthBytes As Long
    bmPlanes As Integer
    bmBitsPixel As Integer
    bmBits As Long
End Type
Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Dim PicBits() As Byte, PicInfo As BITMAP
Dim Cnt As Long, BytesPerLine as Long
Private Sub Command1_Click()
    'KPD-Team 1999
    'URL: http://www.allapi.net/
    'E-Mail: KPDTeam@Allapi.net
    'Get information (such as height and width) about the picturebox
    GetObject Picture1.Image, Len(PicInfo), PicInfo
    'reallocate storage space
    BytesPerLine = (PicInfo.bmWidth * 3 + 3) And &HFFFFFFFC
    ReDim PicBits(1 To BytesPerLine * PicInfo.bmHeight * 3) As Byte
    'Copy the bitmapbits to the array
    GetBitmapBits Picture1.Image, UBound(PicBits), PicBits(1)

'________________________________________________
'From here on it's modifying then reading the image back to the picturebox
'________________________________________________
    'Invert the bits
    For Cnt = 1 To UBound(PicBits)
        PicBits(Cnt) = 255 - PicBits(Cnt)
    Next Cnt
    'Set the bits back to the picture
    SetBitmapBits Picture1.Image, UBound(PicBits), PicBits(1)
    'refresh
    Picture1.Refresh
End Sub
0
PeopleSoft Has Never Been Easier

PeopleSoft Adoption Made Smooth & Simple!

On-The-Job Training Is made Intuitive & Easy With WalkMe's On-Screen Guidance Tool.  Claim Your Free WalkMe Account Now

 

Author Comment

by:Rickyman45
ID: 12127702
Erick37 when ever i try to make it a Variant it says "ByRef argument type mishmatch"
0
 

Author Comment

by:Rickyman45
ID: 12127716
If someone can explain to me what bit array is and how to use it ill give them the points.
0
 
LVL 32

Expert Comment

by:Erick37
ID: 12128101
What is the line which gives the error?

Typically, the "mismatch" error is thrown when you pass a variable of one type to a variable of another type which is incompatible.  For example, if you are using an API solution to winsock, then you cannot use variants.  The Winsock control which comes with VB accepts variant data.
0
 

Author Comment

by:Rickyman45
ID: 12138341
Im trying to send a picture using this example http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=37691&lngWId=1
 but I cant figure out how to send Bits(0, 0, 0)

Hope this helps
0
 
LVL 32

Expert Comment

by:Erick37
ID: 12138610
What are you using for winsock?
0
 

Author Comment

by:Rickyman45
ID: 12150378
winsock control 6.0
0
 
LVL 32

Expert Comment

by:Erick37
ID: 12153307
Hi Rickyman,

I modified the code from PSC a bit so that it reads the image into a single dimension byte array.  I'm assuming you do not need to manipulate RGB image data, so using using a 3 dimension array is not necessary.  The code below reads the picture into the array and sends it out via winsock.  I assume you have worked out the send and receive details in winsock.

Since you are only sending raw image RGB data to the remote computer, it is imperative that the code on the other side know the dimensions of the picturebox in advance and in order to properly interpret the data.  That means that the picturebox on the receive end must be identical in size (and scalemode) to the original picturebox.

Here's the code, good luck!

Private Sub cmdNegative_Click()
    'Private variable declarations
    Dim bmWidth As Long
    Dim bmHeight As Long
    Dim bmSize As Long
    Dim bmBits() As Byte
    Dim x As Long, y As Long
   
    'Get picture's Width and Height
    bmWidth = Picture1.Width
    bmHeight = Picture1.Height
   
    'Store size of bitmap in total pixels
    bmSize = 3 * bmWidth * bmHeight
   
    'ReDefine Bit array to hold all pixels from picture box
    ReDim bmBits(bmSize - 1)
   
    'Grab picture's pixels and load to Bit array
    GetBitmapBits Picture1.Image, bmSize, bmBits(0)
   
    Winsock1.SendData bmBits() '<< Send the byte array

End Sub



0
 

Author Comment

by:Rickyman45
ID: 12157203
I use something in winsock that makes it easier to send lots of data http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=22320&lngWId=1 but for some reason when I do Send_Data picture, bmBits() it gives me the error "ByRef argument type mishmatch" Please help me. PS: I'll give you lots more points if you can help me with this.
0
 
LVL 32

Expert Comment

by:Erick37
ID: 12169897
I am trying to get this to work.  I'm still working on it.
0
 
LVL 32

Accepted Solution

by:
Erick37 earned 405 total points
ID: 12172709
Ok, here is a very simple Client/Server sample which sends picturebox images from the client to the server.
This is by no means a full blown application.  There is no error handling, and no means of detecting lost or coprrupt data packets.  The code is for example only and I'm surprised myself that I got it to work at all.

The Client application sends a byte array to the server.  The first 4 bytes of the array store the size of the remaining picture portion of the array.  The picture data is retrieved from the picturebox using GetBitmapBits.

Here is the Client code::

'This is the Client application which sends a bitmap image via raw data to the Server application
'Start a new project and place a picturebox and a command button on the form
'You must customize the code where you see '********
'
'

Option Explicit

'API declarations
Private Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Dim bError As Boolean

Private Sub Form_Load()
    Me.Caption = "Client"
   
    Command1.Caption = "Send Picture"
   
    'setup the picturebox
    With Picture1
    .ScaleMode = vbPixels
    .BorderStyle = 0
   
    '*********
    .Picture = LoadPicture("c:\tcptest.bmp")
    '*********
   
    .Width = ScaleX(.Picture.Width, vbHimetric, ScaleMode)
    .Height = ScaleY(.Picture.Height, vbHimetric, ScaleMode)
    Debug.Print "Picture dimensions:", .ScaleWidth, .ScaleHeight
    End With
   
    'setup winsock
    With Winsock1
    .Protocol = sckTCPProtocol
    'Turn off firewall and/or open port 5163 on router.
   
    '********
    .RemoteHost = "192.168.1.100" 'Configure to your server
    .RemotePort = 5163 'Any unused port will do
    '********
   
    End With
End Sub

Private Sub Command1_Click()
   
    'Private variable declarations
    Dim bmWidth As Long
    Dim bmHeight As Long
    Dim bmSize As Long
    Dim bmBits() As Byte
    Dim x As Long, y As Long
   
    'Get picture's Width and Height
    bmWidth = Picture1.ScaleWidth
    bmHeight = Picture1.ScaleHeight
   
    'Store size of bitmap in total pixels
    bmSize = 3 * bmWidth * bmHeight
   
    'ReDefine Bit array to hold all pixels from picture box
    ReDim bmBits(bmSize + 3)
   
    'write the size of the bitmap buffer to the beginning of the array
    Call CopyMemory(bmBits(0), bmSize, 4)
   
    'Grab picture's pixels and load to Bit array
    'Start at the 5th location, because we store the size of the buffer in the first 4 bytes
    GetBitmapBits Picture1.Image, bmSize, bmBits(4)
   
    Winsock1.Close
    Winsock1.Connect
   
    Command1.Enabled = False
    bError = False
   
    Do While (Winsock1.State <> sckConnected) And (Not bError)
        Call Sleep(100)
        DoEvents
        If bError Then Exit Do 'check for errors
    Loop
   
    Command1.Enabled = True
   
    If (Winsock1.State = sckConnected) Then
        Winsock1.SendData bmBits
    End If
   
End Sub

Private Sub Winsock1_Error(ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)
    Debug.Print "Winsock Error #" & CStr(Number) & " " & Description
    bError = True
End Sub

0
 
LVL 32

Expert Comment

by:Erick37
ID: 12172771
And here is the Server application.

Note:  Make sure that the picturebox on the client and server have the same dimensions.

'Server code
'Open a new instance of VB and create a new project
'On the form, place a picturebox and a winsock control
'Code marked with '******** needs to be customized to fit your application

Option Explicit

'API declarations
Private Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private Sub Form_Load()
    Me.Caption = "Server"
   
    'Setup the receiving picturebox
    With Picture1
    .AutoRedraw = True
    .BorderStyle = 0
    .ScaleMode = vbPixels
    '//You must hardcode the picturebox dimensions to be exactly
    '//   the same as the client picturebox.  In this case 200x150 pixels.
   
    '********
    .Width = ScaleX(200, vbPixels, ScaleMode)
    .Height = ScaleY(150, vbPixels, ScaleMode)
    '********
   
    End With

    'setup winsock
    With Winsock1
   
    '********
    .LocalPort = 5163 'must match Client port
    '********
   
    .Listen
    End With
End Sub

Private Sub Winsock1_ConnectionRequest(ByVal requestID As Long)
    With Winsock1
    .Close
    .Accept requestID
    Debug.Print "Server: ConnectionRequest"
    End With
End Sub

Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
    Static lBytesReceived As Long
    Static lBuffSize As Long
    Static bData() As Byte
    Dim bTmpData() As Byte
    Dim lRet As Long
   
    If (lBuffSize = 0) Then 'This is the first packet
        'peek at the first 4 bytes and store in lBuffSize
        Winsock1.PeekData lBuffSize, vbLong, 4
        Debug.Print "Image Buffer Size: " & CStr(lBuffSize)
        'Size the buffer to accept all data
        ReDim bData(lBuffSize + 3)
    End If
   
    'Get this chunk
    Winsock1.GetData bTmpData
   
    'Copy the data to the buffer
    Call CopyMemory(bData(lBytesReceived), bTmpData(0), bytesTotal)
   
    'Update our counter
    lBytesReceived = lBytesReceived + bytesTotal
       
    If (lBytesReceived >= lBuffSize) Then 'Finished draw picture
        'Load Bit array to picture box
        lRet = SetBitmapBits(Picture1.Image, lBuffSize, bData(4))
        'SetBitmapBits normally triggers a redraw event,
        'but just in case it doesn't, we'll do one now
        Picture1.Refresh
        'Done: reset variables
        ReDim bData(0)
        lBytesReceived = 0
        lBuffSize = 0
        Debug.Print "Done!"
       
        Winsock1.Close
        Winsock1.Listen

    End If
   
End Sub

0
 

Author Comment

by:Rickyman45
ID: 12173678
Works for me
0
 

Author Comment

by:Rickyman45
ID: 12174491
for some reason when i make the picture the same size it gives me an error but when i make them different its all blury
0
 

Author Comment

by:Rickyman45
ID: 12174820
after messing with it for a while I figured it out, You are my hero! I've been trying to get this code for a very long time. Thank you so much.
0
 
LVL 32

Expert Comment

by:Erick37
ID: 12174981
You're welcome, glad it worked.
0
 

Author Comment

by:Rickyman45
ID: 12176373
even though I accecpted your answer I still have a question. For some reason when I try to send 2 pictures the first one will work but the second will freeze the program I dont even get an error. So im thinking one of the variables wasnt cleared. Do you have any ideas?
0
 
LVL 32

Expert Comment

by:Erick37
ID: 12176600
Which side freezes, client or server?
Does this happen when sending the same picture twice, or different pictures?
0
 

Author Comment

by:Rickyman45
ID: 12183885
server, and sometimes its the same pic sometimes its different.
0
 

Author Comment

by:Rickyman45
ID: 12184276
I've got it 100% working except for the freezeing problem I get this error Visual Basic has encountered a problem and needs to close.  We are sorry for the inconvenience. and i can send the error or dont send it. But everything else is working great the picture will load on the other computer in just a few milli seconds, which is exactly what I needed.
0
 

Author Comment

by:Rickyman45
ID: 12184761
I figured something else out that might help, when I delete the lines
lBytesReceived = 0
lBuffSize = 0
it doesnt crash but I get the error "Script out of range" and it highlights the line
Call CopyMemory(bData(lBytesReceived), bTmpData(0), bytesTotal)
I dont see why I even need to reset the variables because it should just write over them when it gets the next picture. I think it will work if I can just fix this error but I dont know what "script out of range" means.
0
 
LVL 32

Expert Comment

by:Erick37
ID: 12186395
In the Server code:

Static lBytesReceived As Long
Static lBuffSize As Long

Both are declared as Static, that means that they retain their values even when the function ends.  I had to make them static because the DataArrival event is triggered several times while all of the data arrives in chunks and their values are needed to tell when all of the data arrives.

When lBytesReceived >= lBuffSize then we know all of the data has been received and then we can draw the picture.  That is when we reset all of the Static variables.  The error "subscript out of range" means that the index you passed to an array was too big or too little.  In the case of bData(lBytesReceived), unless lBytesReceived is reset to 0, it will get too big and point to an index "out of range" of the array.

If VB is crashing and burning it's probably the CopyMemory line that is causing it.  If lBuffSize is not correct then CopyMemory may be attempting to write data to memory outside the applications allocated heap.  This will crash the app.

It is very important to make sure the size of the buffer is correct on both sides, client and server.  I have updated the Sever code to do some checking before the CopyMemory call.  It will not solve the problem, but it will probably keep the app from crashing while you debug why the buffer is too small.

Here's the updated Server code:

'Server code
'Open a new instance of VB and create a new project
'On the form, place a picturebox and a winsock control
'Code marked with '******** needs to be customized to fit your application

Option Explicit

'API declarations
Private Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private Sub Form_Load()
    Me.Caption = "Server"
   
    'Setup the receiving picturebox
    With Picture1
    .AutoRedraw = True
    .BorderStyle = 0
    .ScaleMode = vbPixels
    '//You must hardcode the picturebox dimensions to be exactly
    '//   the same as the client picturebox.  In this case 200x150 pixels.
   
    '********
    .Width = ScaleX(200, vbPixels, ScaleMode)
    .Height = ScaleY(150, vbPixels, ScaleMode)
    '********
   
    End With

    'setup winsock
    With Winsock1
   
    '********
    .LocalPort = 5163 'must match Client port
    '********
   
    .Listen
    End With
End Sub

Private Sub Winsock1_ConnectionRequest(ByVal requestID As Long)
    With Winsock1
    .Close
    .Accept requestID
    Debug.Print "Server: ConnectionRequest"
    End With
End Sub

Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
    Static lBytesReceived As Long
    Static lBuffSize As Long
    Static bData() As Byte
    Dim bTmpData() As Byte
    Dim lRet As Long
   
    If (lBuffSize = 0) Then 'This is the first packet
        'peek at the first 4 bytes and store in lBuffSize
        Winsock1.PeekData lBuffSize, vbLong, 4
        Debug.Print "Image Buffer Size: " & CStr(lBuffSize)
        'Size the buffer to accept all data
        ReDim bData(lBuffSize + 3)
    End If
   
    'Get this chunk
    Winsock1.GetData bTmpData
   
    '~~~~~~~~~~NEW~~~~~~~~~~~~~~~~~~~~~~~
    If (lBytesReceived + bytesTotal <= lBuffSize + 4) Then
        'Copy the data to the buffer
        Call CopyMemory(bData(lBytesReceived), bTmpData(0), bytesTotal)
    Else
        MsgBox "Buffer is too small", vbCritical, App.Title
        'Reset variables
        ReDim bData(0)
        lBytesReceived = 0
        lBuffSize = 0
        Winsock1.Close
        Winsock1.Listen
        Exit Sub
    End If
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   
    'Update our counter
    lBytesReceived = lBytesReceived + bytesTotal
       
    If (lBytesReceived >= lBuffSize) Then 'Finished draw picture
        'Load Bit array to picture box
        lRet = SetBitmapBits(Picture1.Image, lBuffSize, bData(4))
        'SetBitmapBits normally triggers a redraw event,
        'but just in case it doesn't, we'll do one now
        Picture1.Refresh
        'Done: reset variables
        ReDim bData(0)
        lBytesReceived = 0
        lBuffSize = 0
        Debug.Print "Done!"
       
        Winsock1.Close
        Winsock1.Listen

    End If
   
End Sub

0
 

Author Comment

by:Rickyman45
ID: 12186683
i changed bmSize = 3 * bmWidth * bmHeight to bmSize = 4 * bmWidth * bmHeight because it cut off 1/4 of the picture when set to 3. So when I change it back to 3 it works but it still only shows 3/4 of the picture.
0
 

Author Comment

by:Rickyman45
ID: 12194335
i got it working I dont know why it is but it is. I changed If (lBytesReceived >= lBuffSize) Then to If (lBytesReceived > lBuffSize) Then but... I now have another problem when every I try to transfer it to 127.0.0.1 which is local it only takes about 1/2 second which is what I need but when I send it over lan it takes about 15 seconds why??? It's a big picture but its just a picture how come it takes so long??
0
 
LVL 32

Expert Comment

by:Erick37
ID: 12194707
If your picture is 640 x 480, then the image data is 640 x 480 x 3 = 921,600 bytes!  It's going to take time to send that amount of data through the network, depending on traffic and network speed.
0
 

Author Comment

by:Rickyman45
ID: 12195844
why do I have to multyply it by 3? what happens if I dont?
0
 

Author Comment

by:Rickyman45
ID: 12195858
921,600 is only 0.87890625 megabytes that should not take 15 seconds to send through a network. Its got to be something else that slows it down.
0
 
LVL 32

Expert Comment

by:Erick37
ID: 12195866
3 bytes per pixel, one for red, green, blue.
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
When we want to run, execute or repeat a statement multiple times, a loop is necessary. This article covers the two types of loops in Python: the while loop and the for loop.
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

631 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question