@capturebridge/sdk 0.7.0 → 0.8.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/Camera.js +63 -68
- package/CanonCamera.js +25 -25
- package/CaptureBridge.js +160 -162
- package/CapturePlugin.js +68 -79
- package/Common.js +182 -98
- package/Device.js +547 -451
- package/ICAO.js +70 -70
- package/IFace.js +278 -274
- package/Logs.js +129 -129
- package/MockCamera.js +17 -10
- package/Plugin.js +299 -298
- package/Scanner.js +55 -64
- package/SignatureTablet.js +108 -109
- package/SignatureTabletWidgets.js +164 -153
- package/StreamingCapturePlugin.js +129 -121
- package/TopazSigGem.js +25 -25
- package/Version.js +8 -0
- package/WindowsScanner.js +25 -0
- package/examples/canon.html +66 -0
- package/examples/canon_getframe.html +68 -0
- package/examples/canon_lan.html +68 -0
- package/examples/canon_minimal.html +37 -0
- package/examples/mockcamera.html +61 -0
- package/examples/mockcamera_getframe.html +63 -0
- package/examples/mockcamera_minimal.html +31 -0
- package/examples/windows_scanner_minimal.html +32 -0
- package/package.json +2 -2
package/Device.js
CHANGED
|
@@ -1,451 +1,547 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
* img
|
|
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
|
-
* // the document's body
|
|
128
|
-
* const
|
|
129
|
-
* const
|
|
130
|
-
*
|
|
131
|
-
* document.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
* @
|
|
217
|
-
* @
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
* @
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
* @
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
*
|
|
279
|
-
* @
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
* @
|
|
295
|
-
*
|
|
296
|
-
* @
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
*
|
|
302
|
-
*
|
|
303
|
-
*
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
* (Async/
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
* @
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
* @
|
|
337
|
-
* @
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
*/
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
*
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
*
|
|
410
|
-
*
|
|
411
|
-
*
|
|
412
|
-
*
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
1
|
+
import {
|
|
2
|
+
BASE_URL,
|
|
3
|
+
POST,
|
|
4
|
+
DELETE,
|
|
5
|
+
DEFAULT_STREAM_OPT,
|
|
6
|
+
DEFAULT_CAPTURE_OPT,
|
|
7
|
+
checkResponse,
|
|
8
|
+
timeout,
|
|
9
|
+
asyncToCallback
|
|
10
|
+
} from './Common.js'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Device
|
|
14
|
+
* @classdesc Class for interacting with a Device returned from a plugin.
|
|
15
|
+
*/
|
|
16
|
+
class Device {
|
|
17
|
+
/*
|
|
18
|
+
* @property {Object} device - Device object as received from the API
|
|
19
|
+
* @property {string} device.id - URL safe device identified, this can often be hashed or encoded and should be considered opaque.
|
|
20
|
+
* @property {string?} device.raw_id - When possible, if the id is of some encoded or hashed type, this is the underlying value and can be shown to users.
|
|
21
|
+
* @property {string} device.name - Human friendly name of the device.
|
|
22
|
+
*/
|
|
23
|
+
baseUrl
|
|
24
|
+
plugin
|
|
25
|
+
id
|
|
26
|
+
raw_id
|
|
27
|
+
name
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Instantiate a device.
|
|
31
|
+
* @constructor
|
|
32
|
+
* @param {object} device - Device object as received from the API
|
|
33
|
+
* @param {string} device.id - URL safe device identified, this can often be hashed or encoded and should be considered opaque.
|
|
34
|
+
* @param {string?} device.raw_id - When possible, if the id is of some encoded or hashed type, this is the underlying value and can be shown to users.
|
|
35
|
+
* @param {string} device.name - Human friendly name of the device.
|
|
36
|
+
* @param {object} plugin - Plugin serviced by this device.
|
|
37
|
+
* @param {string} [baseURL] - Protocol, domain, and port for the service.
|
|
38
|
+
*/
|
|
39
|
+
constructor (properties, plugin, baseUrl = BASE_URL) {
|
|
40
|
+
this.baseUrl = baseUrl
|
|
41
|
+
this.plugin = plugin
|
|
42
|
+
Object.assign(this, {}, properties)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
can (method) {
|
|
46
|
+
if (this.plugin.methods.indexOf(method) === -1) {
|
|
47
|
+
throw new Error(`${method} not supported for this device`)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get the stream endpoint URL.
|
|
53
|
+
*
|
|
54
|
+
* @description the URL returned from this endpoint can be attached to an
|
|
55
|
+
* img tag's src attribute. The device's live stream will be started and
|
|
56
|
+
* begin streaming to the img tag as a
|
|
57
|
+
* {@link https://en.wikipedia.org/wiki/Motion_JPEG|Motion JPEG} stream.
|
|
58
|
+
* If the src is changed, the img removed from the DOM, or client disconnected
|
|
59
|
+
* for any reason, the live feed will automatically be stopped.
|
|
60
|
+
*
|
|
61
|
+
* @method
|
|
62
|
+
* @param {StreamOptions} [streamOpt] - Additional options for streaming.
|
|
63
|
+
* @returns {string} stream endpoint URL
|
|
64
|
+
* @example
|
|
65
|
+
* const img = document.createElement('img')
|
|
66
|
+
* img.src = device.streamUrl()
|
|
67
|
+
* document.body.appendChild(img)
|
|
68
|
+
*/
|
|
69
|
+
streamUrl (streamOpt = {}) {
|
|
70
|
+
this.can('start_feed')
|
|
71
|
+
this.can('stop_feed')
|
|
72
|
+
const mergedOpts = Object.assign({}, DEFAULT_STREAM_OPT, streamOpt)
|
|
73
|
+
const params = new URLSearchParams(mergedOpts).toString()
|
|
74
|
+
return `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/stream?${params}`
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Take full capture from the specified device and return an
|
|
79
|
+
* {@link https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL_static|ObjectURL}
|
|
80
|
+
* that can be set directly on an img tag's src attribute. Note that URLs
|
|
81
|
+
* created by this method should be
|
|
82
|
+
* {@link https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL_static|revoked}
|
|
83
|
+
* when they are no longer needed.
|
|
84
|
+
* (Async/Await version)
|
|
85
|
+
*
|
|
86
|
+
* @method
|
|
87
|
+
* @async
|
|
88
|
+
* @param {CaptureOptions} [captureOpt] - Additional options for capturing a
|
|
89
|
+
* frame.
|
|
90
|
+
* @returns {string}
|
|
91
|
+
* @example
|
|
92
|
+
* // Load the blob into FileReader and append to the document's body
|
|
93
|
+
* const blob = await device.captureAsBlob()
|
|
94
|
+
* const reader = new FileReader()
|
|
95
|
+
* reader.onload = event => {
|
|
96
|
+
* const img = document.createElement('img')
|
|
97
|
+
* img.src = event.target.result
|
|
98
|
+
* document.body.appendChild(img)
|
|
99
|
+
* }
|
|
100
|
+
* reader.readAsDataURL(blob)
|
|
101
|
+
*/
|
|
102
|
+
async captureAsObjectURL (captureOpt = {}) {
|
|
103
|
+
this.can('capture')
|
|
104
|
+
const captureParams = Object.assign({}, DEFAULT_CAPTURE_OPT, captureOpt)
|
|
105
|
+
|
|
106
|
+
// Method ignores kind, always returns an object URL
|
|
107
|
+
delete captureParams.kind
|
|
108
|
+
|
|
109
|
+
const params = new URLSearchParams(captureParams).toString()
|
|
110
|
+
const url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/capture?${params}`
|
|
111
|
+
const response = await fetch(url, POST)
|
|
112
|
+
return await response.blob()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Take full capture from the specified device and return a
|
|
117
|
+
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob} that can
|
|
118
|
+
* be used with a {@link https://developer.mozilla.org/en-US/docs/Web/API/FileReader|FileReader}
|
|
119
|
+
* (Async/Await version)
|
|
120
|
+
*
|
|
121
|
+
* @method
|
|
122
|
+
* @async
|
|
123
|
+
* @param {CaptureOptions} [captureOpt] - Additional options for capturing a
|
|
124
|
+
* frame.
|
|
125
|
+
* @returns {object} {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob}
|
|
126
|
+
* @example
|
|
127
|
+
* // Load the blob into FileReader and append to the document's body
|
|
128
|
+
* const blob = await device.captureAsBlob()
|
|
129
|
+
* const reader = new FileReader()
|
|
130
|
+
* reader.onload = event => {
|
|
131
|
+
* const img = document.createElement('img')
|
|
132
|
+
* img.src = event.target.result
|
|
133
|
+
* document.body.appendChild(img)
|
|
134
|
+
* }
|
|
135
|
+
* reader.readAsDataURL(blob)
|
|
136
|
+
*/
|
|
137
|
+
async captureAsBlob (captureOpt = {}) {
|
|
138
|
+
this.can('capture')
|
|
139
|
+
const captureParams = Object.assign({}, DEFAULT_CAPTURE_OPT, captureOpt)
|
|
140
|
+
|
|
141
|
+
// Method ignores kind, always returns binary data (blob)
|
|
142
|
+
delete captureParams.kind
|
|
143
|
+
|
|
144
|
+
const params = new URLSearchParams(captureParams).toString()
|
|
145
|
+
const url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/capture?${params}`
|
|
146
|
+
const response = await fetch(url, POST)
|
|
147
|
+
return await response.blob()
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Take full capture from the specified device and return a
|
|
152
|
+
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob} that can
|
|
153
|
+
* be used with a {@link https://developer.mozilla.org/en-US/docs/Web/API/FileReader|FileReader}
|
|
154
|
+
* (Callback version)
|
|
155
|
+
*
|
|
156
|
+
* @method
|
|
157
|
+
* @param {function} callback
|
|
158
|
+
* @param {CaptureOptions} [captureOpt] - Additional options for capturing a
|
|
159
|
+
* frame.
|
|
160
|
+
* @example
|
|
161
|
+
* // Load the blob into FileReader and append to the document's body
|
|
162
|
+
* device.captureAsBlobHandler((error, blob) => {
|
|
163
|
+
* const reader = new FileReader()
|
|
164
|
+
* reader.onload = event => {
|
|
165
|
+
* const img = document.createElement('img')
|
|
166
|
+
* img.src = event.target.result
|
|
167
|
+
* document.body.appendChild(img)
|
|
168
|
+
* }
|
|
169
|
+
* reader.readAsDataURL(blob)
|
|
170
|
+
* })
|
|
171
|
+
*/
|
|
172
|
+
captureAsBlobHandler (callback, captureOpt = {}) {
|
|
173
|
+
asyncToCallback(this, this.captureAsBlob, captureOpt, callback)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Take full capture from the specified device and return a
|
|
178
|
+
* base64 encoded string of the image that can be used with a
|
|
179
|
+
* {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs|Data URL}
|
|
180
|
+
* (Async/Await version)
|
|
181
|
+
*
|
|
182
|
+
* @method
|
|
183
|
+
* @async
|
|
184
|
+
* @param {CaptureOptions} [captureOpt] - Additional options for capturing a
|
|
185
|
+
* frame.
|
|
186
|
+
* @returns {string} Base64 Encoded image
|
|
187
|
+
* @example
|
|
188
|
+
* // Add the base64 string as a Data URL to an img tag and append to
|
|
189
|
+
* // the document's body
|
|
190
|
+
* const base64 = await device.captureAsBase64()
|
|
191
|
+
* const img = document.createElement('img')
|
|
192
|
+
* img.src = 'data:image/jpeg;base64,' + base64
|
|
193
|
+
* document.body.appendChild(img)
|
|
194
|
+
*/
|
|
195
|
+
async captureAsBase64 (captureOpt = {}) {
|
|
196
|
+
this.can('capture')
|
|
197
|
+
const captureParams = Object.assign({}, DEFAULT_CAPTURE_OPT, captureOpt)
|
|
198
|
+
|
|
199
|
+
// Method ignores kind, always returns base64 data
|
|
200
|
+
delete captureParams.kind
|
|
201
|
+
captureParams.base64 = true
|
|
202
|
+
|
|
203
|
+
const params = new URLSearchParams(captureParams).toString()
|
|
204
|
+
const url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/capture?${params}`
|
|
205
|
+
const response = await fetch(url, POST)
|
|
206
|
+
await checkResponse(response)
|
|
207
|
+
const { image } = await response.json()
|
|
208
|
+
return image
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Take full capture from the specified device and return a
|
|
213
|
+
* base64 encoded string of the image that can be used with a
|
|
214
|
+
* {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs|Data URL}
|
|
215
|
+
* (Callback version)
|
|
216
|
+
* @method
|
|
217
|
+
* @param {function} callback
|
|
218
|
+
* @param {CaptureOptions} [captureOpt] - Additional options for capturing a
|
|
219
|
+
* frame.
|
|
220
|
+
*/
|
|
221
|
+
captureAsBase64Handler (callback, captureOpt = {}) {
|
|
222
|
+
asyncToCallback(this, this.captureAsBase64, callback)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Get a base64 encoded frame from a device's live feed.
|
|
227
|
+
* @method
|
|
228
|
+
*
|
|
229
|
+
* @description This method will startup the live
|
|
230
|
+
* feed if necessary and wait for it to initialize before returning a frame.
|
|
231
|
+
* Subsequent calls will return the next available frame.
|
|
232
|
+
* You must manually stop the live feed if you are using this method.
|
|
233
|
+
*
|
|
234
|
+
* The frame returned will be a base64 encoded string of the image that can
|
|
235
|
+
* be used with a
|
|
236
|
+
* {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs|Data URL}
|
|
237
|
+
*
|
|
238
|
+
* If implementing a real-time preview, it is highly recommended to use the
|
|
239
|
+
* stream endpoint which will stream a Motion JPEG.
|
|
240
|
+
*
|
|
241
|
+
* @see {@link streamUrl}
|
|
242
|
+
* @see {@link stopFeed}
|
|
243
|
+
*
|
|
244
|
+
* @async
|
|
245
|
+
* @param {number} [millis] - Milliseconds to wait if feed is not ready
|
|
246
|
+
* @param {CaptureOptions} [captureOpt] - Additional options for capturing a
|
|
247
|
+
* frame.
|
|
248
|
+
* @returns {string} Base64 Encoded image
|
|
249
|
+
* @example
|
|
250
|
+
* // Add the base64 string as a Data URL to an img tag and append to
|
|
251
|
+
* // the document's body
|
|
252
|
+
* const base64 = await device.frameAsBase64()
|
|
253
|
+
* const img = document.createElement('img')
|
|
254
|
+
* img.src = 'data:image/jpeg;base64,' + base64
|
|
255
|
+
* document.body.appendChild(img)
|
|
256
|
+
*/
|
|
257
|
+
async frameAsBase64 (captureOpt = {}, millis = 500) {
|
|
258
|
+
this.can('start_feed')
|
|
259
|
+
const captureParams = Object.assign({}, DEFAULT_CAPTURE_OPT, captureOpt)
|
|
260
|
+
|
|
261
|
+
// Method ignores kind, always returns base64 data
|
|
262
|
+
delete captureParams.kind
|
|
263
|
+
captureParams.base64 = true
|
|
264
|
+
|
|
265
|
+
const params = new URLSearchParams(captureParams).toString()
|
|
266
|
+
const url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/livefeed?${params}`
|
|
267
|
+
const response = await fetch(url)
|
|
268
|
+
const result = await response.json()
|
|
269
|
+
if (result.error && (result.code === 425 || result.code === 400)) {
|
|
270
|
+
await timeout(millis)
|
|
271
|
+
return await this.frameAsBase64(captureOpt, millis)
|
|
272
|
+
} else {
|
|
273
|
+
return result.image
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get a base64 encoded frame from a device's live feed. (Callback version)
|
|
279
|
+
* @method
|
|
280
|
+
*
|
|
281
|
+
* @description This method will startup the live
|
|
282
|
+
* feed if necessary and wait for it to initialize before returning a frame.
|
|
283
|
+
* Subsequent calls will return the next available frame.
|
|
284
|
+
* You must manually stop the live feed if you are using this method.
|
|
285
|
+
*
|
|
286
|
+
* The frame returned will be a base64 encoded string of the image that can
|
|
287
|
+
* be used with a
|
|
288
|
+
* {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs|Data URL}
|
|
289
|
+
*
|
|
290
|
+
* If implementing a real-time preview, it is highly recommended to use the
|
|
291
|
+
* stream endpoint which will stream a Motion JPEG.
|
|
292
|
+
*
|
|
293
|
+
* @see {@link streamUrl}
|
|
294
|
+
* @see {@link setStopFeed}
|
|
295
|
+
*
|
|
296
|
+
* @param {function} callback
|
|
297
|
+
* @param {CaptureOptions} [captureOpt] - Additional options for capturing a
|
|
298
|
+
* frame.
|
|
299
|
+
* @param {number} [millis] - Milliseconds to wait if feed is not ready
|
|
300
|
+
* @example
|
|
301
|
+
* // Add the base64 string as a Data URL to an img tag and append to
|
|
302
|
+
* // the document's body
|
|
303
|
+
* device.frameAsBase64Handler(base64 => {
|
|
304
|
+
* const img = document.createElement('img')
|
|
305
|
+
* img.src = 'data:image/jpeg;base64,' + base64
|
|
306
|
+
* document.body.appendChild(img)
|
|
307
|
+
* })
|
|
308
|
+
*/
|
|
309
|
+
frameAsBase64Handler (callback, captureOpt = {}, millis = 500) {
|
|
310
|
+
asyncToCallback(this, this.frameAsBase64, callback, captureOpt, millis)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Get a binary frame from a device's live feed. (Async/await version)
|
|
315
|
+
* @method
|
|
316
|
+
*
|
|
317
|
+
* @description This method will startup the live
|
|
318
|
+
* feed if necessary and wait for it to initialize before returning a frame.
|
|
319
|
+
* Subsequent calls will return the next available frame.
|
|
320
|
+
* You must manually stop the live feed if you are using this method.
|
|
321
|
+
*
|
|
322
|
+
* The frame returned will be a
|
|
323
|
+
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob} that can
|
|
324
|
+
* be used with a {@link https://developer.mozilla.org/en-US/docs/Web/API/FileReader|FileReader}
|
|
325
|
+
*
|
|
326
|
+
* If implementing a real-time preview, it is highly recommended to use the
|
|
327
|
+
* stream endpoint which will stream a Motion JPEG.
|
|
328
|
+
*
|
|
329
|
+
* @see {@link streamUrl}
|
|
330
|
+
* @see {@link stopFeed}
|
|
331
|
+
*
|
|
332
|
+
* @async
|
|
333
|
+
* @param {CaptureOptions} [captureOpt] - Additional options for capturing a
|
|
334
|
+
* frame.
|
|
335
|
+
* @param {number} [millis] - Milliseconds to wait if feed is not ready
|
|
336
|
+
* @returns {object} {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob}
|
|
337
|
+
* @example
|
|
338
|
+
* // Load the blob into FileReader and append to the document's body
|
|
339
|
+
* const blob = await device.frameAsBlob()
|
|
340
|
+
* const reader = new FileReader()
|
|
341
|
+
* reader.onload = event => {
|
|
342
|
+
* const img = document.createElement('img')
|
|
343
|
+
* img.src = event.target.result
|
|
344
|
+
* document.body.appendChild(img)
|
|
345
|
+
* }
|
|
346
|
+
* reader.readAsDataURL(blob)
|
|
347
|
+
*/
|
|
348
|
+
async frameAsBlob (captureOpt = {}, millis = 500) {
|
|
349
|
+
this.can('start_feed')
|
|
350
|
+
const captureParams = Object.assign({}, DEFAULT_CAPTURE_OPT, captureOpt)
|
|
351
|
+
|
|
352
|
+
// Method ignores kind, always returns binary data (blob)
|
|
353
|
+
delete captureParams.kind
|
|
354
|
+
|
|
355
|
+
const params = new URLSearchParams(captureParams).toString()
|
|
356
|
+
const url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/livefeed?${params}`
|
|
357
|
+
const result = await this.frameAsBase64(captureOpt, millis)
|
|
358
|
+
if (typeof result === 'string') {
|
|
359
|
+
timeout(millis)
|
|
360
|
+
const response = await fetch(url)
|
|
361
|
+
return await response.blob()
|
|
362
|
+
}
|
|
363
|
+
throw new Error(result || 'Failed to get frame')
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Get a binary frame from a device's live feed. (Callback version)
|
|
368
|
+
* @method
|
|
369
|
+
*
|
|
370
|
+
* @description This method will startup the live
|
|
371
|
+
* feed if necessary and wait for it to initialize before returning a frame.
|
|
372
|
+
* Subsequent calls will return the next available frame.
|
|
373
|
+
* You must manually stop the live feed if you are using this method.
|
|
374
|
+
*
|
|
375
|
+
* The frame returned will be a
|
|
376
|
+
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob} that can
|
|
377
|
+
* be used with a {@link https://developer.mozilla.org/en-US/docs/Web/API/FileReader|FileReader}
|
|
378
|
+
*
|
|
379
|
+
* If implementing a real-time preview, it is highly recommended to use the
|
|
380
|
+
* stream endpoint which will stream a Motion JPEG.
|
|
381
|
+
*
|
|
382
|
+
* @see {@link streamUrl}
|
|
383
|
+
* @see {@link setStopFeed}
|
|
384
|
+
*
|
|
385
|
+
* @param {function} callback
|
|
386
|
+
*
|
|
387
|
+
* @param {CaptureOptions} [captureOpt] - Additional options for capturing a
|
|
388
|
+
* frame.
|
|
389
|
+
*
|
|
390
|
+
* @param {number} [millis] - Milliseconds to wait if feed is not ready
|
|
391
|
+
*
|
|
392
|
+
* @example
|
|
393
|
+
* // Load the blob into FileReader and append to the document's body
|
|
394
|
+
* device.frameAsBlobHandler((error, blob) => {
|
|
395
|
+
* const reader = new FileReader()
|
|
396
|
+
* reader.onload = event => {
|
|
397
|
+
* const img = document.createElement('img')
|
|
398
|
+
* img.src = event.target.result
|
|
399
|
+
* document.body.appendChild(img)
|
|
400
|
+
* }
|
|
401
|
+
* reader.readAsDataURL(blob)
|
|
402
|
+
* })
|
|
403
|
+
*/
|
|
404
|
+
frameAsBlobHandler (callback, captureOpt = {}, millis = 500) {
|
|
405
|
+
asyncToCallback(this, this.frameAsBlob, callback, captureOpt, millis)
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Stop the live feed if it is running.
|
|
410
|
+
* (Async/Await version)
|
|
411
|
+
*
|
|
412
|
+
* @method
|
|
413
|
+
* @async
|
|
414
|
+
* @returns {object} Status of the stop operation
|
|
415
|
+
* @example
|
|
416
|
+
* // Plugin is now running it's live feed in a background thread
|
|
417
|
+
* const blob = await device.frameAsBlob()
|
|
418
|
+
* // Live feed is now stopping
|
|
419
|
+
* console.log(await device.stopFeed())
|
|
420
|
+
*/
|
|
421
|
+
async stopFeed () {
|
|
422
|
+
this.can('stop_feed')
|
|
423
|
+
const url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/livefeed`
|
|
424
|
+
const response = await fetch(url, DELETE)
|
|
425
|
+
return await response.json()
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Stop the live feed if it is running.
|
|
430
|
+
* (Callback version)
|
|
431
|
+
*
|
|
432
|
+
* @method
|
|
433
|
+
* @param {number} [millis] - Milliseconds to wait if feed is not ready
|
|
434
|
+
* @param {function} callback with the status of the stop operation
|
|
435
|
+
* @example
|
|
436
|
+
* device.stopFeedHandler((error, blob) => {
|
|
437
|
+
* // Plugin is now running it's live feed in a background thread
|
|
438
|
+
* device.setStopFeed(result => {
|
|
439
|
+
* // Live feed is now stopping
|
|
440
|
+
* console.log(result)
|
|
441
|
+
* })
|
|
442
|
+
* })
|
|
443
|
+
*/
|
|
444
|
+
stopFeedHandler (callback) {
|
|
445
|
+
asyncToCallback(this, this.frameAsBlob, callback)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Clear a device's display.
|
|
450
|
+
* (Async/Await version)
|
|
451
|
+
*
|
|
452
|
+
* @method
|
|
453
|
+
* @async
|
|
454
|
+
* @param {boolean} [backlight] If provided and set to true, will enable
|
|
455
|
+
* backlight. If false, it will be disabled. If unspecified no action will be
|
|
456
|
+
* taken on the backlight.
|
|
457
|
+
* @returns {object} Status of the clear operation
|
|
458
|
+
* @example
|
|
459
|
+
* console.log(await await device.clear())
|
|
460
|
+
*/
|
|
461
|
+
async clear (backlight) {
|
|
462
|
+
this.can('draw')
|
|
463
|
+
let url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/display`
|
|
464
|
+
if (typeof backlight === 'boolean') {
|
|
465
|
+
url += `?backlight=${backlight}`
|
|
466
|
+
}
|
|
467
|
+
const response = await fetch(url, DELETE)
|
|
468
|
+
return await response.json()
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Clear a device's display.
|
|
473
|
+
* (Callback version)
|
|
474
|
+
*
|
|
475
|
+
* @method
|
|
476
|
+
* @param {function} callback with the status of the clear operation
|
|
477
|
+
* @param {boolean} [backlight] If provided and set to true, will enable
|
|
478
|
+
* backlight. If false, it will be disabled. If unspecified no action will be
|
|
479
|
+
* taken on the backlight.
|
|
480
|
+
* @example
|
|
481
|
+
* device.clearHandler((error, result) => {
|
|
482
|
+
* console.log(result)
|
|
483
|
+
* })
|
|
484
|
+
*/
|
|
485
|
+
clearHandler (callback, backlight) {
|
|
486
|
+
asyncToCallback(this, this.clear, callback, backlight)
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Display an Array of objects on the display.
|
|
491
|
+
*
|
|
492
|
+
* @description If any objects are Button types, the method will wait for one
|
|
493
|
+
* to be clicked and will then return the ID of the clicked object.
|
|
494
|
+
*
|
|
495
|
+
* @param {object[]} objects An array of Signature Tablet Widgets to display.
|
|
496
|
+
*
|
|
497
|
+
* @param {boolean} [clear] If true (the default), the display will be cleared
|
|
498
|
+
* before adding the objects.
|
|
499
|
+
*
|
|
500
|
+
*
|
|
501
|
+
* @async
|
|
502
|
+
* @method
|
|
503
|
+
* @returns {string?} ID of the clicked object if any
|
|
504
|
+
* @example
|
|
505
|
+
* const result = await tablet.displayObjects([
|
|
506
|
+
* new TextButton("OK", 20, 200),
|
|
507
|
+
* new TextButton("Cancel", 80, 200)
|
|
508
|
+
* ])
|
|
509
|
+
*
|
|
510
|
+
* console.log(`${result} was clicked`)
|
|
511
|
+
*/
|
|
512
|
+
async displayObjects (objects, clear = true) {
|
|
513
|
+
this.can('draw')
|
|
514
|
+
const url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/display`
|
|
515
|
+
|
|
516
|
+
const asyncOperations = objects.map(async obj => {
|
|
517
|
+
if (obj.constructor.name === 'Image') {
|
|
518
|
+
await obj.data()
|
|
519
|
+
}
|
|
520
|
+
})
|
|
521
|
+
|
|
522
|
+
// Wait for all async operations to complete
|
|
523
|
+
await Promise.all(asyncOperations)
|
|
524
|
+
|
|
525
|
+
const options = {
|
|
526
|
+
method: 'POST',
|
|
527
|
+
mode: 'cors',
|
|
528
|
+
headers: {
|
|
529
|
+
'Content-Type': 'application/json'
|
|
530
|
+
},
|
|
531
|
+
body: JSON.stringify({
|
|
532
|
+
clear,
|
|
533
|
+
backlight: true,
|
|
534
|
+
objects
|
|
535
|
+
})
|
|
536
|
+
}
|
|
537
|
+
const response = await fetch(url, options)
|
|
538
|
+
const { clicked } = await response.json()
|
|
539
|
+
return clicked
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
async displayObjectsHandler (objects, clear = true, callback) {
|
|
543
|
+
asyncToCallback(this, this.displayObjects, callback, objects, clear)
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
export default Device
|