Pushing (binary) image data using Node.js and Socket.IO

Posted on December 22, 2011

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 ###
 2 
 3 1 SENDING DATA
 4 
 5 1.1 get original image data clicking on it
 6 1.2 get its base64-encoded data
 7 1.3 emit the data by Socket.IO to server (Node.js)
 8 
 9 ###
10 $(".my-image").click (event) =>
11  # get image which was clicked
12  img = event.target
13  # create base64 encoded image
14  imgdata = @getBase64Image(img)
15  # emit data to clients
16  @socket.emit 'onimgdata', {  width: img.width, height: img.height, source:imgdata }
17 
18 
19 ###
20 Helper method to get a base64 encoded image data
21 Based on http://stackoverflow.com/questions/934012/get-image-data-in-javascript
22 ###
23 getBase64Image:(img) ->
24  # create canvas
25  canvas = document.createElement "canvas"
26  canvas.width = img.width
27  canvas.height = img.height
28  context = canvas.getContext "2d"
29  # draw image into canvas
30  context.drawImage   img,
31      0,
32      0
33 
34  ###
35     Get the data-URL formatted image
36     using jpeg format as the type of the image to be returned
37     @see: http://www.w3.org/TR/html5/the-canvas-element.html
38     ###
39  data = canvas.toDataURL "image/jpeg"
40 
41  #return data
42  data
43 
44 ###
45 
46 2 RECEIVING DATA + DISPLAY IMAGE
47 2.1 listen to "showimgdata" event sent from server (Node.js)
48 2.2 push data to HTML image
49 
50 ###
51 
52 @socket.on 'showimgdata', (data) ->
53  #get image
54  img = $('#show-img').get 0
55  message
56  try
57      # set data for image
58      img.width = data.width;
59      img.height = data.height;
60      img.src = data.source;
61 
62      message = ''
63 
64  catch error
65      console.log error
66      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

Any feedback?

comments powered by Disqus