tisdagen den 5:e april 2011

HTML5 WebSockets, sending binary data (Base64) and embedding using data:URI Scheme


The data:URI scheme enables us to include text,images and audio object directly into our webpages using code instead of using external files, saving valuable HTTP requests I noticed that someone wrote some place at the internet.


…saving valuable HTTP requests ?

I haven't really seen the real use-case of this until I was in a customer meeting today, showing the progress of an ongoing project where we use HTML5, WebSockets and JQueryMobile

In this blog post I will show you how we can use the data:URL scheme and WebSockets, a small function in the generates a Bitmap, Base64 encodes and passes the image to the client, this for sure saves valuable HTTP request ?!

The sample code below is based on the jXlent (WebSockets API helper/extender) and the WebSocketServer that me and UlfBjo has been working on.

I’ll start describing it from the client side

First of we need to connect to the WebSocket

var ws = null;
if (ws == null)
   
ws = new jXlent.xWebSocket("ws://myserver:4502/Xlent.WebSocket.Handlers.Stub", null);

jXlent is a JavaScript helper class (WebSockets API extender) that includes functionality such as WebSockets detecting , fallbacks based on Flash or Silverlight and methods for WebSocket message (JSON) construction and a JQuery like way of registering event handlers and triggering events.

ws.bind("open", function () {
   
var msg = new jXlent.WebSocketMessage("GenerateImage").AddProperty("Color", jXlent.DataType.String);
   
msg.DataObject.Color = "Red";
   
msg.AddObject();
   
ws.trigger(msg.ToJson());
});

When the WebSockets is open, a initial message is created called GenerateImage , the WebSocket handler (server) contains a event handler that will generate the image.

The WebSocket handler is written in C# and looks like this

namespace Sample.WebSocket.Handlers
{
   
[Export(typeof(IWebSocket))]
   
public class Stub : XSocketSolution.XSocketCommon.Handlers.Generic
   
{
       
[HandlerEvent("GenerateImage")]
       
public void OnGenerateImage()
       
{
           
var bmp = new Bitmap(100, 100); // create the Bitmap (image)
            var objGraphics = Graphics.FromImage(bmp);
           
objGraphics.FillRectangle(new SolidBrush(Color.Blue), 0, 0, bmp.Width, bmp.Height);
           
var ms = new MemoryStream();
           
bmp.Save(ms, ImageFormat.Jpeg);
           
var base64 = Convert.ToBase64String(ms.GetBuffer()); // Convert to Base64
            ms.Close();
           
bmp.Dispose();
           
var response = new WebSocketResponseMessage<IList<ImageResponse>>
                              
{
                                  
Data = new List<ImageResponse>
                                             
{
                                                 
new ImageResponse
                                                     
{Base64 = base64}
                                             
},
                                  
Event = "GenerateImageResponse"
                              
};
           
var data = response.Serialize();  // Serialize the WebSocketResponse message as text (JSON)
            foreach (var user in Users)
           
{
            
user.Value.WebSocket.Send(data);   // Send the "message" to all "connected" users
            }
       
}
   
}
   
/// <summary>
    /// Simple class representing or image
    /// </summary>
    [Serializable]
   
[DataContract]
   
public class ImageResponse
   
{
       
[DataMember]
       
public string Base64 { get; set; }
   
}
}

There is not much to day about the OnGenerateImage other than it corresponds to the WebSocket event defined in the JavaScript above and that is creates a WebSocketResponse object , adds the Base64 encoded “bitmap” and gives the message an Event name called GenerateImageResponse, the event name will that will be used to route the message to the correct event handler at the client, this looks like this

ws.bind("GenerateImageResponse", function (data) {
   
$(data).each(function () {
       
$("#myImage").attr("src", "data:image/jpg;base64," + this.Base64);
   
});
});

The JSON object (data) created in the client looks like this :

image

By setting the src attribute of myImage (<img/> ) to data:image/jpg,[base64] we are able to “display” and  image that is generated in the WebSockets on demand of the client, passed back over WebSockets and displayed,  this saves HTTP requests, and probably some time?

This is the result

<img id="myImage" src="data:image/jpg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABkAGQDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDxyiiiv3E8wKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA//Z">

Summary

The purpose of this little entry is to show how we cane send binary data (base64) using WebSockets, include it into our webpages, replace traditional HTTP request with WebSockets, giving us new possibilities making us think different?

Of course there are disadvantages, very old browsers does not support the data:URI scheme, the textual representation of an image eats more bytes than a regular binary image as well as there are size limitations , 1,204 bytes is the size a browser is required to support (I may have wrong).

 

Magnus Thor

3 kommentarer:

  1. Where can you download jXlent?

    SvaraRadera
  2. Hi, You cannot download jXlent today, but we ( me and @ulfjbo will soon publish it together with the WebSocketServer (XSockets). Right now we are adding the Hybi07 protocol. You can always follow me on twitter (@dathor) or shoot me an email .

    Kind regards

    Magnus Thor

    SvaraRadera
  3. Thanks for sharing your info. I really appreciate your efforts and I will be waiting for your further write ups thanks once again.
    Android app development| Android app developer|

    SvaraRadera