@exige/web-scanner-sdk 0.2.26 → 0.2.27

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 CHANGED
@@ -138,7 +138,7 @@ The demo hosts a trained checkpoint at `/models/id-fields-yolox-nano.onnx`. **Se
138
138
 
139
139
  `detectDocument` runs DocAligner and returns an ordered `DocumentQuad` with `topLeft`, `topRight`, `bottomRight`, `bottomLeft`, plus typed `top`, `right`, `bottom`, and `left` line segments. Outcomes are `success`, `no-document`, `low-confidence`, or `low-quality`. `scanDocument` uses that same quad for a projective perspective warp and includes the quad in its result.
140
140
 
141
- On touch/mobile-class devices, analysis defaults to a 560px working image (1280px on the long edge when the page is tall) and runs in a module Worker when supported. Perspective output is capped at 4096px by default, the same long-edge memory cap as `capturePhoto()`. Override `maxAnalysisDimension`, `maxOutputDimension`, or `useWorker` in `ScanOptions` when needed. Chrome `takePhoto()` cannot match the Android Camera app (no HDR+ / OEM ISP). On Android, `ScannerProvider` `captureMode="auto"` (the default) opens that Camera app through `pickNativeCameraStill()`, then `scanSystemCameraStill()` crops the most prominent document. Hosts that want the live overlay on Android pass `captureMode="live"`. Force the picker on any platform with `captureMode="system-camera"`.
141
+ On touch/mobile-class devices, analysis defaults to a 560px working image (1280px on the long edge when the page is tall) and runs in a module Worker when supported. Perspective output is capped at 4096px by default, the same long-edge memory cap as `capturePhoto()`. Override `maxAnalysisDimension`, `maxOutputDimension`, or `useWorker` in `ScanOptions` when needed. Chrome `takePhoto()` cannot match the Android Camera app (no HDR+ / OEM ISP). On Android, `ScannerProvider` `captureMode="auto"` (the default) opens that Camera app through `pickNativeCameraStill()` as soon as `open` becomes true from a user gesture — no in-app shutter. Then `scanSystemCameraStill()` crops the most prominent document. Set `open` in the same click as the host button. Hosts that want the live overlay on Android pass `captureMode="live"`. Force the picker on any platform with `captureMode="system-camera"`.
142
142
 
143
143
  ## Live finder and auto-capture
144
144
 
@@ -215,7 +215,7 @@ await setLicenseKey(licenseKey)
215
215
  </ScannerProvider>
