Document Web Scanning in HTML5 and Java

In this tutorial, I am about to make a more complicated solution – Web-based document imaging capture, combining the implementation of Java TWAIN and Java WebSocket with Dynamic .NET TWAIN library, C#, JNI, Java Swing, Jetty and HTML5 WebSocket. Here is the workflow:

Java Web TWAIN workflow

Prerequisites

You need to read the following articles first and try relevant sample code.

How to Run

  1. In Eclipse, run the project as Java Application, and select the class UIMain.jtwain server

    When you see the window, the WebSocket server has already been initialized.

    •  The button Load is used to load images from the local disk.
    • The button Send is used to push images from the WebSocket server to Web clients.
    • The button Scan is used to scan documents locally and automatically send captured images to remote Web clients.
  2. Open a Web client in Chrome, and select a source to scan.jtwain source
  3. Display the captured image.jtwain scan

The Anatomy of Web-based Document Imaging Capture

Import all relevant libraries to the new project.

jtwain libs

Modify the source code of Java TWAIN and Java Websocket to make them parts of the new project.

Create a class named SourceManager, and add all methods from Java TWAIN project:

package com.data;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;

import javatwain.DotNetScanner;
import javatwain.IJavaProxy;
import javatwain.INativeProxy;

import javax.swing.Timer;

import com.server.WSHandler;
import com.util.ImageUtil;

import net.sf.jni4net.Bridge;

public class SourceManager implements INativeProxy {
	private IJavaProxy mScanner;
	private String[] mSources;
	private ScanAction mScanAction;

    public SourceManager() {
		initTWAIN();
		mScanAction = new ScanAction();
    }

	private void initTWAIN() {
		try {
			Bridge.init();
			Bridge.LoadAndRegisterAssemblyFrom(new java.io.File("libs\\jni\\JavaTwain.j4n.dll"));
		}
		catch (Exception e) {
            e.printStackTrace();
        }

		mScanner = new DotNetScanner();
		mScanner.RegisterListener(this);
		mSources = mScanner.GetSources();
	}

	public String[]	getSources() {
		return mSources;
	}

	public synchronized void acquireImage(int index) {
		mScanAction.setIndex(index);
		mScanAction.start();
	}

    @Override
	public boolean Notify(String message, String value) {
    	ArrayList<WSHandler> sessions = WSHandler.getAllSessions();
    	for (WSHandler session : sessions) {
    		session.sendImage(ImageUtil.getImageBytes(new File(value)));
    	}

        return true;
    }

    public class ScanAction {
    	private int mIndex;
    	private int mDelay = 1;
    	private Timer mTimer;

    	public ScanAction() {
    		mTimer = new Timer(mDelay, mTaskPerformer);
    		mTimer.setRepeats(false);
    	}

    	private ActionListener mTaskPerformer = new ActionListener() {
            @Override
    		public void actionPerformed(ActionEvent evt) {
        		mScanner.AcquireImage(mIndex);
            	ActionListener taskPerformer = new ActionListener() {
                    @Override
        			public void actionPerformed(ActionEvent evt) {
        				mScanner.CloseSource();
                    }
                };
        		int delay = 1; 
                Timer timer = new Timer(delay, taskPerformer);
                timer.setRepeats(false);
                timer.start();
            }
        };

        public void setIndex(int index) {
        	mIndex = index;
        }

        public void start() {
        	mTimer.start();
        }
    }
}

The format of the message transferred between Java WebSocket Server and JavaScript client is JSON.

