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.
This article is Part 6 in a 6-Part Series.
- Part 1 - Dynamsoft Service REST API - Scan Documents in Node.js
- Part 2 - Building a Document Digitization App with Flutter for TWAIN, WIA, and eSCL Scanners
- Part 3 - Access Document Scanners in Java
- Part 4 - How to Scan Documents from TWAIN, WIA, SANE Compatible Scanners in Python
- Part 5 - Building .NET Apps for Scanning Documents from TWAIN, WIA, SANE, and eSCL Scanners
- Part 6 - Scanning Documents to Web Pages with JavaScript and Dynamic Web TWAIN RESTful API
Online Demo
https://yushulx.me/web-twain-document-scan-management/examples/rest_api/
Prerequisites
- Install and run Dynamsoft Service.
- Obtain a free trial license for Dynamic Web TWAIN.
-
Include axios.
Axios is a promise-based HTTP client for the browser and Node.js. Since we have used it in a Node.js example, migrating the RESTful API calls to a web page is straightforward.
<script src="https://unpkg.com/axios@1.6.7/dist/axios.min.js"></script>
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>
Source Code
https://github.com/yushulx/web-twain-document-scan-management/tree/main/examples/rest_api