How to Remotely Scan Documents from PCs and Mobile Devices with HTML5 WebSocket and Dynamic .NET TWAIN

In this tutorial, I want to make a more complicated WebSocket demo, which enables me to capture images from scanners on server side, and view the images in desktop web browsers or mobile web browsers. Here is the flowchart:

 flow chart

Prerequisites

Scanning Documents through WebSocket Connection

Initialize Dynamic .NET TWAIN component:

            dynamicDotNetTwain = new Dynamsoft.DotNet.TWAIN.DynamicDotNetTwain(); // create Dynamic .NET TWAIN component
            dynamicDotNetTwain.OnPostAllTransfers += new Dynamsoft.DotNet.TWAIN.Delegate.OnPostAllTransfersHandler(this.dynamicDotNetTwain_OnPostAllTransfers); 
            dynamicDotNetTwain.MaxImagesInBuffer = 64;
            dynamicDotNetTwain.IfAppendImage = true;
            dynamicDotNetTwain.IfThrowException = true;
            dynamicDotNetTwain.IfShowUI = false;

When a client is connected to WebSocket server, query all available scanner sources on server side, and serialize them as JSON data:

            int iIndex;
            dynamicDotNetTwain.OpenSourceManager();

            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);
            using (JsonWriter writer = new JsonTextWriter(sw))
            {
                writer.Formatting = Formatting.Indented;

                writer.WriteStartObject();
                writer.WritePropertyName("Sources");
                writer.WriteStartArray();
                for (iIndex = 0; iIndex < dynamicDotNetTwain.SourceCount; iIndex++)
                {
                    writer.WriteValue(dynamicDotNetTwain.SourceNameItems(Convert.ToInt16(iIndex)));
                }
                writer.WriteEnd();
                writer.WriteEndObject();
            }

            String msg = sw.ToString();
            session.Send(msg);

Send the JSON data to the Web client, and de-serialize the JSON data in JavaScript:

                        var json = JSON.parse(data);
                        var jValue;
                        for (jProperty in json) {
                            jValue = json[jProperty];
                            switch (jProperty) {
                                case "Sources":
                                    showSources(jValue);
                                    break;
                                case "Draw":
                                    var w = jValue[0];
                                    var h = jValue[1];
                                    imageWidth = parseInt(w);
                                    imageHeight = parseInt(h);
                                    break;
                            }
                            break;
                        }

Show the sources in drop-down list with HTML5 elements <select> and <option>:

                var sources = document.getElementById('sources');
                var option;

                var count = values.length;
                if (count == 0) {
                    option = document.createElement('option');
                    option.text = "N/A";
                    sources.appendChild(option);
                }
                else {
                    for (var i = 0; i < 3; i++) {
                        option = document.createElement('option');
                        option.text = values[i];
                        sources.appendChild(option);
                    };
                }

Acquire document images from scanners:

        private void appServer_NewMessageReceived(WebSocketSession session, string message)
        {   
            int iIndex = Int32.Parse(message);

            try
            {
                dynamicDotNetTwain.CloseSource();
                bool success = dynamicDotNetTwain.SelectSourceByIndex(Convert.ToInt16(iIndex));
                dynamicDotNetTwain.OpenSource();
                dynamicDotNetTwain.AcquireImage();
            }
            catch (Dynamsoft.DotNet.TWAIN.TwainException exp)
            {
                String errorstr = "";
                errorstr += "Error " + exp.Code + "\r\n" + "Description: " + exp.Message + "\r\nPosition: " + exp.TargetSite + "\r\nHelp: " + exp.HelpLink + "\r\n";
                MessageBox.Show(errorstr);
            }
            catch (Exception exp)
            {
                String errorstr = "";
                errorstr += "ErrorMessage: " + exp.Message + "\r\n";
                MessageBox.Show(errorstr);
            }
        }

When the image data is ready, send it to the Web client:

private void dynamicDotNetTwain_OnPostAllTransfers()
        {
            if (dynamicDotNetTwain.MaxImagesInBuffer < 1)
            {
                MessageBox.Show("no image");
                return;
            }

            Image img = dynamicDotNetTwain.GetImage(0);

            ImageData imageData = load_image(img);

            /* send width & height in JSON */
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);
            using (JsonWriter writer = new JsonTextWriter(sw))
            {
                writer.Formatting = Formatting.Indented;

                writer.WriteStartObject();
                writer.WritePropertyName("Draw");
                writer.WriteStartArray();
                writer.WriteValue(imageData.Width);
                writer.WriteValue(imageData.Height);
                writer.WriteEnd();
                writer.WriteEndObject();
            }
            String msg = sw.ToString();

            IEnumerable<WebSocketSession> sessions = appServer.GetAllSessions();
            foreach (WebSocketSession session in sessions) 
            {
                session.Send(msg);
                session.Send(imageData.Data, 0, imageData.Data.Length);
            }

            imageData = null;
        }

Finally, I can view the captured document images in Windows Chrome:

scan document with websocket

Based on HTML5, the solution is platform-independent, which means it supports not only Windows, but also Linux, Mac OS, iOS, Android and so forth. Thus I can also access the page and remotely operate scanners in Android Chrome:


android_scan_sources

android_scan_document

Now, you can try to make your own cloud scanner application with Dynamic .NET TWAIN and HTML5 WebSocket.

Source Code

WebSocketScanDocument