216
216
  ```
217
217
 
218
- `useScanner()` reads the session inside the provider. `useScannerRef()` gives the parent an imperative handle, passed as `apiRef`, the same idea as MUI's `useGridApiRef`. The camera covers the viewport, respects safe areas, shows finder/permission/error states, and keeps the existing auto-capture policies. On Android, `captureMode="auto"` skips the live preview and opens the system Camera app; DocAligner then finds the most prominent document on that JPEG. A miss stays on screen with **Try again**. iOS keeps the live overlay and auto-capture. The live path requests an ideal 4K rear-camera stream (no 1080×1920 Android cap), shows that stream in the preview, and continuously mirrors the last non-black frame. Outside WebKit, live capture uses `ImageCapture.takePhoto()` at max photo size and keeps the still even when its aspect differs from the preview; a still longer than 4096px is scaled with high-quality smoothing. WebKit `takePhoto()` returns black stills, so iOS copies the live preview or the mirrored frame. A genuinely blank capture fails loudly instead of exporting black pixels. Finder analysis stays on a 520–1600 working copy. Render `ScannerDiagnostics` for a live diagnostics panel with engine/browser, video and track state, luminance, and the chosen capture path; **Copy report** pastes a shutter-time dump for support. Pass `theme` to `ScannerFrame` to recolor the camera. `primaryColorHex` replaces the yellowish-green accents (`#c8ff45`). `seekingColorHex` and `detectingColorHex` are the waiting box colors (both `#ef6a5b` unless set apart), `unstableColorHex` is `#ffbe40`, `readyColorHex` is `#8af25a`, and `capturedColorHex` is `#ffffff`. Omit `theme` or any field to keep that default. The [React camera guide](site/guide/react-camera-overlay.md#theme) lists what each field paints. The demo source screen chooses Default, Ocean, Violet, or Signal before the camera starts and passes that palette as `theme` on `ScannerFrame`. Capture results include the displayed quad and its bounded-analysis dimensions; use `mapDocumentCornersToFrame()` plus `cropDocument()` so the final crop matches what was on screen. The framework-free imperative APIs remain available from the root package.
218
+ `useScanner()` reads the session inside the provider. `useScannerRef()` gives the parent an imperative handle, passed as `apiRef`, the same idea as MUI's `useGridApiRef`. The camera covers the viewport, respects safe areas, shows finder/permission/error states, and keeps the existing auto-capture policies. On Android, `captureMode="auto"` skips the live preview and opens the system Camera app as soon as `open` becomes true from a user gesture; DocAligner then finds the most prominent document on that JPEG. A miss stays on screen with **Try again**. iOS keeps the live overlay and auto-capture. The live path requests an ideal 4K rear-camera stream (no 1080×1920 Android cap), shows that stream in the preview, and continuously mirrors the last non-black frame. Outside WebKit, live capture uses `ImageCapture.takePhoto()` at max photo size and keeps the still even when its aspect differs from the preview; a still longer than 4096px is scaled with high-quality smoothing. WebKit `takePhoto()` returns black stills, so iOS copies the live preview or the mirrored frame. A genuinely blank capture fails loudly instead of exporting black pixels. Finder analysis stays on a 520–1600 working copy. Render `ScannerDiagnostics` for a live diagnostics panel with engine/browser, video and track state, luminance, and the chosen capture path; **Copy report** pastes a shutter-time dump for support. Pass `theme` to `ScannerFrame` to recolor the camera. `primaryColorHex` replaces the yellowish-green accents (`#c8ff45`). `seekingColorHex` and `detectingColorHex` are the waiting box colors (both `#ef6a5b` unless set apart), `unstableColorHex` is `#ffbe40`, `readyColorHex` is `#8af25a`, and `capturedColorHex` is `#ffffff`. Omit `theme` or any field to keep that default. The [React camera guide](site/guide/react-camera-overlay.md#theme) lists what each field paints. The demo source screen chooses Default, Ocean, Violet, or Signal before the camera starts and passes that palette as `theme` on `ScannerFrame`. Capture results include the displayed quad and its bounded-analysis dimensions; use `mapDocumentCornersToFrame()` plus `cropDocument()` so the final crop matches what was on screen. The framework-free imperative APIs remain available from the root package.
219
219
 
220
220
  ## Run the demo
221
221
 
@@ -984,7 +984,11 @@ async function qe(t, n = {}) {
984
984
  }
985
985
  };
986
986
  }
