Scanning Documents to Web Pages with JavaScript and Dynamic Web TWAIN RESTful API

Dynamic Web TWAIN offers two methods for scanning documents from a web page: the HTML5/JavaScript API and the RESTful API. The former is suitable for web applications that require a high level of customization, while the latter is ideal for enterprise-class web applications, such as Salesforce, Oracle APEX, and Microsoft Power Apps, that need to scan documents in a sandboxed or security-restricted environment. This article will focus on the RESTful API and demonstrate how to scan paper documents to web pages using JavaScript and HTTP requests.

Online Demo

https://yushulx.me/web-twain-document-scan-management/examples/rest_api/

Prerequisites

Step 1: Accessing Dynamic Web TWAIN REST API via HTTP and HTTPS

The Dynamsoft Service runs on default ports 18622 for HTTP and 18623 for HTTPS..

To construct the host URL for the RESTful API:

const port = window.location.protocol === 'https:' ? 18623 : 18622;
const host = window.location.protocol + '//' + "127.0.0.1:" + port;

Step 2: Enumerating Scanners

The endpoint /DWTAPI/Scanners is used to list all available scanners. The response is an array of objects, each containing the scanner’s name and ID.

Fetching Available Scanners

async function getDevices(host, scannerType) {
    devices = [];
    let url = host + '/DWTAPI/Scanners'
    if (scannerType != null) {
        url += '?type=' + scannerType;
    }

    try {
        let response = await axios.get(url)
            .catch(error => {
                console.log(error);
            });

        if (response.status == 200 && response.data.length > 0) {
            console.log('\nAvailable scanners: ' + response.data.length);
            return response.data;
        }
    } catch (error) {
        console.log(error);
    }
    return [];
}

Supported Scanner Protocol Types

The supported scanner protocol types include:

  • TWAIN
  • SANE
  • ICA
  • WIA
  • ESCL

Example: Listing TWAIN Scanners in an HTML Select Element

JavaScript

let queryDevicesButton = document.getElementById("query-devices-button");
    queryDevicesButton.onclick = async () => {
        let scannerType = ScannerType.TWAINSCANNER | ScannerType.TWAINX64SCANNER;
        let devices = await getDevices(host, scannerType);
        let select = document.getElementById("sources");
        select.innerHTML = '';
        for (let i = 0; i < devices.length; i++) {
            let device = devices[i];
            let option = document.createElement("option");
            option.text = device['name'];
            option.value = JSON.stringify(device);
            select.add(option);
        };
    }

HTML

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Dynamsoft RESTful API Example</title>
    <link rel="stylesheet" href="main.css">
    <script src="https://unpkg.com/axios@1.6.7/dist/axios.min.js"></script>
</head>

<body>

    <button id="query-devices-button">Get Devices</button>
    <select id="sources"></select>
    <script src="main.js"></script>
</body>
</html>

Step 3: Scanning Documents

To scan documents, specify the license key, scanner information, and other scan parameters in a JSON object, then post the data to the /DWTAPI/ScanJobs endpoint.

Scan Document

let parameters = {
        license: license,
        device: JSON.parse(device),
};

parameters.config = {
    IfShowUI: false,
    PixelType: 2,
    //XferCount: 1,
    //PageSize: 1,
    Resolution: 200,
    IfFeederEnabled: false, // Set to true if you want to scan multiple pages
    IfDuplexEnabled: false,
};


let jobId = await scanDocument(host, parameters);

async function scanDocument(host, parameters, timeout = 30) {
    let url = host + '/DWTAPI/ScanJobs?timeout=' + timeout;

    try {
        let response = await axios.post(url, parameters)
            .catch(error => {
                console.log('Error: ' + error);
            });

        let jobId = response.data;

        if (response.status == 201) {
            return jobId;
        }
        else {
            console.log(response);
        }
    }
    catch (error) {
        console.log(error);
    }


    return '';
}
  • The timeout parameter is optional. If the scanner does not respond within the specified time, the scan job will be canceled.
  • The job ID is returned if the scan job is created successfully and can be used to retrieve the scanned images.

Step 4: Obtaining the Scanned Images

Use the /DWTAPI/ScanJobs/{jobId}/NextDocument endpoint to retrieve the scanned images.

let url = host + '/DWTAPI/ScanJobs/' + jobId + '/NextDocument';

const response = await axios({
    method: 'GET',
    url: url,
    responseType: 'arraybuffer',
});

Note: Set the response type to stream in Node.js and arraybuffer in the browser.

To display the scanned document in a browser, create a Blob object from the array buffer and use the URL.createObjectURL method to generate a URL for an HTML image element.

const arrayBuffer = response.data;
const blob = new Blob([arrayBuffer], { type: 'image/jpeg' });
const imageUrl = URL.createObjectURL(blob);

Repeat the request until the status code is not 200. Store all scanned image URLs in an array and return them to the caller.

async function getImages(host, jobId) {
    let images = [];
    let url = host + '/DWTAPI/ScanJobs/' + jobId + '/NextDocument';
    console.log('Start downloading images......');
    while (true) {
        try {
            const response = await axios({
                method: 'GET',
                url: url,
                responseType: 'arraybuffer',
            });

            if (response.status == 200) {
                const arrayBuffer = response.data;
                const blob = new Blob([arrayBuffer], { type: 'image/jpeg' });
                const imageUrl = URL.createObjectURL(blob);

                images.push(imageUrl);
            }
            else {
                console.log(response);
            }

        } catch (error) {
            // console.error("Error downloading image:", error);
            console.error('No more images.');
            break;
        }
    }

    return images;
}

Finally, you can display the scanned images as follows:


<div class="row">
    <div class="full-img">
        <img id="document-image">
    </div>
</div>

<div class="row">
    <div class="thumb-bar" id="thumb-bar">
        <div class="thumb-box" id="thumb-box">
        </div>
    </div>
</div>

<script>
let images = await getImages(host, jobId, 'images');

for (let i = 0; i < images.length; i++) {
    let url = images[i];

    let img = document.getElementById('document-image');
    img.src = url;

    data.push(url);

    let option = document.createElement("option");
    option.selected = true;
    option.text = url;
    option.value = url;

    let thumbnails = document.getElementById("thumb-box");
    let newImage = document.createElement('img');
    newImage.setAttribute('src', url);
    if (thumbnails != null) {
        thumbnails.appendChild(newImage);
        newImage.addEventListener('click', e => {
            if (e != null && e.target != null) {
                let target = e.target;
                img.src = target.src;
            }
        });
    }
}
</script>

scan documents via RESTful API in web

Source Code

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