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