987
- async function Je() {
987
+ function Je() {
988
+ let e = typeof navigator > "u" ? void 0 : navigator.userActivation;
989
+ return !e || e.isActive;
990
+ }
991
+ async function Ye() {
988
992
  let e = document.createElement("input");
989
993
  return e.type = "file", e.accept = "image/*", e.capture = "environment", e.setAttribute("capture", "environment"), We(await new Promise((t, n) => {
990
994
  e.addEventListener("change", () => {
@@ -997,12 +1001,12 @@ async function Je() {
997
1001
  }
998
1002
  //#endregion
999
1003
  //#region src/sdk/lighting.ts
1000
- function Ye(e, t) {
1004
+ function Xe(e, t) {
1001
1005
  if (!e.length) return 0;
1002
1006
  let n = [...e].sort((e, t) => e - t);
1003
1007
  return n[Math.min(n.length - 1, Math.floor(n.length * t))];
1004
1008
  }
1005
- function Xe(e, t, n, r = 12) {
1009
+ function Ze(e, t, n, r = 12) {
1006
1010
  if (!t || !n || e.length < t * n) return {
1007
1011
  strong: !1,
1008
1012
  strength: 0,
@@ -1025,7 +1029,7 @@ function Xe(e, t, n, r = 12) {
1025
1029
  });
1026
1030
  }
1027
1031
  }
1028
- let s = Ye(o.map((e) => e.mean), .8), c = o.map((e) => s - e.mean >= 24 && e.mean >= 35), l = new Uint8Array(o.length), u = [];
1032
+ let s = Xe(o.map((e) => e.mean), .8), c = o.map((e) => s - e.mean >= 24 && e.mean >= 35), l = new Uint8Array(o.length), u = [];
1029
1033
  for (let e = 0; e < o.length; e += 1) {
1030
1034
  if (!c[e] || l[e]) continue;
1031
1035
  let t = [], n = [e];
@@ -1073,11 +1077,11 @@ function Xe(e, t, n, r = 12) {
1073
1077
  }
1074
1078
  return d;
1075
1079
  }
1076
- function Ze(e, t, n, r, i, a, o) {
1080
+ function Qe(e, t, n, r, i, a, o) {
1077
1081
  let s = Math.max(0, a - o), c = Math.min(r, a + o + 1), l = Math.max(0, i - o), u = Math.min(n, i + o + 1), d = Math.max(1, (u - l) * (c - s));
1078
1082
  return (e[c * t + u] - e[s * t + u] - e[c * t + l] + e[s * t + l]) / d;
1079
1083
  }
1080
- function Qe(e, t, n) {
1084
+ function $e(e, t, n) {
1081
1085
  let r = t + 1, i = new Uint32Array((t + 1) * (n + 1));
1082
1086
  for (let a = 1; a <= n; a += 1) {
1083
1087
  let n = 0;
@@ -1088,23 +1092,23 @@ function Qe(e, t, n) {
1088
1092
  stride: r
1089
1093
  };
1090
1094
  }
1091
- function $e(e, t, n, r = Math.max(12, Math.round(Math.max(t, n) / 32))) {
1092
- let { integral: i, stride: a } = Qe(e, t, n), o = new Uint8Array(e.length);
1095
+ function et(e, t, n, r = Math.max(12, Math.round(Math.max(t, n) / 32))) {
1096
+ let { integral: i, stride: a } = $e(e, t, n), o = new Uint8Array(e.length);
1093
1097
  for (let s = 0; s < n; s += 1) for (let c = 0; c < t; c += 1) {
1094
- let l = Ze(i, a, t, n, c, s, r);
1098
+ let l = Qe(i, a, t, n, c, s, r);
1095
1099
  o[s * t + c] = Math.max(0, Math.min(255, Math.round(e[s * t + c] * 235 / Math.max(24, l))));
1096
1100
  }
1097
1101
  return o;
1098
1102
  }
1099
- function et(e, t, n, r = Math.max(8, Math.round(Math.max(t, n) / 64)), i = .12) {
1100
- let { integral: a, stride: o } = Qe(e, t, n), s = new Uint8Array(e.length), c = 1 - i;
1103
+ function tt(e, t, n, r = Math.max(8, Math.round(Math.max(t, n) / 64)), i = .12) {
1104
+ let { integral: a, stride: o } = $e(e, t, n), s = new Uint8Array(e.length), c = 1 - i;
1101
1105
  for (let i = 0; i < n; i += 1) for (let l = 0; l < t; l += 1) {
1102
- let u = Ze(a, o, t, n, l, i, r);
1106
+ let u = Qe(a, o, t, n, l, i, r);
1103
1107
  s[i * t + l] = e[i * t + l] < u * c ? 0 : 255;
1104
1108
  }
1105
1109
  return s;
1106
1110
  }
1107
- function tt(e, t, n) {
1111
+ function nt(e, t, n) {
1108
1112
  let r = [
1109
1113
  e.topLeft,
1110
1114
  e.topRight,
@@ -1118,8 +1122,8 @@ function tt(e, t, n) {
1118
1122
  height: s - a
1119
1123
  };
1120
1124
  }
1121
- function nt(e, t) {
1122
- let n = tt(t, e.width, e.height);
1125
+ function rt(e, t) {
1126
+ let n = nt(t, e.width, e.height);
1123
1127
  if (n.width <= 0 || n.height <= 0) return {
1124
1128
  strong: !1,
1125
1129
  strength: 0,
@@ -1138,18 +1142,18 @@ function nt(e, t) {
1138
1142
  i.drawImage(e, n.left, n.top, n.width, n.height, 0, 0, r.width, r.height);
1139
1143
  let a = i.getImageData(0, 0, r.width, r.height).data, o = new Uint8Array(r.width * r.height);
1140
1144
  for (let e = 0, t = 0; e < o.length; e += 1, t += 4) o[e] = Math.round(a[t] * .299 + a[t + 1] * .587 + a[t + 2] * .114);
1141
- return Xe(o, r.width, r.height);
1145
+ return Ze(o, r.width, r.height);
1142
1146
  }
1143
1147
  //#endregion
1144
1148
  //#region src/sdk/finder.ts
1145
- function rt(e, t) {
1149
+ function it(e, t) {
1146
1150
  return t.castShadow && (e.reason === "hold-still" || e.reason === "ready") ? t.hint ?? e.hint : e.hint;
1147
1151
  }
1148
- async function it(e, t) {
1152
+ async function at(e, t) {
1149
1153
  let n = await e();
1150
1154
  return t(), n;
1151
1155
  }
1152
- function at(e) {
1156
+ function ot(e) {
1153
1157
  return e === "alwaysOn" || e === "only" ? {
1154
1158
  visible: !1,
1155
1159
  checked: !0,
@@ -1172,7 +1176,7 @@ function X(e) {
1172
1176
  e.bottomLeft
1173
1177
  ];
1174
1178
  }
1175
- function ot(e, t) {
1179
+ function st(e, t) {
1176
1180
  let n = e.status === "success" && e.modelStatus !== "failed", r = {
1177
1181
  status: e.status,
1178
1182
  confidence: Number(e.confidence.toFixed(3)),
@@ -1195,7 +1199,7 @@ function ot(e, t) {
1195
1199
  detail: r
1196
1200
  };
1197
1201
  }
1198
- function st(e) {
1202
+ function ct(e) {
1199
1203
  let t = 0;
1200
1204
  for (let n = 0; n < e.length; n += 1) {
1201
1205
  let r = e[n], i = e[(n + 1) % e.length];
@@ -1213,23 +1217,23 @@ var Q = {
1213
1217
  areaFill: 0,
1214
1218
  aspectRatio: 1
1215
1219
  };
1216
- function ct(e, t, n) {
1220
+ function lt(e, t, n) {
1217
1221
  let r = X(e), i = r.map(({ x: e }) => e), a = r.map(({ y: e }) => e), o = (Math.max(...i) - Math.min(...i)) / Math.max(1, t), s = (Math.max(...a) - Math.min(...a)) / Math.max(1, n), [c, l, u, d] = r, f = Math.max(Z(c, l), Z(d, u)), p = Math.max(Z(c, d), Z(l, u));
1218
1222
  return {
1219
1223
  widthFill: o,
1220
1224
  heightFill: s,
1221
1225
  limitingFill: Math.max(o, s),
1222
- areaFill: st(r) / Math.max(1, t * n),
1226
+ areaFill: ct(r) / Math.max(1, t * n),
1223
1227
  aspectRatio: Math.max(f, p) / Math.max(1, Math.min(f, p))
1224
1228
  };
1225
1229
  }
1226
- function lt(e, t, n, r = {}) {
1230
+ function ut(e, t, n, r = {}) {
1227
1231
  let i = t ? r.exitFillRatio ?? .64 : r.minFillRatio ?? .72, a = r.highAspectRatio ?? 2.2;
1228
1232
  if (e.aspectRatio < a) return i;
1229
1233
  let o = t ? r.highAspectExitFillRatio : r.highAspectFillRatio;
1230
1234
  return Math.min(o ?? i + .08, 1 - n * 2);
1231
1235
  }
1232
- function ut(e, t, n = {}) {
1236
+ function dt(e, t, n = {}) {
1233
1237
  let r = n.confidenceThreshold ?? .72;
1234
1238
  if (e.status !== "success" || !e.quad || e.confidence < r || !e.sourceWidth || !e.sourceHeight) return {
1235
1239
  hint: "Place the document in the frame",
@@ -1238,7 +1242,7 @@ function ut(e, t, n = {}) {
1238
1242
  fill: Q,
1239
1243
  readyForAutoCapture: !1
1240
1244
  };
1241
- let i = X(e.quad), a = ct(e.quad, e.sourceWidth, e.sourceHeight), o = a.limitingFill, s = t.previouslyReady ? n.exitEdgeMarginRatio ?? .005 : n.edgeMarginRatio ?? .015, c = e.sourceWidth * s, l = e.sourceHeight * s;
1245
+ let i = X(e.quad), a = lt(e.quad, e.sourceWidth, e.sourceHeight), o = a.limitingFill, s = t.previouslyReady ? n.exitEdgeMarginRatio ?? .005 : n.edgeMarginRatio ?? .015, c = e.sourceWidth * s, l = e.sourceHeight * s;
1242
1246
  if (i.some(({ x: t, y: n }) => t <= c || t >= e.sourceWidth - c || n <= l || n >= e.sourceHeight - l)) return {
1243
1247
  hint: "Move farther away",
1244
1248
  reason: "move-farther-away",
@@ -1253,7 +1257,7 @@ function ut(e, t, n = {}) {
1253
1257
  fillRatio: o,
1254
1258
  fill: a,
1255
1259
  readyForAutoCapture: !1
1256
- } : o < lt(a, t.previouslyReady === !0, s, n) ? {
1260
+ } : o < ut(a, t.previouslyReady === !0, s, n) ? {
1257
1261
  hint: "Move closer",
1258
1262
  reason: "move-closer",
1259
1263
  fillRatio: o,
@@ -1295,14 +1299,14 @@ var $ = class {
1295
1299
  };
1296
1300
  }
1297
1301
  };
1298
- function dt(e, n) {
1302
+ function ft(e, n) {
1299
1303
  let r = Math.min(1, n / Math.max(e.width, e.height)), i = document.createElement("canvas");
1300
1304
  i.width = Math.max(1, Math.round(e.width * r)), i.height = Math.max(1, Math.round(e.height * r));
1301
1305
  let a = i.getContext("2d");
1302
1306
  if (!a) throw t();
1303
1307
  return a.drawImage(e, 0, 0, i.width, i.height), i;
1304
1308
  }
1305
- function ft() {
1309
+ function pt() {
1306
1310
  let e = window.AudioContext ?? window.webkitAudioContext;
1307
1311
  if (!e) return;
1308
1312
  let t = new e(), n = Math.round(t.sampleRate * .09), r = t.createBuffer(1, n, t.sampleRate), i = r.getChannelData(0);
@@ -1313,13 +1317,13 @@ function ft() {
1313
1317
  let a = t.createBufferSource(), o = t.createBiquadFilter(), s = t.createGain();
1314
1318
  o.type = "bandpass", o.frequency.value = 1400, s.gain.value = .42, a.buffer = r, a.connect(o).connect(s).connect(t.destination), a.start(), a.onended = () => void t.close();
1315
1319
  }
1316
- async function pt(e) {
1320
+ async function mt(e) {
1317
1321
  let t = document.createElement("video");
1318
1322
  return t.muted = !0, t.autoplay = !0, t.playsInline = !0, t.srcObject = e, await t.play(), t;
1319
1323
  }
1320
- async function mt(t) {
1324
+ async function ht(t) {
1321
1325
  await x("scan");
1322
- let n = at(t.autoCapture), r = new $({
1326
+ let n = ot(t.autoCapture), r = new $({
1323
1327
  stableFrames: t.stableFrames ?? 4,
1324
1328
  confidenceThreshold: t.confidenceThreshold ?? .72,
1325
1329
  cornerTolerance: t.cornerTolerance ?? .024,
@@ -1328,7 +1332,7 @@ async function mt(t) {
1328
1332
  minDimension: 220,
1329
1333
  maxAnalysisDimension: 520,
1330
1334
  ...t.detection
1331
- }, s = typeof MediaStream < "u" && t.source instanceof MediaStream ? await pt(t.source) : t.source, c = !0, l = !1, u = !1, d = 0, f, p = "", m = 0, h = {
1335
+ }, s = typeof MediaStream < "u" && t.source instanceof MediaStream ? await mt(t.source) : t.source, c = !0, l = !1, u = !1, d = 0, f, p = "", m = 0, h = {
1332
1336
  state: "detecting",
1333
1337
  confidence: 0,
1334
1338
  guidance: {
@@ -1345,10 +1349,10 @@ async function mt(t) {
1345
1349
  stableFrames: 0,
1346
1350
  requiredStableFrames: t.stableFrames ?? 4,
1347
1351
  autoCapture: { ...n }
1348
- }, g = () => s instanceof HTMLCanvasElement ? dt(s, i) : Y(s, i), _ = (e) => {
1352
+ }, g = () => s instanceof HTMLCanvasElement ? ft(s, i) : Y(s, i), _ = (e) => {
1349
1353
  h = e, t.onStatus?.(e);
1350
1354
  }, v = (e) => {
1351
- let t = ot(e, s instanceof HTMLVideoElement ? {
1355
+ let t = st(e, s instanceof HTMLVideoElement ? {
1352
1356
  width: s.videoWidth,
1353
1357
  height: s.videoHeight
1354
1358
  } : {
@@ -1363,11 +1367,11 @@ async function mt(t) {
1363
1367
  l = !0;
1364
1368
  let n;
1365
1369
  try {
1366
- n = await it(t.captureFrame ?? g, () => {
1370
+ n = await at(t.captureFrame ?? g, () => {
1367
1371
  _({
1368
1372
  ...h,
1369
1373
  state: "captured"
1370
- }), t.playShutterSound !== !1 && ft(), y();
1374
+ }), t.playShutterSound !== !1 && pt(), y();
1371
1375
  });
1372
1376
  } catch (e) {
1373
1377
  throw l = !1, e instanceof Error ? e : /* @__PURE__ */ Error("The camera frame could not be captured.");
@@ -1383,7 +1387,7 @@ async function mt(t) {
1383
1387
  try {
1384
1388
  let e = g(), i = await R(e, o);
1385
1389
  f = i, v(i);
1386
- let a = i.quad ? nt(e, i.quad) : {
1390
+ let a = i.quad ? rt(e, i.quad) : {
1387
1391
  strong: !1,
1388
1392
  strength: 0
1389
1393
  }, s = a.strong ? {
@@ -1393,7 +1397,7 @@ async function mt(t) {
1393
1397
  } : {
1394
1398
  castShadow: !1,
1395
1399
  strength: a.strength
1396
- }, c = r.update(i), l = ut(i, {
1400
+ }, c = r.update(i), l = dt(i, {
1397
1401
  ...c,
1398
1402
  previouslyReady: u
1399
1403
  }, {
@@ -1475,6 +1479,6 @@ async function mt(t) {
1475
1479
  };
1476
1480
  }
1477
1481
  //#endregion
1478
- export { we as A, b as B, qe as C, R as D, Ce as E, ie as F, e as H, ne as I, a as L, de as M, fe as N, j as O, A as P, o as R, Ee as S, pe as T, t as U, y as V, U as _, ut as a, J as b, et as c, G as d, je as f, Te as g, H as h, ct as i, B as j, z as k, Xe as l, Y as m, at as n, rt as o, ze as p, lt as r, mt as s, $ as t, $e as u, Me as v, K as w, Je as x, q as y, x as z };
1482
+ export { z as A, x as B, Ee as C, Ce as D, pe as E, A as F, y as H, ie as I, ne as L, B as M, de as N, R as O, fe as P, a as R, Ye as S, K as T, e as U, b as V, t as W, Je as _, dt as a, q as b, tt as c, G as d, je as f, Te as g, H as h, lt as i, we as j, j as k, Ze as l, Y as m, ot as n, it as o, ze as p, ut as r, ht as s, $ as t, et as u, U as v, qe as w, J as x, Me as y, o as z };
1479
1483
 
1480
- //# sourceMappingURL=finder-Dcg3mVJM.js.map
1484
+ //# sourceMappingURL=finder-BlN89ZeT.js.map