@capturebridge/sdk 0.9.1 → 0.10.1

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/CHANGELOG.md CHANGED
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.10.0] - 2024-06-17
9
+
10
+ ### Changed
11
+
12
+ - Introduced breaking changes to the structure of the object returned from
13
+ `ICAO.check()`
14
+ - `ICAO` class will default to use the `capture_verify_iface` plugin if no
15
+ plugin is provided to the constructor.
16
+
17
+ ### Added
18
+
19
+ - Coordinates of the cropped photo are now returned from `ICAO.check()` if a face
20
+ was found.
21
+
8
22
  ## [0.9.0] - 2024-06-06
9
23
 
10
24
  ### Added
package/Common.js CHANGED
@@ -133,6 +133,31 @@ export const DATAURL_JPEG = 'data:image/jpeg;base64,'
133
133
  */
134
134
  export const DATAURL_PNG = 'data:image/png;base64,'
135
135
 
136
+ /**
137
+ * @summary For a given base64 string, convert it to the appropriate Data URL
138
+ * @constant
139
+ * @type {string}
140
+ */
141
+ export const base64ToDataURL = base64 => {
142
+ const magicBytes = atob(base64.slice(0, 6))
143
+ const byteArray = new Uint8Array(magicBytes.length)
144
+ for (let i = 0; i < magicBytes.length; i++) {
145
+ byteArray[i] = magicBytes.charCodeAt(i)
146
+ }
147
+
148
+ // Check for JPEG magic number (FF D8 FF)
149
+ if (byteArray[0] === 0xFF && byteArray[1] === 0xD8 && byteArray[2] === 0xFF) {
150
+ return DATAURL_JPEG + base64
151
+ }
152
+
153
+ // Check for PNG magic number (89 50 4E 47)
154
+ if (byteArray[0] === 0x89 && byteArray[1] === 0x50 && byteArray[2] === 0x4E && byteArray[3] === 0x47) {
155
+ return DATAURL_PNG + base64
156
+ }
157
+
158
+ throw new Error('Unknown image format provided in Base64 string')
159
+ }
160
+
136
161
  /**
137
162
  * An Async/Await version of
138
163
  * {@link https://developer.mozilla.org/en-US/docs/Web/API/setTimeout|setTimeout}
package/ICAO.js CHANGED
@@ -5,7 +5,7 @@ import { BASE_URL } from './Common.js'
5
5
  * ICAO
6
6
  * @classdesc Class for invoking ICAO checks on an image
7
7
  * @extends Plugin
8
- * @see {@link CanonScanner}
8
+ * @see {@link IFace}
9
9
  */
