@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.
@@ -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,7 @@
1
+ "use strict";
2
+ /**
3
+ * eSCL/AirPrint Protocol Scanner Types
4
+ * HTTP-based network scanner protocol for Canon, HP, Epson, and other MFP devices
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ //# sourceMappingURL=types.js.map
@@ -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()