TCPSocket stream to picture

Hello,
on server TCPSocket i have a picture loaded as binary stream.
is it possible to send this binary stream via a TCPSocket “write” method to a socket-receiver and convert it back to picture without saving it to a file first and put it e.g. into a canvas?

http://documentation.xojo.com/index.php/Picture.FromData

Thanks!

Is there a save way to check if the image was transferred completely? Is “send complete” fired when finished sending and has the “receiver socket” then received it completely?

Collect some info about the picture before sending it, send that info bundled with the picture-data and check in the receive event of the receiving socket.

i’ searched the forum and did this:

on Server side sending picture

dim f as FolderItem=GetOpenFolderItem("") dim bs as BinaryStream if f <> nil then bs=bs.Open(f,false) end if dim ret() as TCPSocket=MainServerSocket.ActiveConnections for i as integer= 0 to UBound(ret) while not bs.eof ret(i).write(bs.read(512000)+chr(13)+chr(10)) Wend next

and on receiver side in dataavailable:

dim Buffer as String
Dim boundary As Integer = Instr(Me.LookAhead, chr(13)+chr(10)) 
		
 Do Until boundary = 0
		Buffer = Buffer + Me.Read(boundary)
		boundary = Instr(Me.LookAhead, chr(13)+chr(10)) 
Loop
		
dim p as Picture	
p=Picture.FromData(Buffer)
Canvas1.Backdrop=p
Canvas1.Invalidate

i can send a image which is received and displayed in the canvas, but if i send a second image the canvas is empty.
Also when sending a large image, the canvas flashes short (with the image) and then is empty.

Any suggestions?

ok, shure i have to empty the internal buffer afterwards…
sock.purge

but the problem with large images is still there, it loads, flashes shortly and then the canvas is empty.

edit: i see that the receiver only gets the first chunk and displays a partial image, where is the error in combining the chunks?

has anybody a example of sending chunks and combining chunks with tcpsocket?

When sending data, you’re best to delimit it somehow… Seeing as you’re sending binary data, EOT might appear in the data, so you’d either need to convert to non-binary (base64, etc) but this adds overhead and makes the file larger, or you would need to encapsulate the data (wrap it in JSON, etc) or prepend a length marker… Whichever method you choose, when you receive the data, you just appending it to a variable and then when you receive the whole thing, you can do your parsing…

Create a sub-class of the TCPSocket, add a private instance variable (I just call mine mBuffer)
So in the DataReceived event just keep adding the new data to the buffer variable

[code]me.mBuffer = me.mBuffer + me.ReadAll()
DIM offset As Integer = me.mBuffer.InStr(Chr(13) + Chr(10)) // I do this as a variable, as we need to do the lookup twice and if it’s a huge file, it could be a performance hit

if (offset > -1) then
DIM pictureData As String = me.mBuffer.Left(offset) // get the picture data
DIM me.mBuffer = me.mBuffer.Right(offset + 2) // delete the old picture data and take in account the CRLF combo
// do the rest of your stuff here
end if[/code]

This was off the top of my head

Thanks! But i just cannot receive any pic

this is my code in the dataAvailable Event:

me.mBuffer = me.mBuffer + me.ReadAll()
DIM offset As Integer = me.mBuffer.InStr(Chr(13) + Chr(10)) 
			
if (offset > -1) then                        //doesn't that have to be in some kind of loop?
   DIM pictureData As String = me.mBuffer.Left(offset)  
   me.mBuffer = me.mBuffer.Right(offset + 2) 
  end if

 dim p as Picture
 p=Picture.FromData(me.mBuffer)
 window1.canvas1.Backdrop=p

i just want to display the image when completed received…

dim p as Picture
 p=Picture.FromData(me.mBuffer)
 window1.canvas1.Backdrop=p

this has to go in the DOWNLOADCOMPLETE event
otherwise you are attempting to create a picture out of snippets of data, all of which are invalid picture data until you, well “have the whole picture” :smiley:

oh… and you need to store (concatenate) all the calls to DATAAVAILABLE

the TCPSocket has no DOWNLOADCOMPLETE event…?

This is true… Since TCPSocket (my opinion) is more suited to communications streams (which have no specific end)…

I was thinking (and always use) HTTPSocket or HTTPSecureSocket… THOSE do, as they are more suited to downloading a file with a know size and end.

so, please, anybody has a suggestion what i have to write to make my image diplayed when completely received?

ignore my suggestion… no worries

no, i do not ignore your suggestions, i am thankful for every help … but you’re suggestion was based on HTTPSocket but i am using TCPSocket… and my solution (post 5) worked as long as the picture is small so i was hoping for a hint whats wrong with my code…

You are sending raw data to the client so your block terminator (boundary) is unsafe. Imagine a picture that has &c0D0Axx or &cxx0D0A to define a pixel. I would send the length of the block as the first two bytes then wait until the buffer (lookahead) contained the full block before processing it. You can detect EOF by the last block most likely being less than the defined block size or better send a block that is 1 byte with a value of &H00. For very large images you will need to add a block received response to the server so as to not overload the output buffer. Another issue that could come up is corruption of data in transit so sending an MD5 checksum for each block and for the entire image would also be prudent.

So you ARE ignoring my suggestion, which was to NOT use TCPSocket but use HTTPSocket… but thats fine, its you app

[code]me.mBuffer = me.mBuffer + me.ReadAll()
DIM offset As Integer = me.mBuffer.InStr(Chr(13) + Chr(10))

if (offset > -1) then //doesn’t that have to be in some kind of loop?
DIM pictureData As String = me.mBuffer.Left(offset)
me.mBuffer = me.mBuffer.Right(offset + 2)

// do this when you have the full picture, so this needs to be inside the IF statement
dim p as Picture
p=Picture.FromData(me.mBuffer)
window1.canvas1.Backdrop=p

end if

[/code]