Pushing (binary) image data using Node.js and Socket.IO
These days I’m playing around with Node.js and Socket.IO. One of my goal was to push (binary) image data to clients (browser) in real time using WebSockets.
Demo (Video on Vimeo)
Behind the scenes
The simple demo runs with Node.js (Express) and Socket.IO. It generates its HTML code using Jade templates and Stylus (CSS). The code is written in CoffeeScript.
Limitation of pushing binary data
At the time of writing this post sending and receiving binary data using WebSockets are very limited by current browser.
To avoid lack of supporting binary messages by browser all image data have to be encoded in base64 before emitting the message. To do that just draw the image within a Canvas and send the data using Canvas’ toDataURL() over the wire.
Here is a simple roundtrip on client-side (You will find all code of this demo here: https://github.com/sectore/node-socket.io-push-image-demo):
###
1 SENDING DATA
1.1 get original image data clicking on it1.2 get its base64-encoded data1.3 emit the data by Socket.IO to server (Node.js)
###$(".my-image").click (event) => # get image which was clicked img = event.target # create base64 encoded image imgdata = @getBase64Image(img) # emit data to clients @socket.emit 'onimgdata', { width: img.width, height: img.height, source:imgdata }
###Helper method to get a base64 encoded image dataBased on http://stackoverflow.com/questions/934012/get-image-data-in-javascript###getBase64Image:(img) -> # create canvas canvas = document.createElement "canvas" canvas.width = img.width canvas.height = img.height context = canvas.getContext "2d" # draw image into canvas context.drawImage img, 0, 0
### Get the data-URL formatted image using jpeg format as the type of the image to be returned @see: http://www.w3.org/TR/html5/the-canvas-element.html ### data = canvas.toDataURL "image/jpeg"
#return data data
###
2 RECEIVING DATA + DISPLAY IMAGE2.1 listen to "showimgdata" event sent from server (Node.js)2.2 push data to HTML image
###
@socket.on 'showimgdata', (data) -> #get image img = $('#show-img').get 0 message try # set data for image img.width = data.width; img.height = data.height; img.src = data.source;
message = ''
catch error console.log error message = 'error receiving image data...'
The disadvantage of this solution is that “Base64 encoding adds ~30%+ of size to the image” (Quote by Eric Bidelman / Developer Relations, Google: “Mobifying” Your HTML5 Site).
Source code
All source code and its installation instruction available at GitHub.
Have fun!
-Jens
Hey,
I haven’t worked with WebWorkers but I’m sure you could use jDataView in order to read binary mesages sent from the server:
http://blog.vjeux.com/2011/javascript/jdataview-read-binary-file.html
If you need any help, please let me know
@Jens,
Could you not run a compression/zip on the encoded data (before sending)?
Interesting to read. Kepp up the good work!