Sending images using a NetworkStream

ozonic

Member
Joined
Jun 17, 2006
Messages
21
Programming Experience
Beginner
I am new to VB.NET and I have a bit of a problem. I've got a Client/Server program using the TcpClient and TcpListener. I am able to send strings from the Client to the Server using a NetworkStream and converting the strings from text to bytes using the following instructions:

'Convert string to bytes
Dim Buffer As [Byte]() = System.Text.Encoding.ASCII.GetBytes("String to send")

'Send contents of buffer (bytes)
NetworkStream.Write(Buffer, 0, Buffer.Length)

My question is: How can I possibly send an image from the client (TcpClient) to the server (TcpListener)? Would I have to convert the image into bytes in the same way as I've done with the strings, and if so how do I do that? If that's not possible, do you have any other suggestions?

I would greately appreciate any ideas.
 
Save the image to a stream and send the bytes from this stream through the networkstream. Simplified example:
VB.NET:
Dim mem As New IO.MemoryStream
Image.Save(mem)
Dim buffer As Byte() = mem.GetBuffer
NetworkStream.Write(buffer, 0, buffer.length)
 
Thanks JohnH, I think it probably will work, it's just that for some or other reason it doesn't want to save the image to the stream in the Image.Save(mem) instruction.

It tells me that the System.IO.MemoryStream cannot be converted to String, which doesn't make sense to me because it asks for either a filename (string) or an System.IO.Stream to where the image will be saved. I tried changing the System.IO.MemoryStream to System.IO.Stream and it still doesn't work. Do you have any suggestions?
 
Yes, use the Save method that saves to a Stream and specifies ImgeFormat. There are 5 System.Drawing.Image.Save methods as you see in the documentation.
VB.NET:
Image.Save(Stream, ImageFormat)
 
I figured out that I have to include the image format too when saving the image to the memory stream. Simplified code:

'Code on client
Dim mem As New IO.MemoryStream
Dim Format As Drawing.Imaging.ImageFormat = Format.Jpeg()
Image.Save(mem, Format)
Dim buffer as [Byte]() = mem.GetBuffer
NetworkStream.Write(buffer, 0, buffer.length)

But now on the server (TcpListener) I can't figure out how to do the reverse of the above code. I've received the image in bytes (I hope this is correct) with these instructions on the server (simplified code):

'Code on server
Dim Buffer(1048576) As Byte
NetworkStream.Read(Buffer, 0, Buffer.Length)

So how do I convert the contents of Buffer (Bytes) back to an image that I can display? :confused: I've tried the following but it doesn't work, the image is nothing after executing this code:

'Code on server
Dim Buffer(1048576) As Byte
NetworkStream.Read(Buffer, 0, Buffer.Length)
Dim mem As New IO.MemoryStream
mem.Write(Buffer, 0, Buffer.Length)
Image.FromStream(mem)

Please help.
 
Try to seek the mem stream after it is filled, and before you get the image, else image.fromstream will try to read starting from the end of mem stream.
VB.NET:
[COLOR=#ff0000]mem.Write(Buffer, 0, Buffer.Length)[/COLOR]
[SIZE=2]mem.Seek(0, IO.SeekOrigin.Begin)
[COLOR=#ff0000]Image.FromStream(mem)[/COLOR]
[/SIZE]
 
You can also create the MemoryStream based on the byte array:
VB.NET:
[COLOR=#ff0000]Dim mem As New IO.MemoryStream(Buffer)
[/COLOR][SIZE=2][COLOR=red]Image.FromStream(mem)[/COLOR]
[/SIZE]
 
What you said worked and I also changed the Image.FromStream(mem) instruction to Image = Image.FromStream(mem), and now I receive the and I can display it. But I've got one more problem - I'm really sorry to be asking so many questions it's just that I'm a begginner programmer (still a student) and this is really frustrating me. :eek:

The problem now is that the image that I receive is messed up most of the time; like only the top half will come through or it will be faded in different colors (pink, blue, purple etc.).

I've tried changing the size of the buffer that receives the bytes but I thought that 1048576 bytes would be enough to receive one +/-200K image. When I change the buffer to 1024 only the top right hand corner of the picture gets displayed.
 
You must send how many bytes the original image is first and create the image received from the exact bytes.
 
I haven't gotten a chance to try out what you suggested but yesterday I came up with this code and it works. Just thought you or anyone else who reads this might me interested. So this is the code that I used on the server:

Dim buffer(1024) As Byte 'Create a buffer that will transfer one KB at a time
Dim mem As New IO.MemoryStream
'Transfer 1KB every at a time: NetworkStream -> 1KB Buffer -> MemoryStream
Do Until (NetworkStream.DataAvailable = False) And (mem.Length > 0)
NetworkStream.Read(buffer, 0, buffer.Length)
mem.Write(buffer, 0, buffer.Length)
Loop
Image = Image.FromStream(mem)

Thank you very much for all your advice JohnH, you've really been a great help, thanks:).
 
It might work, but I've found NetworkStream.DataAvailable unreliable in the past while sending strings, when I knew there was strings sent they didn't pass through until later. It is most common in network operations that some kind of header is sent first describing the data to follow, doing this enable you to send a lot different data consecutively and easily distinguish and handle them.
 
Code

hi ozonic
can you please post the code of your Client and Server Socket classes here, i need to do the same...i need client and server application using Sockets to commuincate and upload image files (with large size more than 8 bytes) from client to server. requests from multiple clients must be handled asynchronously too.
I searched the net and i couldn't find what i need..
if you can post your code, it will be very appreciated..
thanks
shelal
 
Sorry I haven't been on the site In a quite while and I don't have the code with me right now, but it's basically as I've written it above.

The only change is that I've implemented JohnH's advice and I send the size of the image before sending the image (in other words the buffer.Length) and then on the client side I had a loop I takes the bytes off The NetworkStream and onto the MemoryStream until the size of the memory stream is equal to the size that was sent from the client.

I also found that for some reason taking one byte at a time from the NetworkStream and onto the the MemoryStream is more reliable than taking 1024 bytes at a time. However you may find that it is slower and therefore takes up more CPU time.

Hope that helps.
 
Back
Top