Send JSON data in Java:

        JsonObject jsonObj = new JsonObject();
        JsonArray jsonArray = new JsonArray();

        String[] sources = mSourceManager.getSources();
        if (sources != null) {
        	for (String source : sources) {
        		jsonArray.add(new JsonPrimitive(source));
        	}
        }

        jsonObj.add(Msg.MSG_SOURCES, jsonArray);

        String s = jsonObj.toString();

        try {
			session.getRemote().sendString(s);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

Parse and read JSON data in Java:

public void onMessage(String message) {
    	JsonParser parser = new JsonParser();
    	boolean isJSON = true;
    	JsonElement element = null;
    	try {
    		element =  parser.parse(message);
    	}
    	catch (JsonParseException e) {
    		System.out.println("exception: " + e);
    		isJSON = false;
    	}

        if (isJSON && element != null) {
        	JsonObject obj = element.getAsJsonObject();
        	element = obj.get(Msg.MSG_MESSAGE);
        	if (element != null) {
        		switch (element.getAsString()) {
        		case Msg.MSG_SOURCE:
        			int index = obj.get(Msg.MSG_INDEX).getAsInt();
        			mSourceManager.acquireImage(index);
        			break;
        		}
        	}
        }

        System.out.println("Message: " + message);
    }

Send JSON data in JavaScript:

var json = {};
json.Message = MSG_SOURCE;
json.Index = i;
var msg = JSON.stringify(json);
ws.send(msg);

Parse and read JSON data in JavaScript:

ws.onmessage = function (evt) { 
    var data = evt.data;
    	var json = JSON.parse(data);
    	var value = json[MSG_SOURCES];
    	showSources(value);
    }

Create a class ScanAction which includes a Timer in UI thread. The Timer is used to trigger image capture event.

public class ScanAction {
    	private int mIndex;
    	private int mDelay = 1;
    	private Timer mTimer;

    	public ScanAction() {
    		mTimer = new Timer(mDelay, mTaskPerformer);
    		mTimer.setRepeats(false);
    	}

    	private ActionListener mTaskPerformer = new ActionListener() {
            @Override
    		public void actionPerformed(ActionEvent evt) {
        		mScanner.AcquireImage(mIndex);
            	ActionListener taskPerformer = new ActionListener() {
                    @Override
        			public void actionPerformed(ActionEvent evt) {
        				mScanner.CloseSource();
                    }
                };
        		int delay = 1; 
                Timer timer = new Timer(delay, taskPerformer);
                timer.setRepeats(false);
                timer.start();
            }
        };

        public void setIndex(int index) {
        	mIndex = index;
        }

        public void start() {
        	mTimer.start();
        }
    }

When the image data is available, send it to all Web clients:

public boolean Notify(String message, String value) {
    	ArrayList<WSHandler> sessions = WSHandler.getAllSessions();
    	for (WSHandler session : sessions) {
    		session.sendImage(ImageUtil.getImageBytes(new File(value)));
    	}

        return true;
    }

Source Code

JavaWebTWAIN

Have Fun with the WPF Demo of .NET TWAIN 5.0

Dynamic .NET TWAIN 5.0 has been released for a while. To help users to quickly grasp APIs, a brand-new API demo, written in WPF with C# & VB.NET, is included. In this tutorial, we would like to show the anatomy of this application. Let’s glance at the screenshot as a warm up. As you can see, the functionalities of the demo include scanner control, image loading, barcode recognition, OCR, image manipulation and processing.

WPF UI

How to install Dynamic .NET TWAIN 5.0?

Visit Dynamic .NET TWAIN page and get the installation package by clicking Download button. Follow the InstallShield Wizard step by step.

Where is the API demo?

The demo source code is located at “…\Dynamsoft\Dynamic .NET TWAIN 5.0 Trial\Samples\C# Samples\VS 12” and “…\Dynamsoft\Dynamic .NET TWAIN 5.0 Trial\Samples\VB .NET Samples\VS 12\WpfControlsDemo”. You can choose your preferred programming language, C# or VB.NET.

What does the project look like in Visual Studio?

WPF project

The reference DynamicDotNetTWAIN.Wpf.dll is located at “…\Dynamsoft\Dynamic .NET TWAIN 5.0 Trial\Samples\Bin”. It will be copied to your project folder when you run the Visual Studio solution file “WpfControlsDemo.sln”. If you want to create your own project, don’t forget to add it. In this project, we have created three windows. The main window is “Window1.xaml”.

How to use the relevant APIs to implement following functions?

All implementation logics are same no matter which language you choose. Let’s illustrate with C#.

Read more