@jaak.ai/stamps 1.0.0-dev.7
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 +385 -0
- package/dist/cjs/document-detector_19.cjs.entry.js +8528 -0
- package/dist/cjs/index-5e4e5e7d.js +1685 -0
- package/dist/cjs/index.cjs.js +2 -0
- package/dist/cjs/loader.cjs.js +22 -0
- package/dist/cjs/mb-tooltip.cjs.entry.js +26 -0
- package/dist/cjs/stamps.cjs.js +23 -0
- package/dist/collection/collection-manifest.json +31 -0
- package/dist/collection/components/document-detector/document-detector.css +154 -0
- package/dist/collection/components/document-detector/document-detector.js +383 -0
- package/dist/collection/components/shared/mb-api-process-status/mb-api-process-status.css +360 -0
- package/dist/collection/components/shared/mb-api-process-status/mb-api-process-status.js +124 -0
- package/dist/collection/components/shared/mb-button/mb-button.css +95 -0
- package/dist/collection/components/shared/mb-button/mb-button.js +201 -0
- package/dist/collection/components/shared/mb-button-classic/mb-button-classic.css +100 -0
- package/dist/collection/components/shared/mb-button-classic/mb-button-classic.js +130 -0
- package/dist/collection/components/shared/mb-camera-experience/mb-camera-experience.css +740 -0
- package/dist/collection/components/shared/mb-camera-experience/mb-camera-experience.js +827 -0
- package/dist/collection/components/shared/mb-camera-experience/mb-camera-experience.utils.js +55 -0
- package/dist/collection/components/shared/mb-camera-selection/mb-camera-selection.css +124 -0
- package/dist/collection/components/shared/mb-camera-selection/mb-camera-selection.js +194 -0
- package/dist/collection/components/shared/mb-camera-toolbar/mb-camera-toolbar.css +80 -0
- package/dist/collection/components/shared/mb-camera-toolbar/mb-camera-toolbar.js +275 -0
- package/dist/collection/components/shared/mb-completed/mb-completed.css +17 -0
- package/dist/collection/components/shared/mb-completed/mb-completed.js +48 -0
- package/dist/collection/components/shared/mb-component/mb-component.css +321 -0
- package/dist/collection/components/shared/mb-component/mb-component.js +2269 -0
- package/dist/collection/components/shared/mb-component/mb-component.utils.js +14 -0
- package/dist/collection/components/shared/mb-container/mb-container.css +7 -0
- package/dist/collection/components/shared/mb-container/mb-container.js +23 -0
- package/dist/collection/components/shared/mb-feedback/mb-feedback.css +36 -0
- package/dist/collection/components/shared/mb-feedback/mb-feedback.js +91 -0
- package/dist/collection/components/shared/mb-feedback/mb-feedback.utils.js +11 -0
- package/dist/collection/components/shared/mb-help/mb-help.css +191 -0
- package/dist/collection/components/shared/mb-help/mb-help.js +409 -0
- package/dist/collection/components/shared/mb-help/mb-help.model.js +5 -0
- package/dist/collection/components/shared/mb-image-box/mb-image-box.css +78 -0
- package/dist/collection/components/shared/mb-image-box/mb-image-box.js +150 -0
- package/dist/collection/components/shared/mb-modal/mb-modal.css +106 -0
- package/dist/collection/components/shared/mb-modal/mb-modal.js +239 -0
- package/dist/collection/components/shared/mb-overlay/mb-overlay.css +46 -0
- package/dist/collection/components/shared/mb-overlay/mb-overlay.js +76 -0
- package/dist/collection/components/shared/mb-progress-tracker/mb-progress-tracker.css +24 -0
- package/dist/collection/components/shared/mb-progress-tracker/mb-progress-tracker.js +80 -0
- package/dist/collection/components/shared/mb-screen/mb-screen.css +19 -0
- package/dist/collection/components/shared/mb-screen/mb-screen.js +48 -0
- package/dist/collection/components/shared/mb-spinner/mb-spinner.css +30 -0
- package/dist/collection/components/shared/mb-spinner/mb-spinner.js +67 -0
- package/dist/collection/components/shared/mb-tooltip/mb-tooltip.css +62 -0
- package/dist/collection/components/shared/mb-tooltip/mb-tooltip.js +150 -0
- package/dist/collection/components/shared/mb-tooltip-advanced/mb-tooltip-advanced.css +91 -0
- package/dist/collection/components/shared/mb-tooltip-advanced/mb-tooltip-advanced.js +96 -0
- package/dist/collection/index.js +1 -0
- package/dist/collection/utils/data-structures.js +189 -0
- package/dist/collection/utils/device.helpers.js +37 -0
- package/dist/collection/utils/error-structures.js +47 -0
- package/dist/collection/utils/generic.helpers.js +82 -0
- package/dist/collection/utils/sdk.service.js +943 -0
- package/dist/collection/utils/state-lifter.js +3 -0
- package/dist/collection/utils/status.document-detector.js +15 -0
- package/dist/collection/utils/translation.service.js +97 -0
- package/dist/esm/document-detector_19.entry.js +8506 -0
- package/dist/esm/index-dc740acb.js +1656 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/loader.js +18 -0
- package/dist/esm/mb-tooltip.entry.js +22 -0
- package/dist/esm/polyfills/core-js.js +11 -0
- package/dist/esm/polyfills/css-shim.js +1 -0
- package/dist/esm/polyfills/dom.js +79 -0
- package/dist/esm/polyfills/es5-html-element.js +1 -0
- package/dist/esm/polyfills/index.js +34 -0
- package/dist/esm/polyfills/system.js +6 -0
- package/dist/esm/stamps.js +18 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/stamps/index.esm.js +0 -0
- package/dist/stamps/p-02990b18.entry.js +9 -0
- package/dist/stamps/p-7f07a434.js +2 -0
- package/dist/stamps/p-ec3f5972.entry.js +1 -0
- package/dist/stamps/stamps.esm.js +1 -0
- package/dist/types/components/document-detector/document-detector.d.ts +84 -0
- package/dist/types/components/shared/mb-api-process-status/mb-api-process-status.d.ts +30 -0
- package/dist/types/components/shared/mb-button/mb-button.d.ts +41 -0
- package/dist/types/components/shared/mb-button-classic/mb-button-classic.d.ts +27 -0
- package/dist/types/components/shared/mb-camera-experience/mb-camera-experience.d.ts +141 -0
- package/dist/types/components/shared/mb-camera-experience/mb-camera-experience.utils.d.ts +3 -0
- package/dist/types/components/shared/mb-camera-selection/mb-camera-selection.d.ts +33 -0
- package/dist/types/components/shared/mb-camera-toolbar/mb-camera-toolbar.d.ts +54 -0
- package/dist/types/components/shared/mb-completed/mb-completed.d.ts +12 -0
- package/dist/types/components/shared/mb-component/mb-component.d.ts +308 -0
- package/dist/types/components/shared/mb-component/mb-component.utils.d.ts +3 -0
- package/dist/types/components/shared/mb-container/mb-container.d.ts +8 -0
- package/dist/types/components/shared/mb-feedback/mb-feedback.d.ts +19 -0
- package/dist/types/components/shared/mb-feedback/mb-feedback.utils.d.ts +2 -0
- package/dist/types/components/shared/mb-help/mb-help.d.ts +66 -0
- package/dist/types/components/shared/mb-help/mb-help.model.d.ts +9 -0
- package/dist/types/components/shared/mb-image-box/mb-image-box.d.ts +35 -0
- package/dist/types/components/shared/mb-modal/mb-modal.d.ts +53 -0
- package/dist/types/components/shared/mb-overlay/mb-overlay.d.ts +17 -0
- package/dist/types/components/shared/mb-progress-tracker/mb-progress-tracker.d.ts +19 -0
- package/dist/types/components/shared/mb-screen/mb-screen.d.ts +12 -0
- package/dist/types/components/shared/mb-spinner/mb-spinner.d.ts +16 -0
- package/dist/types/components/shared/mb-tooltip/mb-tooltip.d.ts +10 -0
- package/dist/types/components/shared/mb-tooltip-advanced/mb-tooltip-advanced.d.ts +7 -0
- package/dist/types/components.d.ts +1381 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/stencil-public-runtime.d.ts +1637 -0
- package/dist/types/utils/data-structures.d.ts +264 -0
- package/dist/types/utils/device.helpers.d.ts +7 -0
- package/dist/types/utils/error-structures.d.ts +44 -0
- package/dist/types/utils/generic.helpers.d.ts +21 -0
- package/dist/types/utils/sdk.service.d.ts +52 -0
- package/dist/types/utils/state-lifter.d.ts +3 -0
- package/dist/types/utils/status.document-detector.d.ts +14 -0
- package/dist/types/utils/translation.service.d.ts +77 -0
- package/loader/cdn.js +3 -0
- package/loader/index.cjs.js +3 -0
- package/loader/index.d.ts +21 -0
- package/loader/index.es2017.js +3 -0
- package/loader/index.js +4 -0
- package/loader/package.json +11 -0
- package/package.json +63 -0
|
@@ -0,0 +1,943 @@
|
|
|
1
|
+
import * as BlinkIDSDK from "@microblink/blinkid-in-browser-sdk";
|
|
2
|
+
import { AvailableRecognizers, CameraExperience, EventReady, ImageRecognitionType, RecognitionStatus, SDKError, } from "./data-structures";
|
|
3
|
+
import * as ErrorTypes from "./error-structures";
|
|
4
|
+
import { globalState } from "./state-lifter";
|
|
5
|
+
/**
|
|
6
|
+
* Get the additional processing information from the BlinkIdResult.
|
|
7
|
+
* @param result
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
10
|
+
export function getAdditionalProcessingInfo(result) {
|
|
11
|
+
if ("scanningFirstSideDone" in result) {
|
|
12
|
+
return !result.scanningFirstSideDone
|
|
13
|
+
? result.frontAdditionalProcessingInfo
|
|
14
|
+
: result.backAdditionalProcessingInfo;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
return result.additionalProcessingInfo;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function getImageAnalysisResult(result) {
|
|
21
|
+
if ("scanningFirstSideDone" in result) {
|
|
22
|
+
return !result.scanningFirstSideDone
|
|
23
|
+
? result.frontImageAnalysisResult
|
|
24
|
+
: result.backImageAnalysisResult;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
return result.imageAnalysisResult;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export const isFirstSideDone = (result) => {
|
|
31
|
+
return "scanningFirstSideDone" in result && result.scanningFirstSideDone;
|
|
32
|
+
};
|
|
33
|
+
export async function getCameraDevices() {
|
|
34
|
+
const devices = await BlinkIDSDK.getCameraDevices();
|
|
35
|
+
const allDevices = devices.frontCameras.concat(devices.backCameras);
|
|
36
|
+
const finalEntries = allDevices.map((el) => {
|
|
37
|
+
return {
|
|
38
|
+
prettyName: el.label,
|
|
39
|
+
details: el,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
return finalEntries;
|
|
43
|
+
}
|
|
44
|
+
export class SdkService {
|
|
45
|
+
constructor() {
|
|
46
|
+
this.cancelInitiatedFromOutside = false;
|
|
47
|
+
this.showOverlay = false;
|
|
48
|
+
this.lastKnownCardRotation = BlinkIDSDK.CardRotation.None;
|
|
49
|
+
this.lastDetectionStatus = BlinkIDSDK.DetectionStatus.Failed;
|
|
50
|
+
this.eventEmitter$ = document.createElement("a");
|
|
51
|
+
}
|
|
52
|
+
delete() {
|
|
53
|
+
this.sdk?.delete();
|
|
54
|
+
}
|
|
55
|
+
async initialize(licenseKey, sdkSettings) {
|
|
56
|
+
const loadSettings = new BlinkIDSDK.WasmSDKLoadSettings(licenseKey);
|
|
57
|
+
loadSettings.allowHelloMessage = sdkSettings.allowHelloMessage;
|
|
58
|
+
loadSettings.engineLocation = sdkSettings.engineLocation;
|
|
59
|
+
loadSettings.workerLocation = await fetch(sdkSettings.workerLocation)
|
|
60
|
+
.then((response) => response.blob())
|
|
61
|
+
.then((blob) => window.URL.createObjectURL(blob));
|
|
62
|
+
loadSettings.blinkIdVariant = sdkSettings.blinkIdVariant;
|
|
63
|
+
if (sdkSettings.wasmType) {
|
|
64
|
+
loadSettings.wasmType = sdkSettings.wasmType;
|
|
65
|
+
}
|
|
66
|
+
return new Promise((resolve) => {
|
|
67
|
+
BlinkIDSDK.loadWasmModule(loadSettings)
|
|
68
|
+
.then((sdk) => {
|
|
69
|
+
this.sdk = sdk;
|
|
70
|
+
this.showOverlay = sdk.showOverlay;
|
|
71
|
+
resolve(new EventReady(this.sdk));
|
|
72
|
+
})
|
|
73
|
+
.catch((error) => {
|
|
74
|
+
resolve(new SDKError(ErrorTypes.componentErrors.sdkLoadFailed, error));
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
checkRecognizers(recognizers) {
|
|
79
|
+
if (!recognizers || !recognizers.length) {
|
|
80
|
+
return {
|
|
81
|
+
status: false,
|
|
82
|
+
message: "There are no provided recognizers!",
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
for (const recognizer of recognizers) {
|
|
86
|
+
if (!this.isRecognizerAvailable(recognizer)) {
|
|
87
|
+
return {
|
|
88
|
+
status: false,
|
|
89
|
+
message: `Recognizer "${recognizer}" doesn't exist!`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (recognizer === "BlinkIdMultiSideRecognizer" &&
|
|
93
|
+
recognizers.length > 1) {
|
|
94
|
+
return {
|
|
95
|
+
status: false,
|
|
96
|
+
message: 'Recognizer "BlinkIdMultiSideRecognizer" cannot be used in combination with other recognizers!',
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
status: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
getDesiredCameraExperience(_recognizers = [], _recognizerOptions = {}) {
|
|
105
|
+
if (_recognizers.indexOf("BlinkIdMultiSideRecognizer") > -1) {
|
|
106
|
+
return CameraExperience.CardMultiSide;
|
|
107
|
+
}
|
|
108
|
+
if (_recognizers.indexOf("BlinkIdSingleSideRecognizer") > -1) {
|
|
109
|
+
return CameraExperience.CardSingleSide;
|
|
110
|
+
}
|
|
111
|
+
return CameraExperience.Barcode;
|
|
112
|
+
}
|
|
113
|
+
async scanFromCamera(configuration, eventCallback) {
|
|
114
|
+
eventCallback({ status: RecognitionStatus.Preparing });
|
|
115
|
+
this.cancelInitiatedFromOutside = false;
|
|
116
|
+
// Prepare terminate mechanism before recognizer and runner instances are created
|
|
117
|
+
this.eventEmitter$.addEventListener("terminate", async () => {
|
|
118
|
+
this.videoRecognizer?.cancelRecognition?.();
|
|
119
|
+
window.setTimeout(() => this.videoRecognizer?.releaseVideoFeed?.(), 1);
|
|
120
|
+
if (recognizerRunner) {
|
|
121
|
+
try {
|
|
122
|
+
await recognizerRunner.delete();
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
// Psst, this error should not happen.
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
for (const recognizer of recognizers) {
|
|
129
|
+
if (!recognizer) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (recognizer.recognizer?.objectHandle > -1) {
|
|
133
|
+
recognizer.recognizer.delete?.();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
// Prepare recognizers and runner
|
|
138
|
+
const recognizers = await this.createRecognizers(configuration.recognizers, configuration.recognizerOptions, eventCallback);
|
|
139
|
+
const recognizerRunner = await this.createRecognizerRunner(recognizers);
|
|
140
|
+
if (configuration.pingProxyUrl) {
|
|
141
|
+
await recognizerRunner.setPingProxyUrl(configuration.pingProxyUrl);
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
this.videoRecognizer =
|
|
145
|
+
await BlinkIDSDK.VideoRecognizer.createVideoRecognizerFromCameraStream(configuration.cameraFeed, recognizerRunner, configuration.cameraId);
|
|
146
|
+
eventCallback({ status: RecognitionStatus.Ready });
|
|
147
|
+
await this.videoRecognizer.setVideoRecognitionMode(BlinkIDSDK.VideoRecognitionMode.Recognition);
|
|
148
|
+
const activeRecognizer = recognizers[0]
|
|
149
|
+
.recognizer;
|
|
150
|
+
const recognizerSettings = await activeRecognizer.currentSettings();
|
|
151
|
+
// We do per-frame operations here
|
|
152
|
+
this.videoRecognizer.setOnFrameProcessed((result) => {
|
|
153
|
+
window.setTimeout(() => {
|
|
154
|
+
// detection status callback is triggered before the video frame callback
|
|
155
|
+
// reset it after each frame is done processing
|
|
156
|
+
this.lastDetectionStatus = BlinkIDSDK.DetectionStatus.Failed;
|
|
157
|
+
}, 0);
|
|
158
|
+
const isMultiside = "scanningFirstSideDone" in result;
|
|
159
|
+
const isFrontSuccessFrame = result.processingStatus ===
|
|
160
|
+
BlinkIDSDK.ProcessingStatus.AwaitingOtherSide;
|
|
161
|
+
//We start scanning the second side only after not the success frame
|
|
162
|
+
const isOnSecondSide = isMultiside && result.scanningFirstSideDone && !isFrontSuccessFrame;
|
|
163
|
+
const additionalProcessingInfo = getAdditionalProcessingInfo(result);
|
|
164
|
+
const imageAnalysisResult = getImageAnalysisResult(result);
|
|
165
|
+
const isPassport = result.classInfo.documentType === BlinkIDSDK.DocumentType.PASSPORT;
|
|
166
|
+
// horrible hack to get the passport status to the global state
|
|
167
|
+
globalState.isPassport = isPassport;
|
|
168
|
+
const notDetected = this.lastDetectionStatus === BlinkIDSDK.DetectionStatus.Failed;
|
|
169
|
+
if (imageAnalysisResult.cardRotation) {
|
|
170
|
+
// save last known rotation in case we lose the document
|
|
171
|
+
this.lastKnownCardRotation = imageAnalysisResult.cardRotation;
|
|
172
|
+
}
|
|
173
|
+
// framing
|
|
174
|
+
switch (this.lastDetectionStatus) {
|
|
175
|
+
case BlinkIDSDK.DetectionStatus.CameraTooFar:
|
|
176
|
+
eventCallback({
|
|
177
|
+
status: RecognitionStatus.DetectionStatusCameraTooHigh,
|
|
178
|
+
});
|
|
179
|
+
break;
|
|
180
|
+
case BlinkIDSDK.DetectionStatus.FallbackSuccess:
|
|
181
|
+
eventCallback({
|
|
182
|
+
status: RecognitionStatus.DetectionStatusFallbackSuccess,
|
|
183
|
+
});
|
|
184
|
+
break;
|
|
185
|
+
case BlinkIDSDK.DetectionStatus.DocumentPartiallyVisible:
|
|
186
|
+
eventCallback({ status: RecognitionStatus.DetectionStatusPartial });
|
|
187
|
+
break;
|
|
188
|
+
case BlinkIDSDK.DetectionStatus.CameraAngleTooSteep:
|
|
189
|
+
eventCallback({
|
|
190
|
+
status: RecognitionStatus.DetectionStatusCameraAtAngle,
|
|
191
|
+
});
|
|
192
|
+
break;
|
|
193
|
+
case BlinkIDSDK.DetectionStatus.CameraTooClose:
|
|
194
|
+
eventCallback({
|
|
195
|
+
status: RecognitionStatus.DetectionStatusCameraTooNear,
|
|
196
|
+
});
|
|
197
|
+
break;
|
|
198
|
+
case BlinkIDSDK.DetectionStatus.DocumentTooCloseToCameraEdge:
|
|
199
|
+
eventCallback({
|
|
200
|
+
status: RecognitionStatus.DetectionStatusDocumentTooCloseToEdge,
|
|
201
|
+
});
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
// handle no detection
|
|
205
|
+
if (notDetected) {
|
|
206
|
+
if (!isPassport) {
|
|
207
|
+
eventCallback({
|
|
208
|
+
// this status doesn't seem to do anything
|
|
209
|
+
// the logic is probably handled as a "default" state somewhere else
|
|
210
|
+
status: RecognitionStatus.DetectionStatusFail,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
// Get the user to scan the passport
|
|
215
|
+
// again, refer to the page relative to the last one scanned
|
|
216
|
+
if (isOnSecondSide) {
|
|
217
|
+
switch (this.lastKnownCardRotation) {
|
|
218
|
+
case BlinkIDSDK.CardRotation.None: {
|
|
219
|
+
eventCallback({
|
|
220
|
+
status: RecognitionStatus.MovePassportUpError,
|
|
221
|
+
});
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
case BlinkIDSDK.CardRotation.Clockwise90: {
|
|
225
|
+
eventCallback({
|
|
226
|
+
status: RecognitionStatus.MovePassportRightError,
|
|
227
|
+
});
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
case BlinkIDSDK.CardRotation.CounterClockwise90: {
|
|
231
|
+
eventCallback({
|
|
232
|
+
status: RecognitionStatus.MovePassportLeftError,
|
|
233
|
+
});
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
case BlinkIDSDK.CardRotation.UpsideDown: {
|
|
237
|
+
eventCallback({
|
|
238
|
+
status: RecognitionStatus.MovePassportDownError,
|
|
239
|
+
});
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
// handle glare
|
|
248
|
+
if (imageAnalysisResult.glareDetected &&
|
|
249
|
+
recognizerSettings.enableGlareFilter) {
|
|
250
|
+
eventCallback({
|
|
251
|
+
status: RecognitionStatus.GlareDetected,
|
|
252
|
+
});
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
// handle blur
|
|
256
|
+
if (imageAnalysisResult.blurDetected &&
|
|
257
|
+
recognizerSettings.enableBlurFilter) {
|
|
258
|
+
eventCallback({
|
|
259
|
+
status: RecognitionStatus.BlurDetected,
|
|
260
|
+
});
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
// handle face occlusion
|
|
264
|
+
if (additionalProcessingInfo.imageExtractionFailures?.includes(BlinkIDSDK.ImageExtractionType.Face)) {
|
|
265
|
+
eventCallback({
|
|
266
|
+
status: RecognitionStatus.FacePhotoCovered,
|
|
267
|
+
});
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
// first side done - show flip/move. This status triggers only once
|
|
271
|
+
if (isFrontSuccessFrame) {
|
|
272
|
+
if (!isPassport) {
|
|
273
|
+
eventCallback({ status: RecognitionStatus.OnFirstSideResult });
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
// Passport only branch
|
|
277
|
+
switch (this.lastKnownCardRotation) {
|
|
278
|
+
case BlinkIDSDK.CardRotation.None: {
|
|
279
|
+
eventCallback({
|
|
280
|
+
status: RecognitionStatus.MovePassportUp,
|
|
281
|
+
});
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
case BlinkIDSDK.CardRotation.Clockwise90: {
|
|
285
|
+
eventCallback({
|
|
286
|
+
status: RecognitionStatus.MovePassportRight,
|
|
287
|
+
});
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
case BlinkIDSDK.CardRotation.CounterClockwise90: {
|
|
291
|
+
eventCallback({
|
|
292
|
+
status: RecognitionStatus.MovePassportLeft,
|
|
293
|
+
});
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
case BlinkIDSDK.CardRotation.UpsideDown: {
|
|
297
|
+
eventCallback({
|
|
298
|
+
status: RecognitionStatus.MovePassportDown,
|
|
299
|
+
});
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
// scanning wrong side
|
|
307
|
+
if (result.processingStatus ===
|
|
308
|
+
BlinkIDSDK.ProcessingStatus.ScanningWrongSide) {
|
|
309
|
+
if (isPassport) {
|
|
310
|
+
// Passport only branch
|
|
311
|
+
switch (this.lastKnownCardRotation) {
|
|
312
|
+
case BlinkIDSDK.CardRotation.None: {
|
|
313
|
+
eventCallback({
|
|
314
|
+
status: RecognitionStatus.MovePassportUpError,
|
|
315
|
+
});
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
case BlinkIDSDK.CardRotation.Clockwise90: {
|
|
319
|
+
eventCallback({
|
|
320
|
+
status: RecognitionStatus.MovePassportRightError,
|
|
321
|
+
});
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
case BlinkIDSDK.CardRotation.CounterClockwise90: {
|
|
325
|
+
eventCallback({
|
|
326
|
+
status: RecognitionStatus.MovePassportLeftError,
|
|
327
|
+
});
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
case BlinkIDSDK.CardRotation.UpsideDown: {
|
|
331
|
+
eventCallback({
|
|
332
|
+
status: RecognitionStatus.MovePassportDownError,
|
|
333
|
+
});
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
// some other document, maybe unclassified?
|
|
340
|
+
eventCallback({
|
|
341
|
+
status: RecognitionStatus.WrongSide,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
// fallback - success?
|
|
347
|
+
eventCallback({ status: RecognitionStatus.DetectionStatusSuccess });
|
|
348
|
+
});
|
|
349
|
+
//////////////////////////////////////////////////
|
|
350
|
+
// Start recognition
|
|
351
|
+
await this.videoRecognizer
|
|
352
|
+
.startRecognition(async (recognitionState) => {
|
|
353
|
+
this.videoRecognizer.pauseRecognition();
|
|
354
|
+
eventCallback({ status: RecognitionStatus.Processing });
|
|
355
|
+
if (recognitionState !== BlinkIDSDK.RecognizerResultState.Empty) {
|
|
356
|
+
for (const recognizer of recognizers) {
|
|
357
|
+
const results = await recognizer.recognizer.getResult();
|
|
358
|
+
this.recognizerName = recognizer.recognizer.recognizerName;
|
|
359
|
+
if (!results ||
|
|
360
|
+
results.state === BlinkIDSDK.RecognizerResultState.Empty) {
|
|
361
|
+
eventCallback({
|
|
362
|
+
status: RecognitionStatus.EmptyResultState,
|
|
363
|
+
data: {
|
|
364
|
+
initiatedByUser: this.cancelInitiatedFromOutside,
|
|
365
|
+
recognizerName: this.recognizerName,
|
|
366
|
+
},
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
const recognitionResults = {
|
|
371
|
+
recognizer: results,
|
|
372
|
+
recognizerName: this.recognizerName,
|
|
373
|
+
};
|
|
374
|
+
if (configuration.recognizerOptions?.returnSignedJSON) {
|
|
375
|
+
recognitionResults.resultSignedJSON =
|
|
376
|
+
await recognizer.recognizer.toSignedJSON();
|
|
377
|
+
}
|
|
378
|
+
if (results.fullDocumentFrontImage.encodedImage) {
|
|
379
|
+
results.fullDocumentFrontImage.encodedImage = this.base64ArrayBuffer(results.fullDocumentFrontImage.encodedImage);
|
|
380
|
+
}
|
|
381
|
+
if (results.fullDocumentBackImage.encodedImage) {
|
|
382
|
+
results.fullDocumentBackImage.encodedImage = this.base64ArrayBuffer(results.fullDocumentBackImage.encodedImage);
|
|
383
|
+
}
|
|
384
|
+
if (results.signatureImage.encodedImage) {
|
|
385
|
+
results.signatureImage.encodedImage = this.base64ArrayBuffer(results.signatureImage.encodedImage);
|
|
386
|
+
}
|
|
387
|
+
if (results.faceImage.encodedImage) {
|
|
388
|
+
results.faceImage.encodedImage = this.base64ArrayBuffer(results.faceImage.encodedImage);
|
|
389
|
+
}
|
|
390
|
+
let borderlessFront = undefined;
|
|
391
|
+
let borderlessBack = undefined;
|
|
392
|
+
if (results.fullDocumentFrontImage?.encodedImage) {
|
|
393
|
+
let base64Image;
|
|
394
|
+
if (typeof results.fullDocumentFrontImage.encodedImage === 'string') {
|
|
395
|
+
base64Image = results.fullDocumentFrontImage.encodedImage;
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
base64Image = this.base64ArrayBuffer(results.fullDocumentFrontImage.encodedImage);
|
|
399
|
+
}
|
|
400
|
+
if (!base64Image.startsWith('data:image/')) {
|
|
401
|
+
base64Image = 'data:image/jpeg;base64,' + base64Image;
|
|
402
|
+
}
|
|
403
|
+
borderlessFront = await this.cropDocumentFromImage(base64Image, {
|
|
404
|
+
upFactor: 0.1,
|
|
405
|
+
downFactor: 0.1,
|
|
406
|
+
leftFactor: 0.1,
|
|
407
|
+
rightFactor: 0.1
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
if (results.fullDocumentBackImage?.encodedImage) {
|
|
411
|
+
let base64Image;
|
|
412
|
+
if (typeof results.fullDocumentBackImage.encodedImage === 'string') {
|
|
413
|
+
base64Image = results.fullDocumentBackImage.encodedImage;
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
base64Image = this.base64ArrayBuffer(results.fullDocumentBackImage.encodedImage);
|
|
417
|
+
}
|
|
418
|
+
if (!base64Image.startsWith('data:image/')) {
|
|
419
|
+
base64Image = 'data:image/jpeg;base64,' + base64Image;
|
|
420
|
+
}
|
|
421
|
+
borderlessBack = await this.cropDocumentFromImage(base64Image, {
|
|
422
|
+
upFactor: 0.1,
|
|
423
|
+
downFactor: 0.1,
|
|
424
|
+
leftFactor: 0.1,
|
|
425
|
+
rightFactor: 0.1
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
const scanData = {
|
|
429
|
+
result: {
|
|
430
|
+
status: RecognitionStatus.ScanSuccessful,
|
|
431
|
+
data: {
|
|
432
|
+
type: "RESULTS",
|
|
433
|
+
message: "results-success",
|
|
434
|
+
data: {
|
|
435
|
+
documentData: {
|
|
436
|
+
generalData: {
|
|
437
|
+
type: results.mrz.documentCode,
|
|
438
|
+
nationality: results.nationality.latin,
|
|
439
|
+
name: results.fullName.latin || results.firstName.latin,
|
|
440
|
+
surname: results.fathersName.latin || results.lastName.latin,
|
|
441
|
+
motherSurname: results.mothersName.latin,
|
|
442
|
+
address: results.address.latin,
|
|
443
|
+
expiryPermanent: false,
|
|
444
|
+
birthDate: results.frontViz.dateOfBirth.originalString.latin,
|
|
445
|
+
gender: results.sex.latin,
|
|
446
|
+
documentImage: {
|
|
447
|
+
frontFull: results.fullDocumentFrontImage.encodedImage,
|
|
448
|
+
backFull: results.fullDocumentBackImage.encodedImage,
|
|
449
|
+
front: borderlessFront,
|
|
450
|
+
back: borderlessBack,
|
|
451
|
+
signature: results.signatureImage.encodedImage,
|
|
452
|
+
face: results.faceImage.encodedImage
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
mechanicalReadingZone: results.mrz.rawMRZString,
|
|
456
|
+
specificData: [
|
|
457
|
+
{
|
|
458
|
+
label: "curp",
|
|
459
|
+
value: results.personalIdNumber.latin
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
label: "electorKey",
|
|
463
|
+
value: results.frontViz.documentAdditionalNumber.latin
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
label: "registerYear",
|
|
467
|
+
value: results.frontViz.dateOfIssue.year
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
label: "registerMonth",
|
|
471
|
+
value: results.frontViz.dateOfIssue.month
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
label: "emissionYear",
|
|
475
|
+
value: results.frontViz.dateOfIssue.year
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
label: "identificationOCR",
|
|
479
|
+
value: results.mrz.sanitizedOpt1
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
label: "numIdentificationCredential",
|
|
483
|
+
value: results.mrz.documentNumber
|
|
484
|
+
}
|
|
485
|
+
]
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
},
|
|
489
|
+
},
|
|
490
|
+
initiatedByUser: this.cancelInitiatedFromOutside,
|
|
491
|
+
};
|
|
492
|
+
eventCallback({
|
|
493
|
+
status: RecognitionStatus.ScanSuccessful,
|
|
494
|
+
data: scanData,
|
|
495
|
+
});
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
eventCallback({
|
|
502
|
+
status: RecognitionStatus.EmptyResultState,
|
|
503
|
+
data: {
|
|
504
|
+
initiatedByUser: this.cancelInitiatedFromOutside,
|
|
505
|
+
recognizerName: "",
|
|
506
|
+
},
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
window.setTimeout(() => void this.cancelRecognition(), 400);
|
|
510
|
+
}, configuration.recognitionTimeout)
|
|
511
|
+
.then(() => {
|
|
512
|
+
/* Scanning... */
|
|
513
|
+
})
|
|
514
|
+
.catch((error) => {
|
|
515
|
+
throw error;
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
catch (error) {
|
|
519
|
+
if (!error.code) {
|
|
520
|
+
eventCallback({ status: RecognitionStatus.UnknownError });
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
switch (error.code) {
|
|
524
|
+
case BlinkIDSDK.ErrorCodes.VIDEO_RECOGNIZER_MEDIA_DEVICES_UNSUPPORTED:
|
|
525
|
+
eventCallback({
|
|
526
|
+
status: RecognitionStatus.NoSupportForMediaDevices,
|
|
527
|
+
});
|
|
528
|
+
break;
|
|
529
|
+
case BlinkIDSDK.ErrorCodes.VIDEO_RECOGNIZER_CAMERA_MISSING:
|
|
530
|
+
eventCallback({ status: RecognitionStatus.CameraNotFound });
|
|
531
|
+
break;
|
|
532
|
+
case BlinkIDSDK.ErrorCodes.VIDEO_RECOGNIZER_CAMERA_NOT_ALLOWED:
|
|
533
|
+
eventCallback({ status: RecognitionStatus.CameraNotAllowed });
|
|
534
|
+
break;
|
|
535
|
+
case BlinkIDSDK.ErrorCodes.VIDEO_RECOGNIZER_CAMERA_IN_USE:
|
|
536
|
+
eventCallback({ status: RecognitionStatus.CameraInUse });
|
|
537
|
+
break;
|
|
538
|
+
default:
|
|
539
|
+
eventCallback({ status: RecognitionStatus.UnableToAccessCamera });
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
console.warn("Error in VideoRecognizer", error.code, error.message);
|
|
544
|
+
void this.cancelRecognition();
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
async cropDocumentFromImage(imageBase64, factors) {
|
|
548
|
+
return new Promise((resolve, reject) => {
|
|
549
|
+
const image = new window.Image();
|
|
550
|
+
image.onload = () => {
|
|
551
|
+
const width = image.width;
|
|
552
|
+
const height = image.height;
|
|
553
|
+
const docWidth = width / (1 + factors.leftFactor + factors.rightFactor);
|
|
554
|
+
const docHeight = height / (1 + factors.upFactor + factors.downFactor);
|
|
555
|
+
const offsetX = factors.leftFactor * docWidth;
|
|
556
|
+
const offsetY = factors.upFactor * docHeight;
|
|
557
|
+
const canvas = document.createElement('canvas');
|
|
558
|
+
canvas.width = docWidth;
|
|
559
|
+
canvas.height = docHeight;
|
|
560
|
+
const ctx = canvas.getContext('2d');
|
|
561
|
+
ctx.drawImage(image, offsetX, offsetY, docWidth, docHeight, 0, 0, docWidth, docHeight);
|
|
562
|
+
resolve(canvas.toDataURL().replace(/^data:image\/(png|jpg);base64,/, ""));
|
|
563
|
+
};
|
|
564
|
+
image.onerror = reject;
|
|
565
|
+
image.src = imageBase64;
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
base64ArrayBuffer(arrayBuffer) {
|
|
569
|
+
let base64 = "";
|
|
570
|
+
const encodings = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
571
|
+
const bytes = new Uint8Array(arrayBuffer);
|
|
572
|
+
const byteLength = bytes.byteLength;
|
|
573
|
+
const byteRemainder = byteLength % 3;
|
|
574
|
+
const mainLength = byteLength - byteRemainder;
|
|
575
|
+
let a;
|
|
576
|
+
let b;
|
|
577
|
+
let c;
|
|
578
|
+
let d;
|
|
579
|
+
let chunk;
|
|
580
|
+
// Main loop deals with bytes in chunks of 3
|
|
581
|
+
for (let i = 0; i < mainLength; i = i + 3) {
|
|
582
|
+
// Combine the three bytes into a single integer
|
|
583
|
+
// tslint:disable-next-line:no-bitwise
|
|
584
|
+
chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
|
|
585
|
+
// Use bitmasks to extract 6-bit segments from the triplet
|
|
586
|
+
// tslint:disable-next-line:no-bitwise
|
|
587
|
+
a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18
|
|
588
|
+
// tslint:disable-next-line:no-bitwise
|
|
589
|
+
b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12
|
|
590
|
+
// tslint:disable-next-line:no-bitwise
|
|
591
|
+
c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6
|
|
592
|
+
// tslint:disable-next-line:no-bitwise
|
|
593
|
+
d = chunk & 63; // 63 = 2^6 - 1
|
|
594
|
+
// Convert the raw binary segments to the appropriate ASCII encoding
|
|
595
|
+
base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d];
|
|
596
|
+
}
|
|
597
|
+
// Deal with the remaining bytes and padding
|
|
598
|
+
if (byteRemainder === 1) {
|
|
599
|
+
chunk = bytes[mainLength];
|
|
600
|
+
// tslint:disable-next-line:no-bitwise
|
|
601
|
+
a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2
|
|
602
|
+
// Set the 4 least significant bits to zero
|
|
603
|
+
// tslint:disable-next-line:no-bitwise
|
|
604
|
+
b = (chunk & 3) << 4; // 3 = 2^2 - 1
|
|
605
|
+
base64 += encodings[a] + encodings[b] + "==";
|
|
606
|
+
}
|
|
607
|
+
else if (byteRemainder === 2) {
|
|
608
|
+
// tslint:disable-next-line:no-bitwise
|
|
609
|
+
chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1];
|
|
610
|
+
// tslint:disable-next-line:no-bitwise
|
|
611
|
+
a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10
|
|
612
|
+
// tslint:disable-next-line:no-bitwise
|
|
613
|
+
b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4
|
|
614
|
+
// Set the 2 least significant bits to zero
|
|
615
|
+
// tslint:disable-next-line:no-bitwise
|
|
616
|
+
c = (chunk & 15) << 2; // 15 = 2^4 - 1
|
|
617
|
+
base64 += encodings[a] + encodings[b] + encodings[c] + "=";
|
|
618
|
+
}
|
|
619
|
+
return base64;
|
|
620
|
+
}
|
|
621
|
+
async flipCamera() {
|
|
622
|
+
await this.videoRecognizer.flipCamera();
|
|
623
|
+
}
|
|
624
|
+
isCameraFlipped() {
|
|
625
|
+
if (!this.videoRecognizer) {
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
return this.videoRecognizer.isCameraFlipped();
|
|
629
|
+
}
|
|
630
|
+
isScanFromImageAvailable(_recognizers = [], _recognizerOptions = {}) {
|
|
631
|
+
return true;
|
|
632
|
+
}
|
|
633
|
+
getScanFromImageType(_recognizers = [], _recognizerOptions = {}) {
|
|
634
|
+
if (_recognizers.indexOf("BlinkIdMultiSideRecognizer") > -1) {
|
|
635
|
+
return ImageRecognitionType.MultiSide;
|
|
636
|
+
}
|
|
637
|
+
return ImageRecognitionType.SingleSide;
|
|
638
|
+
}
|
|
639
|
+
async scanFromImage(configuration, eventCallback) {
|
|
640
|
+
eventCallback({ status: RecognitionStatus.Preparing });
|
|
641
|
+
const recognizers = await this.createRecognizers(configuration.recognizers, configuration.recognizerOptions, eventCallback);
|
|
642
|
+
const recognizerRunner = await this.createRecognizerRunner(recognizers);
|
|
643
|
+
if (configuration.pingProxyUrl) {
|
|
644
|
+
await recognizerRunner.setPingProxyUrl(configuration.pingProxyUrl);
|
|
645
|
+
}
|
|
646
|
+
const handleTerminate = async () => {
|
|
647
|
+
this.eventEmitter$.removeEventListener("terminate", handleTerminate);
|
|
648
|
+
if (recognizerRunner) {
|
|
649
|
+
try {
|
|
650
|
+
await recognizerRunner.delete();
|
|
651
|
+
}
|
|
652
|
+
catch (error) {
|
|
653
|
+
// Psst, this error should not happen.
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
for (const recognizer of recognizers) {
|
|
657
|
+
if (!recognizer) {
|
|
658
|
+
continue;
|
|
659
|
+
}
|
|
660
|
+
if (recognizer.recognizer?.objectHandle > -1) {
|
|
661
|
+
recognizer.recognizer.delete?.();
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
this.eventEmitter$.dispatchEvent(new Event("terminate:done"));
|
|
665
|
+
};
|
|
666
|
+
this.eventEmitter$.addEventListener("terminate", handleTerminate);
|
|
667
|
+
// Get image file
|
|
668
|
+
if (!configuration.file ||
|
|
669
|
+
!RegExp(/^image\//).exec(configuration.file.type)) {
|
|
670
|
+
eventCallback({ status: RecognitionStatus.NoImageFileFound });
|
|
671
|
+
window.setTimeout(() => void this.cancelRecognition(), 500);
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
const file = configuration.file;
|
|
675
|
+
const imageElement = new Image();
|
|
676
|
+
imageElement.src = URL.createObjectURL(file);
|
|
677
|
+
await imageElement.decode();
|
|
678
|
+
const imageFrame = BlinkIDSDK.captureFrame(imageElement);
|
|
679
|
+
// Get results
|
|
680
|
+
eventCallback({ status: RecognitionStatus.Processing });
|
|
681
|
+
const processResult = await recognizerRunner.processImage(imageFrame);
|
|
682
|
+
if (processResult !== BlinkIDSDK.RecognizerResultState.Empty) {
|
|
683
|
+
for (const recognizer of recognizers) {
|
|
684
|
+
const results = await recognizer.recognizer.getResult();
|
|
685
|
+
if (!results ||
|
|
686
|
+
results.state === BlinkIDSDK.RecognizerResultState.Empty) {
|
|
687
|
+
eventCallback({
|
|
688
|
+
status: RecognitionStatus.EmptyResultState,
|
|
689
|
+
data: {
|
|
690
|
+
initiatedByUser: this.cancelInitiatedFromOutside,
|
|
691
|
+
recognizerName: recognizer.name,
|
|
692
|
+
},
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
else {
|
|
696
|
+
const recognitionResults = {
|
|
697
|
+
recognizer: results,
|
|
698
|
+
recognizerName: recognizer.name,
|
|
699
|
+
};
|
|
700
|
+
if (configuration.recognizerOptions?.returnSignedJSON) {
|
|
701
|
+
recognitionResults.resultSignedJSON =
|
|
702
|
+
await recognizer.recognizer.toSignedJSON();
|
|
703
|
+
}
|
|
704
|
+
eventCallback({
|
|
705
|
+
status: RecognitionStatus.ScanSuccessful,
|
|
706
|
+
data: recognitionResults,
|
|
707
|
+
});
|
|
708
|
+
break;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
else {
|
|
713
|
+
// If necessary, scan the image once again with different settings
|
|
714
|
+
if (configuration.thoroughScan &&
|
|
715
|
+
configuration.recognizers.indexOf("BlinkIdSingleSideRecognizer") > -1) {
|
|
716
|
+
const c = configuration;
|
|
717
|
+
c.thoroughScan = false;
|
|
718
|
+
c.recognizerOptions = c.recognizerOptions || {};
|
|
719
|
+
for (const r of c.recognizers) {
|
|
720
|
+
c.recognizerOptions[r] = c.recognizerOptions[r] || {};
|
|
721
|
+
c.recognizerOptions[r].scanCroppedDocumentImage =
|
|
722
|
+
!!c.recognizerOptions[r].scanCroppedDocumentImage;
|
|
723
|
+
c.recognizerOptions[r].scanCroppedDocumentImage =
|
|
724
|
+
!c.recognizerOptions[r].scanCroppedDocumentImage;
|
|
725
|
+
}
|
|
726
|
+
const eventHandler = (recognitionEvent) => eventCallback(recognitionEvent);
|
|
727
|
+
const handleTerminateDone = () => {
|
|
728
|
+
this.eventEmitter$.removeEventListener("terminate:done", handleTerminateDone);
|
|
729
|
+
this.scanFromImage(configuration, eventHandler);
|
|
730
|
+
};
|
|
731
|
+
this.eventEmitter$.addEventListener("terminate:done", handleTerminateDone);
|
|
732
|
+
window.setTimeout(() => void this.cancelRecognition(), 500);
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
eventCallback({
|
|
736
|
+
status: RecognitionStatus.EmptyResultState,
|
|
737
|
+
data: {
|
|
738
|
+
initiatedByUser: this.cancelInitiatedFromOutside,
|
|
739
|
+
recognizerName: "",
|
|
740
|
+
},
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
window.setTimeout(() => void this.cancelRecognition(), 500);
|
|
744
|
+
}
|
|
745
|
+
async scanFromImageMultiSide(configuration, eventCallback) {
|
|
746
|
+
eventCallback({ status: RecognitionStatus.Preparing });
|
|
747
|
+
const recognizers = await this.createRecognizers(configuration.recognizers, configuration.recognizerOptions, eventCallback);
|
|
748
|
+
const recognizerRunner = await this.createRecognizerRunner(recognizers);
|
|
749
|
+
if (configuration.pingProxyUrl) {
|
|
750
|
+
await recognizerRunner.setPingProxyUrl(configuration.pingProxyUrl);
|
|
751
|
+
}
|
|
752
|
+
const handleTerminate = async () => {
|
|
753
|
+
this.eventEmitter$.removeEventListener("terminate", handleTerminate);
|
|
754
|
+
if (recognizerRunner) {
|
|
755
|
+
try {
|
|
756
|
+
await recognizerRunner.delete();
|
|
757
|
+
}
|
|
758
|
+
catch (error) {
|
|
759
|
+
// Psst, this error should not happen.
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
for (const recognizer of recognizers) {
|
|
763
|
+
if (!recognizer) {
|
|
764
|
+
continue;
|
|
765
|
+
}
|
|
766
|
+
if (recognizer.recognizer?.objectHandle > -1) {
|
|
767
|
+
recognizer.recognizer.delete?.();
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
this.eventEmitter$.dispatchEvent(new Event("terminate:done"));
|
|
771
|
+
};
|
|
772
|
+
this.eventEmitter$.addEventListener("terminate", handleTerminate);
|
|
773
|
+
if (!configuration.firstFile) {
|
|
774
|
+
eventCallback({ status: RecognitionStatus.NoFirstImageFileFound });
|
|
775
|
+
window.setTimeout(() => void this.cancelRecognition(), 500);
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
if (!configuration.secondFile) {
|
|
779
|
+
eventCallback({ status: RecognitionStatus.NoSecondImageFileFound });
|
|
780
|
+
window.setTimeout(() => void this.cancelRecognition(), 500);
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
// Get results
|
|
784
|
+
eventCallback({ status: RecognitionStatus.Processing });
|
|
785
|
+
const imageElement = new Image();
|
|
786
|
+
imageElement.src = URL.createObjectURL(configuration.firstFile);
|
|
787
|
+
await imageElement.decode();
|
|
788
|
+
const firstFrame = BlinkIDSDK.captureFrame(imageElement);
|
|
789
|
+
const firstProcessResult = await recognizerRunner.processImage(firstFrame);
|
|
790
|
+
if (firstProcessResult !== BlinkIDSDK.RecognizerResultState.Empty) {
|
|
791
|
+
const imageElement = new Image();
|
|
792
|
+
imageElement.src = URL.createObjectURL(configuration.secondFile);
|
|
793
|
+
await imageElement.decode();
|
|
794
|
+
const secondFrame = BlinkIDSDK.captureFrame(imageElement);
|
|
795
|
+
const secondProcessResult = await recognizerRunner.processImage(secondFrame);
|
|
796
|
+
if (secondProcessResult !== BlinkIDSDK.RecognizerResultState.Empty) {
|
|
797
|
+
for (const recognizer of recognizers) {
|
|
798
|
+
const results = await recognizer.recognizer.getResult();
|
|
799
|
+
if (!results ||
|
|
800
|
+
results.state === BlinkIDSDK.RecognizerResultState.Empty) {
|
|
801
|
+
eventCallback({
|
|
802
|
+
status: RecognitionStatus.EmptyResultState,
|
|
803
|
+
data: {
|
|
804
|
+
initiatedByUser: this.cancelInitiatedFromOutside,
|
|
805
|
+
recognizerName: recognizer.name,
|
|
806
|
+
},
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
else {
|
|
810
|
+
const recognitionResults = {
|
|
811
|
+
recognizer: results,
|
|
812
|
+
recognizerName: recognizer.name,
|
|
813
|
+
};
|
|
814
|
+
if (configuration.recognizerOptions?.returnSignedJSON) {
|
|
815
|
+
recognitionResults.resultSignedJSON =
|
|
816
|
+
await recognizer.recognizer.toSignedJSON();
|
|
817
|
+
}
|
|
818
|
+
eventCallback({
|
|
819
|
+
status: RecognitionStatus.ScanSuccessful,
|
|
820
|
+
data: recognitionResults,
|
|
821
|
+
});
|
|
822
|
+
break;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
else {
|
|
827
|
+
eventCallback({
|
|
828
|
+
status: RecognitionStatus.EmptyResultState,
|
|
829
|
+
data: {
|
|
830
|
+
initiatedByUser: this.cancelInitiatedFromOutside,
|
|
831
|
+
recognizerName: "",
|
|
832
|
+
},
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
else {
|
|
837
|
+
// If necessary, scan the image once again with different settings
|
|
838
|
+
if (configuration.thoroughScan &&
|
|
839
|
+
configuration.recognizers.indexOf("BlinkIdMultiSideRecognizer") > -1) {
|
|
840
|
+
const c = configuration;
|
|
841
|
+
c.thoroughScan = false;
|
|
842
|
+
c.recognizerOptions = c.recognizerOptions || {};
|
|
843
|
+
for (const r of c.recognizers) {
|
|
844
|
+
c.recognizerOptions[r] = c.recognizerOptions[r] || {};
|
|
845
|
+
c.recognizerOptions[r].scanCroppedDocumentImage =
|
|
846
|
+
!!c.recognizerOptions[r].scanCroppedDocumentImage;
|
|
847
|
+
c.recognizerOptions[r].scanCroppedDocumentImage =
|
|
848
|
+
!c.recognizerOptions[r].scanCroppedDocumentImage;
|
|
849
|
+
}
|
|
850
|
+
const eventHandler = (recognitionEvent) => eventCallback(recognitionEvent);
|
|
851
|
+
const handleTerminateDone = () => {
|
|
852
|
+
this.eventEmitter$.removeEventListener("terminate:done", handleTerminateDone);
|
|
853
|
+
this.scanFromImageMultiSide(configuration, eventHandler);
|
|
854
|
+
};
|
|
855
|
+
this.eventEmitter$.addEventListener("terminate:done", handleTerminateDone);
|
|
856
|
+
window.setTimeout(() => void this.cancelRecognition(), 500);
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
eventCallback({
|
|
860
|
+
status: RecognitionStatus.EmptyResultState,
|
|
861
|
+
data: {
|
|
862
|
+
initiatedByUser: this.cancelInitiatedFromOutside,
|
|
863
|
+
recognizerName: "",
|
|
864
|
+
},
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
window.setTimeout(() => void this.cancelRecognition(), 500);
|
|
868
|
+
}
|
|
869
|
+
async stopRecognition() {
|
|
870
|
+
void (await this.cancelRecognition(true));
|
|
871
|
+
}
|
|
872
|
+
async resumeRecognition() {
|
|
873
|
+
this.videoRecognizer.resumeRecognition(true);
|
|
874
|
+
}
|
|
875
|
+
changeCameraDevice(camera) {
|
|
876
|
+
return new Promise((resolve) => {
|
|
877
|
+
this.videoRecognizer
|
|
878
|
+
.changeCameraDevice(camera)
|
|
879
|
+
.then(() => resolve(true))
|
|
880
|
+
.catch(() => resolve(false));
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
getProductIntegrationInfo() {
|
|
884
|
+
return this.sdk.getProductIntegrationInfo();
|
|
885
|
+
}
|
|
886
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
887
|
+
//
|
|
888
|
+
// PRIVATE METHODS
|
|
889
|
+
isRecognizerAvailable(recognizer) {
|
|
890
|
+
return !!AvailableRecognizers[recognizer];
|
|
891
|
+
}
|
|
892
|
+
async createRecognizers(recognizers, recognizerOptions, eventCallback) {
|
|
893
|
+
const pureRecognizers = [];
|
|
894
|
+
for (const recognizer of recognizers) {
|
|
895
|
+
const instance = await BlinkIDSDK[AvailableRecognizers[recognizer]](this.sdk);
|
|
896
|
+
pureRecognizers.push(instance);
|
|
897
|
+
}
|
|
898
|
+
if (recognizerOptions && Object.keys(recognizerOptions).length > 0) {
|
|
899
|
+
for (const recognizer of pureRecognizers) {
|
|
900
|
+
const settings = await recognizer.currentSettings();
|
|
901
|
+
if (!recognizerOptions[recognizer.recognizerName] ||
|
|
902
|
+
Object.keys(recognizerOptions[recognizer.recognizerName]).length < 1) {
|
|
903
|
+
continue;
|
|
904
|
+
}
|
|
905
|
+
for (const [key, value] of Object.entries(recognizerOptions[recognizer.recognizerName])) {
|
|
906
|
+
if (key in settings) {
|
|
907
|
+
settings[key] = value;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
settings.barcodeScanningStartedCallback = () => {
|
|
911
|
+
eventCallback({ status: RecognitionStatus.BarcodeScanningStarted });
|
|
912
|
+
};
|
|
913
|
+
settings.classifierCallback = (supported) => {
|
|
914
|
+
eventCallback({
|
|
915
|
+
status: RecognitionStatus.DocumentClassified,
|
|
916
|
+
data: supported,
|
|
917
|
+
});
|
|
918
|
+
};
|
|
919
|
+
await recognizer.updateSettings(settings);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
const recognizerInstances = [];
|
|
923
|
+
for (let i = 0; i < pureRecognizers.length; ++i) {
|
|
924
|
+
const recognizer = pureRecognizers[i];
|
|
925
|
+
const instance = { name: recognizers[i], recognizer };
|
|
926
|
+
recognizerInstances.push(instance);
|
|
927
|
+
}
|
|
928
|
+
return recognizerInstances;
|
|
929
|
+
}
|
|
930
|
+
async createRecognizerRunner(recognizers) {
|
|
931
|
+
const metadataCallbacks = {
|
|
932
|
+
onQuadDetection: (quad) => {
|
|
933
|
+
this.lastDetectionStatus = quad.detectionStatus;
|
|
934
|
+
},
|
|
935
|
+
};
|
|
936
|
+
const recognizerRunner = await BlinkIDSDK.createRecognizerRunner(this.sdk, recognizers.map((el) => el.recognizer), false, metadataCallbacks);
|
|
937
|
+
return recognizerRunner;
|
|
938
|
+
}
|
|
939
|
+
async cancelRecognition(initiatedFromOutside = false) {
|
|
940
|
+
this.cancelInitiatedFromOutside = initiatedFromOutside;
|
|
941
|
+
this.eventEmitter$.dispatchEvent(new Event("terminate"));
|
|
942
|
+
}
|
|
943
|
+
}
|