@capturebridge/sdk 0.7.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/Device.js ADDED
@@ -0,0 +1,451 @@
1
+ import { BASE_URL, POST, DELETE, timeout, asyncToCallback } from './Common.js'
2
+
3
+ /**
4
+ * Device
5
+ * @classdesc Class for interacting with a Device returned from a plugin.
6
+ */
7
+ class Device {
8
+ /*
9
+ * @property {Object} device - Device object as received from the API
10
+ * @property {string} device.id - URL safe device identified, this can often be hashed or encoded and should be considered opaque.
11
+ * @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.
12
+ * @property {string} device.name - Human friendly name of the device.
13
+ */
14
+ baseUrl
15
+ plugin
16
+ id
17
+ raw_id
18
+ name
19
+
20
+ /**
21
+ * Instantiate a device.
22
+ * @constructor
23
+ * @param {object} device - Device object as received from the API
24
+ * @param {string} device.id - URL safe device identified, this can often be hashed or encoded and should be considered opaque.
25
+ * @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.
26
+ * @param {string} device.name - Human friendly name of the device.
27
+ * @param {object} plugin - Plugin serviced by this device.
28
+ * @param {string} [baseURL] - Protocol, domain, and port for the service.
29
+ */
30
+ constructor (properties, plugin, baseUrl = BASE_URL) {
31
+ this.baseUrl = baseUrl
32
+ this.plugin = plugin
33
+ Object.assign(this, {}, properties)
34
+ }
35
+
36
+ can (method) {
37
+ if (this.plugin.methods.indexOf(method) === -1) {
38
+ throw new Error(`${method} not supported for this device`)
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Get the stream endpoint URL.
44
+ *
45
+ * @description the URL returned from this endpoint can be attached to an
46
+ * img tag's src attribute. The device's live stream will be started and
47
+ * begin streaming to the img tag as a
48
+ * {@link https://en.wikipedia.org/wiki/Motion_JPEG|Motion JPEG} stream.
49
+ * If the src is changed, the img removed from the DOM, or client disconnected
50
+ * for any reason, the live feed will automatically be stopped.
51
+ *
52
+ * @method
53
+ * @returns {string} stream endpoint URL
54
+ * @example
55
+ * const img = document.createElement('img')
56
+ * img.src = device.streamUrl()
57
+ * document.body.appendChild(img)
58
+ */
59
+ streamUrl () {
60
+ this.can('start_feed')
61
+ this.can('stop_feed')
62
+ return `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/stream`
63
+ }
64
+
65
+ /**
66
+ * Take full capture from the specified device and return a
67
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob} that can
68
+ * be used with a {@link https://developer.mozilla.org/en-US/docs/Web/API/FileReader|FileReader}
69
+ * (Async/Await version)
70
+ *
71
+ * @method
72
+ * @async
73
+ * @returns {object} {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob}
74
+ * @example
75
+ * // Load the blob into FileReader and append to the document's body
76
+ * const blob = await device.captureAsBlob()
77
+ * const reader = new FileReader()
78
+ * reader.onload = event => {
79
+ * const img = document.createElement('img')
80
+ * img.src = event.target.result
81
+ * document.body.appendChild(img)
82
+ * }
83
+ * reader.readAsDataURL(blob)
84
+ */
85
+ async captureAsBlob () {
86
+ this.can('capture')
87
+ const url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/capture`
88
+ const response = await fetch(url, POST)
89
+ return await response.blob()
90
+ }
91
+
92
+ /**
93
+ * Take full capture from the specified device and return a
94
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob} that can
95
+ * be used with a {@link https://developer.mozilla.org/en-US/docs/Web/API/FileReader|FileReader}
96
+ * (Callback version)
97
+ *
98
+ * @method
99
+ * @param {function} callback - {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob}
100
+ * @example
101
+ * // Load the blob into FileReader and append to the document's body
102
+ * device.captureAsBlobHandler((error, blob) => {
103
+ * const reader = new FileReader()
104
+ * reader.onload = event => {
105
+ * const img = document.createElement('img')
106
+ * img.src = event.target.result
107
+ * document.body.appendChild(img)
108
+ * }
109
+ * reader.readAsDataURL(blob)
110
+ * })
111
+ */
112
+ captureAsBlobHandler (callback) {
113
+ asyncToCallback(this, this.captureAsBlob, callback)
114
+ }
115
+
116
+ /**
117
+ * Take full capture from the specified device and return a
118
+ * base64 encoded string of the image that can be used with a
119
+ * {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs|Data URL}
120
+ * (Async/Await version)
121
+ *
122
+ * @method
123
+ * @async
124
+ * @returns {string} Base64 Encoded image
125
+ * @example
126
+ * // Add the base64 string as a Data URL to an img tag and append to
127
+ * // the document's body
128
+ * const base64 = await device.captureAsBase64()
129
+ * const img = document.createElement('img')
130
+ * img.src = 'data:image/jpeg;base64,' + base64
131
+ * document.body.appendChild(img)
132
+ */
133
+ async captureAsBase64 () {
134
+ this.can('capture')
135
+ const url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/capture?base64=true`
136
+ const response = await fetch(url, POST)
137
+ const { image } = await response.json()
138
+ return image
139
+ }
140
+
141
+ /**
142
+ * Take full capture from the specified device and return a
143
+ * base64 encoded string of the image that can be used with a
144
+ * {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs|Data URL}
145
+ * (Callback version)
146
+ * @method
147
+ * @param {function} callback - Base64 Encoded image
148
+ */
149
+ captureAsBase64Handler (callback) {
150
+ asyncToCallback(this, this.captureAsBase64, callback)
151
+ }
152
+
153
+ /**
154
+ * Get a base64 encoded frame from a device's live feed.
155
+ * @method
156
+ *
157
+ * @description This method will startup the live
158
+ * feed if necessary and wait for it to initialize before returning a frame.
159
+ * Subsequent calls will return the next available frame.
160
+ * You must manually stop the live feed if you are using this method.
161
+ *
162
+ * The frame returned will be a base64 encoded string of the image that can
163
+ * be used with a
164
+ * {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs|Data URL}
165
+ *
166
+ * If implementing a real-time preview, it is highly recommended to use the
167
+ * stream endpoint which will stream a Motion JPEG.
168
+ *
169
+ * @see {@link streamUrl}
170
+ * @see {@link stopFeed}
171
+ *
172
+ * @async
173
+ * @param {number} [millis] - Milliseconds to wait if feed is not ready
174
+ * @returns {string} Base64 Encoded image
175
+ * @example
176
+ * // Add the base64 string as a Data URL to an img tag and append to
177
+ * // the document's body
178
+ * const base64 = await device.frameAsBase64()
179
+ * const img = document.createElement('img')
180
+ * img.src = 'data:image/jpeg;base64,' + base64
181
+ * document.body.appendChild(img)
182
+ */
183
+ async frameAsBase64 (millis = 1000) {
184
+ this.can('start_feed')
185
+ const url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/livefeed?base64=true`
186
+ const response = await fetch(url)
187
+ const result = await response.json()
188
+ if (result.error && (result.code === 425 || result.code === 400)) {
189
+ await timeout(millis)
190
+ return await this.frameAsBase64(millis)
191
+ } else {
192
+ return result.image
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Get a base64 encoded frame from a device's live feed. (Callback version)
198
+ * @method
199
+ *
200
+ * @description This method will startup the live
201
+ * feed if necessary and wait for it to initialize before returning a frame.
202
+ * Subsequent calls will return the next available frame.
203
+ * You must manually stop the live feed if you are using this method.
204
+ *
205
+ * The frame returned will be a base64 encoded string of the image that can
206
+ * be used with a
207
+ * {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs|Data URL}
208
+ *
209
+ * If implementing a real-time preview, it is highly recommended to use the
210
+ * stream endpoint which will stream a Motion JPEG.
211
+ *
212
+ * @see {@link streamUrl}
213
+ * @see {@link setStopFeed}
214
+ *
215
+ * @param {function} callback - Base64 Encoded image
216
+ * @param {number} [millis] - Milliseconds to wait if feed is not ready
217
+ * @example
218
+ * // Add the base64 string as a Data URL to an img tag and append to
219
+ * // the document's body
220
+ * device.frameAsBase64Handler(base64 => {
221
+ * const img = document.createElement('img')
222
+ * img.src = 'data:image/jpeg;base64,' + base64
223
+ * document.body.appendChild(img)
224
+ * })
225
+ */
226
+ frameAsBase64Handler (callback, millis = 1000) {
227
+ asyncToCallback(this, this.frameAsBase64, callback, millis)
228
+ }
229
+
230
+ /**
231
+ * Get a binary frame from a device's live feed. (Async/await version)
232
+ * @method
233
+ *
234
+ * @description This method will startup the live
235
+ * feed if necessary and wait for it to initialize before returning a frame.
236
+ * Subsequent calls will return the next available frame.
237
+ * You must manually stop the live feed if you are using this method.
238
+ *
239
+ * The frame returned will be a
240
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob} that can
241
+ * be used with a {@link https://developer.mozilla.org/en-US/docs/Web/API/FileReader|FileReader}
242
+ *
243
+ * If implementing a real-time preview, it is highly recommended to use the
244
+ * stream endpoint which will stream a Motion JPEG.
245
+ *
246
+ * @see {@link streamUrl}
247
+ * @see {@link stopFeed}
248
+ *
249
+ * @async
250
+ * @param {number} [millis] - Milliseconds to wait if feed is not ready
251
+ * @returns {object} {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob}
252
+ * @example
253
+ * // Load the blob into FileReader and append to the document's body
254
+ * const blob = await device.frameAsBlob()
255
+ * const reader = new FileReader()
256
+ * reader.onload = event => {
257
+ * const img = document.createElement('img')
258
+ * img.src = event.target.result
259
+ * document.body.appendChild(img)
260
+ * }
261
+ * reader.readAsDataURL(blob)
262
+ */
263
+ async frameAsBlob (millis = 1000) {
264
+ this.can('start_feed')
265
+ const url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/livefeed`
266
+ const result = await this.frameAsBase64(millis)
267
+ if (typeof result === 'string') {
268
+ timeout(millis)
269
+ const response = await fetch(url)
270
+ return await response.blob()
271
+ }
272
+ throw new Error(result || 'Failed to get frame')
273
+ }
274
+
275
+ /**
276
+ * Get a binary frame from a device's live feed. (Callback version)
277
+ * @method
278
+ *
279
+ * @description This method will startup the live
280
+ * feed if necessary and wait for it to initialize before returning a frame.
281
+ * Subsequent calls will return the next available frame.
282
+ * You must manually stop the live feed if you are using this method.
283
+ *
284
+ * The frame returned will be a
285
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob} that can
286
+ * be used with a {@link https://developer.mozilla.org/en-US/docs/Web/API/FileReader|FileReader}
287
+ *
288
+ * If implementing a real-time preview, it is highly recommended to use the
289
+ * stream endpoint which will stream a Motion JPEG.
290
+ *
291
+ * @see {@link streamUrl}
292
+ * @see {@link setStopFeed}
293
+ *
294
+ * @param {function} callback -{@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob}
295
+ * @param {number} [millis] - Milliseconds to wait if feed is not ready
296
+ * @example
297
+ * // Load the blob into FileReader and append to the document's body
298
+ * device.frameAsBlobHandler((error, blob) => {
299
+ * const reader = new FileReader()
300
+ * reader.onload = event => {
301
+ * const img = document.createElement('img')
302
+ * img.src = event.target.result
303
+ * document.body.appendChild(img)
304
+ * }
305
+ * reader.readAsDataURL(blob)
306
+ * })
307
+ */
308
+ frameAsBlobHandler (callback, millis = 1000) {
309
+ asyncToCallback(this, this.frameAsBlob, callback, millis)
310
+ }
311
+
312
+ /**
313
+ * Stop the live feed if it is running.
314
+ * (Async/Await version)
315
+ *
316
+ * @method
317
+ * @async
318
+ * @returns {object} Status of the stop operation
319
+ * @example
320
+ * // Plugin is now running it's live feed in a background thread
321
+ * const blob = await device.frameAsBlob()
322
+ * // Live feed is now stopping
323
+ * console.log(await device.stopFeed())
324
+ */
325
+ async stopFeed () {
326
+ this.can('stop_feed')
327
+ const url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/livefeed`
328
+ const response = await fetch(url, DELETE)
329
+ return await response.json()
330
+ }
331
+
332
+ /**
333
+ * Stop the live feed if it is running.
334
+ * (Callback version)
335
+ *
336
+ * @method
337
+ * @param {number} [millis] - Milliseconds to wait if feed is not ready
338
+ * @param {function} callback with the status of the stop operation
339
+ * @example
340
+ * device.stopFeedHandler((error, blob) => {
341
+ * // Plugin is now running it's live feed in a background thread
342
+ * device.setStopFeed(result => {
343
+ * // Live feed is now stopping
344
+ * console.log(result)
345
+ * })
346
+ * })
347
+ */
348
+ stopFeedHandler (callback) {
349
+ asyncToCallback(this, this.frameAsBlob, callback)
350
+ }
351
+
352
+ /**
353
+ * Clear a device's display.
354
+ * (Async/Await version)
355
+ *
356
+ * @method
357
+ * @async
358
+ * @param {boolean} [backlight] If provided and set to true, will enable
359
+ * backlight. If false, it will be disabled. If unspecified no action will be
360
+ * taken on the backlight.
361
+ * @returns {object} Status of the clear operation
362
+ * @example
363
+ * console.log(await await device.clear())
364
+ */
365
+ async clear (backlight) {
366
+ this.can('draw')
367
+ let url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/display`
368
+ if (typeof backlight === 'boolean') {
369
+ url += `?backlight=${backlight}`
370
+ }
371
+ const response = await fetch(url, DELETE)
372
+ return await response.json()
373
+ }
374
+
375
+ /**
376
+ * Clear a device's display.
377
+ * (Callback version)
378
+ *
379
+ * @method
380
+ * @param {function} callback with the status of the clear operation
381
+ * @param {boolean} [backlight] If provided and set to true, will enable
382
+ * backlight. If false, it will be disabled. If unspecified no action will be
383
+ * taken on the backlight.
384
+ * @example
385
+ * device.clearHandler((error, result) => {
386
+ * console.log(result)
387
+ * })
388
+ */
389
+ clearHandler (callback, backlight) {
390
+ asyncToCallback(this, this.clear, callback, backlight)
391
+ }
392
+
393
+ /**
394
+ * Display an Array of objects on the display.
395
+ *
396
+ * @description If any objects are Button types, the method will wait for one
397
+ * to be clicked and will then return the ID of the clicked object.
398
+ *
399
+ * @param {object[]} objects An array of Signature Tablet Widgets to display.
400
+ *
401
+ * @param {boolean} [clear] If true (the default), the display will be cleared
402
+ * before adding the objects.
403
+ *
404
+ *
405
+ * @async
406
+ * @method
407
+ * @returns {string?} ID of the clicked object if any
408
+ * @example
409
+ * const result = await tablet.displayObjects([
410
+ * new TextButton("OK", 20, 200),
411
+ * new TextButton("Cancel", 80, 200)
412
+ * ])
413
+ *
414
+ * console.log(`${result} was clicked`)
415
+ */
416
+ async displayObjects (objects, clear = true) {
417
+ this.can('draw')
418
+ const url = `${this.baseUrl}/plugin/${this.plugin.id}/device/${this.id}/display`
419
+
420
+ const asyncOperations = objects.map(async obj => {
421
+ if (obj.constructor.name === 'Image') {
422
+ await obj.data()
423
+ }
424
+ })
425
+
426
+ // Wait for all async operations to complete
427
+ await Promise.all(asyncOperations)
428
+
429
+ const options = {
430
+ method: 'POST',
431
+ mode: 'cors',
432
+ headers: {
433
+ 'Content-Type': 'application/json'
434
+ },
435
+ body: JSON.stringify({
436
+ clear,
437
+ backlight: true,
438
+ objects
439
+ })
440
+ }
441
+ const response = await fetch(url, options)
442
+ const { clicked } = await response.json()
443
+ return clicked
444
+ }
445
+
446
+ async displayObjectsHandler (objects, clear = true, callback) {
447
+ asyncToCallback(this, this.displayObjects, callback, objects, clear)
448
+ }
449
+ }
450
+
451
+ export default Device
package/ICAO.js ADDED
@@ -0,0 +1,70 @@
1
+ import Plugin from './Plugin.js'
2
+ import { BASE_URL } from './Common.js'
3
+
4
+ /**
5
+ * ICAO
6
+ * @classdesc Class for invoking ICAO checks on an image
7
+ *
8
+ * @see {@link CanonScanner}
9
+ */
10
+ class ICAO extends Plugin {
11
+ /**
12
+ * Instantiate an ICAO plugin
13
+ * @constructor
14
+ * @param {string} [baseURL] - Protocol, domain, and port for the service.
15
+ * @param {string|object} plugin - The ID of the desired plugin to use for
16
+ * this instance or an existing Plugin object. The plugin must support the
17
+ * "icao" method.
18
+ *
19
+ * @example
20
+ * const icao = new ICAO('capture_verify_iface')
21
+ */
22
+ constructor (plugin, baseUrl = BASE_URL) {
23
+ super(plugin, baseUrl)
24
+ }
25
+
26
+ /**
27
+ * Check the ICAO compliance of an image
28
+ * @param {string} image - A base64 encoded image.
29
+ *
30
+ * @param {string|bool} [crop] - If falsy image will not be cropped, otherwise
31
+ * the value will be interpreted as the preferred crop method which will vary
32
+ * by plugin implementation.
33
+ *
34
+ * @returns {object} Results of the ICAO check, this may vary by plugin
35
+ * implementation.
36
+ *
37
+ * @async
38
+ * @example
39
+ * // Take a photo with a Canon Camera and perform ICAO checks on the
40
+ * // returned image
41
+ * const camera = new CanonCamera()
42
+ * const photo = await camera.takePhoto('base64')
43
+ * const icao = new ICAO('capture_verify_iface')
44
+ * const results = await icao.check(photo)
45
+ * const img = document.createElement('img')
46
+ * img.src = 'data:image/jpeg;base64,' + results.cropped
47
+ * console.log(`found ${result.faces_found} faces in the image`)
48
+ * document.body.appendChild(img)
49
+ */
50
+ async check (image, cropMethod = false) {
51
+ const body = {
52
+ base64: image,
53
+ crop: Boolean(cropMethod),
54
+ crop_method: cropMethod || undefined
55
+ }
56
+ const options = {
57
+ method: 'POST',
58
+ mode: 'cors',
59
+ headers: {
60
+ 'Content-Type': 'application/json'
61
+ },
62
+ body: JSON.stringify(body)
63
+ }
64
+ const url = `${this.baseUrl}/plugin/${this.id}/icao`
65
+ const response = await fetch(url, options)
66
+ return await response.json()
67
+ }
68
+ }
69
+
70
+ export default ICAO