Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 133 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,88 +1,158 @@
# Document Scanner SDK for Node.js
The package provides Node.js APIs for invoking **Dynamic Web TWAIN Service REST API**. It helps developers to create **desktop** or **server-side** document scanning applications with ease.

## Key Features
- 🖨️ ​Multi-driver Support
- TWAIN (32-bit & 64-bit)
- WIA (Windows Image Acquisition)
- SANE (Scanner Access Now Easy)
- ICA (Image Capture Architecture)
- eSCL (AirScan/Mopria)
- 🌐 ​Cross-platform Compatibility
- Windows 7+
- Linux (x64/ARM64/MIPS64)
- macOS 10.15+

## Prerequisites
- Install Dynamic Web TWAIN Service.
- Windows: [Dynamsoft-Service-Setup.msi](https://demo.dynamsoft.com/DWT/DWTResources/dist/DynamsoftServiceSetup.msi)
- macOS: [Dynamsoft-Service-Setup.pkg](https://demo.dynamsoft.com/DWT/DWTResources/dist/DynamsoftServiceSetup.pkg)
- Linux:
- [Dynamsoft-Service-Setup.deb](https://demo.dynamsoft.com/DWT/DWTResources/dist/DynamsoftServiceSetup.deb)
- [Dynamsoft-Service-Setup-arm64.deb](https://demo.dynamsoft.com/DWT/DWTResources/dist/DynamsoftServiceSetup-arm64.deb)
- [Dynamsoft-Service-Setup-mips64el.deb](https://demo.dynamsoft.com/DWT/DWTResources/dist/DynamsoftServiceSetup-mips64el.deb)
- [Dynamsoft-Service-Setup.rpm](https://demo.dynamsoft.com/DWT/DWTResources/dist/DynamsoftServiceSetup.rpm)

- Request a [free trial license](https://www.dynamsoft.com/customer/license/trialLicense?product=dwt) for Dynamic Web TWAIN Service.

## Dynamic Web TWAIN Service Configuration
After installing the Dynamic Web TWAIN Service, navigate to `http://127.0.0.1:18625/` in a web browser to configure the host and port settings. The default host IP address is set to `127.0.0.1`. If you wish to make the service accessible over the local network in your office or company, you can update the host setting to a LAN IP address, such as **192.168.8.72**.

The package provides Node.js APIs for invoking the **Dynamic Web TWAIN Service REST API**. It helps developers create **desktop** or **server-side** document scanning and processing applications with ease.

---

## 🚀 Key Features

- 🖨️ **Multi-Driver Support**
- TWAIN (32-bit & 64-bit)
- WIA (Windows Image Acquisition)
- SANE (Scanner Access Now Easy)
- ICA (Image Capture Architecture)
- eSCL (AirScan/Mopria)
- Wi-Fi Direct

- 🌐 **Cross-Platform Compatibility**
- Windows 7+
- macOS 10.15+
- Linux (x64 / ARM64 / MIPS64)

---

## ⚙️ Prerequisites

### ✅ Install Dynamic Web TWAIN Service:

- **Windows**: [Dynamsoft-Service-Setup.msi](https://demo.dynamsoft.com/DWT/DWTResources/dist/DynamsoftServiceSetup.msi)
- **macOS**: [Dynamsoft-Service-Setup.pkg](https://demo.dynamsoft.com/DWT/DWTResources/dist/DynamsoftServiceSetup.pkg)
- **Linux**:
- [Dynamsoft-Service-Setup.deb](https://demo.dynamsoft.com/DWT/DWTResources/dist/DynamsoftServiceSetup.deb)
- [Dynamsoft-Service-Setup-arm64.deb](https://demo.dynamsoft.com/DWT/DWTResources/dist/DynamsoftServiceSetup-arm64.deb)
- [Dynamsoft-Service-Setup-mips64el.deb](https://demo.dynamsoft.com/DWT/DWTResources/dist/DynamsoftServiceSetup-mips64el.deb)
- [Dynamsoft-Service-Setup.rpm](https://demo.dynamsoft.com/DWT/DWTResources/dist/DynamsoftServiceSetup.rpm)

### 🔑 Get a License

Request a [free trial license](https://www.dynamsoft.com/customer/license/trialLicense/?product=dcv&package=cross-platform) for the Dynamic Web TWAIN Service.

---

## 🧩 Configuration

After installation, open `http://127.0.0.1:18625/` in your browser to configure the **host** and **port** settings.

> By default, the service is bound to `127.0.0.1`. To access it across the LAN, change the host to your local IP (e.g., `192.168.8.72`).

![dynamsoft-service-config](https://github.com/yushulx/dynamsoft-service-REST-API/assets/2202306/e2b1292e-dfbd-4821-bf41-70e2847dd51e)

## REST API Reference
By default, the REST API's host address is set to `http://127.0.0.1:18622`.
---

## 📡 REST API Endpoints

[https://www.dynamsoft.com/web-twain/docs/info/api/restful.html](https://www.dynamsoft.com/web-twain/docs/info/api/restful.html)

## 📦 Node.js APIs

### 🔍 Scanner APIs

- `getDevices(host, scannerType)`
Get available scanners. Returns an array of devices.

- `createJob(host, parameters)`
Create a new scan job. Returns a job object.

| Method | Endpoint | Description | Parameters | Response |
|--------|-----------------|-------------------------------|------------------------------------|-------------------------------|
| GET | `/DWTAPI/Scanners` | Get a list of scanners | None | `200 OK` with scanner list |
| POST | `/DWTAPI/ScanJobs` | Creates a scan job | `license`, `device`, `config` | `201 Created` with job ID |
| GET | `/DWTAPI/ScanJobs/:id/NextDocument`| Retrieves a document image | `id`: Job ID | `200 OK` with image stream |
| DELETE | `/DWTAPI/ScanJobs/:id`| Deletes a scan job | `id`: Job ID | `200 OK` |
- `checkJob(host, jobId)`
Check job status (e.g., running, canceled, etc.)

## Node.js API
- `getDevices(host, scannerType)` - Get all available scanners. It returns an array of scanner objects.
- `scanDocument(host, parameters, timeout)` - Create a scanner job by feeding one or multiple physical documents. It returns the job id.
- `getImageFile(host, jobId, directory)` - Get one document image by job id. The directory specifies the physical location to save the images. It returns the image path.
- `getImageFiles(host, jobId, directory)` - Get document images by job id. The directory specifies the physical location to save the images. It returns an array of image paths.
- `deleteJob(host, jobId)` - Delete a scan job by job id. It can interrupt the scan process.
- `getImageStreams(host, jobId)` - Get document images by job id. It returns an array of image streams.
- `deleteJob(host, jobId)`
Delete a scan job and terminate scanning.

## Parameter Configuration
The parameter configuration is based on [Dynamsoft Web TWAIN documentation](https://www.dynamsoft.com/web-twain/docs/info/api/Interfaces.html#DeviceConfiguration). It controls the behavior of the scanner.
- `updateJob(host, jobId, parameters)`
Update job status (e.g., cancel a running job).

For example, you can set the resolution to 200 DPI and the pixel type to color:
- `getScannerCapabilities(host, jobId)`
Get scanner capabilities like resolution, color modes.

### 🖼️ Image Retrieval

- `getImageFile(host, jobId, directory)`
Fetch one image and save to local disk.

- `getImageFiles(host, jobId, directory)`
Fetch all images for a job and save to local disk.

- `getImageStream(host, jobId)`
Fetch one image as a readable stream.

- `getImageStreams(host, jobId)`
Fetch all images as streams.

- `getImageInfo(host, jobId)`
Retrieve metadata of the next page.

### 📄 Document APIs

- `createDocument(host, parameters)`
Create a new empty document (PDF).

- `getDocumentInfo(host, docId)`
Get document metadata and structure.

- `deleteDocument(host, docId)`
Delete an existing document.

- `getDocumentFile(host, docId, directory)`
Download the document and save as a PDF.

- `getDocumentStream(host, docId)`
Download document as a stream.

- `insertPage(host, docId, parameters)`
Insert a new page into an existing document.

- `deletePage(host, docId, pageId)`
Remove a page from an existing document.

---

## ⚙️ Scan Job Parameters

The configuration follows [Dynamsoft Web TWAIN DeviceConfiguration](https://www.dynamsoft.com/web-twain/docs/info/api/Interfaces.html#DeviceConfiguration).

```js
let parameters = {
license: "LICENSE-KEY",
device: devices[index].device,
};

parameters.config = {
license: "LICENSE-KEY",
device: devices[0].device,
config: {
IfShowUI: false,
PixelType: 2, // color
PixelType: 2, // Color
Resolution: 200,
IfFeederEnabled: false,
IfDuplexEnabled: false,
IfDuplexEnabled: false
}
};
```

## Examples
Set the `LICENSE-KEY` before running the following examples.
---

## 🧪 Examples

- [Command-line](https://github.com/yushulx/dynamsoft-service-REST-API/tree/main/examples/command-line)
Set the `LICENSE-KEY` before running the examples.

Get all available scanners
### 🖥️ Command-line App

![image](https://github.com/yushulx/dynamsoft-service-REST-API/assets/2202306/24fcb45d-1bea-45ba-9569-b9a2ef377b63)
- [Command-line Example](https://github.com/yushulx/dynamsoft-service-REST-API/tree/main/examples/command-line)

Acquire a Document

![image](https://github.com/yushulx/dynamsoft-service-REST-API/assets/2202306/2688269d-4f05-4734-bf1c-7ba4e2638d66)
- Discover devices
![image](https://github.com/yushulx/dynamsoft-service-REST-API/assets/2202306/24fcb45d-1bea-45ba-9569-b9a2ef377b63)

- [Web server](https://github.com/yushulx/dynamsoft-service-REST-API/tree/main/examples/web)
- Scan and save documents
![image](https://github.com/yushulx/dynamsoft-service-REST-API/assets/2202306/2688269d-4f05-4734-bf1c-7ba4e2638d66)

![server-side-document-scan](https://github.com/yushulx/dynamsoft-service-REST-API/assets/2202306/9a161dda-6f9d-473b-a2d4-168ebd5f6b0b)
### 🌐 Web Server App

- [Web Server Example](https://github.com/yushulx/dynamsoft-service-REST-API/tree/main/examples/web)

![server-side-document-scan](https://github.com/yushulx/dynamsoft-service-REST-API/assets/2202306/9a161dda-6f9d-473b-a2d4-168ebd5f6b0b)
9 changes: 5 additions & 4 deletions examples/REST/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ app.get('/devices', (req, res) => {
});
});

app.post('/scandocument', async (req, res) => {
const json = req.body;
app.post('/createJob', async (req, res) => {
const data = req.body;

let parameters = {
license: "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ==",
device: json['scan'],
device: data['scan'],
};

parameters.config = {
Expand All @@ -38,7 +38,8 @@ app.post('/scandocument', async (req, res) => {
IfDuplexEnabled: false,
};

let jobId = await docscan4nodejs.scanDocument(dynamsoftService, parameters);
let json = await docscan4nodejs.createJob(dynamsoftService, parameters);
let jobId = json.jobuid;
let filename = await docscan4nodejs.getImageFile(dynamsoftService, jobId, './public');

res.send(JSON.stringify({
Expand Down
2 changes: 1 addition & 1 deletion examples/REST/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ <h1> Document Scanning Sample</h1>

async function acquireImage() {
if (devices.length > 0 && selectSources.selectedIndex >= 0) {
const response = await fetch('/scandocument', {
const response = await fetch('/createJob', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
Expand Down
54 changes: 47 additions & 7 deletions examples/command-line/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ const docscan4nodejs = require("../../index.js")
const readline = require('readline');

let devices = [];
// let host = 'http://192.168.8.119:18622';
let host = 'http://127.0.0.1:18622';

docscan4nodejs.getServerInfo(host).then((info) => {
console.log('Server info:', info);
});

const questions = `
Please select an operation:
1. Get scanners
Expand Down Expand Up @@ -51,6 +54,7 @@ function askQuestion() {
let parameters = {
license: "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ==",
device: devices[index].device,
autoRun: true
};

parameters.config = {
Expand All @@ -59,23 +63,59 @@ function askQuestion() {
//XferCount: 1,
//PageSize: 1,
Resolution: 200,
IfFeederEnabled: false,
IfFeederEnabled: true,
IfDuplexEnabled: false,
};

docscan4nodejs.scanDocument(host, parameters).then((jobId) => {
if (jobId !== '') {
console.log('job id: ' + jobId);
docscan4nodejs.createJob(host, parameters).then((job) => {
try {
let jobId = job.jobuid;

(async () => {
// let status = await docscan4nodejs.checkJob(host, jobId);
// console.log('Job status:', status);

// let caps = await docscan4nodejs.getScannerCapabilities(host, jobId);
// console.log('Capabilities:', caps);

// let updateStatus = await docscan4nodejs.updateJob(host, jobId, {
// status: docscan4nodejs.JobStatus.RUNNING
// });
// console.log('Update status:', updateStatus);
let doc = await docscan4nodejs.createDocument(host, {});
// console.log('Document:', doc);


let images = await docscan4nodejs.getImageFiles(host, jobId, './');
for (let i = 0; i < images.length; i++) {
console.log('Image ' + i + ': ' + images[i]);
let info = await docscan4nodejs.getImageInfo(host, jobId);
// console.log('Image info:', info);

let insertPage = await docscan4nodejs.insertPage(host, doc.uid, { password: '', source: info.url });
// console.log('Insert page:', insertPage);
}
// await docscan4nodejs.deleteJob(host, jobId);


let docinfo = await docscan4nodejs.getDocumentInfo(host, doc.uid);
// console.log('Document info:', docinfo);

// let deletePage = await docscan4nodejs.deletePage(host, doc.uid, insertPage.pages[0].uid);
// console.log('Delete page:', deletePage);
let docfile = await docscan4nodejs.getDocumentFile(host, doc.uid, './');
console.log('Document file:', docfile);

let deleteDoc = await docscan4nodejs.deleteDocument(host, doc.uid);
console.log('Delete document:', deleteDoc);

await docscan4nodejs.deleteJob(host, jobId);
askQuestion();
})();
}

catch (error) {
console.error('Job creation failed:', error.message);
askQuestion();
}
});
}
}
Expand Down
Loading