10
10
  class ICAO extends Plugin {
11
11
  /**
@@ -14,18 +14,19 @@ class ICAO extends Plugin {
14
14
  * @param {string} [baseURL] - Protocol, domain, and port for the service.
15
15
  * @param {string|object} plugin - The ID of the desired plugin to use for
16
16
  * this instance or an existing Plugin object. The plugin must support the
17
- * "icao" method.
17
+ * `icao` method. Defaults to the `capture_verify_iface` plugin.
18
18
  *
19
19
  * @example
20
- * const icao = new ICAO('capture_verify_iface')
20
+ * const icao = new ICAO()
21
21
  */
22
- constructor (plugin, baseUrl = BASE_URL) {
22
+ constructor (plugin = 'capture_verify_iface', baseUrl = BASE_URL) {
23
23
  super(plugin, baseUrl)
24
24
  }
25
25
 
26
26
  /**
27
27
  * Check the ICAO compliance of an image
28
- * @param {string} image - A base64 encoded image.
28
+ * @param {string|ImageSource} image - A string containing base64 encoded image
29
+ * data or an ImageSource object.
29
30
  *
30
31
  * @param {string|bool} [crop] - If falsy image will not be cropped, otherwise
31
32
  * the value will be interpreted as the preferred crop method which will vary
@@ -40,7 +41,7 @@ class ICAO extends Plugin {
40
41
  * // returned image
41
42
  * const camera = new CanonCamera()
42
43
  * const photo = await camera.takePhoto('base64')
43
- * const icao = new ICAO('capture_verify_iface')
44
+ * const icao = new ICAO()
44
45
  * const results = await icao.check(photo)
45
46
  * const img = document.createElement('img')
46
47
  * img.src = 'data:image/jpeg;base64,' + results.cropped
@@ -48,8 +49,19 @@ class ICAO extends Plugin {
48
49
  * document.body.appendChild(img)
49
50
  */
50
51
  async check (image, cropMethod = false) {
52
+ let imageData
53
+
54
+ // If this is an ImageSource object fetch it's image data
55
+ if (typeof image === 'object' && image.constructor.name === 'ImageSource') {
56
+ imageData = await image.data()
57
+ } else if (typeof image === 'string') {
58
+ imageData = image
59
+ } else {
60
+ throw new Error('Unexpected value provided for image parameter')
61
+ }
62
+
51
63
  const body = {
52
- base64: image,
64
+ base64: imageData,
53
65
  crop: Boolean(cropMethod),
54
66
  crop_method: cropMethod || undefined
55
67
  }
package/IFace.js CHANGED
@@ -3,7 +3,8 @@
3
3
  */
4
4
 
5
5
  import ICAO from './ICAO.js'
6
- import { BASE_URL, blobToBase64 } from './Common.js'
6
+ import ImageSource from './ImageSource.js'
7
+ import { BASE_URL } from './Common.js'
7
8
 
8
9
  // This is not exported as we may eventually detect this from the plugin
9
10
  // See: Iface.matchModes()
@@ -15,10 +16,7 @@ const VALID_MODES = ['accurate', 'balanced', 'fast', 'accurate_server']
15
16
  *
16
17
  * @see {@link IFace}
17
18
  */
18
- export class Probe {
19
- source
20
- url
21
- imageData
19
+ export class Probe extends ImageSource {
22
20
  /**
23
21
  * Instantiate an IFace Probe
24
22
  * @constructor
@@ -30,59 +28,17 @@ export class Probe {
30
28
  * const candidate = new Candidate('/person/123.jpg', '123', 'url')
31
29
  */
32
30
  constructor (source, type = 'base64') {
33
- // TODO:
34
- // If the source is typeof object and/or type=object we should do some duck
35
- // typing and accept any of...
36
- // - The result of an ICAO check that contains a cropped image
37
- // - An Image tag (fetch the source)
38
- // - A Blob
39
- // - An Array Buffer
40
- // - An object that has a fullCapture method (call function in .data())
41
- switch (type) {
42
- case 'url':
43
- this.url = source
44
- break
45
- case 'base64':
46
- this.imageData = source
47
- break
48
- case 'dataurl':
49
- this.imageData = source.split(',')[1]
50
- break
51
- case undefined:
52
- case null:
53
- default:
54
- throw new Error('Invalid image source type provided')
55
- }
56
- }
57
-
58
- /**
59
- * Fetch the image data and base64 encode it
60
- * @async
61
- * @example
62
- * const probe = new Probe("/img/photo.jpg")
63
- * await probe.data()
64
- * console.log(probe.imageData)
65
- */
66
- async data () {
67
- if (!this.imageData) {
68
- const response = await fetch(this.url)
69
- const blob = await response.blob()
70
- this.imageData = await blobToBase64(blob)
71
- }
72
- }
73
-
74
- toJSON () {
75
- return this.imageData
31
+ super(source, type)
76
32
  }
77
33
  }
78
34
 
79
35
  /**
80
36
  * Candidate
81
37
  * @classdesc Candidate Class for Innovatrics IFace SDK
82
- * @extends Probe
38
+ * @extends ImageSource
83
39
  * @see {@link IFace}
84
40
  */
85
- export class Candidate extends Probe {
41
+ export class Candidate extends ImageSource {
86
42
  id
87
43
 
88
44
  // TODO: Support setting different modes on individual candidates
package/ImageSource.js ADDED
@@ -0,0 +1,110 @@
1
+ import { blobToBase64, base64ToDataURL, checkResponse } from './Common.js'
2
+
3
+ /**
4
+ * ImageSource
5
+ * @classdesc Class to handle loading various image formats
6
+ *
7
+ * @see {@link Probe}
8
+ */
9
+ export class ImageSource {
10
+ source
11
+ url
12
+ imageData
13
+ type
14
+ /**
15
+ * Instantiate an ImageSource
16
+ * @constructor
17
+ * @param {string} source - The source of the image data.
18
+ * @param {string} [type] - The type of data in the image source, valid values
19
+ * are 'url', 'base64', and 'dataurl'. If not provided 'base64' is the default.
20
+ *
21
+ * @example
22
+ * const personPhoto = new ImageSource('/person/123.jpg', '123', 'url')
23
+ */
24
+ constructor (source, type = 'base64') {
25
+ // TODO:
26
+ // If the source is typeof object and/or type=object we should do some duck
27
+ // typing and accept any of...
28
+ // - The result of an ICAO check that contains a cropped image
29
+ // - An Image tag (fetch the source)
30
+ // - A Blob
31
+ // - An Array Buffer
32
+ // - An object that has a fullCapture method (call function in .data())
33
+ this.type = type
34
+ switch (this.type) {
35
+ case 'url':
36
+ this.url = source
37
+ break
38
+ case 'base64':
39
+ this.imageData = source
40
+ break
41
+ case 'dataurl':
42
+ this.imageData = source.split(',')[1]
43
+ break
44
+ case undefined:
45
+ case null:
46
+ default:
47
+ throw new Error('Invalid image source type provided')
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Fetch the image data and base64 encode it
53
+ * @async
54
+ * @example
55
+ * const personPhoto = new ImageSource("/img/photo.jpg")
56
+ * await personPhoto.data()
57
+ * console.log(personPhoto.imageData)
58
+ */
59
+ async data () {
60
+ if (!this.imageData && this.url) {
61
+ const response = await fetch(this.url)
62
+ await checkResponse(response)
63
+ const blob = await response.blob()
64
+ this.imageData = await blobToBase64(blob)
65
+ }
66
+ return this.imageData
67
+ }
68
+
69
+ /**
70
+ * Create an <img> element, wait for it to load and return it
71
+ * @async
72
+ * @example
73
+ * // Load the image and draw it on a Canvas
74
+ * const img = await imgSrc.toImage()
75
+ * const canvas = document.createElement('canvas')
76
+ * const ctx = canvas.getContext('2d')
77
+ * canvas.width = img.width
78
+ * canvas.height = img.height
79
+ * ctx.drawImage(img, canvas.width, canvas.height, img.width, img.height)
80
+ */
81
+ async toImage () {
82
+ const img = new window.Image()
83
+ const promise = new Promise((resolve, reject) => {
84
+ img.onload = (data) => resolve(img)
85
+ img.onerror = (err) => reject(err)
86
+ })
87
+ switch (this.type) {
88
+ case 'url':
89
+ img.src = this.url
90
+ break
91
+ case 'base64':
92
+ img.src = base64ToDataURL(this.imageData)
93
+ break
94
+ case 'dataurl':
95
+ img.src = this.source
96
+ break
97
+ case undefined:
98
+ case null:
99
+ default:
100
+ throw new Error('Invalid image source type provided')
101
+ }
102
+ return promise
103
+ }
104
+
105
+ toJSON () {
106
+ return this.imageData
107
+ }
108
+ }
109
+
110
+ export default ImageSource
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Capture Bridge JavaScript SDK for web applications
2
+
3
+ See the [Changelog](CHANGELOG.md) for new features and breaking changes.
package/Version.js CHANGED
@@ -4,5 +4,5 @@
4
4
  * @constant
5
5
  * @type {string}
6
6
  */
7
- const VERSION = '0.9.1'
7
+ const VERSION = '0.10.1'
8
8
  export default VERSION
@@ -15,52 +15,6 @@
15
15
  Stream
16
16
  </button>
17
17
  </div>
18
- <script type="module">
19
- import CanonCamera from '/sdk/js/CanonCamera.js'
20
- (async () => {
21
- const defaultSrc = '/demo/img/empty.jpg'
22
- const defaultWidth = 400
23
- const img = document.getElementById('img')
24
- const capture = document.getElementById('capture')
25
- const stream = document.getElementById('stream')
26
- const rotation = document.getElementById('rotate')
27
-
28
- img.src = defaultSrc
29
- img.width = defaultWidth
30
-
31
- try {
32
- const camera = new CanonCamera()
33
- const devices = await camera.devices();
34
-
35
- if (!devices.length) {
36
- return alert('No Canon Camera devices found')
37
- }
38
-
39
- // Start the first device's live feed and stream it to the img tag
40
- stream.addEventListener('click', async () => {
41
- const rotate = parseInt(rotation.value)
42
- rotation.disabled = true
43
- stream.disabled = true
44
- img.src = await camera.streamUrl({rotate})
45
- })
46
-
47
- // Take a full capture and add the image to the page
48
- capture.addEventListener('click', async () => {
49
- const rotate = parseInt(rotation.value)
50
- const capture = document.createElement('img')
51
- img.src = defaultSrc
52
- capture.src = await camera.takePhoto({rotate})
53
- capture.width = defaultWidth
54
- document.body.appendChild(capture)
55
- rotation.disabled = false
56
- stream.disabled = false
57
- })
58
-
59
- } catch (e) {
60
- console.error(e)
61
- alert(`Error: ${e.message}`)
62
- }
63
- })()
64
- </script>
18
+ <script type="module" src="./canon.js"></script>
65
19
  </body>
66
20
  </html>
@@ -0,0 +1,44 @@
1
+ import CanonCamera from '../../../../sdk/js/CanonCamera.js'
2
+ (async () => {
3
+ const defaultSrc = 'empty.jpg'
4
+ const defaultWidth = 400
5
+ const img = document.getElementById('img')
6
+ const capture = document.getElementById('capture')
7
+ const stream = document.getElementById('stream')
8
+ const rotation = document.getElementById('rotate')
9
+
10
+ img.src = defaultSrc
11
+ img.width = defaultWidth
12
+
13
+ try {
14
+ const camera = new CanonCamera()
15
+ const devices = await camera.devices()
16
+
17
+ if (!devices.length) {
18
+ return window.alert('No Canon Camera devices found')
19
+ }
20
+
21
+ // Start the first device's live feed and stream it to the img tag
22
+ stream.addEventListener('click', async () => {
23
+ const rotate = parseInt(rotation.value)
24
+ rotation.disabled = true
25
+ stream.disabled = true
26
+ img.src = await camera.streamUrl({ rotate })
27
+ })
28
+
29
+ // Take a full capture and add the image to the page
30
+ capture.addEventListener('click', async () => {
31
+ const rotate = parseInt(rotation.value)
32
+ const capture = document.createElement('img')
33
+ img.src = defaultSrc
34
+ capture.src = await camera.takePhoto({ rotate })
35
+ capture.width = defaultWidth
36
+ document.body.appendChild(capture)
37
+ rotation.disabled = false
38
+ stream.disabled = false
39
+ })
40
+ } catch (e) {
41
+ console.error(e)
42
+ window.alert(`Error: ${e.message}`)
43
+ }
44
+ })()
@@ -15,54 +15,6 @@
15
15
  Stop Feed
16
16
  </button>
17
17
  </div>
18
- <script type="module">
19
- import CanonCamera from '/sdk/js/CanonCamera.js'
20
- (async () => {
21
- const defaultSrc = '/demo/img/empty.jpg'
22
- const img = document.getElementById('img')
23
- const rotation = document.getElementById('rotate')
24
- const frame = document.getElementById('frame')
25
- const stop = document.getElementById('stop')
26
-
27
- img.src = defaultSrc
28
- img.width = 400
29
-
30
- try {
31
- const camera = new CanonCamera()
32
- const devices = await camera.devices()
33
-
34
- if (!devices.length) {
35
- return alert('No Canon Camera devices found')
36
- }
37
-
38
- // Acquiring the first frame will take a few seconds while the camera
39
- // starts up and begins streaming, subsequent frames will be returned
40
- // instantaneously
41
- let lastFrame;
42
- frame.addEventListener('click', async () => {
43
- stop.disabled = true
44
- rotation.disabled = true
45
- const rotate = parseInt(rotation.value)
46
- // Cleanup the last frame captured, if any
47
- if (lastFrame) {
48
- URL.revokeObjectURL(lastFrame)
49
- }
50
- img.src = lastFrame = await camera.getMostRecentFrame({rotate})
51
- rotation.disabled = false
52
- stop.disabled = false
53
- })
54
-
55
- // Stop live feed
56
- stop.addEventListener('click', async () => {
57
- const result = await camera.stopFeed()
58
- alert(result.message || result.status)
59
- })
60
-
61
- } catch (e) {
62
- console.error(e)
63
- alert(`Error: ${e.message}`)
64
- }
65
- })()
66
- </script>
18
+ <script type="module" src="./canon_getframe.js"></script>
67
19
  </body>
68
20
  </html>
@@ -0,0 +1,46 @@
1
+ import CanonCamera from '../../../../sdk/js/CanonCamera.js'
2
+ (async () => {
3
+ const defaultSrc = 'empty.jpg'
4
+ const img = document.getElementById('img')
5
+ const rotation = document.getElementById('rotate')
6
+ const frame = document.getElementById('frame')
7
+ const stop = document.getElementById('stop')
8
+
9
+ img.src = defaultSrc
10
+ img.width = 400
11
+
12
+ try {
13
+ const camera = new CanonCamera()
14
+ const devices = await camera.devices()
15
+
16
+ if (!devices.length) {
17
+ return window.alert('No Canon Camera devices found')
18
+ }
19
+
20
+ // Acquiring the first frame will take a few seconds while the camera
21
+ // starts up and begins streaming, subsequent frames will be returned
22
+ // instantaneously
23
+ let lastFrame
24
+ frame.addEventListener('click', async () => {
25
+ stop.disabled = true
26
+ rotation.disabled = true
27
+ const rotate = parseInt(rotation.value)
28
+ // Cleanup the last frame captured, if any
29
+ if (lastFrame) {
30
+ URL.revokeObjectURL(lastFrame)
31
+ }
32
+ img.src = lastFrame = await camera.getMostRecentFrame({ rotate })
33
+ rotation.disabled = false
34
+ stop.disabled = false
35
+ })
36
+
37
+ // Stop live feed
38
+ stop.addEventListener('click', async () => {
39
+ const result = await camera.stopFeed()
40
+ window.alert(result.message || result.status)
41
+ })
42
+ } catch (e) {
43
+ console.error(e)
44
+ window.alert(`Error: ${e.message}`)
45
+ }
46
+ })()
@@ -15,54 +15,6 @@
15
15
  Stream
16
16
  </button>
17
17
  </div>
18
- <script type="module">
19
- import CanonCamera from '/sdk/js/CanonCamera.js'
20
- (async () => {
21
- const defaultSrc = '/demo/img/empty.jpg'
22
- const defaultWidth = 400
23
- const img = document.getElementById('img')
24
- const capture = document.getElementById('capture')
25
- const stream = document.getElementById('stream')
26
- const rotation = document.getElementById('rotate')
27
-
28
- img.src = defaultSrc
29
- img.width = defaultWidth
30
-
31
- try {
32
- const defaultURL = 'https://windev2-local.capturebridge.net:9001'
33
- const url = prompt('Enter remote Base URL', defaultURL)
34
- const camera = new CanonCamera(url)
35
- const devices = await camera.devices();
36
-
37
- if (!devices.length) {
38
- return alert('No Canon Camera devices found')
39
- }
40
-
41
- // Start the first device's live feed and stream it to the img tag
42
- stream.addEventListener('click', async () => {
43
- const rotate = parseInt(rotation.value)
44
- rotation.disabled = true
45
- stream.disabled = true
46
- img.src = await camera.streamUrl({rotate})
47
- })
48
-
49
- // Take a full capture and add the image to the page
50
- capture.addEventListener('click', async () => {
51
- const rotate = parseInt(rotation.value)
52
- const capture = document.createElement('img')
53
- img.src = defaultSrc
54
- capture.src = await camera.takePhoto({rotate})
55
- capture.width = defaultWidth
56
- document.body.appendChild(capture)
57
- rotation.disabled = false
58
- stream.disabled = false
59
- })
60
-
61
- } catch (e) {
62
- console.error(e)
63
- alert(`Error: ${e.message}`)
64
- }
65
- })()
66
- </script>
18
+ <script type="module" src="./canon_lan.js"></script>
67
19
  </body>
68
20
  </html>
@@ -0,0 +1,46 @@
1
+ import CanonCamera from '../../../../sdk/js/CanonCamera.js'
2
+ (async () => {
3
+ const defaultSrc = 'empty.jpg'
4
+ const defaultWidth = 400
5
+ const img = document.getElementById('img')
6
+ const capture = document.getElementById('capture')
7
+ const stream = document.getElementById('stream')
8
+ const rotation = document.getElementById('rotate')
9
+
10
+ img.src = defaultSrc
11
+ img.width = defaultWidth
12
+
13
+ try {
14
+ const defaultURL = 'https://windev2-local.capturebridge.net:9001'
15
+ const url = window.prompt('Enter remote Base URL', defaultURL)
16
+ const camera = new CanonCamera(url)
17
+ const devices = await camera.devices()
18
+
19
+ if (!devices.length) {
20
+ return window.alert('No Canon Camera devices found')
21
+ }
22
+
23
+ // Start the first device's live feed and stream it to the img tag
24
+ stream.addEventListener('click', async () => {
25
+ const rotate = parseInt(rotation.value)
26
+ rotation.disabled = true
27
+ stream.disabled = true
28
+ img.src = await camera.streamUrl({ rotate })
29
+ })
30
+
31
+ // Take a full capture and add the image to the page
32
+ capture.addEventListener('click', async () => {
33
+ const rotate = parseInt(rotation.value)
34
+ const capture = document.createElement('img')
35
+ img.src = defaultSrc
36
+ capture.src = await camera.takePhoto({ rotate })
37
+ capture.width = defaultWidth
38
+ document.body.appendChild(capture)
39
+ rotation.disabled = false
40
+ stream.disabled = false
41
+ })
42
+ } catch (e) {
43
+ console.error(e)
44
+ window.alert(`Error: ${e.message}`)
45
+ }
46
+ })()
@@ -2,36 +2,6 @@
2
2
  <html>
3
3
  <head><title>Canon Camera Minimal Example</title></head>
4
4
  <body>
5
- <script type="module">
6
- import CanonCamera from '/sdk/js/CanonCamera.js'
7
- (async () => {
8
- try {
9
-
10
- // Instantiate a Canon Camera
11
- const camera = new CanonCamera()
12
-
13
- const devices = await camera.devices();
14
-
15
- if (!devices.length) {
16
- return alert('No Canon Camera devices found')
17
- }
18
-
19
- // Start the device's live feed and stream it to an img tag
20
- const img = document.createElement('img')
21
- img.src = await camera.streamUrl()
22
- img.height = 400
23
- document.body.appendChild(img)
24
-
25
- // Demo live feed for a few seconds, take a picture, and update the img tag
26
- setTimeout(async () => {
27
- img.src = await camera.takePhoto()
28
- }, 9000)
29
-
30
- } catch (e) {
31
- console.error(e)
32
- alert(`Error: ${e.message}`)
33
- }
34
- })()
35
- </script>
5
+ <script type="module" src="./canon_minimal.js"></script>
36
6
  </body>
37
7
  </html>
@@ -0,0 +1,27 @@
1
+ import CanonCamera from '../../../../sdk/js/CanonCamera.js'
2
+ (async () => {
3
+ try {
4
+ // Instantiate a Canon Camera
5
+ const camera = new CanonCamera()
6
+
7
+ const devices = await camera.devices()
8
+
9
+ if (!devices.length) {
10
+ return window.alert('No Canon Camera devices found')
11
+ }
12
+
13
+ // Start the device's live feed and stream it to an img tag
14
+ const img = document.createElement('img')
15
+ img.src = await camera.streamUrl()
16
+ img.height = 400
17
+ document.body.appendChild(img)
18
+
19
+ // Demo live feed for a few seconds, take a picture, and update the img tag
20
+ setTimeout(async () => {
21
+ img.src = await camera.takePhoto()
22
+ }, 9000)
23
+ } catch (e) {
24
+ console.error(e)
25
+ window.alert(`Error: ${e.message}`)
26
+ }
27
+ })()
Binary file
@@ -0,0 +1,7 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head><title>ICAO Example</title></head>
4
+ <body>
5
+ <script type="module" src="./icao.js"></script>
6
+ </body>
7
+ </html>
Binary file
@@ -0,0 +1,80 @@
1
+ import ICAO from '../../../../sdk/js/ICAO.js'
2
+ import ImageSource from '../../../../sdk/js/ImageSource.js'
3
+
4
+ (async () => {
5
+ try {
6
+ const icao = new ICAO()
7
+ const imgSrc = new ImageSource('icao.jpg', 'url')
8
+
9
+ // Perform an ICAO check against the provided Image and return cropped
10
+ const results = await icao.check(imgSrc, true)
11
+
12
+ // Our stock photo is zoomed in too close, so we pad the canvas to allow for
13
+ // drawing a box around the cropped portion
14
+ const padding = 150
15
+
16
+ // stroke/arc color
17
+ const color = 'rgba(0,255,0,0.5)'
18
+
19
+ // Load the image and draw it on a Canvas
20
+ const img = await imgSrc.toImage()
21
+ const canvas = document.createElement('canvas')
22
+ const ctx = canvas.getContext('2d')
23
+ canvas.width = img.width + padding
24
+ canvas.height = img.height + padding
25
+ ctx.drawImage(img, padding / 2, padding / 2, img.width, img.height)
26
+
27
+ document.body.appendChild(canvas)
28
+
29
+ ctx.strokeStyle = color
30
+ ctx.lineWidth = 4
31
+
32
+ // Insert cropped image into the DOM
33
+ const croppedSrc = new ImageSource(results.cropped)
34
+ document.body.appendChild(await croppedSrc.toImage())
35
+
36
+ // Draw points for left and right eye
37
+ ctx.beginPath()
38
+ ctx.arc(results.face.left_eye.x + padding / 2,
39
+ results.face.left_eye.y + padding / 2, 5, 0, 2 * Math.PI)
40
+ ctx.fillStyle = color
41
+ ctx.fill()
42
+
43
+ ctx.beginPath()
44
+ ctx.arc(results.face.right_eye.x + padding / 2,
45
+ results.face.right_eye.y + padding / 2, 5, 0, 2 * Math.PI)
46
+ ctx.fillStyle = color
47
+ ctx.fill()
48
+
49
+ // Draw bounding box where image was cropped
50
+ ctx.beginPath()
51
+ ctx.moveTo(results.crop_boundary[0].x + padding / 2,
52
+ results.crop_boundary[0].y + padding / 2)
53
+ for (let i = 1; i < results.crop_boundary.length; i++) {
54
+ ctx.lineTo(results.crop_boundary[i].x + padding / 2,
55
+ results.crop_boundary[i].y + padding / 2)
56
+ }
57
+ ctx.closePath()
58
+ ctx.stroke()
59
+
60
+ // Display ICAO attributes
61
+ const output = document.createElement('textarea')
62
+ output.style.display = 'block'
63
+ output.rows = 35
64
+ output.cols = 50
65
+ output.value = '# Checks\n\n'
66
+ document.body.appendChild(output)
67
+ results.attributes.filter(attr => attr.type === 'check').forEach(({ id, score, compliant }) => {
68
+ output.value += (compliant ? '✅' : '❌') + `${id}: ${score}\n`
69
+ })
70
+
71
+ output.value += '\n\n# Data\n\n'
72
+
73
+ results.attributes.filter(attr => attr.type === 'data').forEach(({ id, score, data }) => {
74
+ output.value += `${id}: ${data || score}\n`
75
+ })
76
+ } catch (e) {
77
+ console.error(e)
78
+ window.alert(`Error: ${e.message}`)
79
+ }
80
+ })()
@@ -2,7 +2,7 @@
2
2
  <html>
3
3
  <head><title>Mock Camera Example</title></head>
4
4
  <body>
5
- <img id="img" src="/demo/img/empty.jpg"/>
5
+ <img id="img" src="empty.jpg"/>
6
6
  <div>
7
7
  <div>
8
8
  <label>Rotate</label>
@@ -15,47 +15,6 @@
15
15
  Stream
16
16
  </button>
17
17
  </div>
18
- <script type="module">
19
- import MockCamera from '/sdk/js/MockCamera.js'
20
- (async () => {
21
- const defaultSrc = '/demo/img/empty.jpg'
22
- const defaultWidth = 400
23
- const img = document.getElementById('img')
24
- const capture = document.getElementById('capture')
25
- const stream = document.getElementById('stream')
26
- const rotation = document.getElementById('rotate')
27
-
28
- img.src = defaultSrc
29
- img.width = defaultWidth
30
-
31
- try {
32
- const camera = new MockCamera()
33
-
34
- // Start the first device's live feed and stream it to the img tag
35
- stream.addEventListener('click', async () => {
36
- const rotate = parseInt(rotation.value)
37
- rotation.disabled = true
38
- stream.disabled = true
39
- img.src = await camera.streamUrl({rotate})
40
- })
41
-
42
- // Take a full capture and add the image to the page
43
- capture.addEventListener('click', async () => {
44
- const rotate = parseInt(rotation.value)
45
- const capture = document.createElement('img')
46
- img.src = defaultSrc
47
- capture.src = await camera.takePhoto({rotate})
48
- capture.width = defaultWidth
49
- document.body.appendChild(capture)
50
- rotation.disabled = false
51
- stream.disabled = false
52
- })
53
-
54
- } catch (e) {
55
- console.error(e)
56
- alert(`Error: ${e.message}`)
57
- }
58
- })()
59
- </script>
18
+ <script type="module" src="./mockcamera.js"></script>
60
19
  </body>
61
20
  </html>
@@ -0,0 +1,39 @@
1
+ import MockCamera from '../../../../sdk/js/MockCamera.js'
2
+ (async () => {
3
+ const defaultSrc = 'empty.jpg'
4
+ const defaultWidth = 400
5
+ const img = document.getElementById('img')
6
+ const capture = document.getElementById('capture')
7
+ const stream = document.getElementById('stream')
8
+ const rotation = document.getElementById('rotate')
9
+
10
+ img.src = defaultSrc
11
+ img.width = defaultWidth
12
+
13
+ try {
14
+ const camera = new MockCamera()
15
+
16
+ // Start the first device's live feed and stream it to the img tag
17
+ stream.addEventListener('click', async () => {
18
+ const rotate = parseInt(rotation.value)
19
+ rotation.disabled = true
20
+ stream.disabled = true
21
+ img.src = await camera.streamUrl({ rotate })
22
+ })
23
+
24
+ // Take a full capture and add the image to the page
25
+ capture.addEventListener('click', async () => {
26
+ const rotate = parseInt(rotation.value)
27
+ const capture = document.createElement('img')
28
+ img.src = defaultSrc
29
+ capture.src = await camera.takePhoto({ rotate })
30
+ capture.width = defaultWidth
31
+ document.body.appendChild(capture)
32
+ rotation.disabled = false
33
+ stream.disabled = false
34
+ })
35
+ } catch (e) {
36
+ console.error(e)
37
+ window.alert(`Error: ${e.message}`)
38
+ }
39
+ })()
@@ -15,49 +15,6 @@
15
15
  Stop Feed
16
16
  </button>
17
17
  </div>
18
- <script type="module">
19
- import MockCamera from '/sdk/js/MockCamera.js'
20
- (async () => {
21
- const defaultSrc = '/demo/img/empty.jpg'
22
- const img = document.getElementById('img')
23
- const rotation = document.getElementById('rotate')
24
- const frame = document.getElementById('frame')
25
- const stop = document.getElementById('stop')
26
-
27
- img.src = defaultSrc
28
- img.width = 400
29
-
30
- try {
31
- const camera = new MockCamera()
32
- const devices = await camera.devices()
33
-
34
- // Grab a frame from the live feed
35
- let lastFrame;
36
- frame.addEventListener('click', async () => {
37
- stop.disabled = true
38
- rotation.disabled = true
39
- const rotate = parseInt(rotation.value)
40
- // Cleanup the last frame captured, if any
41
- if (lastFrame) {
42
- URL.revokeObjectURL(lastFrame)
43
- }
44
- img.src = lastFrame = await camera.getMostRecentFrame({rotate})
45
- document.body.appendChild(frame)
46
- rotation.disabled = false
47
- stop.disabled = false
48
- })
49
-
50
- // Stop live feed
51
- stop.addEventListener('click', async () => {
52
- const result = await camera.stopFeed()
53
- alert(result.message || result.status)
54
- })
55
-
56
- } catch (e) {
57
- console.error(e)
58
- alert(`Error: ${e.message}`)
59
- }
60
- })()
61
- </script>
18
+ <script type="module" src="./mockcamera_getframe.js"></script>
62
19
  </body>
63
20
  </html>
@@ -0,0 +1,40 @@
1
+ import MockCamera from '../../../../sdk/js/MockCamera.js'
2
+ (async () => {
3
+ const defaultSrc = 'empty.jpg'
4
+ const img = document.getElementById('img')
5
+ const rotation = document.getElementById('rotate')
6
+ const frame = document.getElementById('frame')
7
+ const stop = document.getElementById('stop')
8
+
9
+ img.src = defaultSrc
10
+ img.width = 400
11
+
12
+ try {
13
+ const camera = new MockCamera()
14
+
15
+ // Grab a frame from the live feed
16
+ let lastFrame
17
+ frame.addEventListener('click', async () => {
18
+ stop.disabled = true
19
+ rotation.disabled = true
20
+ const rotate = parseInt(rotation.value)
21
+ // Cleanup the last frame captured, if any
22
+ if (lastFrame) {
23
+ URL.revokeObjectURL(lastFrame)
24
+ }
25
+ img.src = lastFrame = await camera.getMostRecentFrame({ rotate })
26
+ document.body.appendChild(frame)
27
+ rotation.disabled = false
28
+ stop.disabled = false
29
+ })
30
+
31
+ // Stop live feed
32
+ stop.addEventListener('click', async () => {
33
+ const result = await camera.stopFeed()
34
+ window.alert(result.message || result.status)
35
+ })
36
+ } catch (e) {
37
+ console.error(e)
38
+ window.alert(`Error: ${e.message}`)
39
+ }
40
+ })()
@@ -2,30 +2,6 @@
2
2
  <html>
3
3
  <head><title>Mock Camera Minimal Example</title></head>
4
4
  <body>
5
- <script type="module">
6
- import MockCamera from '/sdk/js/MockCamera.js'
7
- (async () => {
8
- try {
9
-
10
- // Instantiate a Mock Camera
11
- const camera = new MockCamera()
12
-
13
- // Start the device's live feed and stream it to an img tag
14
- const img = document.createElement('img')
15
- img.src = await camera.streamUrl()
16
- img.height = 400
17
- document.body.appendChild(img)
18
-
19
- // Demo live feed for a few seconds, take a picture, and update the img tag
20
- setTimeout(async () => {
21
- img.src = await camera.takePhoto()
22
- }, 9000)
23
-
24
- } catch (e) {
25
- console.error(e)
26
- alert(`Error: ${e.message}`)
27
- }
28
- })()
29
- </script>
5
+ <script type="module" src="./mockcamera_minimal.js"></script>
30
6
  </body>
31
7
  </html>
@@ -0,0 +1,21 @@
1
+ import MockCamera from '../../../../sdk/js/MockCamera.js'
2
+ (async () => {
3
+ try {
4
+ // Instantiate a Mock Camera
5
+ const camera = new MockCamera()
6
+
7
+ // Start the device's live feed and stream it to an img tag
8
+ const img = document.createElement('img')
9
+ img.src = await camera.streamUrl()
10
+ img.height = 400
11
+ document.body.appendChild(img)
12
+
13
+ // Demo live feed for a few seconds, take a picture, and update the img tag
14
+ setTimeout(async () => {
15
+ img.src = await camera.takePhoto()
16
+ }, 9000)
17
+ } catch (e) {
18
+ console.error(e)
19
+ window.alert(`Error: ${e.message}`)
20
+ }
21
+ })()
@@ -0,0 +1,7 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head><title>Verifone Minimal Example</title></head>
4
+ <body>
5
+ <script type="module" src="./verifone_signature.js"></script>
6
+ </body>
7
+ </html>
@@ -0,0 +1,14 @@
1
+ import Verifone from '../../../../sdk/js/Verifone.js'
2
+ (async () => {
3
+ try {
4
+ const tablet = new Verifone()
5
+
6
+ const img = document.createElement('img')
7
+ img.src = await tablet.signature({ format: 'jpg' })
8
+ await tablet.clear()
9
+ document.body.appendChild(img)
10
+ } catch (e) {
11
+ console.error(e)
12
+ window.alert(`Error: ${e.message}`)
13
+ }
14
+ })()
@@ -3,30 +3,6 @@
3
3
  <head><title>Windows Scanner Example</title></head>
4
4
  <body>
5
5
  <img id="img"/>
6
- <script type="module">
7
- import WindowsScanner from '/sdk/js/WindowsScanner.js'
8
- (async () => {
9
- try {
10
-
11
- const scanner = new WindowsScanner()
12
-
13
- const devices = await scanner.devices();
14
-
15
- if (!devices.length) {
16
- return alert('No Scanner devices found')
17
- }
18
-
19
- let scan = await scanner.scan()
20
-
21
- document.createElement('img')
22
- img.src = await scanner.scan()
23
- document.body.appendChild(img)
24
-
25
- } catch (e) {
26
- console.error(e)
27
- alert(`Error: ${e.message}`)
28
- }
29
- })()
30
- </script>
6
+ <script type="module" src="./windows_scanner_minimal.js"></script>
31
7
  </body>
32
8
  </html>
@@ -0,0 +1,19 @@
1
+ import WindowsScanner from '../../../../sdk/js/WindowsScanner.js'
2
+ (async () => {
3
+ try {
4
+ const scanner = new WindowsScanner()
5
+
6
+ const devices = await scanner.devices()
7
+
8
+ if (!devices.length) {
9
+ return window.alert('No Scanner devices found')
10
+ }
11
+
12
+ const img = document.createElement('img')
13
+ img.src = await scanner.scan()
14
+ document.body.appendChild(img)
15
+ } catch (e) {
16
+ console.error(e)
17
+ window.alert(`Error: ${e.message}`)
18
+ }
19
+ })()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capturebridge/sdk",
3
- "version": "0.9.1",
3
+ "version": "0.10.1",
4
4
  "description": "Capture Bridge JavaScript SDK for web applications",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0"
@@ -1,23 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head><title>Verifone Minimal Example</title></head>
4
- <body>
5
- <script type="module">
6
- import Verifone from '/sdk/js/Verifone.js'
7
- (async () => {
8
- try {
9
- const tablet = new Verifone()
10
-
11
- const img = document.createElement('img')
12
- img.src = await tablet.signature({format: 'jpg'})
13
- await tablet.clear()
14
- document.body.appendChild(img)
15
-
16
- } catch (e) {
17
- console.error(e)
18
- alert(`Error: ${e.message}`)
19
- }
20
- })()
21
- </script>
22
- </body>
23
- </html>