Building a Cross-platform Document Scanning and Management Application with Electron

Electron is a framework for building cross-platform desktop applications with HTML, JavaScript, and CSS. Since Dynamic Web TWAIN is also a cross-platform JavaScript library for document scanning and management, we can combine Electron and Dynamic Web TWAIN to implement a desktop document scanning and management application for Windows, Linux, and macOS.

Prerequisites

Install Electron and Dynamic Web TWAIN

npm install -g electron
npm install dwt

References

Electron Application for Document Scanning and Management

Step 1. Electron Quick Start

Let’s get started with electron-quick-start:

git clone https://github.com/electron/electron-quick-start
cd electron-quick-start
npm install
npm start

Here is the basic structure of an Electron project:

app/

├── package.json

├── main.js

└── index.html

The main.js file is the entry point of Electron, defined in the package.json file:

"main": "main.js",
"scripts": {
    "start": "electron main.js"
},

The index.html file is loaded in the main.js file:

mainWindow.loadURL('file://' + __dirname + '/index.htm');
// or
mainWindow.loadFile('index.html');

Although the default code works fine, if you want to make the window bigger and resizable, you can change the code:

mainWindow = new BrowserWindow({ width: 1024, height: 1024, resizable: true });

Step 2. Include Dynamic Web TWAIN JavaScript Library

To implement document scanning and document management, we just need to put some effort into the HTML5 code in index.html. There is no difference compared to building a web application.

The JavaScript library files of Dynamic Web TWAIN are located in the node_modules folder. We can include the library in the HTML file:

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Document Scanner</title>
    <script src="node_modules/dwt/dist/dynamsoft.webtwain.min.js"></script>
</head>

To make the SDK work, you must set the product key and specify the path of the resources:

Dynamsoft.DWT.ProductKey = 'LICENSE-KEY';
Dynamsoft.DWT.ResourcesPath = "node_modules/dwt/dist/";

Step 3. Added UI Elements

Create a select element for selecting connected document scanners, a div element as the document image container, and three buttons for scanning, loading, and saving images:

<select size="1" id="source"></select>
<div id="dwtcontrolContainer"></div>
<input type="button" value="Scan" onclick="scanImage();" />
<input type="button" value="Load" onclick="loadImage();" />
<div class="row">
    <label style="font-size: x-large;">
        <input type="radio" value="jpg" name="ImageType" id="imgTypejpeg" />JPEG</label>
    <label style="font-size: x-large;">
        <input type="radio" value="tif" name="ImageType" id="imgTypetiff" />TIFF</label>
    <label style="font-size: x-large;">
        <input type="radio" value="pdf" name="ImageType" id="imgTypepdf" checked="checked" />PDF</label>
    <input type="button" value="Save" onclick="saveImage();" />
</div>

The radio buttons are used to select the image format for saving. The default format is PDF.

Step 4. Implement document scanning: button events

The following JavaScript code implementation includes the initialization of the Dynamic Web TWAIN object and the corresponding button events:

var dwtObject;

var selectSources = document.getElementById("source");

Dynamsoft.DWT.CreateDWTObjectEx({ "WebTwainId": "container" }, (obj) => {
    dwtObject = obj;

    dwtObject.Viewer.bind(document.getElementById("dwtcontrolContainer"));
    dwtObject.Viewer.width = 640;
    dwtObject.Viewer.height = 640;
    dwtObject.Viewer.show();
    onReady();
}, (errorString) => {
    console.log(errorString);
});

function onReady() {
    if (dwtObject) {
        dwtObject.IfShowUI = false;
        dwtObject.GetDevicesAsync(Dynamsoft.DWT.EnumDWT_DeviceType.TWAINSCANNER | Dynamsoft.DWT.EnumDWT_DeviceType.TWAINX64SCANNER | Dynamsoft.DWT.EnumDWT_DeviceType.ESCLSCANNER).then((sources) => {
            sourceList = sources;

            selectSources.options.length = 0;
            for (let i = 0; i < sources.length; i++) {
                let option = document.createElement("option");
                option.text = sources[i].displayName;
                option.value = i.toString();
                selectSources.add(option);
            }
        });
    }
}

function scanImage() {
    if (!dwtObject)
        return;

    if (selectSources) {
        var pixelTypeInputs = document.getElementsByName("PixelType");
        for (var i = 0; i < pixelTypeInputs.length; i++) {
            if ((pixelTypeInputs[i]).checked) {
                pixelType = (pixelTypeInputs[i]).value;
                break;
            }
        }
        dwtObject.SelectDeviceAsync(sourceList[selectSources.selectedIndex]).then(() => {
            return dwtObject.OpenSourceAsync()
        }).then(() => {
            return dwtObject.AcquireImageAsync({
                IfDisableSourceAfterAcquire: true
            })
        }).then(() => {
            if (dwtObject) {
                dwtObject.CloseSource();
            }

        }).catch(
            (e) => {
                console.error(e)
            }
        )
    } else {
        alert("No Source Available!");
    }
}

function loadImage() {
    if (!dwtObject) return;

    let onSuccess = function () { };
    let onFailure = function (errorCode, errorString) { };

    dwtObject.IfShowFileDialog = true;
    dwtObject.LoadImageEx("", Dynamsoft.DWT.EnumDWT_ImageType.IT_ALL, onSuccess, onFailure);
}

function saveImage() {
    if (dwtObject) {
        if ((document.getElementById("imgTypejpeg")).checked == true) {
            if (dwtObject.GetImageBitDepth(dwtObject.CurrentImageIndexInBuffer) == 1)
                dwtObject.ConvertToGrayScale(dwtObject.CurrentImageIndexInBuffer);
            dwtObject.SaveAsJPEG("DynamicWebTWAIN.jpg", dwtObject.CurrentImageIndexInBuffer);
        }
        else if ((document.getElementById("imgTypetiff")).checked == true)
            dwtObject.SaveAllAsMultiPageTIFF("DynamicWebTWAIN.tiff");
        else if ((document.getElementById("imgTypepdf")).checked == true)
            dwtObject.SaveAllAsPDF("DynamicWebTWAIN.pdf");
    }
}

Now save the changes and reload the UI. A simple desktop document scanning application is complete.

Electron document scanning and management

Electron Application Packaging and Distribution

To package and distribute the Electron project:

  1. Install asar to pack the application into an archive file:

     npm install -g asar
     asar pack app app.asar
    
  2. Download the Electron prebuilt package and place app.asar into the recourses folder.

    electron distribution

  3. Double-click electron.exe to check whether your application runs successfully.
  4. Compress the entire folder into a zip file for distribution.

Source Code

https://github.com/yushulx/web-twain-document-scan-management/tree/main/examples/electron