@crowsgear/escl-protocol-scanner 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +663 -0
- package/dist/client.d.ts +69 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +320 -0
- package/dist/client.js.map +1 -0
- package/dist/discovery.d.ts +71 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +269 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.d.ts +76 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +250 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +170 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +63 -0
- package/python/base.py +57 -0
- package/python/escl_backend.py +541 -0
- package/python/escl_main.py +119 -0
- package/scripts/check-python-deps.js +185 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* eSCL Scanner Discovery via Python Subprocess
|
|
4
|
+
* Uses Python's zeroconf library for mDNS discovery
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.ESCLDiscovery = void 0;
|
|
41
|
+
exports.discoverScanners = discoverScanners;
|
|
42
|
+
const child_process_1 = require("child_process");
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
/**
|
|
46
|
+
* eSCL Scanner Discovery Service
|
|
47
|
+
* Spawns Python subprocess to handle mDNS discovery using zeroconf
|
|
48
|
+
*/
|
|
49
|
+
class ESCLDiscovery {
|
|
50
|
+
constructor(timeout, options) {
|
|
51
|
+
this.pythonProcess = null;
|
|
52
|
+
this.discovered = new Map();
|
|
53
|
+
this.listeners = new Set();
|
|
54
|
+
this.timeout = 5000;
|
|
55
|
+
this.processReady = false;
|
|
56
|
+
this.pythonPath = 'python3';
|
|
57
|
+
if (timeout) {
|
|
58
|
+
this.timeout = timeout;
|
|
59
|
+
}
|
|
60
|
+
if (options?.pythonPath) {
|
|
61
|
+
this.pythonPath = options.pythonPath;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Validate Python path exists and is executable
|
|
66
|
+
* @throws Error if Python path is invalid
|
|
67
|
+
*/
|
|
68
|
+
validatePythonPath() {
|
|
69
|
+
// Check if it's an absolute path
|
|
70
|
+
if (path.isAbsolute(this.pythonPath)) {
|
|
71
|
+
if (!fs.existsSync(this.pythonPath)) {
|
|
72
|
+
throw new Error(`Python executable not found at: ${this.pythonPath}\n` +
|
|
73
|
+
`Please ensure the Python virtual environment exists or provide a valid python3 path.`);
|
|
74
|
+
}
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
// For relative paths like './venv/bin/python3', check from current working directory
|
|
78
|
+
const resolvedPath = path.resolve(process.cwd(), this.pythonPath);
|
|
79
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
80
|
+
throw new Error(`Python executable not found at: ${resolvedPath}\n` +
|
|
81
|
+
`Current working directory: ${process.cwd()}\n` +
|
|
82
|
+
`Please ensure the Python virtual environment exists or provide a valid python3 path.`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Start discovering scanners
|
|
87
|
+
* @param timeout Optional timeout in milliseconds (default: 5000ms)
|
|
88
|
+
* @returns Promise resolving with discovery response containing success status and scanner data
|
|
89
|
+
*/
|
|
90
|
+
async startDiscovery(timeout) {
|
|
91
|
+
const discoveryTimeout = timeout || this.timeout;
|
|
92
|
+
return new Promise((resolve, reject) => {
|
|
93
|
+
try {
|
|
94
|
+
// Validate Python path before proceeding
|
|
95
|
+
this.validatePythonPath();
|
|
96
|
+
this.discovered.clear();
|
|
97
|
+
let resolved = false;
|
|
98
|
+
// Timeout fallback (in case Python doesn't respond)
|
|
99
|
+
const timeoutHandle = setTimeout(() => {
|
|
100
|
+
if (!resolved) {
|
|
101
|
+
resolved = true;
|
|
102
|
+
this.stopDiscovery();
|
|
103
|
+
const scanners = Array.from(this.discovered.values());
|
|
104
|
+
resolve({
|
|
105
|
+
success: true,
|
|
106
|
+
data: scanners
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}, discoveryTimeout);
|
|
110
|
+
// Set up listener for Python response
|
|
111
|
+
const responseHandler = (scanners) => {
|
|
112
|
+
if (!resolved) {
|
|
113
|
+
resolved = true;
|
|
114
|
+
clearTimeout(timeoutHandle);
|
|
115
|
+
this.offScannerDiscovered(responseHandler);
|
|
116
|
+
this.stopDiscovery();
|
|
117
|
+
resolve({
|
|
118
|
+
success: true,
|
|
119
|
+
data: scanners
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
this.onScannerDiscovered(responseHandler);
|
|
124
|
+
this.startPythonService();
|
|
125
|
+
// Send list command to Python subprocess
|
|
126
|
+
if (this.pythonProcess && this.pythonProcess.stdin) {
|
|
127
|
+
const command = { action: 'list' };
|
|
128
|
+
this.pythonProcess.stdin.write(JSON.stringify(command) + '\n');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
reject(error);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Stop active discovery and cleanup subprocess
|
|
138
|
+
*/
|
|
139
|
+
stopDiscovery() {
|
|
140
|
+
this.cleanup();
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Get currently discovered scanners
|
|
144
|
+
*/
|
|
145
|
+
getScanners() {
|
|
146
|
+
return Array.from(this.discovered.values());
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Subscribe to scanner discovery updates
|
|
150
|
+
*/
|
|
151
|
+
onScannerDiscovered(callback) {
|
|
152
|
+
this.listeners.add(callback);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Unsubscribe from scanner discovery updates
|
|
156
|
+
*/
|
|
157
|
+
offScannerDiscovered(callback) {
|
|
158
|
+
this.listeners.delete(callback);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Start Python subprocess for eSCL operations
|
|
162
|
+
*/
|
|
163
|
+
startPythonService() {
|
|
164
|
+
if (this.pythonProcess) {
|
|
165
|
+
return; // Already running
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
// Get path to Python script relative to this module
|
|
169
|
+
const pythonScriptPath = path.join(__dirname, '..', 'python', 'escl_main.py');
|
|
170
|
+
this.pythonProcess = (0, child_process_1.spawn)(this.pythonPath, [pythonScriptPath], {
|
|
171
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
172
|
+
windowsHide: true
|
|
173
|
+
});
|
|
174
|
+
// Handle stdout - parse JSON responses
|
|
175
|
+
if (this.pythonProcess.stdout) {
|
|
176
|
+
this.pythonProcess.stdout.on('data', (data) => {
|
|
177
|
+
try {
|
|
178
|
+
const lines = data.toString().split('\n');
|
|
179
|
+
for (const line of lines) {
|
|
180
|
+
if (line.trim()) {
|
|
181
|
+
const response = JSON.parse(line);
|
|
182
|
+
if (!response.success && response.error) {
|
|
183
|
+
// Handle error response from Python
|
|
184
|
+
console.error('[eSCL Error]', response.error);
|
|
185
|
+
}
|
|
186
|
+
else if (response.success && response.scanners) {
|
|
187
|
+
this.discovered.clear();
|
|
188
|
+
for (const scanner of response.scanners) {
|
|
189
|
+
this.discovered.set(scanner.name, scanner);
|
|
190
|
+
}
|
|
191
|
+
this.notifyListeners();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
console.error('Error parsing Python response:', error);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
// Handle stderr - logging
|
|
202
|
+
if (this.pythonProcess.stderr) {
|
|
203
|
+
this.pythonProcess.stderr.on('data', (data) => {
|
|
204
|
+
console.error('[eSCL Python]', data.toString());
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
// Handle process exit
|
|
208
|
+
this.pythonProcess.on('exit', (code) => {
|
|
209
|
+
console.log(`[eSCL] Python subprocess exited with code ${code}`);
|
|
210
|
+
this.pythonProcess = null;
|
|
211
|
+
this.processReady = false;
|
|
212
|
+
});
|
|
213
|
+
this.processReady = true;
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
console.error('Failed to start Python service:', error);
|
|
217
|
+
this.pythonProcess = null;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Cleanup Python subprocess
|
|
222
|
+
*/
|
|
223
|
+
cleanup() {
|
|
224
|
+
if (this.pythonProcess) {
|
|
225
|
+
try {
|
|
226
|
+
// Send exit command
|
|
227
|
+
if (this.pythonProcess.stdin) {
|
|
228
|
+
const command = { action: 'exit' };
|
|
229
|
+
this.pythonProcess.stdin.write(JSON.stringify(command) + '\n');
|
|
230
|
+
}
|
|
231
|
+
// Force kill after timeout
|
|
232
|
+
setTimeout(() => {
|
|
233
|
+
if (this.pythonProcess) {
|
|
234
|
+
this.pythonProcess.kill();
|
|
235
|
+
this.pythonProcess = null;
|
|
236
|
+
}
|
|
237
|
+
}, 1000);
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
console.error('Error during cleanup:', error);
|
|
241
|
+
if (this.pythonProcess) {
|
|
242
|
+
this.pythonProcess.kill();
|
|
243
|
+
this.pythonProcess = null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
this.processReady = false;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Notify all listeners of scanner changes
|
|
251
|
+
*/
|
|
252
|
+
notifyListeners() {
|
|
253
|
+
const scanners = Array.from(this.discovered.values());
|
|
254
|
+
this.listeners.forEach((callback) => {
|
|
255
|
+
callback(scanners);
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
exports.ESCLDiscovery = ESCLDiscovery;
|
|
260
|
+
/**
|
|
261
|
+
* Convenience function for quick scanner discovery
|
|
262
|
+
* @param timeout Discovery timeout in milliseconds (default: 5000)
|
|
263
|
+
* @returns Discovery response with success status and scanner data
|
|
264
|
+
*/
|
|
265
|
+
async function discoverScanners(timeout = 5000) {
|
|
266
|
+
const discovery = new ESCLDiscovery(timeout);
|
|
267
|
+
return discovery.startDiscovery(timeout);
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @escl-protocol/scanner
|
|
3
|
+
* eSCL/AirPrint Protocol Scanner Library
|
|
4
|
+
*
|
|
5
|
+
* A comprehensive TypeScript/Node.js library for discovering and communicating
|
|
6
|
+
* with network scanners using the eSCL (eSC Lexmark) protocol, which is based
|
|
7
|
+
* on AirPrint standards.
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - Automatic scanner discovery via mDNS/Bonjour
|
|
11
|
+
* - HTTP-based communication with eSCL devices
|
|
12
|
+
* - Support for multiple color modes and resolutions
|
|
13
|
+
* - Image download and processing
|
|
14
|
+
* - Compatible with Canon, HP, Epson, and other MFP devices
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { discoverScanners, ESCLClient } from '@escl-protocol/scanner';
|
|
19
|
+
*
|
|
20
|
+
* // Discover available scanners
|
|
21
|
+
* const scanners = await discoverScanners(5000);
|
|
22
|
+
* console.log(`Found ${scanners.length} scanners`);
|
|
23
|
+
*
|
|
24
|
+
* // Get scanner capabilities
|
|
25
|
+
* const client = new ESCLClient();
|
|
26
|
+
* const caps = await client.getCapabilities(scanners[0]);
|
|
27
|
+
* console.log('Available resolutions:', caps?.resolutions);
|
|
28
|
+
*
|
|
29
|
+
* // Perform a scan
|
|
30
|
+
* const jobId = await client.createScanJob(
|
|
31
|
+
* scanners[0],
|
|
32
|
+
* 300, // 300 DPI
|
|
33
|
+
* 'RGB24', // Full color
|
|
34
|
+
* 'Platen' // Flatbed
|
|
35
|
+
* );
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export type { ESCLScanner, ESCLCapabilities, ESCLScanParams, ScannedImage, ESCLResponse, ScannerResponse, ColorModeMap, SaveImageParams, SaveImageResult, ESCLCommand, PythonCommand, ScanParams, ProcessSpawnOptions, DiscoveryResponse } from './types';
|
|
39
|
+
export type { ESCLDiscoveryOptions } from './discovery';
|
|
40
|
+
export { ESCLClient } from './client';
|
|
41
|
+
export { ESCLDiscovery, discoverScanners } from './discovery';
|
|
42
|
+
export declare const VERSION = "1.0.0";
|
|
43
|
+
/**
|
|
44
|
+
* Quick scan helper - convenience function for common scan workflow
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* import { quickScan } from '@escl-protocol/scanner';
|
|
49
|
+
*
|
|
50
|
+
* // With custom save path
|
|
51
|
+
* const filePaths = await quickScan({
|
|
52
|
+
* scanner: scannerDevice,
|
|
53
|
+
* dpi: 300,
|
|
54
|
+
* mode: 'color',
|
|
55
|
+
* source: 'Platen',
|
|
56
|
+
* savePath: '/path/to/save/folder'
|
|
57
|
+
* });
|
|
58
|
+
*
|
|
59
|
+
* // Without save path - defaults to current working directory
|
|
60
|
+
* const filePaths = await quickScan({
|
|
61
|
+
* scanner: scannerDevice,
|
|
62
|
+
* dpi: 300,
|
|
63
|
+
* mode: 'color',
|
|
64
|
+
* source: 'Platen'
|
|
65
|
+
* });
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare function quickScan(params: {
|
|
69
|
+
scanner: any;
|
|
70
|
+
dpi: number;
|
|
71
|
+
mode: 'bw' | 'gray' | 'color';
|
|
72
|
+
source: 'Platen' | 'Feeder';
|
|
73
|
+
timeout?: number;
|
|
74
|
+
savePath?: string;
|
|
75
|
+
}): Promise<string[] | null>;
|
|
76
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAGH,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,eAAe,EACf,eAAe,EACf,WAAW,EACX,aAAa,EACb,UAAU,EACV,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAIxD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG9D,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE;IACtC,OAAO,EAAE,GAAG,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC;IAC9B,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CA+E3B"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @escl-protocol/scanner
|
|
4
|
+
* eSCL/AirPrint Protocol Scanner Library
|
|
5
|
+
*
|
|
6
|
+
* A comprehensive TypeScript/Node.js library for discovering and communicating
|
|
7
|
+
* with network scanners using the eSCL (eSC Lexmark) protocol, which is based
|
|
8
|
+
* on AirPrint standards.
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Automatic scanner discovery via mDNS/Bonjour
|
|
12
|
+
* - HTTP-based communication with eSCL devices
|
|
13
|
+
* - Support for multiple color modes and resolutions
|
|
14
|
+
* - Image download and processing
|
|
15
|
+
* - Compatible with Canon, HP, Epson, and other MFP devices
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { discoverScanners, ESCLClient } from '@escl-protocol/scanner';
|
|
20
|
+
*
|
|
21
|
+
* // Discover available scanners
|
|
22
|
+
* const scanners = await discoverScanners(5000);
|
|
23
|
+
* console.log(`Found ${scanners.length} scanners`);
|
|
24
|
+
*
|
|
25
|
+
* // Get scanner capabilities
|
|
26
|
+
* const client = new ESCLClient();
|
|
27
|
+
* const caps = await client.getCapabilities(scanners[0]);
|
|
28
|
+
* console.log('Available resolutions:', caps?.resolutions);
|
|
29
|
+
*
|
|
30
|
+
* // Perform a scan
|
|
31
|
+
* const jobId = await client.createScanJob(
|
|
32
|
+
* scanners[0],
|
|
33
|
+
* 300, // 300 DPI
|
|
34
|
+
* 'RGB24', // Full color
|
|
35
|
+
* 'Platen' // Flatbed
|
|
36
|
+
* );
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.VERSION = exports.discoverScanners = exports.ESCLDiscovery = exports.ESCLClient = void 0;
|
|
41
|
+
exports.quickScan = quickScan;
|
|
42
|
+
// Class imports and exports
|
|
43
|
+
const client_1 = require("./client");
|
|
44
|
+
var client_2 = require("./client");
|
|
45
|
+
Object.defineProperty(exports, "ESCLClient", { enumerable: true, get: function () { return client_2.ESCLClient; } });
|
|
46
|
+
var discovery_1 = require("./discovery");
|
|
47
|
+
Object.defineProperty(exports, "ESCLDiscovery", { enumerable: true, get: function () { return discovery_1.ESCLDiscovery; } });
|
|
48
|
+
Object.defineProperty(exports, "discoverScanners", { enumerable: true, get: function () { return discovery_1.discoverScanners; } });
|
|
49
|
+
// Version
|
|
50
|
+
exports.VERSION = '1.0.0';
|
|
51
|
+
/**
|
|
52
|
+
* Quick scan helper - convenience function for common scan workflow
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* import { quickScan } from '@escl-protocol/scanner';
|
|
57
|
+
*
|
|
58
|
+
* // With custom save path
|
|
59
|
+
* const filePaths = await quickScan({
|
|
60
|
+
* scanner: scannerDevice,
|
|
61
|
+
* dpi: 300,
|
|
62
|
+
* mode: 'color',
|
|
63
|
+
* source: 'Platen',
|
|
64
|
+
* savePath: '/path/to/save/folder'
|
|
65
|
+
* });
|
|
66
|
+
*
|
|
67
|
+
* // Without save path - defaults to current working directory
|
|
68
|
+
* const filePaths = await quickScan({
|
|
69
|
+
* scanner: scannerDevice,
|
|
70
|
+
* dpi: 300,
|
|
71
|
+
* mode: 'color',
|
|
72
|
+
* source: 'Platen'
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
async function quickScan(params) {
|
|
77
|
+
let { scanner, dpi, mode, source, timeout, savePath } = params;
|
|
78
|
+
const client = new client_1.ESCLClient(timeout);
|
|
79
|
+
// Default save path to current working directory if not provided
|
|
80
|
+
if (!savePath) {
|
|
81
|
+
savePath = process.cwd();
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
// Map mode to eSCL color mode
|
|
85
|
+
const colorModeMap = {
|
|
86
|
+
'bw': 'BlackAndWhite1',
|
|
87
|
+
'gray': 'Grayscale8',
|
|
88
|
+
'color': 'RGB24'
|
|
89
|
+
};
|
|
90
|
+
const colorMode = colorModeMap[mode];
|
|
91
|
+
if (!colorMode) {
|
|
92
|
+
throw new Error(`Invalid color mode: ${mode}`);
|
|
93
|
+
}
|
|
94
|
+
// 1. Create scan job
|
|
95
|
+
const jobId = await client.createScanJob(scanner, dpi, colorMode, source);
|
|
96
|
+
if (!jobId) {
|
|
97
|
+
throw new Error('Failed to create scan job');
|
|
98
|
+
}
|
|
99
|
+
const jobUrl = `http://${scanner.host}:${scanner.port}/eSCL/ScanJobs/${jobId}`;
|
|
100
|
+
console.log(`[eSCL] Scan job created: ${jobUrl}`);
|
|
101
|
+
// 2. Wait for scan to complete (5 seconds)
|
|
102
|
+
console.log('[eSCL] Waiting for scan to complete (5 seconds)...');
|
|
103
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
104
|
+
// 3. Download images via NextDocument endpoint
|
|
105
|
+
const filePaths = [];
|
|
106
|
+
let pageNum = 1;
|
|
107
|
+
const isAdf = source === 'Feeder';
|
|
108
|
+
while (true) {
|
|
109
|
+
console.log(`[eSCL] Attempting to download page ${pageNum}...`);
|
|
110
|
+
const imageBuffer = await downloadNextDocument(jobUrl);
|
|
111
|
+
if (!imageBuffer) {
|
|
112
|
+
// 404 or error
|
|
113
|
+
if (pageNum === 1) {
|
|
114
|
+
// First page failed
|
|
115
|
+
throw new Error('Failed to download scan result. Make sure document is loaded in scanner.');
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
// Subsequent pages: 404 is normal (scan complete)
|
|
119
|
+
console.log(`[eSCL] Scan completed: ${pageNum - 1} pages`);
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Successfully got image data
|
|
124
|
+
console.log(`[eSCL] Page ${pageNum} downloaded: ${imageBuffer.length} bytes`);
|
|
125
|
+
// Save image to file
|
|
126
|
+
const filePath = await saveImageToFile(savePath, imageBuffer, pageNum);
|
|
127
|
+
filePaths.push(filePath);
|
|
128
|
+
// Platen (flatbed) only has 1 page
|
|
129
|
+
if (!isAdf) {
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
pageNum++;
|
|
133
|
+
}
|
|
134
|
+
// 4. Delete scan job (cleanup)
|
|
135
|
+
await deleteScanJob(jobUrl);
|
|
136
|
+
return filePaths.length > 0 ? filePaths : null;
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
console.error('Quick scan failed:', error);
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Save image to file system
|
|
145
|
+
*/
|
|
146
|
+
async function saveImageToFile(folderPath, imageBuffer, pageNum) {
|
|
147
|
+
return new Promise((resolve, reject) => {
|
|
148
|
+
const fs = require('fs');
|
|
149
|
+
const path = require('path');
|
|
150
|
+
try {
|
|
151
|
+
// Create folder if it doesn't exist
|
|
152
|
+
if (!fs.existsSync(folderPath)) {
|
|
153
|
+
fs.mkdirSync(folderPath, { recursive: true });
|
|
154
|
+
}
|
|
155
|
+
// Generate filename with timestamp
|
|
156
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
|
|
157
|
+
const fileName = `scan_${timestamp}_page${pageNum}.jpg`;
|
|
158
|
+
const filePath = path.join(folderPath, fileName);
|
|
159
|
+
// Write file synchronously
|
|
160
|
+
fs.writeFileSync(filePath, imageBuffer);
|
|
161
|
+
console.log(`[eSCL] Image saved: ${filePath}`);
|
|
162
|
+
resolve(filePath);
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
reject(error);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Download next document from scan job
|
|
171
|
+
*/
|
|
172
|
+
async function downloadNextDocument(jobUrl) {
|
|
173
|
+
try {
|
|
174
|
+
const nextDocUrl = `${jobUrl}/NextDocument`;
|
|
175
|
+
return await httpGetBinary(nextDocUrl);
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
// 404 is expected when scan is complete
|
|
179
|
+
if (error.code === 404 || (error.message && error.message.includes('404'))) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
console.error('[eSCL] Failed to download next document:', error);
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Delete scan job (cleanup)
|
|
188
|
+
*/
|
|
189
|
+
async function deleteScanJob(jobUrl) {
|
|
190
|
+
try {
|
|
191
|
+
await httpDelete(jobUrl);
|
|
192
|
+
console.log('[eSCL] Scan job deleted');
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
// Failure to delete is not critical
|
|
196
|
+
console.log('[eSCL] Scan job delete attempted (already deleted by scanner)');
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* HTTP GET binary helper
|
|
201
|
+
*/
|
|
202
|
+
function httpGetBinary(url, timeout = 10000) {
|
|
203
|
+
return new Promise((resolve, reject) => {
|
|
204
|
+
const req = require('http').get(url, { timeout }, (res) => {
|
|
205
|
+
const chunks = [];
|
|
206
|
+
res.on('data', (chunk) => {
|
|
207
|
+
chunks.push(chunk);
|
|
208
|
+
});
|
|
209
|
+
res.on('end', () => {
|
|
210
|
+
if (res.statusCode === 200) {
|
|
211
|
+
resolve(Buffer.concat(chunks));
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
const error = new Error(`HTTP ${res.statusCode}`);
|
|
215
|
+
error.code = res.statusCode;
|
|
216
|
+
reject(error);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
req.on('timeout', () => {
|
|
221
|
+
req.destroy();
|
|
222
|
+
reject(new Error('Request timeout'));
|
|
223
|
+
});
|
|
224
|
+
req.on('error', reject);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* HTTP DELETE helper
|
|
229
|
+
*/
|
|
230
|
+
function httpDelete(url, timeout = 10000) {
|
|
231
|
+
return new Promise((resolve, reject) => {
|
|
232
|
+
const options = {
|
|
233
|
+
method: 'DELETE',
|
|
234
|
+
timeout
|
|
235
|
+
};
|
|
236
|
+
const req = require('http').request(url, options, (res) => {
|
|
237
|
+
res.on('data', () => { });
|
|
238
|
+
res.on('end', () => {
|
|
239
|
+
resolve();
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
req.on('timeout', () => {
|
|
243
|
+
req.destroy();
|
|
244
|
+
reject(new Error('Request timeout'));
|
|
245
|
+
});
|
|
246
|
+
req.on('error', reject);
|
|
247
|
+
req.end();
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|