@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
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* eSCL/AirPrint Protocol Scanner Types
|
|
3
|
+
* HTTP-based network scanner protocol for Canon, HP, Epson, and other MFP devices
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* eSCL Scanner device information
|
|
7
|
+
*/
|
|
8
|
+
export interface ESCLScanner {
|
|
9
|
+
/** Device name from mDNS (cleaned of service type suffix) */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Network hostname or IP address */
|
|
12
|
+
host: string;
|
|
13
|
+
/** HTTP service port (typically 80) */
|
|
14
|
+
port: number;
|
|
15
|
+
/** Full mDNS service name */
|
|
16
|
+
serviceName?: string;
|
|
17
|
+
/** Device model from mDNS TXT record */
|
|
18
|
+
model?: string;
|
|
19
|
+
/** Device manufacturer */
|
|
20
|
+
manufacturer?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Scanner capabilities response
|
|
24
|
+
*/
|
|
25
|
+
export interface ESCLCapabilities {
|
|
26
|
+
/** Available scan resolutions in DPI */
|
|
27
|
+
resolutions: number[];
|
|
28
|
+
/** Supported color modes */
|
|
29
|
+
colorModes: ('BlackAndWhite1' | 'Grayscale8' | 'RGB24')[];
|
|
30
|
+
/** Available scan sources */
|
|
31
|
+
sources: ('Platen' | 'Adf' | 'Feeder')[];
|
|
32
|
+
/** Maximum scannable area width in mm */
|
|
33
|
+
maxWidth?: number;
|
|
34
|
+
/** Maximum scannable area height in mm */
|
|
35
|
+
maxHeight?: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Scan request parameters
|
|
39
|
+
*/
|
|
40
|
+
export interface ESCLScanParams {
|
|
41
|
+
/** Target scanner device */
|
|
42
|
+
scanner: ESCLScanner;
|
|
43
|
+
/** Resolution in DPI (e.g., 200, 300) */
|
|
44
|
+
dpi: number;
|
|
45
|
+
/** Color mode for scanning */
|
|
46
|
+
mode: 'bw' | 'gray' | 'color';
|
|
47
|
+
/** Scan source */
|
|
48
|
+
source: 'Platen' | 'Feeder';
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Scanned image data
|
|
52
|
+
*/
|
|
53
|
+
export interface ScannedImage {
|
|
54
|
+
/** Base64 encoded PNG image data */
|
|
55
|
+
data: string;
|
|
56
|
+
/** Image dimensions */
|
|
57
|
+
width: number;
|
|
58
|
+
height: number;
|
|
59
|
+
/** Color mode used for scanning */
|
|
60
|
+
colorMode: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Generic eSCL response wrapper
|
|
64
|
+
*/
|
|
65
|
+
export interface ESCLResponse {
|
|
66
|
+
/** Operation success status */
|
|
67
|
+
success: boolean;
|
|
68
|
+
/** List of discovered scanners */
|
|
69
|
+
scanners?: ESCLScanner[];
|
|
70
|
+
/** Scanner capabilities */
|
|
71
|
+
capabilities?: ESCLCapabilities;
|
|
72
|
+
/** Scanned images */
|
|
73
|
+
images?: string[];
|
|
74
|
+
/** Number of images returned */
|
|
75
|
+
count?: number;
|
|
76
|
+
/** Error message if operation failed */
|
|
77
|
+
error?: string;
|
|
78
|
+
/** Additional response metadata */
|
|
79
|
+
metadata?: Record<string, unknown>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Scanner response for local scanner backend
|
|
83
|
+
*/
|
|
84
|
+
export interface ScannerResponse {
|
|
85
|
+
success: boolean;
|
|
86
|
+
scanners?: Array<{
|
|
87
|
+
id: string;
|
|
88
|
+
name: string;
|
|
89
|
+
type: string;
|
|
90
|
+
}>;
|
|
91
|
+
images?: string[];
|
|
92
|
+
count?: number;
|
|
93
|
+
error?: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Color mode mapping for UI display
|
|
97
|
+
*/
|
|
98
|
+
export interface ColorModeMap {
|
|
99
|
+
[key: string]: {
|
|
100
|
+
value: 'bw' | 'gray' | 'color';
|
|
101
|
+
label: string;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Image save parameters
|
|
106
|
+
*/
|
|
107
|
+
export interface SaveImageParams {
|
|
108
|
+
folderPath: string;
|
|
109
|
+
fileName: string;
|
|
110
|
+
imageData: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Image save result
|
|
114
|
+
*/
|
|
115
|
+
export interface SaveImageResult {
|
|
116
|
+
success: boolean;
|
|
117
|
+
filePath?: string;
|
|
118
|
+
error?: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Python subprocess command types
|
|
122
|
+
*/
|
|
123
|
+
export type ESCLCommand = {
|
|
124
|
+
action: 'list' | 'scan' | 'capabilities' | 'exit';
|
|
125
|
+
params?: ESCLScanParams;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Python subprocess command for legacy Python scanner
|
|
129
|
+
*/
|
|
130
|
+
export type PythonCommand = {
|
|
131
|
+
type: 'list' | 'scan' | 'exit';
|
|
132
|
+
params?: Record<string, unknown>;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Scan parameters for legacy Python scanner
|
|
136
|
+
*/
|
|
137
|
+
export interface ScanParams {
|
|
138
|
+
scanner?: {
|
|
139
|
+
name: string;
|
|
140
|
+
id: string;
|
|
141
|
+
};
|
|
142
|
+
dpi?: number;
|
|
143
|
+
mode?: string;
|
|
144
|
+
source?: string;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Python process spawn options
|
|
148
|
+
*/
|
|
149
|
+
export interface ProcessSpawnOptions {
|
|
150
|
+
/** Python executable path */
|
|
151
|
+
pythonPath?: string;
|
|
152
|
+
/** Enable verbose logging */
|
|
153
|
+
verbose?: boolean;
|
|
154
|
+
/** Timeout for subprocess communication (ms) */
|
|
155
|
+
timeout?: number;
|
|
156
|
+
/** Environment variables for Python process */
|
|
157
|
+
env?: NodeJS.ProcessEnv;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Scanner discovery response
|
|
161
|
+
*/
|
|
162
|
+
export interface DiscoveryResponse {
|
|
163
|
+
/** Operation success status */
|
|
164
|
+
success: boolean;
|
|
165
|
+
/** List of discovered scanners */
|
|
166
|
+
data: ESCLScanner[];
|
|
167
|
+
/** Error message if operation failed */
|
|
168
|
+
error?: string;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;GAGG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@crowsgear/escl-protocol-scanner",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "eSCL/AirPrint Protocol Scanner Library - HTTP-based network scanner support with mDNS discovery",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "byeong1",
|
|
7
|
+
"homepage": "https://github.com/byeong1/escl-protocol-scanner",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git@github.com:byeong1/escl-protocol-scanner.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/byeong1/escl-protocol-scanner/issues"
|
|
14
|
+
},
|
|
15
|
+
"main": "dist/index.js",
|
|
16
|
+
"types": "dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"import": "./dist/index.js",
|
|
20
|
+
"require": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts"
|
|
22
|
+
},
|
|
23
|
+
"./types": {
|
|
24
|
+
"import": "./dist/types.js",
|
|
25
|
+
"types": "./dist/types.d.ts"
|
|
26
|
+
},
|
|
27
|
+
"./client": {
|
|
28
|
+
"import": "./dist/client.js",
|
|
29
|
+
"types": "./dist/client.d.ts"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"python",
|
|
35
|
+
"scripts",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsc",
|
|
41
|
+
"build:watch": "tsc --watch",
|
|
42
|
+
"clean": "rm -rf dist",
|
|
43
|
+
"prepublishOnly": "yarn run build",
|
|
44
|
+
"prepack": "yarn run build",
|
|
45
|
+
"postinstall": "node scripts/check-python-deps.js"
|
|
46
|
+
},
|
|
47
|
+
"keywords": [
|
|
48
|
+
"escl",
|
|
49
|
+
"scanner",
|
|
50
|
+
"airprint",
|
|
51
|
+
"network",
|
|
52
|
+
"mfp",
|
|
53
|
+
"printer"
|
|
54
|
+
],
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=14.0.0"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/node": "^24.7.2",
|
|
61
|
+
"typescript": "^5.9.3"
|
|
62
|
+
}
|
|
63
|
+
}
|
package/python/base.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Scanner Backend Base Classes and Common Utilities
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
import sys
|
|
9
|
+
import json
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ScannerBackend(ABC):
|
|
13
|
+
"""Abstract base class for scanner backends"""
|
|
14
|
+
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def list_scanners(self):
|
|
17
|
+
"""
|
|
18
|
+
Return list of available scanners
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
dict: {'success': bool, 'scanners': list, 'backend': str}
|
|
22
|
+
or {'success': False, 'error': str}
|
|
23
|
+
"""
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def scan(self, params):
|
|
28
|
+
"""
|
|
29
|
+
Execute scan with given parameters
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
params (dict): {
|
|
33
|
+
'scanner': str, # Scanner name/ID
|
|
34
|
+
'dpi': int, # Resolution (default: 300)
|
|
35
|
+
'mode': str, # 'gray', 'bw', 'color' (default: 'gray')
|
|
36
|
+
'format': str, # 'a3', 'a4', 'b4', 'b5' (default: 'a3')
|
|
37
|
+
'adf': bool, # Auto Document Feeder (default: True)
|
|
38
|
+
'duplex': bool # Double-sided scanning (default: False)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
dict: {'success': bool, 'images': list, 'count': int, 'backend': str}
|
|
43
|
+
or {'success': False, 'error': str}
|
|
44
|
+
"""
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def send_response(data):
|
|
49
|
+
"""
|
|
50
|
+
Send JSON response via stdout
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
data (dict): Response data to send
|
|
54
|
+
"""
|
|
55
|
+
response = json.dumps(data, ensure_ascii=False)
|
|
56
|
+
sys.stdout.write(response + '\n')
|
|
57
|
+
sys.stdout.flush()
|