Web TWAIN SDK от Dynamsoft уже давно является лидером на рынке веб-сканирования документов, предоставляя многочисленным организациям возможность разрабатывать собственные системы управления документами. SDK состоял из двух основных компонентов: службы Dynamsoft для управления сканером и библиотеки JavaScript для внешней разработки. Раньше доступ к этому сервису можно было получить только через библиотеку JavaScript. В следующем выпуске служба Dynamsoft предоставит базовую функцию сканирования документов через REST API. Эта новая функция позволяет разработчикам использовать различные языки программирования для задач сканирования документов. Теперь, помимо веб-приложений, SDK также можно использовать для создания настольных и мобильных приложений для сканирования документов, а также серверные службы сканирования. В этой статье я покажу вам процесс использования нового REST API для сканирования документов в Node.js.
Пакет НПМ
https://www.npmjs.com/package/docscan4nodejs
Предварительные условия
- Установите Dynamsoft Service REST Preview для Windows.
В настоящее время REST API доступен исключительно для Windows, но скоро появится поддержка Linux (x64 и ARM64) и macOS.
- Запросите бесплатную пробную лицензию для Dynamsoft Service.
Справочник по REST API
По умолчанию адрес хоста REST API установлен на http://127.0.0.1:18622
. Чтобы изменить его на IP-адрес локальной сети, перейдите к http://127.0.0.1:18625/
в веб-браузере.
Параметры конечной точки /DWTAPI/ScanJobs
описаны в Документации Dynamic Web TWAIN и управляют поведением сканера.
Например, вы можете установить разрешение 200 DPI и цветной тип пикселя:
let parameters = { license: "LICENSE-KEY", device: device, }; parameters.config = { IfShowUI: false, PixelType: 2, // color Resolution: 200, IfFeederEnabled: false, IfDuplexEnabled: false, };
Разработка функций Node.js для вызова REST API
Установите Axios для отправки HTTP-запросов напрямую из Node.js в RESTful API и получения их ответов.
npm install axios
Согласно справочнику REST API, мы реализуем пять функций: getDevices()
, scanDocument()
, deleteJob
, getImageFiles
и getImageStreams()
.
const axios = require('axios'); const fs = require('fs'); const path = require('path'); module.exports = { getDevices: async function (host) { return []; }, scanDocument: async function (host, parameters) { return ''; }, deleteJob: async function (host, jobId) { }, getImageFiles: async function (host, jobId, directory) { let images = []; return images; }, getImageStreams: async function (host, jobId) { let streams = []; return streams; }, };
getDevices()
получает список сканеров.
getDevices: async function (host) { devices = []; let url = host + '/DWTAPI/Scanners' 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 []; },
scanDocument()
создает задание сканирования и возвращает его идентификатор.
scanDocument: async function (host, parameters) { let url = host + '/DWTAPI/ScanJobs'; 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 ''; },
deleteJob()
удаляет задание сканирования.
deleteJob: async function (host, jobId) { if (!jobId) return; let url = host + '/DWTAPI/ScanJobs/' + jobId; console.log('Delete job: ' + url); axios({ method: 'DELETE', url: url }) .then(response => { console.log('Deleted:', response.data); }) .catch(error => { }); },
getImageFiles()
извлекает файлы изображений задания сканирования.
getImageFiles: async function (host, jobId, directory) { 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: 'stream', }); if (response.status == 200) { await new Promise((resolve, reject) => { const timestamp = Date.now(); const imagePath = path.join(directory, `image_${timestamp}.jpg`); const writer = fs.createWriteStream(imagePath); response.data.pipe(writer); writer.on('finish', () => { images.push(imagePath); console.log('Saved image to ' + imagePath + '\n'); resolve(); }); writer.on('error', (err) => { console.log(err); reject(err); }); }); } else { console.log(response); } } catch (error) { console.error('No more images.'); break; } } return images; },
getImageStreams()
извлекает потоки изображений задания сканирования.
getImageStreams: async function (host, jobId) { let streams = []; let url = host + '/DWTAPI/ScanJobs/' + jobId + '/NextDocument'; console.log('Start downloading images......'); while (true) { try { const response = await axios({ method: 'GET', url: url, responseType: 'stream', }); if (response.status == 200) { streams.push(response.data); } else { console.log(response); } } catch (error) { console.error('No more images.'); break; } } return streams; },
Сканирование документов из командной строки в терминале
Создадим файл app.js
для сканирования документов из командной строки.
- Импортируйте
docscan4nodejs
иreadline
. Модульdocscan4nodejs
— это то, что мы только что реализовали, аreadline
используется для чтения пользовательского ввода из командной строки.
const docscan4nodejs = require("docscan4nodejs") const readline = require('readline');
2. Создайте экземпляр readline.Interface
для чтения вводимых пользователем данных из командной строки.
const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); rl.question(questions, function (answer) {});
3. Получите все доступные сканеры, совместимые с TWAIN, SANE, ICA, WIA и eSCL. .
let devices = await docscan4nodejs.getDevices(host);
4. Выберите сканер из списка для сканирования документов. Требуется действительный лицензионный ключ.
let parameters = { license: "LICENSE-KEY", device: devices[index].device, }; parameters.config = { IfShowUI: false, PixelType: 2, //XferCount: 1, //PageSize: 1, Resolution: 200, IfFeederEnabled: false, IfDuplexEnabled: false, }; docscan4nodejs.scanDocument(host, parameters).then((jobId) => { if (jobId !== '') { console.log('job id: ' + jobId); (async () => { let images = await docscan4nodejs.getImageFiles(host, jobId, './'); for (let i = 0; i < images.length; i++) { console.log('Image ' + i + ': ' + images[i]); } await docscan4nodejs.deleteJob(jobId); })(); } });
5. Запустите скрипт в терминале.
node app.js
Получить все доступные сканеры
Получить документ
Реализация сканирования документов на стороне сервера для веб-приложений
Более продвинутый вариант использования предполагает реализацию сканирования документов на стороне сервера для веб-приложений. Ключевым преимуществом этой стратегии является то, что она позволяет сканировать документы непосредственно из веб-браузера, устраняя необходимость установки дополнительного программного обеспечения. Например, если в вашем офисе есть единственный сканер документов, и вы хотите поделиться им с несколькими коллегами, веб-приложение позволит им инициировать сканирование со своих отдельных компьютеров.
Мы используем express
для создания веб-сервера и socket.io
для передачи данных между сервером и клиентом.
npm install express socket.io
Веб-сервер Node.js
- Инициализируйте
express
иsocket.io
.
const express = require('express'); const path = require('path'); const fs = require('fs'); const app = express(); const http = require('http'); const server = http.createServer(app); const io = require('socket.io')(server); const docscan4nodejs = require("docscan4nodejs") const { PassThrough } = require('stream'); app.use(express.static('public')); app.use('/node_modules', express.static(__dirname + '/node_modules')); const connections = new Map(); io.on('connection', (socket) => { connections.set(socket.id, socket); console.log(socket.id + ' connected'); socket.on('disconnect', () => { console.log(socket.id + ' disconnected'); connections.delete(socket.id); }); socket.on('message', async (message) => { }); }); // Start the server const port = process.env.PORT || 3000; server.listen(port, '0.0.0.0', () => { console.log(`Server running at http://0.0.0.0:${port}/`); });
2. Как только соединение socket.io
будет установлено, достаньте доступные сканеры и отправьте их клиенту.
io.on('connection', (socket) => { ... docscan4nodejs.getDevices(host).then((scanners) => { socket.emit('message', JSON.stringify({ 'devices': scanners })); }); });
3. При получении события сканирования инициируйте сканирование документа и передайте полученный поток изображений веб-клиенту:
socket.on('message', async (message) => { let json = JSON.parse(message); if (json) { if (json['scan']) { console.log('device: ' + json['scan']); let parameters = { license: "LICENSE-KEY", device: json['scan'], }; parameters.config = { IfShowUI: false, PixelType: 2, //XferCount: 1, //PageSize: 1, Resolution: 200, IfFeederEnabled: false, IfDuplexEnabled: false, }; let jobId = await docscan4nodejs.scanDocument(host, parameters); if (jobId !== '') { console.log('job id: ' + jobId); let streams = await docscan4nodejs.getImageStreams(host, jobId); for (let i = 0; i < streams.length; i++) { await new Promise((resolve, reject) => { try { const passThrough = new PassThrough(); const chunks = []; streams[i].pipe(passThrough); passThrough.on('data', (chunk) => { chunks.push(chunk); }); passThrough.on('end', () => { const buffer = Buffer.concat(chunks); socket.emit('image', buffer); resolve(); }); } catch (error) { reject(error); } }); } } } } });
Веб-клиент
- Установите
socket.io
соединение с сервером.
const socket = io(); var data = []; var devices = []; var selectSources = document.getElementById("sources"); socket.on('message', (message) => { }); socket.on('image', (buffer) => { });
2. Обновите элемент <select>
, указав доступные сканеры.
socket.on('message', (message) => { try { let json = JSON.parse(message); if (json) { if (json['devices']) { selectSources.options.length = 0; devices = json['devices']; for (let i = 0; i < devices.length; i++) { console.log('\nIndex: ' + i + ', Name: ' + devices[i]['name']); let option = document.createElement("option"); option.text = devices[i]['name']; option.value = i.toString(); selectSources.add(option); } } } } catch (error) { console.log(error) } });
3. Отправьте событие сканирования на сервер, когда пользователь нажимает кнопку Scan
.
<button onclick="acquireImage()">Scan Documents</button> function acquireImage() { if (devices.length > 0 && selectSources.selectedIndex >= 0) { socket.emit('message', JSON.stringify({ 'scan': devices[selectSources.selectedIndex]['device'] })); } }
4. Отобразите поток изображений в элементе <img>
.
socket.on('image', (buffer) => { // Convert the Buffer into a base64 string const base64Image = btoa( new Uint8Array(buffer) .reduce((data, byte) => data + String.fromCharCode(byte), '') ); // Set the image src to display the image let img = document.getElementById('document-image'); let url = `data:image/jpeg;base64,${base64Image}`; 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; } }); } });
Запустите веб-сервер на своем компьютере с Windows, а затем перейдите к http://LAN-IP:18625/
с помощью Safari на macOS.
Исходный код
https://github.com/yushulx/dynamsoft-service-REST-API
Оригинально опубликовано на сайте https://www.dynamsoft.com 6 сентября 2023 г.