smartcomply-web-sdk 1.0.80 → 1.0.82
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/dist/camera/ActionDetector.d.ts.map +1 -1
- package/dist/camera/ActionDetector.js +7 -5
- package/dist/camera/ActionDetector.js.map +1 -1
- package/dist/client/Smartcomply.d.ts +1 -1
- package/dist/client/Smartcomply.js +1 -1
- package/dist/esm/camera/ActionDetector.d.ts.map +1 -1
- package/dist/esm/camera/ActionDetector.js +7 -5
- package/dist/esm/camera/ActionDetector.js.map +1 -1
- package/dist/esm/client/Smartcomply.d.ts +1 -1
- package/dist/esm/client/Smartcomply.js +1 -1
- package/dist/esm/flow/DocumentCapture.d.ts +42 -5
- package/dist/esm/flow/DocumentCapture.d.ts.map +1 -1
- package/dist/esm/flow/DocumentCapture.js +176 -19
- package/dist/esm/flow/DocumentCapture.js.map +1 -1
- package/dist/esm/flow/SmartComplyFlow.d.ts +10 -0
- package/dist/esm/flow/SmartComplyFlow.d.ts.map +1 -1
- package/dist/esm/flow/SmartComplyFlow.js +53 -0
- package/dist/esm/flow/SmartComplyFlow.js.map +1 -1
- package/dist/esm/utils/ImageQuality.d.ts +38 -0
- package/dist/esm/utils/ImageQuality.d.ts.map +1 -1
- package/dist/esm/utils/ImageQuality.js +98 -0
- package/dist/esm/utils/ImageQuality.js.map +1 -1
- package/dist/flow/DocumentCapture.d.ts +42 -5
- package/dist/flow/DocumentCapture.d.ts.map +1 -1
- package/dist/flow/DocumentCapture.js +175 -18
- package/dist/flow/DocumentCapture.js.map +1 -1
- package/dist/flow/SmartComplyFlow.d.ts +10 -0
- package/dist/flow/SmartComplyFlow.d.ts.map +1 -1
- package/dist/flow/SmartComplyFlow.js +53 -0
- package/dist/flow/SmartComplyFlow.js.map +1 -1
- package/dist/smartcomply.browser.js +256 -11
- package/dist/smartcomply.browser.js.map +3 -3
- package/dist/utils/ImageQuality.d.ts +38 -0
- package/dist/utils/ImageQuality.d.ts.map +1 -1
- package/dist/utils/ImageQuality.js +99 -0
- package/dist/utils/ImageQuality.js.map +1 -1
- package/package.json +1 -1
|
@@ -163,6 +163,104 @@ export function assessQuality(imageData) {
|
|
|
163
163
|
quality: metrics,
|
|
164
164
|
};
|
|
165
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Lightweight, dependency-free framing heuristic — NOT real document/edge
|
|
168
|
+
* detection (that needs actual computer vision, e.g. OpenCV.js). This is the
|
|
169
|
+
* same class of check as assessQuality above: cheap enough to run every
|
|
170
|
+
* ~300ms on a mid-range phone, good enough to catch the obvious failure
|
|
171
|
+
* (no document in frame, badly cropped, document far outside the guide box),
|
|
172
|
+
* not intended to catch subtle/partial cropping — that's still the backend
|
|
173
|
+
* OCR + registry check's job.
|
|
174
|
+
*
|
|
175
|
+
* Approach: a real physical document produces a sharp intensity edge at its
|
|
176
|
+
* own boundary. If the guide box is roughly aligned with a real document,
|
|
177
|
+
* that edge should sit close to the guide box's own border. Sample a thin
|
|
178
|
+
* ring around the guide box border and check edge strength there (Sobel-style
|
|
179
|
+
* gradient, cheaper than the full Laplacian pass in calculateSharpness), plus
|
|
180
|
+
* confirm the box interior isn't just blank/uniform background (a document
|
|
181
|
+
* held further back than the guide, or no document at all, leaves the
|
|
182
|
+
* interior looking like flat background/desk).
|
|
183
|
+
*
|
|
184
|
+
* guideBoxPct: the guide box's position as a fraction of imageData's full
|
|
185
|
+
* width/height (0-1) — callers pass the SAME percentages used to size the
|
|
186
|
+
* on-screen CSS guide box (see DocumentCapture's guideWrap), computed against
|
|
187
|
+
* the raw video frame's own pixel dimensions so no CSS/object-fit mapping is
|
|
188
|
+
* needed.
|
|
189
|
+
*/
|
|
190
|
+
export function assessFraming(imageData, guideBoxPct) {
|
|
191
|
+
const { width: W, height: H, data } = imageData;
|
|
192
|
+
const gray = new Uint8Array(W * H);
|
|
193
|
+
for (let i = 0; i < W * H; i++) {
|
|
194
|
+
const idx = i * 4;
|
|
195
|
+
gray[i] = Math.round(0.299 * data[idx] + 0.587 * data[idx + 1] + 0.114 * data[idx + 2]);
|
|
196
|
+
}
|
|
197
|
+
const gx0 = Math.round(guideBoxPct.x * W);
|
|
198
|
+
const gy0 = Math.round(guideBoxPct.y * H);
|
|
199
|
+
const gx1 = Math.round((guideBoxPct.x + guideBoxPct.width) * W);
|
|
200
|
+
const gy1 = Math.round((guideBoxPct.y + guideBoxPct.height) * H);
|
|
201
|
+
const edgeAt = (x, y) => {
|
|
202
|
+
if (x < 1 || y < 1 || x >= W - 1 || y >= H - 1)
|
|
203
|
+
return 0;
|
|
204
|
+
const gxVal = gray[y * W + x + 1] - gray[y * W + x - 1];
|
|
205
|
+
const gyVal = gray[(y + 1) * W + x] - gray[(y - 1) * W + x];
|
|
206
|
+
return Math.sqrt(gxVal * gxVal + gyVal * gyVal);
|
|
207
|
+
};
|
|
208
|
+
const EDGE_THRESHOLD = 40;
|
|
209
|
+
const BORDER_BAND = Math.max(4, Math.round(Math.min(W, H) * 0.015));
|
|
210
|
+
// Sample points along the guide box border ring (top/bottom edges, left/right edges).
|
|
211
|
+
let borderPoints = 0;
|
|
212
|
+
let borderHits = 0;
|
|
213
|
+
const SAMPLES_PER_SIDE = 24;
|
|
214
|
+
const sampleBand = (fixed, isX, start, end) => {
|
|
215
|
+
for (let s = 0; s < SAMPLES_PER_SIDE; s++) {
|
|
216
|
+
const t = start + ((end - start) * s) / (SAMPLES_PER_SIDE - 1);
|
|
217
|
+
let bestEdge = 0;
|
|
218
|
+
for (let b = -BORDER_BAND; b <= BORDER_BAND; b++) {
|
|
219
|
+
const x = isX ? fixed + b : Math.round(t);
|
|
220
|
+
const y = isX ? Math.round(t) : fixed + b;
|
|
221
|
+
bestEdge = Math.max(bestEdge, edgeAt(x, y));
|
|
222
|
+
}
|
|
223
|
+
borderPoints++;
|
|
224
|
+
if (bestEdge >= EDGE_THRESHOLD)
|
|
225
|
+
borderHits++;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
sampleBand(gy0, false, gx0, gx1); // top
|
|
229
|
+
sampleBand(gy1, false, gx0, gx1); // bottom
|
|
230
|
+
sampleBand(gx0, true, gy0, gy1); // left
|
|
231
|
+
sampleBand(gx1, true, gy0, gy1); // right
|
|
232
|
+
const borderEdgeCoverage = borderPoints > 0 ? borderHits / borderPoints : 0;
|
|
233
|
+
// Interior variance — sample a coarse grid inside the box, well clear of
|
|
234
|
+
// the border band, and check the spread of gray values isn't flat.
|
|
235
|
+
let sum = 0, sumSq = 0, n = 0;
|
|
236
|
+
const GRID = 12;
|
|
237
|
+
const insetX = Math.round((gx1 - gx0) * 0.1);
|
|
238
|
+
const insetY = Math.round((gy1 - gy0) * 0.1);
|
|
239
|
+
for (let iy = 0; iy < GRID; iy++) {
|
|
240
|
+
for (let ix = 0; ix < GRID; ix++) {
|
|
241
|
+
const x = gx0 + insetX + Math.round(((gx1 - gx0 - 2 * insetX) * ix) / (GRID - 1));
|
|
242
|
+
const y = gy0 + insetY + Math.round(((gy1 - gy0 - 2 * insetY) * iy) / (GRID - 1));
|
|
243
|
+
if (x < 0 || y < 0 || x >= W || y >= H)
|
|
244
|
+
continue;
|
|
245
|
+
const v = gray[y * W + x];
|
|
246
|
+
sum += v;
|
|
247
|
+
sumSq += v * v;
|
|
248
|
+
n++;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const mean = n > 0 ? sum / n : 0;
|
|
252
|
+
const variance = n > 0 ? sumSq / n - mean * mean : 0;
|
|
253
|
+
// Normalize against a "reasonable document photo" ballpark std-dev (~35)
|
|
254
|
+
// so the 0-1 scale is comparable across lighting conditions.
|
|
255
|
+
const interiorVariance = Math.min(1, Math.sqrt(Math.max(0, variance)) / 35);
|
|
256
|
+
// Require a solid majority of the border ring to show an edge AND some
|
|
257
|
+
// real content inside — either alone can false-positive (a plain wall has
|
|
258
|
+
// no edges but so does a document photographed at very low contrast; a
|
|
259
|
+
// cluttered background has edges everywhere but nothing document-shaped
|
|
260
|
+
// where the guide box actually is).
|
|
261
|
+
const isFramed = borderEdgeCoverage >= 0.55 && interiorVariance >= 0.25;
|
|
262
|
+
return { isFramed, borderEdgeCoverage, interiorVariance };
|
|
263
|
+
}
|
|
166
264
|
/**
|
|
167
265
|
* Get quality color for UI feedback
|
|
168
266
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageQuality.js","sourceRoot":"","sources":["../../../src/utils/ImageQuality.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ImageQuality.js","sourceRoot":"","sources":["../../../src/utils/ImageQuality.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,6 +27,9 @@ export declare class DocumentCapture {
|
|
|
27
27
|
private backBlob;
|
|
28
28
|
private currentSide;
|
|
29
29
|
private requiresBackOverride;
|
|
30
|
+
private framingTimer;
|
|
31
|
+
private framingStableCount;
|
|
32
|
+
private framingAutoTriggered;
|
|
30
33
|
/**
|
|
31
34
|
* Mount the document capture UI and return a promise that resolves
|
|
32
35
|
* with the captured document image(s).
|
|
@@ -58,15 +61,49 @@ export declare class DocumentCapture {
|
|
|
58
61
|
*/
|
|
59
62
|
private _watchOrientation;
|
|
60
63
|
private _unwatchOrientation;
|
|
64
|
+
/**
|
|
65
|
+
* Auto-capture-on-stability — the same pattern the liveness module already
|
|
66
|
+
* uses for face-lock (see liveness.ts's checkFace), applied to documents:
|
|
67
|
+
* poll the raw video frame on an interval, score it against the guide box
|
|
68
|
+
* with assessFraming() (see utils/ImageQuality.ts), and fire the shutter
|
|
69
|
+
* automatically once several consecutive samples score as "framed". This
|
|
70
|
+
* is industry-standard for document capture (Persona/Onfido/Jumio-style
|
|
71
|
+
* SDKs all auto-capture rather than trust a manual tap against a static
|
|
72
|
+
* guide overlay) — the guide box alone never blocked a badly cropped tap.
|
|
73
|
+
*
|
|
74
|
+
* The manual capture button still works throughout and always wins
|
|
75
|
+
* (framingAutoTriggered guards against a race between the two).
|
|
76
|
+
*/
|
|
77
|
+
private _startFramingLoop;
|
|
78
|
+
private _stopFramingLoop;
|
|
61
79
|
private openCamera;
|
|
62
80
|
private captureFrame;
|
|
63
81
|
private showPreview;
|
|
64
82
|
/**
|
|
65
|
-
* Runs the shared client-side quality
|
|
66
|
-
* brightness
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
83
|
+
* Runs the shared client-side quality heuristics — blur/glare/contrast/
|
|
84
|
+
* brightness (assessQuality) and document framing/completeness
|
|
85
|
+
* (assessFraming) — against the just-captured or just-uploaded photo, and
|
|
86
|
+
* shows a plain-language nudge on the preview screen if either scores
|
|
87
|
+
* poorly. This is the one chokepoint both the camera and manual-upload
|
|
88
|
+
* paths funnel through (see showPreview), so it's the only place that
|
|
89
|
+
* reliably catches a badly cropped document regardless of how the photo
|
|
90
|
+
* arrived — the camera's own auto-capture framing loop only guards live
|
|
91
|
+
* capture, and does nothing for an uploaded file or a manual shutter tap
|
|
92
|
+
* fired before the loop ever samples.
|
|
93
|
+
*
|
|
94
|
+
* Framing here checks the WHOLE image (guideBoxPct = full frame), not a
|
|
95
|
+
* guide-box region — there's no guide overlay for an arbitrary uploaded
|
|
96
|
+
* photo, so "does the document fill most of the frame" is the correct
|
|
97
|
+
* question, matching the same border-edge + interior-variance heuristic
|
|
98
|
+
* the camera loop already uses.
|
|
99
|
+
*
|
|
100
|
+
* A framing failure disables useBtn — unlike the blur/glare nudge, this
|
|
101
|
+
* one blocks: a cropped ID reads as a confident, wrong identity downstream
|
|
102
|
+
* (partial OCR fields, a registry check against a truncated ID number)
|
|
103
|
+
* with no further chance to catch it, so the user must retake/re-upload
|
|
104
|
+
* rather than being trusted to notice an advisory nudge and act on it
|
|
105
|
+
* voluntarily. Fails open on decode error — this heuristic not running at
|
|
106
|
+
* all must not lock the user out of a photo it never actually scored.
|
|
70
107
|
*/
|
|
71
108
|
private _checkPhotoQuality;
|
|
72
109
|
/** Decodes to a canvas, optionally downscaled to maxDim on the long edge (never upscales). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocumentCapture.d.ts","sourceRoot":"","sources":["../../src/flow/DocumentCapture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAgB,MAAM,SAAS,CAAC;AACpD,OAAO,EAAuC,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAQ3F;;;;;;;;GAQG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,IAAI,CAAC;IACZ,IAAI,CAAC,EAAE,IAAI,CAAC;IAKZ,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,IAAI,CAA+B;IAC3C,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,aAAa,CAAsC;IAC3D,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,cAAc,CAA0D;IAChF,OAAO,CAAC,aAAa,CAAuC;IAC5D,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,oBAAoB,CAAuC;
|
|
1
|
+
{"version":3,"file":"DocumentCapture.d.ts","sourceRoot":"","sources":["../../src/flow/DocumentCapture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAgB,MAAM,SAAS,CAAC;AACpD,OAAO,EAAuC,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAQ3F;;;;;;;;GAQG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,IAAI,CAAC;IACZ,IAAI,CAAC,EAAE,IAAI,CAAC;IAKZ,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,IAAI,CAA+B;IAC3C,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,aAAa,CAAsC;IAC3D,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,cAAc,CAA0D;IAChF,OAAO,CAAC,aAAa,CAAuC;IAC5D,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,oBAAoB,CAAuC;IACnE,OAAO,CAAC,YAAY,CAA8C;IAClE,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,oBAAoB,CAAS;IAErC;;;OAGG;IACH,OAAO,CACL,SAAS,EAAE,WAAW,EACtB,KAAK,EAAE,WAAW,EAClB,YAAY,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,qBAAqB,CAAC;IAiCjC,OAAO,IAAI,IAAI;IAuBf,OAAO,CAAC,eAAe;IAOvB,8EAA8E;IAC9E,OAAO,CAAC,qBAAqB;IAI7B,0EAA0E;IAC1E,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,kBAAkB;IA4L1B,wDAAwD;IACxD,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,gBAAgB;IA0IxB;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;IAQpB;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,mBAAmB;IAQ3B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,iBAAiB;IA2FzB,OAAO,CAAC,gBAAgB;YAOV,UAAU;IAsExB,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,WAAW;IA+JnB;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;YACW,kBAAkB;IAsDhC,8FAA8F;IAC9F,OAAO,CAAC,aAAa;IAqBrB;;;;;;;;OAQG;IACH,OAAO,CAAC,YAAY;IA2BpB,OAAO,CAAC,qBAAqB;IAyC7B,OAAO,CAAC,wBAAwB;IAShC,OAAO,CAAC,YAAY;IAsBpB;;;;;;;;OAQG;YACW,sBAAsB;IASpC,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,SAAS;IAoCjB,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,aAAa;IA4ErB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAuC5B,OAAO,CAAC,gBAAgB;CAazB"}
|
|
@@ -23,6 +23,9 @@ class DocumentCapture {
|
|
|
23
23
|
this.backBlob = null;
|
|
24
24
|
this.currentSide = 'front';
|
|
25
25
|
this.requiresBackOverride = undefined;
|
|
26
|
+
this.framingTimer = null;
|
|
27
|
+
this.framingStableCount = 0;
|
|
28
|
+
this.framingAutoTriggered = false;
|
|
26
29
|
}
|
|
27
30
|
/**
|
|
28
31
|
* Mount the document capture UI and return a promise that resolves
|
|
@@ -332,7 +335,7 @@ class DocumentCapture {
|
|
|
332
335
|
svg.appendChild(bracketGroup);
|
|
333
336
|
guideWrap.appendChild(svg);
|
|
334
337
|
wrapper.appendChild(guideWrap);
|
|
335
|
-
// Header — gradient scrim + document label
|
|
338
|
+
// Header — gradient scrim + document label + live framing status
|
|
336
339
|
const header = document.createElement("div");
|
|
337
340
|
header.style.cssText = `
|
|
338
341
|
position:absolute;top:0;left:0;right:0;
|
|
@@ -340,6 +343,13 @@ class DocumentCapture {
|
|
|
340
343
|
padding:14px 16px 32px;text-align:center;
|
|
341
344
|
`;
|
|
342
345
|
header.innerHTML = `<div style="color:#fff;font-size:${theme_1.TYPE.sm}px;font-weight:600;">Align your ${this.getDocumentLabel(documentType)} within the frame</div>`;
|
|
346
|
+
const framingStatus = document.createElement("div");
|
|
347
|
+
framingStatus.style.cssText = `
|
|
348
|
+
margin-top:6px;font-size:${theme_1.TYPE.xs}px;font-weight:600;
|
|
349
|
+
color:rgba(255,255,255,0.7);transition:color 0.2s ease;
|
|
350
|
+
`;
|
|
351
|
+
framingStatus.textContent = "Fit the document inside the frame";
|
|
352
|
+
header.appendChild(framingStatus);
|
|
343
353
|
wrapper.appendChild(header);
|
|
344
354
|
// Footer — gradient scrim + tips
|
|
345
355
|
const footer = document.createElement("div");
|
|
@@ -374,11 +384,17 @@ class DocumentCapture {
|
|
|
374
384
|
inner.style.transform = "translate(-50%,-50%) scale(1)";
|
|
375
385
|
});
|
|
376
386
|
captureBtn.addEventListener("click", () => {
|
|
387
|
+
this.framingAutoTriggered = true; // manual tap always wins, skip any pending auto-trigger
|
|
377
388
|
this.captureFrame(container, theme, documentType);
|
|
378
389
|
});
|
|
379
390
|
container.appendChild(captureBtn);
|
|
380
|
-
// Open camera
|
|
381
|
-
|
|
391
|
+
// Open camera, then start the auto-capture framing loop once the stream
|
|
392
|
+
// has real dimensions to sample against.
|
|
393
|
+
this.openCamera().then(() => {
|
|
394
|
+
if (this.videoEl) {
|
|
395
|
+
this.videoEl.addEventListener("loadedmetadata", () => this._startFramingLoop(container, theme, documentType, framingStatus), { once: true });
|
|
396
|
+
}
|
|
397
|
+
});
|
|
382
398
|
}
|
|
383
399
|
/**
|
|
384
400
|
* Matches the video box's aspect-ratio CSS to the stream's actual
|
|
@@ -415,6 +431,103 @@ class DocumentCapture {
|
|
|
415
431
|
this.orientationHandler = null;
|
|
416
432
|
}
|
|
417
433
|
}
|
|
434
|
+
/**
|
|
435
|
+
* Auto-capture-on-stability — the same pattern the liveness module already
|
|
436
|
+
* uses for face-lock (see liveness.ts's checkFace), applied to documents:
|
|
437
|
+
* poll the raw video frame on an interval, score it against the guide box
|
|
438
|
+
* with assessFraming() (see utils/ImageQuality.ts), and fire the shutter
|
|
439
|
+
* automatically once several consecutive samples score as "framed". This
|
|
440
|
+
* is industry-standard for document capture (Persona/Onfido/Jumio-style
|
|
441
|
+
* SDKs all auto-capture rather than trust a manual tap against a static
|
|
442
|
+
* guide overlay) — the guide box alone never blocked a badly cropped tap.
|
|
443
|
+
*
|
|
444
|
+
* The manual capture button still works throughout and always wins
|
|
445
|
+
* (framingAutoTriggered guards against a race between the two).
|
|
446
|
+
*/
|
|
447
|
+
_startFramingLoop(container, theme, documentType, statusEl) {
|
|
448
|
+
if (!this.videoEl)
|
|
449
|
+
return;
|
|
450
|
+
this.framingStableCount = 0;
|
|
451
|
+
this.framingAutoTriggered = false;
|
|
452
|
+
const STABLE_REQUIRED = 3; // consecutive good samples before firing
|
|
453
|
+
const SAMPLE_INTERVAL_MS = 350; // cheap enough to run this often; not every animation frame
|
|
454
|
+
const MAX_WAIT_MS = 12000; // give up auto-capture, leave the manual button as the only path
|
|
455
|
+
const startTime = performance.now();
|
|
456
|
+
// Guide box in fractional coordinates, matching the on-screen CSS guide
|
|
457
|
+
// (width:84%, aspect-ratio:16/10, centered) — computed directly against
|
|
458
|
+
// the video's own pixel dimensions so no CSS/object-fit mapping is needed.
|
|
459
|
+
const boxWidthPct = 0.84;
|
|
460
|
+
const boxAspect = 16 / 10;
|
|
461
|
+
const tick = () => {
|
|
462
|
+
if (!this.videoEl || this.framingAutoTriggered)
|
|
463
|
+
return;
|
|
464
|
+
if (performance.now() - startTime >= MAX_WAIT_MS) {
|
|
465
|
+
statusEl.textContent = "Fit the document inside the frame";
|
|
466
|
+
return; // stop auto-detecting; manual capture button remains available
|
|
467
|
+
}
|
|
468
|
+
const w = this.videoEl.videoWidth;
|
|
469
|
+
const h = this.videoEl.videoHeight;
|
|
470
|
+
if (!w || !h || this.videoEl.readyState < 2) {
|
|
471
|
+
this.framingTimer = setTimeout(tick, SAMPLE_INTERVAL_MS);
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
try {
|
|
475
|
+
const boxWidthPx = w * boxWidthPct;
|
|
476
|
+
const boxHeightPx = boxWidthPx / boxAspect;
|
|
477
|
+
const boxXPct = (1 - boxWidthPct) / 2;
|
|
478
|
+
const boxHeightPct = boxHeightPx / h;
|
|
479
|
+
const boxYPct = (1 - boxHeightPct) / 2;
|
|
480
|
+
const canvas = document.createElement("canvas");
|
|
481
|
+
// Downscaled sampling copy only — matches _checkPhotoQuality's own
|
|
482
|
+
// reasoning for why this must not run against the full-resolution
|
|
483
|
+
// frame on every tick.
|
|
484
|
+
const scale = Math.min(1, 480 / w);
|
|
485
|
+
canvas.width = Math.round(w * scale);
|
|
486
|
+
canvas.height = Math.round(h * scale);
|
|
487
|
+
const ctx = canvas.getContext("2d", { willReadFrequently: true });
|
|
488
|
+
if (!ctx) {
|
|
489
|
+
this.framingTimer = setTimeout(tick, SAMPLE_INTERVAL_MS);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
ctx.drawImage(this.videoEl, 0, 0, canvas.width, canvas.height);
|
|
493
|
+
const pixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
494
|
+
const result = (0, ImageQuality_1.assessFraming)(pixels, {
|
|
495
|
+
x: boxXPct, y: boxYPct, width: boxWidthPct, height: boxHeightPct,
|
|
496
|
+
});
|
|
497
|
+
if (result.isFramed) {
|
|
498
|
+
this.framingStableCount++;
|
|
499
|
+
statusEl.style.color = theme.primary;
|
|
500
|
+
statusEl.textContent = this.framingStableCount >= STABLE_REQUIRED
|
|
501
|
+
? "Capturing…"
|
|
502
|
+
: "Hold steady…";
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
this.framingStableCount = 0;
|
|
506
|
+
statusEl.style.color = "rgba(255,255,255,0.7)";
|
|
507
|
+
statusEl.textContent = result.interiorVariance < 0.25
|
|
508
|
+
? "Move closer — fill the frame with your document"
|
|
509
|
+
: "Align all 4 corners within the guide";
|
|
510
|
+
}
|
|
511
|
+
if (this.framingStableCount >= STABLE_REQUIRED) {
|
|
512
|
+
this.framingAutoTriggered = true;
|
|
513
|
+
this.captureFrame(container, theme, documentType);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
catch {
|
|
518
|
+
// Advisory/auto-capture only — a scoring failure just falls back to
|
|
519
|
+
// the manual capture button, never blocks the flow.
|
|
520
|
+
}
|
|
521
|
+
this.framingTimer = setTimeout(tick, SAMPLE_INTERVAL_MS);
|
|
522
|
+
};
|
|
523
|
+
this.framingTimer = setTimeout(tick, SAMPLE_INTERVAL_MS);
|
|
524
|
+
}
|
|
525
|
+
_stopFramingLoop() {
|
|
526
|
+
if (this.framingTimer !== null) {
|
|
527
|
+
clearTimeout(this.framingTimer);
|
|
528
|
+
this.framingTimer = null;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
418
531
|
async openCamera() {
|
|
419
532
|
// Check browser compatibility
|
|
420
533
|
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
|
@@ -576,7 +689,7 @@ class DocumentCapture {
|
|
|
576
689
|
URL.revokeObjectURL(currentUrl);
|
|
577
690
|
currentUrl = URL.createObjectURL(rotated);
|
|
578
691
|
img.src = currentUrl;
|
|
579
|
-
this._checkPhotoQuality(currentBlob, qualityNotice, theme);
|
|
692
|
+
this._checkPhotoQuality(currentBlob, qualityNotice, theme, useBtn);
|
|
580
693
|
}
|
|
581
694
|
catch {
|
|
582
695
|
// Leave the current photo untouched — rotation is a convenience,
|
|
@@ -598,12 +711,14 @@ class DocumentCapture {
|
|
|
598
711
|
sublabel.style.cssText = `color:${theme.textMuted};font-size:${theme_1.TYPE.xs}px;text-align:center;line-height:1.6;`;
|
|
599
712
|
sublabel.textContent = "All text must be readable and all four corners must be visible. Sideways or upside-down? Use Rotate on the photo above.";
|
|
600
713
|
this.root.appendChild(sublabel);
|
|
601
|
-
//
|
|
602
|
-
//
|
|
603
|
-
//
|
|
604
|
-
//
|
|
605
|
-
//
|
|
606
|
-
//
|
|
714
|
+
// Quality/framing notice. Blur/glare/contrast issues (assessQuality) stay
|
|
715
|
+
// advisory-only — a heuristic that's off shouldn't block a photo that's
|
|
716
|
+
// actually fine. A framing failure (document not fully in frame —
|
|
717
|
+
// assessFraming) DOES block "Use Photo": a cropped ID reads as a
|
|
718
|
+
// confident, wrong identity downstream (partial OCR fields, a registry
|
|
719
|
+
// check against a truncated ID number) with no further chance to catch
|
|
720
|
+
// it, so this is the one signal worth hard-blocking on rather than
|
|
721
|
+
// trusting the user to notice and retake voluntarily.
|
|
607
722
|
const qualityNotice = document.createElement("div");
|
|
608
723
|
qualityNotice.style.cssText = `
|
|
609
724
|
display:none;width:100%;padding:10px 14px;border-radius:${theme_1.RADIUS.md}px;
|
|
@@ -612,7 +727,6 @@ class DocumentCapture {
|
|
|
612
727
|
`;
|
|
613
728
|
qualityNotice.setAttribute("role", "status");
|
|
614
729
|
this.root.appendChild(qualityNotice);
|
|
615
|
-
this._checkPhotoQuality(currentBlob, qualityNotice, theme);
|
|
616
730
|
// Buttons
|
|
617
731
|
const btnRow = document.createElement("div");
|
|
618
732
|
btnRow.style.cssText = "display:flex;gap:12px;width:100%;";
|
|
@@ -638,15 +752,35 @@ class DocumentCapture {
|
|
|
638
752
|
btnRow.appendChild(retakeBtn);
|
|
639
753
|
btnRow.appendChild(useBtn);
|
|
640
754
|
this.root.appendChild(btnRow);
|
|
755
|
+
this._checkPhotoQuality(currentBlob, qualityNotice, theme, useBtn);
|
|
641
756
|
}
|
|
642
757
|
/**
|
|
643
|
-
* Runs the shared client-side quality
|
|
644
|
-
* brightness
|
|
645
|
-
*
|
|
646
|
-
*
|
|
647
|
-
*
|
|
758
|
+
* Runs the shared client-side quality heuristics — blur/glare/contrast/
|
|
759
|
+
* brightness (assessQuality) and document framing/completeness
|
|
760
|
+
* (assessFraming) — against the just-captured or just-uploaded photo, and
|
|
761
|
+
* shows a plain-language nudge on the preview screen if either scores
|
|
762
|
+
* poorly. This is the one chokepoint both the camera and manual-upload
|
|
763
|
+
* paths funnel through (see showPreview), so it's the only place that
|
|
764
|
+
* reliably catches a badly cropped document regardless of how the photo
|
|
765
|
+
* arrived — the camera's own auto-capture framing loop only guards live
|
|
766
|
+
* capture, and does nothing for an uploaded file or a manual shutter tap
|
|
767
|
+
* fired before the loop ever samples.
|
|
768
|
+
*
|
|
769
|
+
* Framing here checks the WHOLE image (guideBoxPct = full frame), not a
|
|
770
|
+
* guide-box region — there's no guide overlay for an arbitrary uploaded
|
|
771
|
+
* photo, so "does the document fill most of the frame" is the correct
|
|
772
|
+
* question, matching the same border-edge + interior-variance heuristic
|
|
773
|
+
* the camera loop already uses.
|
|
774
|
+
*
|
|
775
|
+
* A framing failure disables useBtn — unlike the blur/glare nudge, this
|
|
776
|
+
* one blocks: a cropped ID reads as a confident, wrong identity downstream
|
|
777
|
+
* (partial OCR fields, a registry check against a truncated ID number)
|
|
778
|
+
* with no further chance to catch it, so the user must retake/re-upload
|
|
779
|
+
* rather than being trusted to notice an advisory nudge and act on it
|
|
780
|
+
* voluntarily. Fails open on decode error — this heuristic not running at
|
|
781
|
+
* all must not lock the user out of a photo it never actually scored.
|
|
648
782
|
*/
|
|
649
|
-
async _checkPhotoQuality(imageData, noticeEl, theme) {
|
|
783
|
+
async _checkPhotoQuality(imageData, noticeEl, theme, useBtn) {
|
|
650
784
|
try {
|
|
651
785
|
// Document photos are captured at up to DOC_CAMERA_IDEAL_WIDTH/HEIGHT
|
|
652
786
|
// (2000x1500) — scoring every pixel across four full-image passes in
|
|
@@ -659,6 +793,28 @@ class DocumentCapture {
|
|
|
659
793
|
if (!ctx)
|
|
660
794
|
return;
|
|
661
795
|
const pixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
796
|
+
const framing = (0, ImageQuality_1.assessFraming)(pixels, { x: 0, y: 0, width: 1, height: 1 });
|
|
797
|
+
if (!framing.isFramed) {
|
|
798
|
+
if (noticeEl.isConnected) {
|
|
799
|
+
noticeEl.style.display = "block";
|
|
800
|
+
noticeEl.textContent = framing.interiorVariance < 0.25
|
|
801
|
+
? "We couldn't detect a document in this photo — make sure the ID is clearly visible and try again."
|
|
802
|
+
: "Part of the document looks cut off — make sure all four corners are visible and try again.";
|
|
803
|
+
}
|
|
804
|
+
if (useBtn.isConnected) {
|
|
805
|
+
useBtn.disabled = true;
|
|
806
|
+
useBtn.style.opacity = "0.5";
|
|
807
|
+
useBtn.style.cursor = "not-allowed";
|
|
808
|
+
}
|
|
809
|
+
return; // framing issue is the more actionable/specific one — don't also show the quality nudge
|
|
810
|
+
}
|
|
811
|
+
// Framing passed — make sure a previous failed attempt (before Retake/
|
|
812
|
+
// Rotate) doesn't leave the button stuck disabled.
|
|
813
|
+
if (useBtn.isConnected) {
|
|
814
|
+
useBtn.disabled = false;
|
|
815
|
+
useBtn.style.opacity = "1";
|
|
816
|
+
useBtn.style.cursor = "pointer";
|
|
817
|
+
}
|
|
662
818
|
const result = (0, ImageQuality_1.assessQuality)(pixels);
|
|
663
819
|
if (noticeEl.isConnected && !result.isValid) {
|
|
664
820
|
noticeEl.style.display = "block";
|
|
@@ -668,7 +824,7 @@ class DocumentCapture {
|
|
|
668
824
|
}
|
|
669
825
|
}
|
|
670
826
|
catch {
|
|
671
|
-
//
|
|
827
|
+
// Fails open — no notice, button stays enabled, if scoring fails for any reason.
|
|
672
828
|
}
|
|
673
829
|
}
|
|
674
830
|
/** Decodes to a canvas, optionally downscaled to maxDim on the long edge (never upscales). */
|
|
@@ -805,6 +961,7 @@ class DocumentCapture {
|
|
|
805
961
|
input.click();
|
|
806
962
|
}
|
|
807
963
|
stopCamera() {
|
|
964
|
+
this._stopFramingLoop();
|
|
808
965
|
this._unwatchOrientation();
|
|
809
966
|
this.cameraManager.stop();
|
|
810
967
|
if (this.videoEl) {
|