node-hp-scan-to 1.0.0 → 1.2.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/README.md +92 -11
- package/dist/Destination.d.ts +8 -0
- package/dist/Destination.js +116 -0
- package/dist/Destination.js.map +1 -0
- package/dist/Event.d.ts +21 -0
- package/dist/Event.js +47 -0
- package/dist/Event.js.map +1 -0
- package/dist/EventTable.d.ts +11 -0
- package/dist/EventTable.js +27 -0
- package/dist/EventTable.js.map +1 -0
- package/dist/HPApi.d.ts +42 -0
- package/dist/HPApi.js +529 -0
- package/dist/HPApi.js.map +1 -0
- package/dist/Job.d.ts +36 -0
- package/dist/Job.js +95 -0
- package/dist/Job.js.map +1 -0
- package/dist/JpegUtil.d.ts +26 -0
- package/dist/JpegUtil.js +238 -0
- package/dist/JpegUtil.js.map +1 -0
- package/dist/PathHelper.d.ts +5 -0
- package/dist/PathHelper.js +79 -0
- package/dist/PathHelper.js.map +1 -0
- package/dist/ScanContent.d.ts +12 -0
- package/dist/ScanContent.js +82 -0
- package/dist/ScanContent.js.map +1 -0
- package/dist/ScanJobSettings.d.ts +6 -0
- package/dist/ScanJobSettings.js +96 -0
- package/dist/ScanJobSettings.js.map +1 -0
- package/dist/ScanStatus.d.ts +18 -0
- package/dist/ScanStatus.js +36 -0
- package/dist/ScanStatus.js.map +1 -0
- package/dist/WalkupScanDestination.d.ts +24 -0
- package/dist/WalkupScanDestination.js +41 -0
- package/dist/WalkupScanDestination.js.map +1 -0
- package/dist/WalkupScanDestinations.d.ts +11 -0
- package/dist/WalkupScanDestinations.js +27 -0
- package/dist/WalkupScanDestinations.js.map +1 -0
- package/dist/WalkupScanToCompDestination.d.ts +26 -0
- package/dist/WalkupScanToCompDestination.js +44 -0
- package/dist/WalkupScanToCompDestination.js.map +1 -0
- package/dist/WalkupScanToCompDestinations.d.ts +11 -0
- package/dist/WalkupScanToCompDestinations.js +27 -0
- package/dist/WalkupScanToCompDestinations.js.map +1 -0
- package/dist/WalkupScanToCompEvent.d.ts +10 -0
- package/dist/WalkupScanToCompEvent.js +17 -0
- package/dist/WalkupScanToCompEvent.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +630 -292
- package/dist/index.js.map +1 -0
- package/nodemon.json +5 -5
- package/package.json +72 -51
- package/src/Destination.ts +63 -45
- package/src/Event.ts +45 -31
- package/src/EventTable.ts +25 -25
- package/src/HPApi.ts +365 -222
- package/src/Job.ts +100 -62
- package/src/JpegUtil.ts +319 -0
- package/src/PathHelper.ts +44 -0
- package/src/ScanContent.ts +34 -0
- package/src/ScanJobSettings.ts +55 -55
- package/src/ScanStatus.ts +36 -31
- package/src/WalkupScanDestination.ts +46 -44
- package/src/WalkupScanDestinations.ts +29 -27
- package/src/WalkupScanToCompDestination.ts +55 -0
- package/src/WalkupScanToCompDestinations.ts +34 -0
- package/src/WalkupScanToCompEvent.ts +18 -0
- package/src/index.ts +555 -205
- package/tsconfig.json +33 -33
- package/.travis.yml +0 -13
- package/protocol_doc/index.md +0 -1484
- package/test/dummy.js +0 -0
package/src/index.ts
CHANGED
|
@@ -1,205 +1,555 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
import Bonjour
|
|
10
|
-
|
|
11
|
-
import Destination from "./Destination";
|
|
12
|
-
import ScanJobSettings from "./ScanJobSettings";
|
|
13
|
-
import Event from "./Event";
|
|
14
|
-
import HPApi from "./HPApi";
|
|
15
|
-
import Job from "./Job";
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
} else {
|
|
137
|
-
console.log(`
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// noinspection XmlDeprecatedElement,HtmlDeprecatedTag
|
|
3
|
+
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
import os from "os";
|
|
7
|
+
import fs from "fs/promises";
|
|
8
|
+
import { Command } from "commander";
|
|
9
|
+
import Bonjour from "bonjour";
|
|
10
|
+
|
|
11
|
+
import Destination from "./Destination";
|
|
12
|
+
import ScanJobSettings from "./ScanJobSettings";
|
|
13
|
+
import Event from "./Event";
|
|
14
|
+
import HPApi from "./HPApi";
|
|
15
|
+
import Job from "./Job";
|
|
16
|
+
import WalkupScanDestination from "./WalkupScanDestination";
|
|
17
|
+
import WalkupScanToCompDestination from "./WalkupScanToCompDestination";
|
|
18
|
+
import JpegUtil from "../src/JpegUtil";
|
|
19
|
+
import PathHelper from "./PathHelper";
|
|
20
|
+
import { createPdfFrom, ScanContent, ScanPage } from "./ScanContent";
|
|
21
|
+
|
|
22
|
+
const program = new Command();
|
|
23
|
+
|
|
24
|
+
function delay(t: number): Promise<void> {
|
|
25
|
+
return new Promise(function (resolve) {
|
|
26
|
+
setTimeout(resolve, t);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function waitForScanEvent(
|
|
31
|
+
resourceURI: string,
|
|
32
|
+
afterEtag: string | null = null
|
|
33
|
+
): Promise<Event> {
|
|
34
|
+
console.log("Start listening for new ScanEvent");
|
|
35
|
+
|
|
36
|
+
let eventTable = await HPApi.getEvents(afterEtag ?? "");
|
|
37
|
+
let acceptedScanEvent = null;
|
|
38
|
+
let currentEtag = eventTable.etag;
|
|
39
|
+
while (acceptedScanEvent == null) {
|
|
40
|
+
eventTable = await HPApi.getEvents(currentEtag, 1200);
|
|
41
|
+
currentEtag = eventTable.etag;
|
|
42
|
+
|
|
43
|
+
acceptedScanEvent = eventTable.eventTable.events.find(
|
|
44
|
+
(ev) =>
|
|
45
|
+
ev.isScanEvent &&
|
|
46
|
+
ev.destinationURI &&
|
|
47
|
+
ev.destinationURI.indexOf(resourceURI) >= 0
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
return acceptedScanEvent;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function waitPrinterUntilItIsReadyToUploadOrCompleted(
|
|
54
|
+
jobUrl: string
|
|
55
|
+
): Promise<Job> {
|
|
56
|
+
let job = null;
|
|
57
|
+
let isReadyToUpload = false;
|
|
58
|
+
do {
|
|
59
|
+
job = await HPApi.getJob(jobUrl);
|
|
60
|
+
if (job.jobState === "Canceled") {
|
|
61
|
+
return job;
|
|
62
|
+
} else if (
|
|
63
|
+
job.pageState === "ReadyToUpload" ||
|
|
64
|
+
job.jobState === "Completed"
|
|
65
|
+
) {
|
|
66
|
+
isReadyToUpload = true;
|
|
67
|
+
} else if (job.jobState == "Processing") {
|
|
68
|
+
isReadyToUpload = false;
|
|
69
|
+
} else {
|
|
70
|
+
console.log(`Unknown jobState: ${job.jobState}`);
|
|
71
|
+
}
|
|
72
|
+
await delay(300);
|
|
73
|
+
} while (!isReadyToUpload);
|
|
74
|
+
return job;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function register(): Promise<string> {
|
|
78
|
+
let destination;
|
|
79
|
+
const hostname = os.hostname();
|
|
80
|
+
const toComp = await HPApi.getWalkupScanToCompCaps();
|
|
81
|
+
|
|
82
|
+
if (toComp) {
|
|
83
|
+
const walkupScanDestinations =
|
|
84
|
+
await HPApi.getWalkupScanToCompDestinations();
|
|
85
|
+
const destinations = walkupScanDestinations.destinations;
|
|
86
|
+
|
|
87
|
+
console.log(
|
|
88
|
+
"Host destinations fetched:",
|
|
89
|
+
destinations.map((d) => d.name).join(", ")
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
destination = destinations.find((x) => x.name === hostname);
|
|
93
|
+
} else {
|
|
94
|
+
const walkupScanDestinations = await HPApi.getWalkupScanDestinations();
|
|
95
|
+
const destinations = walkupScanDestinations.destinations;
|
|
96
|
+
|
|
97
|
+
console.log(
|
|
98
|
+
"Host destinations fetched:",
|
|
99
|
+
destinations.map((d) => d.name).join(", ")
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
destination = destinations.find((x) => x.name === hostname);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let resourceURI;
|
|
106
|
+
if (destination) {
|
|
107
|
+
console.log(
|
|
108
|
+
`Re-using existing destination: ${hostname} - ${destination.resourceURI}`
|
|
109
|
+
);
|
|
110
|
+
resourceURI = destination.resourceURI;
|
|
111
|
+
} else {
|
|
112
|
+
resourceURI = await HPApi.registerDestination(
|
|
113
|
+
new Destination(hostname, hostname, toComp),
|
|
114
|
+
toComp
|
|
115
|
+
);
|
|
116
|
+
console.log(`New Destination registered: ${hostname} - ${resourceURI}`);
|
|
117
|
+
}
|
|
118
|
+
return resourceURI;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function TryGetDestination(event: Event) {
|
|
122
|
+
//this code can in some cases be executed before the user actually chooses between Document or Photo
|
|
123
|
+
//so lets fetch the contentType (Document or Photo) until we get a value
|
|
124
|
+
let destination: WalkupScanDestination | WalkupScanToCompDestination | null =
|
|
125
|
+
null;
|
|
126
|
+
|
|
127
|
+
for (let i = 0; i < 20; i++) {
|
|
128
|
+
const destinationURI = event.destinationURI;
|
|
129
|
+
if (destinationURI) {
|
|
130
|
+
destination = await HPApi.getDestination(destinationURI);
|
|
131
|
+
|
|
132
|
+
const shortcut = destination.shortcut;
|
|
133
|
+
if (shortcut !== "") {
|
|
134
|
+
return destination;
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
console.log(`No destination URI found`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
console.log(`No shortcut yet available, attempt: ${i + 1}/20`);
|
|
141
|
+
await new Promise((resolve) => setTimeout(resolve, 1000)); //wait 1s
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
console.log("Failing to detect destination shortcut");
|
|
145
|
+
console.log(JSON.stringify(destination));
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function fixJpegSize(filePath: string): Promise<number | null> {
|
|
150
|
+
const buffer: Buffer = await fs.readFile(filePath);
|
|
151
|
+
|
|
152
|
+
let height = JpegUtil.fixSizeWithDNL(buffer);
|
|
153
|
+
if (height != null) {
|
|
154
|
+
// rewrite the fixed file
|
|
155
|
+
await fs.writeFile(filePath, buffer);
|
|
156
|
+
return height;
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function createScanPage(
|
|
162
|
+
job: Job,
|
|
163
|
+
currentPageNumber: number,
|
|
164
|
+
filePath: string,
|
|
165
|
+
sizeFixed: number | null
|
|
166
|
+
): ScanPage {
|
|
167
|
+
let height = sizeFixed ?? job.imageHeight;
|
|
168
|
+
return {
|
|
169
|
+
path: filePath,
|
|
170
|
+
pageNumber: currentPageNumber,
|
|
171
|
+
width: job.imageWidth,
|
|
172
|
+
height,
|
|
173
|
+
xResolution: job.xResolution,
|
|
174
|
+
yResolution: job.yResolution,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function handleProcessingState(
|
|
179
|
+
job: Job,
|
|
180
|
+
inputSource: "Adf" | "Platen",
|
|
181
|
+
folder: string,
|
|
182
|
+
scanCount: number,
|
|
183
|
+
currentPageNumber: number
|
|
184
|
+
): Promise<ScanPage | null> {
|
|
185
|
+
if (
|
|
186
|
+
job.pageState == "ReadyToUpload" &&
|
|
187
|
+
job.binaryURL != null &&
|
|
188
|
+
job.currentPageNumber != null
|
|
189
|
+
) {
|
|
190
|
+
console.log(
|
|
191
|
+
`Ready to download page job page ${job.currentPageNumber} at:`,
|
|
192
|
+
job.binaryURL
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const destinationFilePath = PathHelper.getFileForPage(
|
|
196
|
+
folder,
|
|
197
|
+
scanCount,
|
|
198
|
+
currentPageNumber,
|
|
199
|
+
program.opts().pattern,
|
|
200
|
+
"jpg"
|
|
201
|
+
);
|
|
202
|
+
const filePath = await HPApi.downloadPage(
|
|
203
|
+
job.binaryURL,
|
|
204
|
+
destinationFilePath
|
|
205
|
+
);
|
|
206
|
+
console.log("Page downloaded to:", filePath);
|
|
207
|
+
|
|
208
|
+
let sizeFixed: null | number = null;
|
|
209
|
+
if (inputSource == "Adf") {
|
|
210
|
+
sizeFixed = await fixJpegSize(filePath);
|
|
211
|
+
if (sizeFixed == null) {
|
|
212
|
+
console.log(
|
|
213
|
+
`File size has not been fixed, DNF may not have been found and approximate height is: ${job.imageHeight}`
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return createScanPage(job, currentPageNumber, filePath, sizeFixed);
|
|
218
|
+
} else {
|
|
219
|
+
console.log(`Unknown pageState: ${job.pageState}`);
|
|
220
|
+
await delay(200);
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async function waitScanRequest(compEventURI: string): Promise<boolean> {
|
|
226
|
+
const waitMax = 50;
|
|
227
|
+
for (let i = 0; i < waitMax; i++) {
|
|
228
|
+
let walkupScanToCompEvent = await HPApi.getWalkupScanToCompEvent(
|
|
229
|
+
compEventURI
|
|
230
|
+
);
|
|
231
|
+
let message = walkupScanToCompEvent.eventType;
|
|
232
|
+
if (message === "HostSelected") {
|
|
233
|
+
// this ok to wait
|
|
234
|
+
} else if (message === "ScanRequested") {
|
|
235
|
+
break;
|
|
236
|
+
} else if (message === "ScanNewPageRequested") {
|
|
237
|
+
break;
|
|
238
|
+
} else if (message === "ScanPagesComplete") {
|
|
239
|
+
console.log("no more page to scan, scan is finished");
|
|
240
|
+
return false;
|
|
241
|
+
} else {
|
|
242
|
+
console.log(`Unknown eventType: ${message}`);
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
console.log(`Waiting user input: ${i + 1}/${waitMax}`);
|
|
247
|
+
await new Promise((resolve) => setTimeout(resolve, 1000)); //wait 1s
|
|
248
|
+
}
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function executeScanJob(
|
|
253
|
+
scanJobSettings: ScanJobSettings,
|
|
254
|
+
inputSource: "Adf" | "Platen",
|
|
255
|
+
folder: string,
|
|
256
|
+
scanCount: number,
|
|
257
|
+
scanJobContent: ScanContent
|
|
258
|
+
) {
|
|
259
|
+
const jobUrl = await HPApi.postJob(scanJobSettings);
|
|
260
|
+
|
|
261
|
+
console.log("New job created:", jobUrl);
|
|
262
|
+
|
|
263
|
+
let job = await HPApi.getJob(jobUrl);
|
|
264
|
+
while (job.jobState !== "Completed") {
|
|
265
|
+
job = await waitPrinterUntilItIsReadyToUploadOrCompleted(jobUrl);
|
|
266
|
+
|
|
267
|
+
if (job.jobState == "Completed") {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (job.jobState === "Processing") {
|
|
272
|
+
const page = await handleProcessingState(
|
|
273
|
+
job,
|
|
274
|
+
inputSource,
|
|
275
|
+
folder,
|
|
276
|
+
scanCount,
|
|
277
|
+
scanJobContent.elements.length + 1
|
|
278
|
+
);
|
|
279
|
+
if (page != null) {
|
|
280
|
+
scanJobContent.elements.push(page);
|
|
281
|
+
}
|
|
282
|
+
} else if (job.jobState === "Canceled") {
|
|
283
|
+
console.log("Job cancelled by device");
|
|
284
|
+
break;
|
|
285
|
+
} else {
|
|
286
|
+
console.log(`Unhandled jobState: ${job.jobState}`);
|
|
287
|
+
await delay(200);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
console.log(
|
|
291
|
+
`Job state: ${job.jobState}, totalPages: ${job.totalPageNumber}:`
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async function waitScanNewPageRequest(compEventURI: string): Promise<boolean> {
|
|
296
|
+
let startNewScanJob = false;
|
|
297
|
+
let wait = true;
|
|
298
|
+
while (wait) {
|
|
299
|
+
await new Promise((resolve) => setTimeout(resolve, 1000)); //wait 1s
|
|
300
|
+
|
|
301
|
+
let walkupScanToCompEvent = await HPApi.getWalkupScanToCompEvent(
|
|
302
|
+
compEventURI
|
|
303
|
+
);
|
|
304
|
+
let message = walkupScanToCompEvent.eventType;
|
|
305
|
+
|
|
306
|
+
if (message === "ScanNewPageRequested") {
|
|
307
|
+
startNewScanJob = true;
|
|
308
|
+
wait = false;
|
|
309
|
+
} else if (message === "ScanPagesComplete") {
|
|
310
|
+
wait = false;
|
|
311
|
+
} else if (message === "ScanRequested") {
|
|
312
|
+
// continue waiting
|
|
313
|
+
} else {
|
|
314
|
+
wait = false;
|
|
315
|
+
console.log(`Unknown eventType: ${message}`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return startNewScanJob;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async function executeScanJobs(
|
|
322
|
+
scanJobSettings: ScanJobSettings,
|
|
323
|
+
inputSource: "Adf" | "Platen",
|
|
324
|
+
folder: string,
|
|
325
|
+
scanCount: number,
|
|
326
|
+
scanJobContent: ScanContent,
|
|
327
|
+
firstEvent: Event
|
|
328
|
+
) {
|
|
329
|
+
await executeScanJob(
|
|
330
|
+
scanJobSettings,
|
|
331
|
+
inputSource,
|
|
332
|
+
folder,
|
|
333
|
+
scanCount,
|
|
334
|
+
scanJobContent
|
|
335
|
+
);
|
|
336
|
+
let lastEvent = firstEvent;
|
|
337
|
+
if (
|
|
338
|
+
lastEvent.compEventURI &&
|
|
339
|
+
inputSource !== "Adf" &&
|
|
340
|
+
lastEvent.destinationURI
|
|
341
|
+
) {
|
|
342
|
+
lastEvent = await waitForScanEvent(
|
|
343
|
+
lastEvent.destinationURI,
|
|
344
|
+
lastEvent.agingStamp
|
|
345
|
+
);
|
|
346
|
+
if (!lastEvent.compEventURI) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
let startNewScanJob = await waitScanNewPageRequest(lastEvent.compEventURI);
|
|
350
|
+
while (startNewScanJob) {
|
|
351
|
+
await executeScanJob(
|
|
352
|
+
scanJobSettings,
|
|
353
|
+
inputSource,
|
|
354
|
+
folder,
|
|
355
|
+
scanCount,
|
|
356
|
+
scanJobContent
|
|
357
|
+
);
|
|
358
|
+
if (!lastEvent.destinationURI) {
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
lastEvent = await waitForScanEvent(
|
|
362
|
+
lastEvent.destinationURI,
|
|
363
|
+
lastEvent.agingStamp
|
|
364
|
+
);
|
|
365
|
+
if (!lastEvent.compEventURI) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
startNewScanJob = await waitScanNewPageRequest(lastEvent.compEventURI);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
async function mergeToPdf(folder: string, scanCount: number, scanJobContent: ScanContent) {
|
|
374
|
+
const pdfFilePath = PathHelper.getFileForScan(
|
|
375
|
+
folder,
|
|
376
|
+
scanCount,
|
|
377
|
+
program.opts().pattern,
|
|
378
|
+
"pdf"
|
|
379
|
+
);
|
|
380
|
+
await createPdfFrom(scanJobContent, pdfFilePath);
|
|
381
|
+
scanJobContent.elements.forEach((e) => fs.unlink(e.path));
|
|
382
|
+
return pdfFilePath;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function displayPdfScan(pdfFilePath: string, scanJobContent: ScanContent) {
|
|
386
|
+
console.log(
|
|
387
|
+
`The following page(s) have been rendered inside '${pdfFilePath}': `
|
|
388
|
+
);
|
|
389
|
+
scanJobContent.elements.forEach((e) =>
|
|
390
|
+
console.log(
|
|
391
|
+
`\t- page ${e.pageNumber.toString().padStart(3, " ")} - ${e.width}x${
|
|
392
|
+
e.height
|
|
393
|
+
}`
|
|
394
|
+
)
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function displayJpegScan(scanJobContent: ScanContent) {
|
|
399
|
+
scanJobContent.elements.forEach((e) =>
|
|
400
|
+
console.log(
|
|
401
|
+
`\t- page ${e.pageNumber.toString().padStart(3, " ")} - ${e.width}x${
|
|
402
|
+
e.height
|
|
403
|
+
} - ${e.path}`
|
|
404
|
+
)
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
async function saveScan(
|
|
409
|
+
event: Event,
|
|
410
|
+
folder: string,
|
|
411
|
+
scanCount: number
|
|
412
|
+
): Promise<void> {
|
|
413
|
+
if (event.compEventURI) {
|
|
414
|
+
const proceedToScan = await waitScanRequest(event.compEventURI);
|
|
415
|
+
if (!proceedToScan) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const destination = await TryGetDestination(event);
|
|
421
|
+
if (!destination) {
|
|
422
|
+
console.log("No shortcut selected!");
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
console.log("Selected shortcut: " + destination.shortcut);
|
|
426
|
+
|
|
427
|
+
const contentType = destination.getContentType();
|
|
428
|
+
const toPdf =
|
|
429
|
+
destination.shortcut === "SavePDF" || destination.shortcut === "EmailPDF";
|
|
430
|
+
|
|
431
|
+
const scanStatus = await HPApi.getScanStatus();
|
|
432
|
+
console.log("Afd is : " + scanStatus.adfState);
|
|
433
|
+
|
|
434
|
+
let inputSource = scanStatus.getInputSource();
|
|
435
|
+
|
|
436
|
+
let scanJobSettings = new ScanJobSettings(inputSource, contentType);
|
|
437
|
+
|
|
438
|
+
let scanJobContent: ScanContent = { elements: [] };
|
|
439
|
+
|
|
440
|
+
await executeScanJobs(
|
|
441
|
+
scanJobSettings,
|
|
442
|
+
inputSource,
|
|
443
|
+
folder,
|
|
444
|
+
scanCount,
|
|
445
|
+
scanJobContent,
|
|
446
|
+
event
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
console.log(
|
|
450
|
+
`Scan of page(s) completed totalPages: ${scanJobContent.elements.length}:`
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
if (toPdf) {
|
|
454
|
+
const pdfFilePath = await mergeToPdf(folder, scanCount, scanJobContent);
|
|
455
|
+
displayPdfScan(pdfFilePath, scanJobContent);
|
|
456
|
+
} else {
|
|
457
|
+
displayJpegScan(scanJobContent);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
let iteration = 0;
|
|
462
|
+
async function init() {
|
|
463
|
+
const folder = await PathHelper.getOutputFolder(program.opts().directory);
|
|
464
|
+
console.log(`Target folder: ${folder}`);
|
|
465
|
+
|
|
466
|
+
let scanCount = 0;
|
|
467
|
+
|
|
468
|
+
let keepActive = true;
|
|
469
|
+
let errorCount = 0;
|
|
470
|
+
while (keepActive) {
|
|
471
|
+
console.log(`Running iteration: ${iteration} - errorCount: ${errorCount}`);
|
|
472
|
+
try {
|
|
473
|
+
let resourceURI = await register();
|
|
474
|
+
|
|
475
|
+
console.log("Waiting scan event for:", resourceURI);
|
|
476
|
+
const event = await waitForScanEvent(resourceURI);
|
|
477
|
+
|
|
478
|
+
scanCount++;
|
|
479
|
+
console.log(`Scan event captured, saving scan #${scanCount}`);
|
|
480
|
+
await saveScan(event, folder, scanCount);
|
|
481
|
+
} catch (e) {
|
|
482
|
+
errorCount++;
|
|
483
|
+
console.error(e);
|
|
484
|
+
console.log(e);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (errorCount === 50) {
|
|
488
|
+
keepActive = false;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
await delay(1000);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function findOfficejetIp(): Promise<string> {
|
|
496
|
+
return new Promise((resolve) => {
|
|
497
|
+
const bonjour = Bonjour();
|
|
498
|
+
console.log("Searching printer...");
|
|
499
|
+
let browser = bonjour.find(
|
|
500
|
+
{
|
|
501
|
+
type: "http",
|
|
502
|
+
},
|
|
503
|
+
(service) => {
|
|
504
|
+
console.log(".");
|
|
505
|
+
if (
|
|
506
|
+
service.name.startsWith(program.opts().name) &&
|
|
507
|
+
service.port === 80 &&
|
|
508
|
+
service.type === "http" &&
|
|
509
|
+
service.addresses != null
|
|
510
|
+
) {
|
|
511
|
+
browser.stop();
|
|
512
|
+
bonjour.destroy();
|
|
513
|
+
console.log(`Found: ${service.name}`);
|
|
514
|
+
resolve(service.addresses[0]);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
);
|
|
518
|
+
browser.start();
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
async function main() {
|
|
523
|
+
program.option(
|
|
524
|
+
"-ip, --address <ip>",
|
|
525
|
+
"IP address of the printer (this overrides -p)"
|
|
526
|
+
);
|
|
527
|
+
program.option(
|
|
528
|
+
"-n, --name <name>",
|
|
529
|
+
"Name of the printer for service discovery",
|
|
530
|
+
"HP Smart Tank Plus 570 series"
|
|
531
|
+
); //or i.e. 'Deskjet 3520 series'
|
|
532
|
+
program.option(
|
|
533
|
+
"-d, --directory <dir>",
|
|
534
|
+
"Directory where scans are saved (defaults to /tmp/scan-to-pc<random>)"
|
|
535
|
+
);
|
|
536
|
+
program.option(
|
|
537
|
+
"-p, --pattern <pattern>",
|
|
538
|
+
'Pattern for filename (i.e. "scan"_dd.mm.yyyy_hh:MM:ss, without this its scanPage<number>)'
|
|
539
|
+
);
|
|
540
|
+
program.option("-D, --debug", "Enable debug");
|
|
541
|
+
program.parse(process.argv);
|
|
542
|
+
|
|
543
|
+
let ip = program.opts().address || "192.168.1.53";
|
|
544
|
+
if (!ip) {
|
|
545
|
+
ip = await findOfficejetIp();
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
const debug = program.opts().debug != null;
|
|
549
|
+
|
|
550
|
+
HPApi.setDebug(debug);
|
|
551
|
+
HPApi.setPrinterIP(ip);
|
|
552
|
+
await init();
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
main();
|