@exige/web-scanner-sdk 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +288 -0
  2. package/dist/assets/document-worker-QjcJjl9-.js +2 -0
  3. package/dist/assets/document-worker-QjcJjl9-.js.map +1 -0
  4. package/dist/assets/ort.min-CA5AZ7mL.js +2937 -0
  5. package/dist/assets/ort.min-CA5AZ7mL.js.map +1 -0
  6. package/dist/components/ScannerCameraOverlay.d.ts +36 -0
  7. package/dist/components/scanner-camera-overlay.css +2 -0
  8. package/dist/finder-Clo7f2gN.js +1447 -0
  9. package/dist/finder-Clo7f2gN.js.map +1 -0
  10. package/dist/index.d.ts +20 -0
  11. package/dist/live-overlay-geometry.d.ts +11 -0
  12. package/dist/react.d.ts +2 -0
  13. package/dist/react.js +448 -0
  14. package/dist/react.js.map +1 -0
  15. package/dist/scanner-sdk.js +921 -0
  16. package/dist/scanner-sdk.js.map +1 -0
  17. package/dist/sdk/camera.d.ts +142 -0
  18. package/dist/sdk/detect.d.ts +3 -0
  19. package/dist/sdk/display-quad.d.ts +23 -0
  20. package/dist/sdk/document-analysis.d.ts +14 -0
  21. package/dist/sdk/document-geometry.d.ts +21 -0
  22. package/dist/sdk/field-model.d.ts +4 -0
  23. package/dist/sdk/finder-simulator.d.ts +17 -0
  24. package/dist/sdk/finder.d.ts +166 -0
  25. package/dist/sdk/frame-geometry.d.ts +6 -0
  26. package/dist/sdk/image.d.ts +18 -0
  27. package/dist/sdk/license-codec.d.ts +2 -0
  28. package/dist/sdk/license-public-key.d.ts +9 -0
  29. package/dist/sdk/license-runtime.d.ts +2 -0
  30. package/dist/sdk/license.d.ts +76 -0
  31. package/dist/sdk/lighting.d.ts +22 -0
  32. package/dist/sdk/ocr.d.ts +75 -0
  33. package/dist/sdk/programmatic-redaction.d.ts +102 -0
  34. package/dist/sdk/redact.d.ts +12 -0
  35. package/dist/sdk/scan.d.ts +32 -0
  36. package/dist/sdk/types.d.ts +92 -0
  37. package/package.json +74 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finder-Clo7f2gN.js","names":[],"sources":["../src/sdk/license-codec.ts","../src/sdk/license-public-key.ts","../src/sdk/license-runtime.ts","../src/sdk/license.ts","../src/sdk/document-geometry.ts","../src/sdk/document-analysis.ts","../src/sdk/image.ts","../src/sdk/scan.ts","../src/sdk/camera.ts","../src/sdk/lighting.ts","../src/sdk/finder.ts"],"sourcesContent":["export function bytesToBase64Url(bytes: Uint8Array): string {\n let binary = ''\n for (const byte of bytes) binary += String.fromCharCode(byte)\n return btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/u, '')\n}\n\nexport function base64UrlToBytes(value: string): Uint8Array {\n const normalized = value.replaceAll('-', '+').replaceAll('_', '/')\n const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4)\n const binary = atob(padded)\n const bytes = new Uint8Array(binary.length)\n for (let index = 0; index < binary.length; index += 1) {\n bytes[index] = binary.charCodeAt(index)\n }\n return bytes\n}\n","/**\n * Raw Ed25519 public key: 32 bytes, base64url, no padding.\n *\n * The license portal signs with `LICENSE_SIGNING_PRIVATE_KEY`.\n * Generate a pair with `npm run generate-keypair --prefix license-portal`,\n * then replace this constant with the printed public key and rebuild the\n * library. Never commit the private key.\n */\nexport const LICENSE_PUBLIC_KEY_BASE64 = 'uFpA_UXGk-1AjjG31cFP6cqXOQX0w2TnuR7Bl-msZ6I'\n","import { base64UrlToBytes } from './license-codec'\nimport { LICENSE_PUBLIC_KEY_BASE64 } from './license-public-key'\n\n/** Public key embedded in the published package. Tests replace this module. */\nexport function embeddedLicensePublicKey(): Uint8Array {\n return base64UrlToBytes(LICENSE_PUBLIC_KEY_BASE64)\n}\n","import { base64UrlToBytes } from './license-codec'\nimport { embeddedLicensePublicKey } from './license-runtime'\n\n/**\n * Hosts that may use the SDK before a paid license exists.\n * Add a production hostname here when it should run without a signed key.\n *\n * An entry is either an exact hostname or a single `*.suffix` pattern.\n * `*.exige.io` matches `exige.io` and any host that ends with `.exige.io`.\n * It does not match `exige.io.evil.com`. Other entries are exact:\n * `exige-park-app.ngrok.io` does not allow the rest of ngrok, and nothing\n * here allows `*.vercel.app`. Paid license `domains` stay exact hostnames.\n */\nexport const DEV_LICENSE_HOSTS = [\n 'localhost',\n '127.0.0.1',\n 'exige-scanner-sdk.vercel.app',\n 'exige-park-app.ngrok.io',\n '*.exige.io',\n] as const\n\nexport const LICENSE_FEATURES = ['scan', 'ocr', 'redaction', 'vehicles', 'torch'] as const\n\nexport type LicenseFeature = (typeof LICENSE_FEATURES)[number]\n\nexport type LicenseErrorCode =\n | 'missing'\n | 'malformed'\n | 'invalid-signature'\n | 'expired'\n | 'domain'\n | 'feature'\n\nexport interface LicenseFeatures {\n scan: boolean\n ocr: boolean\n redaction: boolean\n vehicles: boolean\n torch: boolean\n}\n\nexport interface LicenseClaims {\n customerId: string\n /** Exact hostnames. `localhost` and `127.0.0.1` are included only when listed. */\n domains: string[]\n /** Unix expiry in seconds. The key is valid while `now < exp`. */\n exp: number\n features: LicenseFeatures\n}\n\n/**\n * Compact signed payload: `base64url(json).base64url(ed25519 signature)`.\n * The signature covers the raw JSON bytes. Public APIs do not accept a\n * caller-supplied public key or hostname.\n */\nexport interface LicenseVerification {\n publicKey: Uint8Array\n /** Injected only for Node tests. Browsers use `location.hostname`. */\n hostname: string\n /** Unix time in seconds. */\n now: number\n}\n\nexport class LicenseError extends Error {\n readonly code: LicenseErrorCode\n\n constructor(code: LicenseErrorCode, message: string) {\n super(message)\n this.name = 'LicenseError'\n this.code = code\n }\n}\n\nlet activeToken: string | undefined\nlet activeClaims: LicenseClaims | undefined\n\nexport function normalizeHostname(value: string): string {\n return value.trim().toLowerCase().replace(/\\.$/u, '')\n}\n\n/**\n * Canonical JSON signed by the license portal. Key order is part of the\n * signature bytes. Keep this in lockstep with `license-portal/lib/license-token.ts`.\n */\nexport function canonicalLicensePayload(claims: LicenseClaims): string {\n const domains = [...new Set(claims.domains.map(normalizeHostname).filter(Boolean))].sort()\n const features = {\n ocr: claims.features.ocr === true,\n redaction: claims.features.redaction === true,\n scan: claims.features.scan === true,\n torch: claims.features.torch === true,\n vehicles: claims.features.vehicles === true,\n }\n return JSON.stringify({\n customerId: claims.customerId,\n domains,\n exp: claims.exp,\n features,\n })\n}\n\nfunction readBrowserHostname(): string | undefined {\n const host = (globalThis as { location?: { hostname?: string } }).location?.hostname\n if (typeof host !== 'string') return undefined\n const normalized = normalizeHostname(host)\n return normalized || undefined\n}\n\nfunction unixNow(): number {\n return Math.floor(Date.now() / 1000)\n}\n\nfunction matchesDevLicenseEntry(hostname: string, entry: string): boolean {\n const pattern = normalizeHostname(entry)\n if (pattern.startsWith('*.')) {\n const suffix = pattern.slice(2)\n if (!suffix.includes('.') || suffix.startsWith('.') || suffix.includes('*')) return false\n return hostname === suffix || hostname.endsWith(`.${suffix}`)\n }\n return hostname === pattern\n}\n\nfunction isDevLicenseHost(hostname: string): boolean {\n const host = normalizeHostname(hostname)\n if (!host || host.includes('*')) return false\n return DEV_LICENSE_HOSTS.some((entry) => matchesDevLicenseEntry(host, entry))\n}\n\n/** All features, only for the host that matched `DEV_LICENSE_HOSTS`. */\nfunction developmentLicense(hostname: string): LicenseClaims {\n return {\n customerId: 'dev',\n domains: [hostname],\n exp: 4_102_444_800,\n features: {\n scan: true,\n ocr: true,\n redaction: true,\n vehicles: true,\n torch: true,\n },\n }\n}\n\nfunction copyClaims(claims: LicenseClaims): LicenseClaims {\n return {\n customerId: claims.customerId,\n domains: [...claims.domains],\n exp: claims.exp,\n features: { ...claims.features },\n }\n}\n\nfunction malformed(message = 'This license key is not a signed payload.'): LicenseError {\n return new LicenseError('malformed', message)\n}\n\nfunction parseClaims(payload: unknown): LicenseClaims {\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) throw malformed()\n const record = payload as Record<string, unknown>\n if (typeof record.customerId !== 'string' || record.customerId.trim() === '' || record.customerId.length > 200) {\n throw malformed('This license key is missing a customer id.')\n }\n if (!Array.isArray(record.domains) || record.domains.some((domain) => typeof domain !== 'string')) {\n throw malformed('This license key is missing a domain list.')\n }\n if (typeof record.exp !== 'number' || !Number.isSafeInteger(record.exp) || record.exp <= 0) {\n throw malformed('This license key is missing a Unix expiry.')\n }\n if (!record.features || typeof record.features !== 'object' || Array.isArray(record.features)) {\n throw malformed('This license key is missing feature flags.')\n }\n const flags = record.features as Record<string, unknown>\n const domains = [...new Set(record.domains.map((domain) => normalizeHostname(domain)).filter(Boolean))].sort()\n return {\n customerId: record.customerId.trim(),\n domains,\n exp: record.exp,\n features: {\n scan: flags.scan === true,\n ocr: flags.ocr === true,\n redaction: flags.redaction === true,\n vehicles: flags.vehicles === true,\n torch: flags.torch === true,\n },\n }\n}\n\n/**\n * Verifies a compact license. Hostname and public key are explicit so Node\n * tests can inject them. Published entry points call `assertLicense`, which\n * always uses the embedded public key and `location.hostname`.\n */\nexport async function verifyLicenseToken(\n licenseKey: string,\n verification: LicenseVerification,\n): Promise<LicenseClaims> {\n const parts = licenseKey.trim().split('.')\n if (parts.length !== 2 || !parts[0] || !parts[1]) throw malformed()\n let payloadBytes: Uint8Array\n let signature: Uint8Array\n try {\n payloadBytes = base64UrlToBytes(parts[0])\n signature = base64UrlToBytes(parts[1])\n } catch {\n throw malformed()\n }\n let key: CryptoKey\n let valid = false\n try {\n key = await crypto.subtle.importKey(\n 'raw',\n verification.publicKey as BufferSource,\n { name: 'Ed25519' },\n false,\n ['verify'],\n )\n valid = await crypto.subtle.verify('Ed25519', key, signature as BufferSource, payloadBytes as BufferSource)\n } catch {\n valid = false\n }\n if (!valid) {\n throw new LicenseError('invalid-signature', 'This license key signature does not match the SDK public key.')\n }\n let parsed: unknown\n try {\n parsed = JSON.parse(new TextDecoder().decode(payloadBytes))\n } catch {\n throw malformed()\n }\n const claims = parseClaims(parsed)\n if (claims.exp <= verification.now) {\n throw new LicenseError('expired', 'This license key has expired.')\n }\n const hostname = normalizeHostname(verification.hostname)\n if (!hostname || !claims.domains.includes(hostname)) {\n throw new LicenseError('domain', `This license key is not valid for ${hostname || 'this host'}.`)\n }\n return claims\n}\n\n/**\n * Verifies `licenseKey` for the current page and keeps it for later calls.\n * Throws `LicenseError` when the key is missing, malformed, badly signed,\n * expired, or not issued for `location.hostname`.\n */\nexport async function setLicenseKey(licenseKey: string): Promise<LicenseClaims> {\n const hostname = readBrowserHostname()\n if (!hostname) {\n throw new LicenseError('domain', 'The license check requires a browser hostname.')\n }\n const claims = await verifyLicenseToken(licenseKey, {\n publicKey: embeddedLicensePublicKey(),\n hostname,\n now: unixNow(),\n })\n activeToken = licenseKey.trim()\n activeClaims = claims\n return copyClaims(claims)\n}\n\n/**\n * Feature flags from the key most recently accepted by `setLicenseKey`.\n * Returns null when no key is loaded, the key is expired, or this hostname\n * is not on the key. Enforcement still re-checks the signature in `assertLicense`.\n */\nexport function getLicense(): LicenseClaims | null {\n const hostname = readBrowserHostname()\n if (activeClaims && hostname && activeClaims.domains.includes(hostname) && activeClaims.exp > unixNow()) {\n return copyClaims(activeClaims)\n }\n if (!activeToken && hostname && isDevLicenseHost(hostname)) return copyClaims(developmentLicense(hostname))\n return null\n}\n\n/**\n * Fail-closed gate used by the public camera, finder, scan, OCR, redaction,\n * and vehicle entry points. Throws before those APIs do any work.\n */\nexport async function assertLicense(feature: LicenseFeature): Promise<LicenseClaims> {\n const hostname = readBrowserHostname()\n if (!hostname) {\n throw new LicenseError('domain', 'The license check requires a browser hostname.')\n }\n if (!activeToken) {\n if (isDevLicenseHost(hostname)) return copyClaims(developmentLicense(hostname))\n throw new LicenseError(\n 'missing',\n 'A license key is required. Call setLicenseKey() before using the scanner SDK.',\n )\n }\n const claims = await verifyLicenseToken(activeToken, {\n publicKey: embeddedLicensePublicKey(),\n hostname,\n now: unixNow(),\n })\n activeClaims = claims\n if (!claims.features[feature]) {\n throw new LicenseError('feature', `This license key does not include the ${feature} feature.`)\n }\n return copyClaims(claims)\n}\n\n/** Drops the in-memory key. Not part of the published package entry. */\nexport function clearLicenseForTests(): void {\n activeToken = undefined\n activeClaims = undefined\n}\n","import type { DocumentCorners, Point } from './types'\n\nexport interface QuadCandidate {\n corners: DocumentCorners\n confidence: number\n areaRatio: number\n}\n\nexport interface PerspectiveQuadScore {\n total: number\n areaRatio: number\n angleScore: number\n oppositeAngleScore: number\n parallelScore: number\n homographyScore: number\n aspectBoost: number\n}\n\nfunction cross(origin: Point, a: Point, b: Point) {\n return (a.x - origin.x) * (b.y - origin.y) - (a.y - origin.y) * (b.x - origin.x)\n}\n\nfunction convexHull(points: Point[]) {\n const sorted = [...points].sort((a, b) => a.x - b.x || a.y - b.y)\n if (sorted.length <= 3) return sorted\n const lower: Point[] = []\n for (const point of sorted) {\n while (lower.length >= 2 && cross(lower.at(-2)!, lower.at(-1)!, point) <= 0) lower.pop()\n lower.push(point)\n }\n const upper: Point[] = []\n for (let index = sorted.length - 1; index >= 0; index -= 1) {\n const point = sorted[index]\n while (upper.length >= 2 && cross(upper.at(-2)!, upper.at(-1)!, point) <= 0) upper.pop()\n upper.push(point)\n }\n lower.pop()\n upper.pop()\n return lower.concat(upper)\n}\n\nexport function polygonArea(points: Point[]) {\n let sum = 0\n for (let index = 0; index < points.length; index += 1) {\n const current = points[index]\n const next = points[(index + 1) % points.length]\n sum += current.x * next.y - next.x * current.y\n }\n return Math.abs(sum) / 2\n}\n\nexport function orderCorners(points: Point[]): DocumentCorners | undefined {\n if (points.length < 4) return undefined\n const topLeft = points.reduce((best, point) => point.x + point.y < best.x + best.y ? point : best)\n const bottomRight = points.reduce((best, point) => point.x + point.y > best.x + best.y ? point : best)\n const topRight = points.reduce((best, point) => point.x - point.y > best.x - best.y ? point : best)\n const bottomLeft = points.reduce((best, point) => point.x - point.y < best.x - best.y ? point : best)\n const unique = new Set([topLeft, topRight, bottomRight, bottomLeft])\n if (unique.size !== 4) return undefined\n return { topLeft, topRight, bottomRight, bottomLeft }\n}\n\nfunction clamp01(value: number) {\n return Math.max(0, Math.min(1, value))\n}\n\nfunction distance(a: Point, b: Point) {\n return Math.hypot(a.x - b.x, a.y - b.y)\n}\n\nfunction interiorAngle(previous: Point, vertex: Point, next: Point) {\n const ax = previous.x - vertex.x\n const ay = previous.y - vertex.y\n const bx = next.x - vertex.x\n const by = next.y - vertex.y\n const denominator = Math.max(1e-6, Math.hypot(ax, ay) * Math.hypot(bx, by))\n return Math.acos(Math.max(-1, Math.min(1, (ax * bx + ay * by) / denominator))) * 180 / Math.PI\n}\n\nfunction directionDifference(a: Point, b: Point, c: Point, d: Point) {\n const first = Math.atan2(b.y - a.y, b.x - a.x)\n const second = Math.atan2(d.y - c.y, d.x - c.x)\n let difference = Math.abs(first - second) % Math.PI\n if (difference > Math.PI / 2) difference = Math.PI - difference\n return difference\n}\n\nfunction unitToQuadCoefficients(corners: DocumentCorners) {\n const { topLeft: tl, topRight: tr, bottomRight: br, bottomLeft: bl } = corners\n const dx1 = tr.x - br.x\n const dx2 = bl.x - br.x\n const dy1 = tr.y - br.y\n const dy2 = bl.y - br.y\n const sx = tl.x - tr.x + br.x - bl.x\n const sy = tl.y - tr.y + br.y - bl.y\n const denominator = dx1 * dy2 - dx2 * dy1\n const g = Math.abs(denominator) < 1e-6 ? 0 : (sx * dy2 - dx2 * sy) / denominator\n const h = Math.abs(denominator) < 1e-6 ? 0 : (dx1 * sy - sx * dy1) / denominator\n return {\n a: tr.x - tl.x + g * tr.x,\n b: bl.x - tl.x + h * bl.x,\n c: tl.x,\n d: tr.y - tl.y + g * tr.y,\n e: bl.y - tl.y + h * bl.y,\n f: tl.y,\n g,\n h,\n }\n}\n\nfunction quadToUnit(point: Point, coefficients: ReturnType<typeof unitToQuadCoefficients>) {\n const { a, b, c, d, e, f, g, h } = coefficients\n const aa = a - point.x * g\n const bb = b - point.x * h\n const dd = d - point.y * g\n const ee = e - point.y * h\n const xx = point.x - c\n const yy = point.y - f\n const determinant = aa * ee - bb * dd\n if (Math.abs(determinant) < 1e-8) return undefined\n return {\n x: (xx * ee - bb * yy) / determinant,\n y: (aa * yy - xx * dd) / determinant,\n }\n}\n\nfunction homographyBoundaryScore(corners: DocumentCorners, hull: Point[]) {\n if (!hull.length) return 0\n const coefficients = unitToQuadCoefficients(corners)\n let squaredResidual = 0\n let samples = 0\n const stride = Math.max(1, Math.floor(hull.length / 80))\n for (let index = 0; index < hull.length; index += stride) {\n const unit = quadToUnit(hull[index], coefficients)\n if (!unit) return 0\n const boundaryDistance = Math.min(\n Math.abs(unit.x),\n Math.abs(1 - unit.x),\n Math.abs(unit.y),\n Math.abs(1 - unit.y),\n )\n const outside = Math.max(0, -unit.x, unit.x - 1, -unit.y, unit.y - 1)\n const residual = boundaryDistance + outside * 2\n squaredResidual += residual * residual\n samples += 1\n }\n const rms = Math.sqrt(squaredResidual / Math.max(1, samples))\n return Math.exp(-rms / 0.08)\n}\n\nexport function scorePerspectiveQuad(\n corners: DocumentCorners,\n frameWidth: number,\n frameHeight: number,\n hull: Point[] = [corners.topLeft, corners.topRight, corners.bottomRight, corners.bottomLeft],\n): PerspectiveQuadScore {\n const ordered = [corners.topLeft, corners.topRight, corners.bottomRight, corners.bottomLeft]\n const frameScale = Math.max(1, Math.min(frameWidth, frameHeight))\n const outsideRatio = Math.max(\n 0,\n ...ordered.map((point) => Math.max(\n -point.x,\n -point.y,\n point.x - frameWidth,\n point.y - frameHeight,\n ) / frameScale),\n )\n const signedCrosses = ordered.map((point, index) =>\n cross(point, ordered[(index + 1) % 4], ordered[(index + 2) % 4]),\n )\n const convex = signedCrosses.every((value) => value > 0) ||\n signedCrosses.every((value) => value < 0)\n const areaRatio = polygonArea(ordered) / Math.max(1, frameWidth * frameHeight)\n if (\n !convex ||\n areaRatio < 0.04 ||\n areaRatio > 0.995 ||\n outsideRatio > 0.12\n ) {\n return {\n total: 0,\n areaRatio,\n angleScore: 0,\n oppositeAngleScore: 0,\n parallelScore: 0,\n homographyScore: 0,\n aspectBoost: 0,\n }\n }\n\n const angles = ordered.map((point, index) =>\n interiorAngle(ordered[(index + 3) % 4], point, ordered[(index + 1) % 4]),\n )\n const edgeLengths = ordered.map((point, index) => distance(point, ordered[(index + 1) % 4]))\n const horizontalScaleRatio = Math.max(edgeLengths[0], edgeLengths[2]) /\n Math.max(1, Math.min(edgeLengths[0], edgeLengths[2]))\n const verticalScaleRatio = Math.max(edgeLengths[1], edgeLengths[3]) /\n Math.max(1, Math.min(edgeLengths[1], edgeLengths[3]))\n if (\n angles.some((angle) => angle < 18 || angle > 162) ||\n horizontalScaleRatio > 4 ||\n verticalScaleRatio > 4\n ) {\n return {\n total: 0,\n areaRatio,\n angleScore: 0,\n oppositeAngleScore: 0,\n parallelScore: 0,\n homographyScore: 0,\n aspectBoost: 0,\n }\n }\n const angleScore = angles.reduce(\n (sum, angle) => sum + Math.exp(-Math.abs(angle - 90) / 48),\n 0,\n ) / 4\n const oppositeAngleScore = (\n Math.exp(-Math.abs(angles[0] + angles[2] - 180) / 55) +\n Math.exp(-Math.abs(angles[1] + angles[3] - 180) / 55)\n ) / 2\n const parallelScore = (\n Math.exp(-directionDifference(ordered[0], ordered[1], ordered[3], ordered[2]) / 0.62) +\n Math.exp(-directionDifference(ordered[0], ordered[3], ordered[1], ordered[2]) / 0.62)\n ) / 2\n const homographyScore = homographyBoundaryScore(corners, hull)\n const areaScore = clamp01((areaRatio - 0.04) / 0.5) *\n (areaRatio > 0.94 ? clamp01((0.995 - areaRatio) / 0.055) : 1)\n const perspectiveScaleScore = Math.exp(\n -Math.max(0, Math.max(horizontalScaleRatio, verticalScaleRatio) - 1.6) / 1.5,\n )\n const frameVisibilityScore = outsideRatio ? Math.exp(-outsideRatio / 0.07) : 1\n const width = Math.max(distance(ordered[0], ordered[1]), distance(ordered[3], ordered[2]))\n const height = Math.max(distance(ordered[0], ordered[3]), distance(ordered[1], ordered[2]))\n const aspect = Math.max(width, height) / Math.max(1, Math.min(width, height))\n const idBoost = Math.exp(-Math.abs(aspect - 1.58) / 0.18)\n const letterBoost = Math.exp(-Math.abs(aspect - 1.29) / 0.18)\n const receiptBoost = aspect >= 2 ? clamp01((aspect - 2) / 2) : 0\n const aspectBoost = Math.max(idBoost, letterBoost, receiptBoost) * 0.08\n const geometricScore = clamp01(\n areaScore * 0.18 +\n angleScore * 0.2 +\n oppositeAngleScore * 0.14 +\n parallelScore * 0.18 +\n homographyScore * 0.3 +\n aspectBoost\n )\n const total = geometricScore * (0.72 + perspectiveScaleScore * 0.28) * frameVisibilityScore\n return {\n total,\n areaRatio,\n angleScore,\n oppositeAngleScore,\n parallelScore,\n homographyScore,\n aspectBoost,\n }\n}\n\nfunction dilate(input: Uint8Array, width: number, height: number) {\n const output = new Uint8Array(input.length)\n for (let y = 1; y < height - 1; y += 1) {\n for (let x = 1; x < width - 1; x += 1) {\n const index = y * width + x\n if (!input[index]) continue\n for (let offsetY = -1; offsetY <= 1; offsetY += 1) {\n for (let offsetX = -1; offsetX <= 1; offsetX += 1) {\n output[index + offsetY * width + offsetX] = 1\n }\n }\n }\n }\n return output\n}\n\ninterface HoughLine {\n theta: number\n rho: number\n votes: number\n}\n\nfunction lineIntersection(first: HoughLine, second: HoughLine): Point | undefined {\n const firstCos = Math.cos(first.theta)\n const firstSin = Math.sin(first.theta)\n const secondCos = Math.cos(second.theta)\n const secondSin = Math.sin(second.theta)\n const determinant = firstCos * secondSin - secondCos * firstSin\n if (Math.abs(determinant) < 0.12) return undefined\n return {\n x: (first.rho * secondSin - second.rho * firstSin) / determinant,\n y: (firstCos * second.rho - secondCos * first.rho) / determinant,\n }\n}\n\nfunction angularDistance(first: number, second: number) {\n let difference = Math.abs(first - second) % Math.PI\n if (difference > Math.PI / 2) difference = Math.PI - difference\n return difference\n}\n\nfunction strongestHoughLines(edgeMap: Uint8Array, width: number, height: number) {\n const thetaBins = 72\n const diagonal = Math.ceil(Math.hypot(width, height))\n const rhoBins = diagonal * 2 + 1\n const accumulator = new Uint16Array(thetaBins * rhoBins)\n const cosines = Array.from({ length: thetaBins }, (_, index) => Math.cos(index * Math.PI / thetaBins))\n const sines = Array.from({ length: thetaBins }, (_, index) => Math.sin(index * Math.PI / thetaBins))\n const edgeIndexes: number[] = []\n const edgeCount = edgeMap.reduce((sum, value) => sum + value, 0)\n const stride = Math.max(1, Math.ceil(edgeCount / 7000))\n let seen = 0\n for (let index = 0; index < edgeMap.length; index += 1) {\n if (!edgeMap[index]) continue\n if (seen++ % stride) continue\n edgeIndexes.push(index)\n }\n for (const index of edgeIndexes) {\n const x = index % width\n const y = Math.floor(index / width)\n for (let thetaIndex = 0; thetaIndex < thetaBins; thetaIndex += 1) {\n const rho = Math.round(x * cosines[thetaIndex] + y * sines[thetaIndex]) + diagonal\n const offset = thetaIndex * rhoBins + rho\n if (accumulator[offset] < 65_535) accumulator[offset] += 1\n }\n }\n const candidates: HoughLine[] = []\n const minimumVotes = Math.max(12, Math.round(Math.min(width, height) * 0.08 / stride))\n for (let thetaIndex = 0; thetaIndex < thetaBins; thetaIndex += 1) {\n for (let rhoIndex = 0; rhoIndex < rhoBins; rhoIndex += 1) {\n const votes = accumulator[thetaIndex * rhoBins + rhoIndex]\n if (votes < minimumVotes) continue\n candidates.push({\n theta: thetaIndex * Math.PI / thetaBins,\n rho: rhoIndex - diagonal,\n votes,\n })\n }\n }\n candidates.sort((a, b) => b.votes - a.votes)\n const selected: HoughLine[] = []\n for (const candidate of candidates) {\n if (selected.some((line) =>\n angularDistance(line.theta, candidate.theta) < Math.PI / 36 &&\n Math.abs(line.rho - candidate.rho) < Math.min(width, height) * 0.035,\n )) continue\n selected.push(candidate)\n if (selected.length === 12) break\n }\n return selected\n}\n\nfunction detectQuadFromLines(\n edgeMap: Uint8Array,\n width: number,\n height: number,\n): QuadCandidate | undefined {\n const lines = strongestHoughLines(edgeMap, width, height)\n let best: QuadCandidate | undefined\n let bestScore = 0\n for (let firstA = 0; firstA < lines.length; firstA += 1) {\n for (let firstB = firstA + 1; firstB < lines.length; firstB += 1) {\n if (angularDistance(lines[firstA].theta, lines[firstB].theta) > 0.38) continue\n if (Math.abs(lines[firstA].rho - lines[firstB].rho) < Math.min(width, height) * 0.16) continue\n for (let secondA = 0; secondA < lines.length; secondA += 1) {\n if (secondA === firstA || secondA === firstB) continue\n if (angularDistance(lines[firstA].theta, lines[secondA].theta) < 0.52) continue\n for (let secondB = secondA + 1; secondB < lines.length; secondB += 1) {\n if (secondB === firstA || secondB === firstB) continue\n if (angularDistance(lines[secondA].theta, lines[secondB].theta) > 0.38) continue\n if (Math.abs(lines[secondA].rho - lines[secondB].rho) < Math.min(width, height) * 0.16) continue\n const intersections = [\n lineIntersection(lines[firstA], lines[secondA]),\n lineIntersection(lines[firstA], lines[secondB]),\n lineIntersection(lines[firstB], lines[secondA]),\n lineIntersection(lines[firstB], lines[secondB]),\n ]\n if (intersections.some((point) => !point)) continue\n const points = intersections as Point[]\n if (points.some((point) =>\n point.x < 0 || point.y < 0 ||\n point.x > width - 1 || point.y > height - 1,\n )) continue\n const corners = orderCorners(points)\n if (!corners) continue\n const geometry = scorePerspectiveQuad(corners, width, height)\n if (!geometry.total) continue\n const voteScore = clamp01(\n (lines[firstA].votes + lines[firstB].votes + lines[secondA].votes + lines[secondB].votes) /\n Math.max(1, Math.min(width, height) * 1.2),\n )\n const confidence = clamp01(geometry.total * 0.9 + voteScore * 0.1)\n const score = confidence * Math.sqrt(geometry.areaRatio)\n if (score > bestScore) {\n bestScore = score\n best = { corners, confidence, areaRatio: geometry.areaRatio }\n }\n }\n }\n }\n }\n return best\n}\n\nexport function detectQuadFromEdges(\n edgeMap: Uint8Array,\n width: number,\n height: number,\n options: { lineFallback?: boolean } = {},\n): QuadCandidate | undefined {\n if (edgeMap.length !== width * height) throw new Error('Edge map dimensions do not match.')\n const connectedEdges = dilate(edgeMap, width, height)\n const visited = new Uint8Array(connectedEdges.length)\n const queue = new Int32Array(connectedEdges.length)\n let best: QuadCandidate | undefined\n let bestScore = 0\n const minimumComponent = Math.max(24, Math.round(width * height * 0.0015))\n\n for (let seed = 0; seed < connectedEdges.length; seed += 1) {\n if (!connectedEdges[seed] || visited[seed]) continue\n let read = 0\n let write = 0\n queue[write++] = seed\n visited[seed] = 1\n const points: Point[] = []\n let boundaryPoints = 0\n while (read < write) {\n const index = queue[read++]\n const x = index % width\n const y = Math.floor(index / width)\n const boundary =\n x === 0 || y === 0 || x === width - 1 || y === height - 1 ||\n !connectedEdges[index - 1] || !connectedEdges[index + 1] ||\n !connectedEdges[index - width] || !connectedEdges[index + width]\n if (boundary) {\n boundaryPoints += 1\n const point = { x, y }\n if (points.length < 12_000) {\n points.push(point)\n } else {\n const slot = ((boundaryPoints * 2_654_435_761) >>> 0) % boundaryPoints\n if (slot < points.length) points[slot] = point\n }\n }\n for (let offsetY = -1; offsetY <= 1; offsetY += 1) {\n for (let offsetX = -1; offsetX <= 1; offsetX += 1) {\n if ((!offsetX && !offsetY) || x + offsetX < 0 || x + offsetX >= width || y + offsetY < 0 || y + offsetY >= height) continue\n const neighbor = index + offsetY * width + offsetX\n if (connectedEdges[neighbor] && !visited[neighbor]) {\n visited[neighbor] = 1\n queue[write++] = neighbor\n }\n }\n }\n }\n if (write < minimumComponent || write > width * height * 0.65 || points.length < 4) continue\n const hull = convexHull(points)\n const corners = orderCorners(hull)\n if (!corners) continue\n const ordered = [corners.topLeft, corners.topRight, corners.bottomRight, corners.bottomLeft]\n const quadArea = polygonArea(ordered)\n const hullArea = polygonArea(hull)\n if (quadArea <= 0) continue\n const geometry = scorePerspectiveQuad(corners, width, height, hull)\n if (!geometry.total) continue\n const contourFit = Math.min(1, hullArea / quadArea)\n const perimeterSignal = Math.min(1, write / Math.max(1, Math.sqrt(quadArea) * 10))\n const confidence = Math.min(\n 0.98,\n geometry.total * 0.82 + contourFit * 0.08 + perimeterSignal * 0.1,\n )\n const score = confidence * Math.sqrt(geometry.areaRatio)\n if (score > bestScore) {\n bestScore = score\n best = { corners, confidence, areaRatio: geometry.areaRatio }\n }\n }\n return best ?? (options.lineFallback ? detectQuadFromLines(edgeMap, width, height) : undefined)\n}\n","import { detectQuadFromEdges, type QuadCandidate } from './document-geometry'\nimport type { DocumentDetectionResult, DocumentModelStatus } from './types'\n\nexport interface PixelAnalysis {\n sharpness: number\n candidate?: QuadCandidate\n edgeMap?: Uint8Array\n detector?: NonNullable<DocumentDetectionResult['detector']>\n modelStatus?: DocumentModelStatus\n modelProvider?: NonNullable<DocumentDetectionResult['modelProvider']>\n modelError?: string\n inferenceMs?: number\n}\n\nexport const MIN_DOCUMENT_SHARPNESS = 3\n\nfunction percentileThreshold(magnitudes: Uint16Array, percentile: number) {\n const histogram = new Uint32Array(511)\n let samples = 0\n for (const value of magnitudes) {\n if (!value) continue\n histogram[Math.min(510, value)] += 1\n samples += 1\n }\n const target = samples * percentile\n let seen = 0\n for (let value = 0; value < histogram.length; value += 1) {\n seen += histogram[value]\n if (seen >= target) return value\n }\n return 72\n}\n\nfunction sobelMagnitude(channel: ArrayLike<number>, index: number, width: number) {\n const gx =\n -channel[index - width - 1] + channel[index - width + 1] -\n 2 * channel[index - 1] + 2 * channel[index + 1] -\n channel[index + width - 1] + channel[index + width + 1]\n const gy =\n -channel[index - width - 1] - 2 * channel[index - width] -\n channel[index - width + 1] + channel[index + width - 1] +\n 2 * channel[index + width] + channel[index + width + 1]\n return (Math.abs(gx) + Math.abs(gy)) / 2\n}\n\nfunction sampleTileGrid(\n values: Float32Array,\n columns: number,\n rows: number,\n x: number,\n y: number,\n) {\n const left = Math.floor(x)\n const top = Math.floor(y)\n const horizontalMix = x - left\n const verticalMix = y - top\n const leftColumn = Math.max(0, Math.min(columns - 1, left))\n const rightColumn = Math.max(0, Math.min(columns - 1, left + 1))\n const topRow = Math.max(0, Math.min(rows - 1, top))\n const bottomRow = Math.max(0, Math.min(rows - 1, top + 1))\n const upper = values[topRow * columns + leftColumn] * (1 - horizontalMix) +\n values[topRow * columns + rightColumn] * horizontalMix\n const lower = values[bottomRow * columns + leftColumn] * (1 - horizontalMix) +\n values[bottomRow * columns + rightColumn] * horizontalMix\n return upper * (1 - verticalMix) + lower * verticalMix\n}\n\nexport function analyzeDocumentPixels(\n pixels: Uint8ClampedArray,\n width: number,\n height: number,\n requestedThreshold?: number,\n priorEdgeMaps: Uint8Array[] = [],\n lineFallback = false,\n): PixelAnalysis {\n const gray = new Uint8Array(width * height)\n const redGreen = new Int16Array(width * height)\n const blueGreen = new Int16Array(width * height)\n for (let index = 0; index < gray.length; index += 1) {\n const offset = index * 4\n gray[index] = Math.round(\n pixels[offset] * 0.299 + pixels[offset + 1] * 0.587 + pixels[offset + 2] * 0.114,\n )\n redGreen[index] = pixels[offset] - pixels[offset + 1]\n blueGreen[index] = pixels[offset + 2] - pixels[offset + 1]\n }\n\n const enhanced = new Uint8Array(gray)\n const tileSize = Math.max(24, Math.round(Math.min(width, height) / 12))\n const tileColumns = Math.ceil(width / tileSize)\n const tileRows = Math.ceil(height / tileSize)\n const tileMeans = new Float32Array(tileColumns * tileRows)\n const tileGains = new Float32Array(tileColumns * tileRows)\n for (let tileRow = 0; tileRow < tileRows; tileRow += 1) {\n for (let tileColumn = 0; tileColumn < tileColumns; tileColumn += 1) {\n const tileX = tileColumn * tileSize\n const tileY = tileRow * tileSize\n const endX = Math.min(width, tileX + tileSize)\n const endY = Math.min(height, tileY + tileSize)\n let minimum = 255\n let maximum = 0\n let sum = 0\n let count = 0\n for (let y = tileY; y < endY; y += 1) {\n for (let x = tileX; x < endX; x += 1) {\n const value = gray[y * width + x]\n minimum = Math.min(minimum, value)\n maximum = Math.max(maximum, value)\n sum += value\n count += 1\n }\n }\n const range = maximum - minimum\n const tileIndex = tileRow * tileColumns + tileColumn\n tileMeans[tileIndex] = sum / Math.max(1, count)\n tileGains[tileIndex] = range < 10 ? 1 : Math.min(3, Math.max(1, 72 / range))\n }\n }\n for (let y = 0; y < height; y += 1) {\n const tileY = y / tileSize - 0.5\n for (let x = 0; x < width; x += 1) {\n const tileX = x / tileSize - 0.5\n const index = y * width + x\n const mean = sampleTileGrid(tileMeans, tileColumns, tileRows, tileX, tileY)\n const gain = sampleTileGrid(tileGains, tileColumns, tileRows, tileX, tileY)\n const contrasted = mean + (gray[index] - mean) * gain\n enhanced[index] = Math.max(\n 0,\n Math.min(255, Math.round(gray[index] * 0.58 + contrasted * 0.42)),\n )\n }\n }\n const magnitudes = new Uint16Array(enhanced.length)\n let focusEnergy = 0\n let focusSamples = 0\n for (let y = 1; y < height - 1; y += 1) {\n for (let x = 1; x < width - 1; x += 1) {\n const index = y * width + x\n const lumaMagnitude = sobelMagnitude(enhanced, index, width)\n const chromaMagnitude = Math.max(\n sobelMagnitude(redGreen, index, width),\n sobelMagnitude(blueGreen, index, width),\n )\n const magnitude = Math.min(510, Math.round(lumaMagnitude + chromaMagnitude * 0.38))\n magnitudes[index] = magnitude\n focusEnergy += magnitude\n focusSamples += 1\n }\n }\n const sharpness = focusEnergy / Math.max(1, focusSamples)\n if (sharpness < MIN_DOCUMENT_SHARPNESS) return { sharpness }\n const threshold = requestedThreshold ?? Math.max(26, percentileThreshold(magnitudes, 0.82))\n const strongEdges = new Uint8Array(gray.length)\n const weakEdges = new Uint8Array(gray.length)\n for (let index = 0; index < magnitudes.length; index += 1) {\n if (magnitudes[index] >= threshold) strongEdges[index] = 1\n else if (magnitudes[index] >= threshold * 0.55) weakEdges[index] = 1\n }\n const edgeMap = new Uint8Array(strongEdges)\n for (let pass = 0; pass < 2; pass += 1) {\n const next = new Uint8Array(edgeMap)\n for (let y = 1; y < height - 1; y += 1) {\n for (let x = 1; x < width - 1; x += 1) {\n const index = y * width + x\n if (!weakEdges[index] || edgeMap[index]) continue\n for (let offsetY = -1; offsetY <= 1 && !next[index]; offsetY += 1) {\n for (let offsetX = -1; offsetX <= 1; offsetX += 1) {\n if (edgeMap[index + offsetY * width + offsetX]) {\n next[index] = 1\n break\n }\n }\n }\n }\n }\n edgeMap.set(next)\n }\n const combinedEdges = new Uint8Array(edgeMap)\n for (const previous of priorEdgeMaps) {\n if (previous.length !== combinedEdges.length) continue\n for (let index = 0; index < combinedEdges.length; index += 1) {\n combinedEdges[index] ||= previous[index]\n }\n }\n return {\n sharpness,\n edgeMap,\n candidate: detectQuadFromEdges(combinedEdges, width, height, { lineFallback }),\n }\n}\n","import type { ImageSource } from './types'\n\nexport interface CanvasSourceOptions {\n cloneCanvas?: boolean\n maxDimension?: number\n}\n\nfunction scaledSize(width: number, height: number, maxDimension?: number) {\n const scale = maxDimension ? Math.min(1, maxDimension / Math.max(width, height)) : 1\n return {\n width: Math.max(1, Math.round(width * scale)),\n height: Math.max(1, Math.round(height * scale)),\n }\n}\n\nasync function blobToImage(blob: Blob) {\n const url = URL.createObjectURL(blob)\n try {\n const image = new Image()\n image.src = url\n await image.decode()\n return image\n } finally {\n URL.revokeObjectURL(url)\n }\n}\n\nexport async function sourceToCanvas(\n source: ImageSource,\n options: CanvasSourceOptions = {},\n): Promise<HTMLCanvasElement> {\n if (source instanceof HTMLCanvasElement && options.cloneCanvas === false && !options.maxDimension) {\n return source\n }\n const canvas = document.createElement('canvas')\n const context = canvas.getContext('2d', { willReadFrequently: true })\n if (!context) throw new Error('Canvas 2D is unavailable in this browser.')\n\n if (source instanceof Blob) {\n if ('createImageBitmap' in window) {\n try {\n const bitmap = await createImageBitmap(source)\n const size = scaledSize(bitmap.width, bitmap.height, options.maxDimension)\n canvas.width = size.width\n canvas.height = size.height\n context.drawImage(bitmap, 0, 0, size.width, size.height)\n bitmap.close()\n return canvas\n } catch {\n // Fall through to HTMLImageElement decoding for iOS/WebKit formats.\n }\n }\n source = await blobToImage(source)\n }\n\n const width = source instanceof HTMLImageElement ? source.naturalWidth : source.width\n const height = source instanceof HTMLImageElement ? source.naturalHeight : source.height\n if (!width || !height) throw new Error('The image has no readable dimensions.')\n const size = scaledSize(width, height, options.maxDimension)\n canvas.width = size.width\n canvas.height = size.height\n context.drawImage(source, 0, 0, size.width, size.height)\n return canvas\n}\n\nexport function canvasToBlob(\n canvas: HTMLCanvasElement,\n type = 'image/png',\n quality = 0.92,\n): Promise<Blob> {\n return new Promise((resolve, reject) =>\n canvas.toBlob(\n (blob) => (blob ? resolve(blob) : reject(new Error('Could not encode the image.'))),\n type,\n quality,\n ),\n )\n}\n\nexport function clampBox(\n box: { x: number; y: number; width: number; height: number },\n width: number,\n height: number,\n) {\n const x = Math.max(0, Math.min(width, box.x))\n const y = Math.max(0, Math.min(height, box.y))\n return {\n x,\n y,\n width: Math.max(0, Math.min(width - x, box.width)),\n height: Math.max(0, Math.min(height - y, box.height)),\n }\n}\n","import {\n analyzeDocumentPixels,\n MIN_DOCUMENT_SHARPNESS,\n type PixelAnalysis,\n} from './document-analysis'\nimport { assertLicense } from './license'\nimport { sourceToCanvas } from './image'\nimport type {\n DocumentCorners,\n DocumentDetectionResult,\n DocumentDetectorMode,\n DocumentQuad,\n ImageSource,\n Point,\n ScanResult,\n} from './types'\n\nexport interface ScanOptions {\n minDimension?: number\n edgeThreshold?: number\n minConfidence?: number\n maxAnalysisDimension?: number\n maxOutputDimension?: number\n useWorker?: boolean\n /** OR the current edge map with recent frames; useful for live finder input. */\n temporalEdgeWindow?: number\n /** Enables experimental Hough line assembly when no connected contour survives. */\n lineFallback?: boolean\n /** Selects zero-download classical detection, strict ML, or ML with classical fallback. */\n detector?: DocumentDetectorMode\n /** URL of a DocAligner-compatible [1,3,256,256] ONNX heatmap model. */\n modelUrl?: string\n /** Heatmap threshold used before largest-component corner centroids. */\n heatmapThreshold?: number\n /** Reuse model bytes through the browser HTTP cache. */\n cacheModel?: boolean\n /** Base URL for ONNX Runtime WASM files when WebGPU is unavailable. */\n ortWasmPaths?: string\n}\n\nexport const DEFAULT_DOCUMENT_MODEL_URL =\n 'https://exige-scanner-sdk.vercel.app/models/docaligner-lcnet100-f4117b78.onnx'\n\nexport function resolveDocumentModelUrl(\n detector: DocumentDetectorMode = 'classical',\n modelUrl?: string,\n) {\n if (detector === 'classical') return undefined\n return modelUrl?.trim() || DEFAULT_DOCUMENT_MODEL_URL\n}\n\nconst temporalEdgeHistory = new WeakMap<ScanOptions, Uint8Array[]>()\nlet analysisWorker: Worker | undefined\nlet analysisRequestId = 0\nconst analysisRequests = new Map<number, {\n resolve: (analysis: PixelAnalysis) => void\n reject: (error: Error) => void\n}>()\n\nfunction distance(a: Point, b: Point) {\n return Math.hypot(a.x - b.x, a.y - b.y)\n}\n\nfunction toQuad(corners: DocumentCorners): DocumentQuad {\n return {\n ...corners,\n edges: {\n top: { start: corners.topLeft, end: corners.topRight },\n right: { start: corners.topRight, end: corners.bottomRight },\n bottom: { start: corners.bottomRight, end: corners.bottomLeft },\n left: { start: corners.bottomLeft, end: corners.topLeft },\n },\n }\n}\n\nfunction scaleCorners(corners: DocumentCorners, scale: number): DocumentCorners {\n const resize = (point: Point) => ({ x: point.x / scale, y: point.y / scale })\n return {\n topLeft: resize(corners.topLeft),\n topRight: resize(corners.topRight),\n bottomRight: resize(corners.bottomRight),\n bottomLeft: resize(corners.bottomLeft),\n }\n}\n\nfunction isMobileClassDevice() {\n if (typeof navigator === 'undefined') return false\n return navigator.maxTouchPoints > 0 || navigator.hardwareConcurrency <= 4 ||\n (typeof matchMedia === 'function' && matchMedia('(pointer: coarse)').matches)\n}\n\nfunction analyzeInWorker(\n pixels: Uint8ClampedArray,\n width: number,\n height: number,\n options: ScanOptions,\n priorEdgeMaps: Uint8Array[] = [],\n): Promise<PixelAnalysis> {\n return new Promise((resolve, reject) => {\n if (!analysisWorker) {\n analysisWorker = new Worker(new URL('./document-worker.ts', import.meta.url), { type: 'module' })\n analysisWorker.onmessage = (event: MessageEvent<{\n id: number\n result?: PixelAnalysis\n error?: string\n }>) => {\n const pending = analysisRequests.get(event.data.id)\n if (!pending) return\n analysisRequests.delete(event.data.id)\n if (event.data.error) pending.reject(new Error(event.data.error))\n else if (event.data.result) pending.resolve(event.data.result)\n else pending.reject(new Error('The document worker returned no result.'))\n }\n analysisWorker.onerror = () => {\n const error = new Error('The document worker could not start.')\n for (const pending of analysisRequests.values()) pending.reject(error)\n analysisRequests.clear()\n analysisWorker?.terminate()\n analysisWorker = undefined\n }\n }\n const id = ++analysisRequestId\n analysisRequests.set(id, { resolve, reject })\n const transferable = pixels.slice().buffer\n analysisWorker.postMessage({\n id,\n pixels: transferable,\n width,\n height,\n edgeThreshold: options.edgeThreshold,\n priorEdgeMaps,\n lineFallback: options.lineFallback,\n detector: options.detector,\n modelUrl: resolveDocumentModelUrl(options.detector, options.modelUrl),\n heatmapThreshold: options.heatmapThreshold,\n cacheModel: options.cacheModel,\n ortWasmPaths: options.ortWasmPaths,\n }, [transferable])\n })\n}\n\nasync function analyzeCanvas(\n canvas: HTMLCanvasElement,\n options: ScanOptions,\n): Promise<DocumentDetectionResult> {\n const { width, height } = canvas\n const minDimension = options.minDimension ?? 360\n if (Math.min(width, height) < minDimension) {\n return {\n status: 'low-quality',\n confidence: 0,\n message: `Use an image at least ${minDimension}px on its shortest side.`,\n sourceWidth: width,\n sourceHeight: height,\n }\n }\n\n const defaultAnalysisDimension = isMobileClassDevice() ? 560 : 900\n const scale = Math.min(1, (options.maxAnalysisDimension ?? defaultAnalysisDimension) / Math.max(width, height))\n const sample = document.createElement('canvas')\n sample.width = Math.max(1, Math.round(width * scale))\n sample.height = Math.max(1, Math.round(height * scale))\n const context = sample.getContext('2d', { willReadFrequently: true })\n if (!context) throw new Error('Canvas 2D is unavailable in this browser.')\n context.drawImage(canvas, 0, 0, sample.width, sample.height)\n const pixels = context.getImageData(0, 0, sample.width, sample.height).data\n const temporalWindow = Math.max(1, Math.min(4, options.temporalEdgeWindow ?? 1))\n const priorEdgeMaps = temporalWindow > 1 ? temporalEdgeHistory.get(options) ?? [] : []\n let analysis: PixelAnalysis\n if (options.useWorker !== false && typeof Worker !== 'undefined') {\n try {\n analysis = await analyzeInWorker(\n pixels,\n sample.width,\n sample.height,\n options,\n priorEdgeMaps,\n )\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Document worker failed.'\n if (options.detector === 'ml') {\n analysis = {\n sharpness: 20,\n detector: 'ml',\n modelStatus: 'failed',\n modelError: message,\n }\n } else {\n analysis = {\n ...analyzeDocumentPixels(\n pixels,\n sample.width,\n sample.height,\n options.edgeThreshold,\n priorEdgeMaps,\n options.lineFallback,\n ),\n detector: 'classical',\n modelStatus: options.detector === 'auto' ? 'fallback' : 'not-requested',\n modelError: options.detector === 'auto' ? message : undefined,\n }\n }\n }\n } else {\n const modelRequested = options.detector === 'ml' || options.detector === 'auto'\n analysis = {\n ...analyzeDocumentPixels(\n pixels,\n sample.width,\n sample.height,\n options.edgeThreshold,\n priorEdgeMaps,\n options.lineFallback,\n ),\n detector: 'classical',\n modelStatus: modelRequested ? 'fallback' : 'not-requested',\n modelError: modelRequested ? 'ML detection requires a Web Worker.' : undefined,\n }\n }\n if (temporalWindow > 1 && analysis.edgeMap) {\n temporalEdgeHistory.set(\n options,\n [analysis.edgeMap, ...priorEdgeMaps].slice(0, temporalWindow - 1),\n )\n }\n const {\n sharpness,\n candidate,\n detector,\n modelStatus,\n modelProvider,\n modelError,\n inferenceMs,\n } = analysis\n const detectorMetadata = {\n detector,\n modelStatus,\n modelProvider,\n modelError,\n inferenceMs,\n }\n if (sharpness < MIN_DOCUMENT_SHARPNESS) {\n return {\n status: 'low-quality',\n confidence: Math.min(0.3, sharpness / 18),\n message: 'The image is too soft or dark to resolve four document edges.',\n sourceWidth: width,\n sourceHeight: height,\n ...detectorMetadata,\n }\n }\n\n if (!candidate) {\n return {\n status: 'no-document',\n confidence: 0,\n message: 'No closed document contour found. Place all four edges on a contrasting surface.',\n sourceWidth: width,\n sourceHeight: height,\n ...detectorMetadata,\n }\n }\n\n const corners = scaleCorners(candidate.corners, scale)\n const quad = toQuad(corners)\n const minimumConfidence = options.minConfidence ?? 0.58\n if (candidate.confidence < minimumConfidence) {\n return {\n status: 'low-confidence',\n quad,\n corners,\n confidence: candidate.confidence,\n message: 'Four possible edges were found, but the contour is not reliable enough to crop.',\n sourceWidth: width,\n sourceHeight: height,\n ...detectorMetadata,\n }\n }\n return {\n status: 'success',\n quad,\n corners,\n confidence: candidate.confidence,\n message: 'Four document edges detected.',\n sourceWidth: width,\n sourceHeight: height,\n ...detectorMetadata,\n }\n}\n\nexport function perspectiveOutputSize(corners: DocumentCorners, maxDimension: number) {\n const naturalWidth = Math.max(\n 1,\n Math.round(Math.max(\n distance(corners.topLeft, corners.topRight),\n distance(corners.bottomLeft, corners.bottomRight),\n )),\n )\n const naturalHeight = Math.max(\n 1,\n Math.round(Math.max(\n distance(corners.topLeft, corners.bottomLeft),\n distance(corners.topRight, corners.bottomRight),\n )),\n )\n const outputScale = Math.min(1, maxDimension / Math.max(naturalWidth, naturalHeight))\n return {\n width: Math.max(1, Math.round(naturalWidth * outputScale)),\n height: Math.max(1, Math.round(naturalHeight * outputScale)),\n }\n}\n\nfunction perspectiveWarp(source: HTMLCanvasElement, corners: DocumentCorners, maxDimension: number) {\n const { width, height } = perspectiveOutputSize(corners, maxDimension)\n const sourceContext = source.getContext('2d', { willReadFrequently: true })\n if (!sourceContext) throw new Error('Canvas 2D is unavailable in this browser.')\n const sourcePixels = sourceContext.getImageData(0, 0, source.width, source.height)\n const output = document.createElement('canvas')\n output.width = width\n output.height = height\n const outputContext = output.getContext('2d')\n if (!outputContext) throw new Error('Canvas 2D is unavailable in this browser.')\n const outputPixels = outputContext.createImageData(width, height)\n const { topLeft: tl, topRight: tr, bottomRight: br, bottomLeft: bl } = corners\n const dx1 = tr.x - br.x\n const dx2 = bl.x - br.x\n const dy1 = tr.y - br.y\n const dy2 = bl.y - br.y\n const sx = tl.x - tr.x + br.x - bl.x\n const sy = tl.y - tr.y + br.y - bl.y\n const denominator = dx1 * dy2 - dx2 * dy1\n const projectiveX = Math.abs(denominator) < 0.0001 ? 0 : (sx * dy2 - dx2 * sy) / denominator\n const projectiveY = Math.abs(denominator) < 0.0001 ? 0 : (dx1 * sy - sx * dy1) / denominator\n const a = tr.x - tl.x + projectiveX * tr.x\n const b = bl.x - tl.x + projectiveY * bl.x\n const d = tr.y - tl.y + projectiveX * tr.y\n const e = bl.y - tl.y + projectiveY * bl.y\n\n for (let y = 0; y < height; y += 1) {\n const v = y / Math.max(1, height - 1)\n for (let x = 0; x < width; x += 1) {\n const u = x / Math.max(1, width - 1)\n const divisor = projectiveX * u + projectiveY * v + 1\n const sourceX = Math.max(0, Math.min(source.width - 1, Math.round((a * u + b * v + tl.x) / divisor)))\n const sourceY = Math.max(0, Math.min(source.height - 1, Math.round((d * u + e * v + tl.y) / divisor)))\n const sourceOffset = (sourceY * source.width + sourceX) * 4\n const outputOffset = (y * width + x) * 4\n outputPixels.data[outputOffset] = sourcePixels.data[sourceOffset]\n outputPixels.data[outputOffset + 1] = sourcePixels.data[sourceOffset + 1]\n outputPixels.data[outputOffset + 2] = sourcePixels.data[sourceOffset + 2]\n outputPixels.data[outputOffset + 3] = sourcePixels.data[sourceOffset + 3]\n }\n }\n outputContext.putImageData(outputPixels, 0, 0)\n return output\n}\n\nexport async function detectDocument(\n source: ImageSource,\n options: ScanOptions = {},\n): Promise<DocumentDetectionResult> {\n await assertLicense('scan')\n return analyzeCanvas(await sourceToCanvas(source, { cloneCanvas: false }), options)\n}\n\nexport async function cropDocument(\n source: ImageSource,\n corners: DocumentCorners,\n options: Pick<ScanOptions, 'maxOutputDimension'> = {},\n): Promise<ScanResult> {\n await assertLicense('scan')\n const canvas = await sourceToCanvas(source, { cloneCanvas: false })\n const maxOutputDimension = options.maxOutputDimension ?? (isMobileClassDevice() ? 2048 : 4096)\n return {\n status: 'success',\n corners,\n quad: toQuad(corners),\n confidence: 1,\n message: 'Captured with the document edges shown in the finder.',\n sourceWidth: canvas.width,\n sourceHeight: canvas.height,\n canvas: perspectiveWarp(canvas, corners, maxOutputDimension),\n }\n}\n\nexport async function scanDocument(\n source: ImageSource,\n options: ScanOptions = {},\n): Promise<ScanResult> {\n await assertLicense('scan')\n const canvas = await sourceToCanvas(source, { cloneCanvas: false })\n const detection = await analyzeCanvas(canvas, options)\n if (detection.status !== 'success' || !detection.corners) return detection\n const maxOutputDimension = options.maxOutputDimension ?? (isMobileClassDevice() ? 2048 : 4096)\n return {\n ...detection,\n canvas: perspectiveWarp(canvas, detection.corners, maxOutputDimension),\n message: 'Four document edges detected and perspective-corrected.',\n }\n}\n","import { assertLicense } from './license'\n\nexport interface CameraOptions {\n facingMode?: 'environment' | 'user'\n idealWidth?: number\n idealHeight?: number\n maxWidth?: number\n maxHeight?: number\n maxFrameRate?: number\n /** Rear-camera torch policy. Defaults to `alwaysOff`. */\n torch?: TorchMode\n}\n\nexport type TorchMode =\n | 'defaultOn'\n | 'defaultOff'\n | 'alwaysOn'\n | 'alwaysOff'\n | 'auto'\n\nexport interface TorchStatus {\n mode: TorchMode\n supported: boolean\n on: boolean\n /** Whether the camera UI should show a torch control. */\n visible: boolean\n /** Whether an end user can change the control with `setTorch()`. */\n mutable: boolean\n /** True when luminance hysteresis, rather than an end user, owns the state. */\n automatic: boolean\n}\n\nexport interface CameraSession {\n stream: MediaStream\n readonly torchMode: TorchMode\n readonly torchSupported: boolean\n readonly torchOn: boolean\n capture: (maxDimension?: number) => HTMLCanvasElement\n capturePhoto: () => Promise<CameraPhoto>\n getSettings: () => MediaTrackSettings\n getDiagnostics: () => CameraDiagnostics\n getTorchStatus: () => TorchStatus\n /**\n * Changes torch state only for `defaultOn` and `defaultOff`.\n * Returns false, without throwing, for unsupported or immutable modes.\n */\n setTorch: (enabled: boolean) => Promise<boolean>\n stop: () => void\n}\n\nexport type CapturePath = 'video-frame' | 'live-mirror'\n\nexport interface CameraPhoto {\n frame: HTMLCanvasElement\n method: CapturePath\n settings: MediaTrackSettings\n fallbackReason?: 'video-frame-empty'\n luminance: number\n diagnostics: CameraDiagnostics\n}\n\nexport interface CameraDiagnostics {\n videoWidth: number\n videoHeight: number\n readyState: number\n paused: boolean\n connected: boolean\n rendered: boolean\n trackReadyState: MediaStreamTrackState | 'missing'\n trackEnabled: boolean\n trackMuted: boolean\n liveLuminance: number\n mirrorLuminance: number\n mirrorAgeMs: number\n /**\n * Whether the browser exposes `ImageCapture`. Reported for support triage\n * only: capture never calls `takePhoto()`. WebKit exposes the constructor\n * but returns an all-black still from it.\n */\n hasImageCapture: boolean\n torchMode: TorchMode\n torchSupported: boolean\n torchOn: boolean\n torch: TorchStatus\n engine: BrowserEngine\n}\n\nexport interface CaptureDiagnosticsReport {\n capturedAt?: string\n error?: string\n captureMethod?: CapturePath\n luminance?: number\n fallbackReason?: CameraPhoto['fallbackReason']\n shutter?: CameraDiagnostics\n live?: CameraDiagnostics\n finder?: {\n state?: string\n confidence?: number\n stableFrames?: number\n requiredStableFrames?: number\n detector?: string\n modelStatus?: string\n sourceWidth?: number\n sourceHeight?: number\n }\n}\n\nfunction formatDiagnosticsBlock(label: string, diagnostics: CameraDiagnostics) {\n const { engine } = diagnostics\n return [\n `${label}:`,\n ` engine: ${engine.engine}/${engine.browser}${engine.iosWebKit ? ' ios-webkit' : ''}`,\n ` ua: ${engine.userAgent}`,\n ` video: ${diagnostics.videoWidth}x${diagnostics.videoHeight} readyState=${diagnostics.readyState}${diagnostics.paused ? ' paused' : ''}${diagnostics.rendered ? '' : ' hidden'}${diagnostics.connected ? '' : ' disconnected'}`,\n ` track: ${diagnostics.trackReadyState}${diagnostics.trackEnabled ? '' : ' disabled'}${diagnostics.trackMuted ? ' muted' : ''}`,\n ` liveLuma: ${diagnostics.liveLuminance.toFixed(1)}`,\n ` mirrorLuma: ${diagnostics.mirrorLuminance.toFixed(1)}`,\n ` mirrorAgeMs: ${Number.isFinite(diagnostics.mirrorAgeMs) ? Math.round(diagnostics.mirrorAgeMs) : 'none'}`,\n ` hasImageCapture: ${diagnostics.hasImageCapture} (never used)`,\n ` torch: ${diagnostics.torch.mode} supported=${diagnostics.torch.supported} on=${diagnostics.torch.on}`,\n ].join('\\n')\n}\n\n/** Plain-text dump safe to paste into chat or a ticket. */\nexport function formatCaptureDiagnosticsReport(report: CaptureDiagnosticsReport) {\n const lines = [\n 'Exige scanner capture report',\n `time: ${report.capturedAt ?? new Date().toISOString()}`,\n ]\n if (report.error) lines.push(`error: ${report.error}`)\n if (report.captureMethod) lines.push(`method: ${report.captureMethod}`)\n if (report.luminance !== undefined) lines.push(`luminance: ${report.luminance.toFixed(1)}`)\n if (report.fallbackReason) lines.push(`fallback: ${report.fallbackReason}`)\n if (report.shutter) lines.push(formatDiagnosticsBlock('shutter', report.shutter))\n if (report.live) lines.push(formatDiagnosticsBlock('live', report.live))\n if (report.finder) {\n const finder = report.finder\n lines.push(\n [\n 'finder:',\n ` state: ${finder.state ?? 'unknown'}`,\n ` confidence: ${finder.confidence === undefined ? '—' : finder.confidence.toFixed(3)}`,\n ` stable: ${finder.stableFrames ?? '—'}/${finder.requiredStableFrames ?? '—'}`,\n ` detector: ${finder.detector ?? '—'} ${finder.modelStatus ?? ''}`.trim(),\n ` source: ${finder.sourceWidth ?? '—'}x${finder.sourceHeight ?? '—'}`,\n ].join('\\n'),\n )\n }\n return `${lines.join('\\n')}\\n`\n}\n\nexport interface BrowserEngine {\n /** Engine actually executing, not the vendor shell around it. */\n engine: 'webkit' | 'blink' | 'gecko' | 'unknown'\n /** Vendor shell, which on iOS is only a wrapper around WebKit. */\n browser: string\n iosWebKit: boolean\n userAgent: string\n}\n\n/**\n * Identifies the rendering engine by capability plus the vendor shell by name.\n * Every iOS browser is WebKit, so behavior must never be gated on Safari alone.\n */\nexport function detectBrowserEngine(\n userAgent = typeof navigator === 'undefined' ? '' : navigator.userAgent,\n maxTouchPoints = typeof navigator === 'undefined' ? 0 : navigator.maxTouchPoints,\n): BrowserEngine {\n const browser = /CriOS|Chrome/i.test(userAgent)\n ? 'chrome'\n : /EdgiOS|Edg/i.test(userAgent)\n ? 'edge'\n : /FxiOS|Firefox/i.test(userAgent)\n ? 'firefox'\n : /Safari/i.test(userAgent)\n ? 'safari'\n : 'unknown'\n const iosDevice = /iPhone|iPad|iPod/i.test(userAgent) ||\n (/Macintosh/i.test(userAgent) && maxTouchPoints > 1)\n const iosShell = /CriOS|EdgiOS|FxiOS|OPiOS|Mercury/i.test(userAgent)\n const iosWebKit = iosDevice || iosShell\n const engine = iosWebKit || (/AppleWebKit/i.test(userAgent) && !/Chrome|Chromium|Edg/i.test(userAgent))\n ? 'webkit'\n : /Chrome|Chromium|Edg/i.test(userAgent)\n ? 'blink'\n : /Gecko\\//i.test(userAgent)\n ? 'gecko'\n : 'unknown'\n return { engine, browser, iosWebKit, userAgent }\n}\n\n/** Mean luminance below this is treated as an empty/black frame. */\nexport const NEAR_BLACK_LUMINANCE = 10\n\nexport interface AutoTorchOptions {\n /** Luminance at or below which dark samples accumulate. */\n turnOnLuminance?: number\n /** Luminance at or above which bright samples accumulate. */\n turnOffLuminance?: number\n /** Consecutive dark samples required before enabling the torch. */\n darkSamples?: number\n /** Consecutive bright samples required before disabling the torch. */\n brightSamples?: number\n}\n\n/**\n * Stateful automatic torch policy. The wide threshold gap and consecutive\n * sample counts prevent exposure changes and hand movement from flickering the\n * LED. `update()` returns a new requested state only when the state changes.\n */\nexport class AutoTorchController {\n private on = false\n private darkCount = 0\n private brightCount = 0\n private readonly turnOnLuminance: number\n private readonly turnOffLuminance: number\n private readonly darkSamples: number\n private readonly brightSamples: number\n\n constructor(options: AutoTorchOptions = {}) {\n this.turnOnLuminance = options.turnOnLuminance ?? 62\n this.turnOffLuminance = options.turnOffLuminance ?? 155\n this.darkSamples = options.darkSamples ?? 3\n this.brightSamples = options.brightSamples ?? 8\n }\n\n update(luminance: number) {\n if (!Number.isFinite(luminance) || luminance <= NEAR_BLACK_LUMINANCE) {\n this.darkCount = 0\n this.brightCount = 0\n return undefined\n }\n if (!this.on) {\n this.brightCount = 0\n this.darkCount = luminance <= this.turnOnLuminance ? this.darkCount + 1 : 0\n if (this.darkCount < this.darkSamples) return undefined\n this.darkCount = 0\n this.on = true\n return true\n }\n this.darkCount = 0\n this.brightCount = luminance >= this.turnOffLuminance ? this.brightCount + 1 : 0\n if (this.brightCount < this.brightSamples) return undefined\n this.brightCount = 0\n this.on = false\n return false\n }\n\n getState() {\n return this.on\n }\n}\n\nexport function torchControl(\n mode: TorchMode,\n supported: boolean,\n): TorchStatus {\n if (!supported) {\n return {\n mode,\n supported: false,\n on: false,\n visible: false,\n mutable: false,\n automatic: mode === 'auto',\n }\n }\n if (mode === 'alwaysOn' || mode === 'alwaysOff') {\n return {\n mode,\n supported: true,\n on: mode === 'alwaysOn',\n visible: false,\n mutable: false,\n automatic: false,\n }\n }\n return {\n mode,\n supported: true,\n on: mode === 'defaultOn',\n visible: true,\n mutable: mode !== 'auto',\n automatic: mode === 'auto',\n }\n}\n\nexport function meanFrameLuminance(pixels: Uint8ClampedArray) {\n const pixelCount = Math.floor(pixels.length / 4)\n if (!pixelCount) return 0\n let luminance = 0\n for (let offset = 0; offset < pixelCount * 4; offset += 4) {\n luminance += pixels[offset] * 0.299 +\n pixels[offset + 1] * 0.587 +\n pixels[offset + 2] * 0.114\n }\n return luminance / pixelCount\n}\n\nexport function isNearBlackFrame(\n pixels: Uint8ClampedArray,\n blackThreshold = NEAR_BLACK_LUMINANCE,\n) {\n if (pixels.length < 4) return true\n const pixelCount = Math.floor(pixels.length / 4)\n let visiblePixels = 0\n for (let offset = 0; offset < pixelCount * 4; offset += 4) {\n const value = pixels[offset] * 0.299 +\n pixels[offset + 1] * 0.587 +\n pixels[offset + 2] * 0.114\n if (value > blackThreshold * 2) visiblePixels += 1\n }\n return meanFrameLuminance(pixels) <= blackThreshold &&\n visiblePixels / pixelCount < 0.01\n}\n\nfunction sampleCanvasLuminance(source: CanvasImageSource, width: number, height: number) {\n if (!width || !height) return 0\n const sample = document.createElement('canvas')\n sample.width = Math.min(32, width)\n sample.height = Math.min(32, height)\n const context = sample.getContext('2d', { willReadFrequently: true })\n if (!context) return 0\n context.drawImage(source, 0, 0, sample.width, sample.height)\n return meanFrameLuminance(context.getImageData(0, 0, sample.width, sample.height).data)\n}\n\nfunction canvasLuminance(canvas: HTMLCanvasElement) {\n return sampleCanvasLuminance(canvas, canvas.width, canvas.height)\n}\n\ntype VideoFrameCallbackElement = HTMLVideoElement & Partial<{\n requestVideoFrameCallback: (callback: () => void) => number\n cancelVideoFrameCallback: (handle: number) => void\n}>\n\n/**\n * Keeps an offscreen copy of the most recent non-black video frame. WebKit can\n * blank a `<video>` at the moment of a tap, teardown, or compositing change, so\n * capture must not depend on the pixels available at that exact instant.\n */\nfunction startFrameMirror(video: VideoFrameCallbackElement, minIntervalMs = 120) {\n const canvas = document.createElement('canvas')\n const context = canvas.getContext('2d')\n const supportsFrameCallback = typeof video.requestVideoFrameCallback === 'function'\n let running = true\n let handle = 0\n let lastCopyAt = 0\n let lastGoodAt = 0\n let liveLuminance = 0\n let mirrorLuminance = 0\n\n const schedule = () => {\n if (!running) return\n handle = supportsFrameCallback\n ? video.requestVideoFrameCallback!(grab)\n : requestAnimationFrame(grab)\n }\n\n function grab() {\n if (!running) return\n const { videoWidth, videoHeight } = video\n const now = performance.now()\n if (context && videoWidth && videoHeight && now - lastCopyAt >= minIntervalMs) {\n lastCopyAt = now\n liveLuminance = sampleCanvasLuminance(video, videoWidth, videoHeight)\n if (liveLuminance > NEAR_BLACK_LUMINANCE) {\n if (canvas.width !== videoWidth || canvas.height !== videoHeight) {\n canvas.width = videoWidth\n canvas.height = videoHeight\n }\n context.drawImage(video, 0, 0, videoWidth, videoHeight)\n mirrorLuminance = liveLuminance\n lastGoodAt = now\n }\n }\n schedule()\n }\n\n schedule()\n return {\n stop() {\n running = false\n if (supportsFrameCallback) video.cancelVideoFrameCallback?.(handle)\n else cancelAnimationFrame(handle)\n },\n getFrame: () => lastGoodAt ? canvas : undefined,\n getLiveLuminance: () => liveLuminance,\n getMirrorLuminance: () => mirrorLuminance,\n getMirrorAgeMs: () => lastGoodAt ? performance.now() - lastGoodAt : Infinity,\n }\n}\n\nfunction cloneFrame(source: HTMLCanvasElement) {\n const copy = document.createElement('canvas')\n copy.width = source.width\n copy.height = source.height\n copy.getContext('2d')?.drawImage(source, 0, 0)\n return copy\n}\n\nexport function mobileCameraConstraints(options: CameraOptions = {}): MediaStreamConstraints {\n const width: MediaTrackConstraintSet['width'] = { ideal: options.idealWidth ?? 3840 }\n const height: MediaTrackConstraintSet['height'] = { ideal: options.idealHeight ?? 2160 }\n if (options.maxWidth) (width as ConstrainULongRange).max = options.maxWidth\n if (options.maxHeight) (height as ConstrainULongRange).max = options.maxHeight\n return {\n audio: false,\n video: {\n facingMode: { ideal: options.facingMode ?? 'environment' },\n width,\n height,\n frameRate: { ideal: options.maxFrameRate ?? 30, max: options.maxFrameRate ?? 30 },\n },\n }\n}\n\nexport function captureVideoFrame(video: HTMLVideoElement, maxDimension?: number) {\n if (!video.videoWidth || !video.videoHeight) {\n throw new Error('The camera is not ready to capture a frame.')\n }\n const scale = maxDimension\n ? Math.min(1, maxDimension / Math.max(video.videoWidth, video.videoHeight))\n : 1\n const canvas = document.createElement('canvas')\n canvas.width = Math.max(1, Math.round(video.videoWidth * scale))\n canvas.height = Math.max(1, Math.round(video.videoHeight * scale))\n const context = canvas.getContext('2d')\n if (!context) throw new Error('Canvas 2D is unavailable in this browser.')\n context.drawImage(video, 0, 0, canvas.width, canvas.height)\n return canvas\n}\n\nfunction cameraConstraintCandidates(options: CameraOptions) {\n if (options.idealWidth || options.idealHeight || options.maxWidth || options.maxHeight) {\n return [mobileCameraConstraints(options)]\n }\n return [\n mobileCameraConstraints({ ...options, idealWidth: 3840, idealHeight: 2160 }),\n mobileCameraConstraints({ ...options, idealWidth: 2560, idealHeight: 1440 }),\n mobileCameraConstraints({ ...options, idealWidth: 1920, idealHeight: 1080 }),\n ]\n}\n\nexport async function startCamera(\n video: HTMLVideoElement,\n options: CameraOptions = {},\n): Promise<CameraSession> {\n await assertLicense('scan')\n const torchMode = options.torch ?? 'alwaysOff'\n if (torchMode !== 'alwaysOff') await assertLicense('torch')\n if (!window.isSecureContext && location.hostname !== 'localhost') {\n throw new Error('Camera access requires HTTPS.')\n }\n if (!navigator.mediaDevices?.getUserMedia) {\n throw new Error('Live camera access is unavailable. Use the native camera picker instead.')\n }\n video.muted = true\n video.autoplay = true\n video.playsInline = true\n video.setAttribute('playsinline', '')\n let stream: MediaStream | undefined\n let resolutionError: unknown\n for (const constraints of cameraConstraintCandidates(options)) {\n try {\n stream = await navigator.mediaDevices.getUserMedia(constraints)\n break\n } catch (cause) {\n resolutionError = cause\n if (!(cause instanceof DOMException) || cause.name !== 'OverconstrainedError') throw cause\n }\n }\n if (!stream) throw resolutionError ?? new Error('No rear camera resolution is available.')\n video.srcObject = stream\n await video.play()\n const track = stream.getVideoTracks()[0]\n if (!track) {\n for (const streamTrack of stream.getTracks()) streamTrack.stop()\n throw new Error('The camera did not provide a video track.')\n }\n const mirror = startFrameMirror(video)\n const hasImageCapture = 'ImageCapture' in globalThis\n const capabilities = typeof track.getCapabilities === 'function'\n ? track.getCapabilities() as MediaTrackCapabilities & { torch?: boolean }\n : undefined\n let torchStatus = torchControl(torchMode, capabilities?.torch === true)\n let torchUpdatePending = false\n const applyTorch = async (enabled: boolean) => {\n if (!torchStatus.supported || track.readyState !== 'live') return false\n try {\n await track.applyConstraints({\n advanced: [{ torch: enabled } as MediaTrackConstraintSet],\n })\n torchStatus = { ...torchStatus, on: enabled }\n return true\n } catch {\n // Some browsers report a torch capability but reject its constraint.\n // Fail closed and hide the control without disturbing the live track.\n torchStatus = {\n ...torchStatus,\n supported: false,\n on: false,\n visible: false,\n mutable: false,\n }\n return false\n }\n }\n\n if (torchStatus.on) await applyTorch(true)\n\n const autoTorch = torchMode === 'auto' && torchStatus.supported\n ? new AutoTorchController()\n : undefined\n const autoTorchTimer = autoTorch\n ? window.setInterval(() => {\n if (torchUpdatePending || !torchStatus.supported) return\n const requested = autoTorch.update(mirror.getLiveLuminance())\n if (requested === undefined || requested === torchStatus.on) return\n torchUpdatePending = true\n void applyTorch(requested).finally(() => {\n torchUpdatePending = false\n })\n }, 350)\n : 0\n\n const diagnostics = (): CameraDiagnostics => {\n const bounds = video.getBoundingClientRect()\n return {\n videoWidth: video.videoWidth,\n videoHeight: video.videoHeight,\n readyState: video.readyState,\n paused: video.paused,\n connected: video.isConnected,\n rendered: bounds.width > 0 && bounds.height > 0,\n trackReadyState: track.readyState ?? 'missing',\n trackEnabled: track.enabled,\n trackMuted: track.muted,\n liveLuminance: mirror.getLiveLuminance(),\n mirrorLuminance: mirror.getMirrorLuminance(),\n mirrorAgeMs: mirror.getMirrorAgeMs(),\n hasImageCapture,\n torchMode: torchStatus.mode,\n torchSupported: torchStatus.supported,\n torchOn: torchStatus.on,\n torch: { ...torchStatus },\n engine: detectBrowserEngine(),\n }\n }\n\n return {\n stream,\n get torchMode() {\n return torchStatus.mode\n },\n get torchSupported() {\n return torchStatus.supported\n },\n get torchOn() {\n return torchStatus.on\n },\n capture: (maxDimension) => captureVideoFrame(video, maxDimension),\n // The document capture path never calls `ImageCapture.takePhoto()`. WebKit\n // exposes the constructor and resolves it with an all-black still, and the\n // preview frames are already full sensor resolution.\n async capturePhoto() {\n // Copy before any await: WebKit can blank the element during the tap\n // that triggers capture, so fall back to the last known-good frame.\n let liveFrame: HTMLCanvasElement | undefined\n let liveLuminance = 0\n try {\n liveFrame = captureVideoFrame(video)\n liveLuminance = canvasLuminance(liveFrame)\n } catch {\n liveFrame = undefined\n }\n const mirrorFrame = mirror.getFrame()\n const usableLive = liveFrame && liveLuminance > NEAR_BLACK_LUMINANCE\n ? liveFrame\n : undefined\n const snapshot = usableLive ?? (mirrorFrame ? cloneFrame(mirrorFrame) : undefined)\n if (!snapshot) {\n throw new Error(\n 'The camera preview produced no visible pixels. Keep the scanner on screen, wait for the preview, and retake.',\n )\n }\n return {\n frame: snapshot,\n method: usableLive ? 'video-frame' : 'live-mirror',\n settings: track.getSettings(),\n fallbackReason: usableLive ? undefined : 'video-frame-empty',\n luminance: usableLive ? liveLuminance : mirror.getMirrorLuminance(),\n diagnostics: diagnostics(),\n }\n },\n getSettings: () => track.getSettings(),\n getDiagnostics: diagnostics,\n getTorchStatus: () => ({ ...torchStatus }),\n async setTorch(enabled) {\n if (!torchStatus.mutable) return false\n return applyTorch(enabled)\n },\n stop() {\n if (autoTorchTimer) window.clearInterval(autoTorchTimer)\n mirror.stop()\n for (const track of stream.getTracks()) track.stop()\n if (video.srcObject === stream) video.srcObject = null\n },\n }\n}\n","import type { DocumentQuad } from './types'\n\nexport interface CastShadowRegion {\n x: number\n y: number\n width: number\n height: number\n}\n\nexport interface CastShadowAnalysis {\n strong: boolean\n strength: number\n darkness: number\n areaRatio: number\n region?: CastShadowRegion\n}\n\nfunction percentile(values: number[], fraction: number) {\n if (!values.length) return 0\n const sorted = [...values].sort((first, second) => first - second)\n return sorted[Math.min(sorted.length - 1, Math.floor(sorted.length * fraction))]\n}\n\n/**\n * Finds a connected, page-sized dark blob in any direction. A component must\n * cover meaningful area and contain local contrast, distinguishing cast\n * shadows over printed paper from a dark border or isolated illustration.\n */\nexport function analyzeCastShadowLuminance(\n luminance: Uint8Array,\n width: number,\n height: number,\n gridSize = 12,\n): CastShadowAnalysis {\n if (!width || !height || luminance.length < width * height) {\n return { strong: false, strength: 0, darkness: 0, areaRatio: 0 }\n }\n const columns = Math.min(gridSize, width)\n const rows = Math.min(gridSize, height)\n const cells: Array<{ mean: number; deviation: number }> = []\n for (let row = 0; row < rows; row += 1) {\n const top = Math.floor(row * height / rows)\n const bottom = Math.max(top + 1, Math.floor((row + 1) * height / rows))\n for (let column = 0; column < columns; column += 1) {\n const left = Math.floor(column * width / columns)\n const right = Math.max(left + 1, Math.floor((column + 1) * width / columns))\n let sum = 0\n let squared = 0\n let count = 0\n for (let y = top; y < bottom; y += 1) {\n for (let x = left; x < right; x += 1) {\n const value = luminance[y * width + x]\n sum += value\n squared += value * value\n count += 1\n }\n }\n const mean = sum / count\n cells.push({\n mean,\n deviation: Math.sqrt(Math.max(0, squared / count - mean * mean)),\n })\n }\n }\n\n const brightPaper = percentile(cells.map((cell) => cell.mean), 0.8)\n const dark = cells.map((cell) =>\n brightPaper - cell.mean >= 24 &&\n cell.mean >= 35,\n )\n const visited = new Uint8Array(cells.length)\n const components: number[][] = []\n for (let start = 0; start < cells.length; start += 1) {\n if (!dark[start] || visited[start]) continue\n const component: number[] = []\n const queue = [start]\n visited[start] = 1\n while (queue.length) {\n const index = queue.shift()!\n component.push(index)\n const row = Math.floor(index / columns)\n const column = index % columns\n for (const [nextColumn, nextRow] of [\n [column - 1, row],\n [column + 1, row],\n [column, row - 1],\n [column, row + 1],\n ]) {\n if (\n nextColumn < 0 ||\n nextColumn >= columns ||\n nextRow < 0 ||\n nextRow >= rows\n ) continue\n const next = nextRow * columns + nextColumn\n if (dark[next] && !visited[next]) {\n visited[next] = 1\n queue.push(next)\n }\n }\n }\n components.push(component)\n }\n\n let best: CastShadowAnalysis = {\n strong: false,\n strength: 0,\n darkness: 0,\n areaRatio: 0,\n }\n for (const component of components) {\n const areaRatio = component.length / cells.length\n if (areaRatio < 0.06 || areaRatio > 0.75) continue\n const darkness = component.reduce(\n (total, index) => total + brightPaper - cells[index].mean,\n 0,\n ) / component.length\n const printedCells = component.filter((index) => cells[index].deviation >= 9).length\n const printRatio = printedCells / component.length\n if (printRatio < 0.08 && darkness < 42) continue\n const columnsInComponent = component.map((index) => index % columns)\n const rowsInComponent = component.map((index) => Math.floor(index / columns))\n const minColumn = Math.min(...columnsInComponent)\n const maxColumn = Math.max(...columnsInComponent)\n const minRow = Math.min(...rowsInComponent)\n const maxRow = Math.max(...rowsInComponent)\n const padding = 1\n const left = Math.max(0, minColumn - padding) / columns\n const top = Math.max(0, minRow - padding) / rows\n const right = Math.min(columns, maxColumn + padding + 1) / columns\n const bottom = Math.min(rows, maxRow + padding + 1) / rows\n const strength = darkness * Math.sqrt(areaRatio) * (0.75 + Math.min(0.25, printRatio))\n if (strength > best.strength) {\n best = {\n strong: strength >= 10,\n strength,\n darkness,\n areaRatio,\n region: {\n x: left,\n y: top,\n width: right - left,\n height: bottom - top,\n },\n }\n }\n }\n return best\n}\n\nexport function flattenIlluminationLuminance(\n luminance: Uint8Array,\n width: number,\n height: number,\n radius = Math.max(12, Math.round(Math.max(width, height) / 32)),\n) {\n const stride = width + 1\n const integral = new Uint32Array((width + 1) * (height + 1))\n for (let y = 1; y <= height; y += 1) {\n let row = 0\n for (let x = 1; x <= width; x += 1) {\n row += luminance[(y - 1) * width + x - 1]\n integral[y * stride + x] = integral[(y - 1) * stride + x] + row\n }\n }\n const output = new Uint8Array(luminance.length)\n for (let y = 0; y < height; y += 1) {\n const top = Math.max(0, y - radius)\n const bottom = Math.min(height, y + radius + 1)\n for (let x = 0; x < width; x += 1) {\n const left = Math.max(0, x - radius)\n const right = Math.min(width, x + radius + 1)\n const area = (right - left) * (bottom - top)\n const background = (\n integral[bottom * stride + right] -\n integral[top * stride + right] -\n integral[bottom * stride + left] +\n integral[top * stride + left]\n ) / area\n output[y * width + x] = Math.max(\n 0,\n Math.min(255, Math.round(luminance[y * width + x] * 235 / Math.max(24, background))),\n )\n }\n }\n return output\n}\n\nfunction quadBounds(quad: DocumentQuad, width: number, height: number) {\n const points = [quad.topLeft, quad.topRight, quad.bottomRight, quad.bottomLeft]\n const left = Math.max(0, Math.min(...points.map((point) => point.x)))\n const top = Math.max(0, Math.min(...points.map((point) => point.y)))\n const right = Math.min(width, Math.max(...points.map((point) => point.x)))\n const bottom = Math.min(height, Math.max(...points.map((point) => point.y)))\n return { left, top, width: right - left, height: bottom - top }\n}\n\nexport function analyzeCanvasCastShadow(\n canvas: HTMLCanvasElement,\n quad: DocumentQuad,\n): CastShadowAnalysis {\n const bounds = quadBounds(quad, canvas.width, canvas.height)\n if (bounds.width <= 0 || bounds.height <= 0) {\n return { strong: false, strength: 0, darkness: 0, areaRatio: 0 }\n }\n const sample = document.createElement('canvas')\n sample.width = 60\n sample.height = 60\n const context = sample.getContext('2d', { willReadFrequently: true })\n if (!context) return { strong: false, strength: 0, darkness: 0, areaRatio: 0 }\n context.drawImage(\n canvas,\n bounds.left,\n bounds.top,\n bounds.width,\n bounds.height,\n 0,\n 0,\n sample.width,\n sample.height,\n )\n const pixels = context.getImageData(0, 0, sample.width, sample.height).data\n const luminance = new Uint8Array(sample.width * sample.height)\n for (let pixel = 0, offset = 0; pixel < luminance.length; pixel += 1, offset += 4) {\n luminance[pixel] = Math.round(\n pixels[offset] * 0.299 +\n pixels[offset + 1] * 0.587 +\n pixels[offset + 2] * 0.114,\n )\n }\n return analyzeCastShadowLuminance(luminance, sample.width, sample.height)\n}\n","import { captureVideoFrame } from './camera'\nimport { assertLicense } from './license'\nimport { detectDocument, type ScanOptions } from './scan'\nimport { analyzeCanvasCastShadow } from './lighting'\nimport type {\n DocumentDetectionResult,\n DocumentModelStatus,\n DocumentQuad,\n Point,\n} from './types'\n\nexport type AutoCaptureMode = 'defaultOn' | 'defaultOff' | 'alwaysOn' | 'alwaysOff'\nexport type FinderSource = HTMLVideoElement | MediaStream | HTMLCanvasElement\nexport type FinderState = 'seeking' | 'detecting' | 'unstable' | 'ready' | 'captured'\nexport type FinderGuidanceReason =\n | 'place-document'\n | 'move-closer'\n | 'move-farther-away'\n | 'straighten-camera'\n | 'hold-still'\n | 'ready'\n\nexport interface QuadFill {\n /** Raw quad bounds width divided by the analysis frame width. */\n widthFill: number\n /** Raw quad bounds height divided by the analysis frame height. */\n heightFill: number\n /** Fill on the limiting axis: `max(widthFill, heightFill)`. */\n limitingFill: number\n /** Shoelace polygon area divided by the analysis frame area. Diagnostic only. */\n areaFill: number\n /** Long side divided by short side of the raw quad. */\n aspectRatio: number\n}\n\nexport interface FinderGuidance {\n hint: string\n reason: FinderGuidanceReason\n /**\n * Fill on the limiting axis of the raw quad: the larger of its width and\n * height fill. A tall receipt that fills the frame height is fully framed\n * even though its bounding box covers little frame area.\n */\n fillRatio: number\n /** Component fills, polygon area fill, and aspect ratio behind `fillRatio`. */\n fill: QuadFill\n readyForAutoCapture: boolean\n}\n\nexport interface FinderLighting {\n castShadow: boolean\n strength: number\n hint?: string\n}\n\nexport function selectFinderHint(\n guidance: FinderGuidance,\n lighting: FinderLighting,\n) {\n return lighting.castShadow &&\n (guidance.reason === 'hold-still' || guidance.reason === 'ready')\n ? lighting.hint ?? guidance.hint\n : guidance.hint\n}\n\nexport interface AutoCaptureControl {\n visible: boolean\n checked: boolean\n mutable: boolean\n}\n\nexport interface FinderStatus {\n state: FinderState\n confidence: number\n quad?: DocumentQuad\n guidance: FinderGuidance\n lighting: FinderLighting\n stableFrames: number\n requiredStableFrames: number\n autoCapture: AutoCaptureControl\n sourceWidth?: number\n sourceHeight?: number\n detector?: DocumentDetectionResult['detector']\n modelStatus?: DocumentModelStatus\n modelProvider?: DocumentDetectionResult['modelProvider']\n modelError?: string\n inferenceMs?: number\n}\n\nexport interface FinderCapture {\n frame: HTMLCanvasElement\n detection?: DocumentDetectionResult\n reason: 'auto' | 'manual'\n}\n\nexport interface FinderOptions {\n source: FinderSource\n autoCapture: AutoCaptureMode\n /** Supplies the final full-resolution frame while finder analysis stays bounded. */\n captureFrame?: () => HTMLCanvasElement | Promise<HTMLCanvasElement>\n onStatus?: (status: FinderStatus) => void\n onCapture?: (capture: FinderCapture) => void | Promise<void>\n /** Reports capture failures, including automatic captures, instead of swallowing them. */\n onCaptureError?: (error: Error) => void\n /** Consecutive stable raw detections required. Defaults to 4. */\n stableFrames?: number\n /** Minimum detector confidence on the normalized 0–1 scale. Defaults to 0.72. */\n confidenceThreshold?: number\n /** Maximum normalized corner movement while entering ready. Defaults to 0.024. */\n cornerTolerance?: number\n /** Movement allowed after ready before dropping out. Defaults to 0.036. */\n exitCornerTolerance?: number\n intervalMs?: number\n maxFrameDimension?: number\n guidance?: FinderGuidanceOptions\n detection?: ScanOptions\n playShutterSound?: boolean\n}\n\nexport interface FinderSession {\n stop: () => void\n capture: () => Promise<FinderCapture>\n setAutoCapture: (enabled: boolean) => boolean\n getStatus: () => FinderStatus\n}\n\nexport async function snapshotBeforeCaptureFeedback<T>(\n snapshot: () => T | Promise<T>,\n feedback: () => void,\n) {\n const captured = await snapshot()\n feedback()\n return captured\n}\n\nexport function autoCaptureControl(mode: AutoCaptureMode): AutoCaptureControl {\n if (mode === 'alwaysOn') return { visible: false, checked: true, mutable: false }\n if (mode === 'alwaysOff') return { visible: false, checked: false, mutable: false }\n return {\n visible: true,\n checked: mode === 'defaultOn',\n mutable: true,\n }\n}\n\nfunction cornerList(quad: DocumentQuad): Point[] {\n return [quad.topLeft, quad.topRight, quad.bottomRight, quad.bottomLeft]\n}\n\nexport interface StabilityOptions {\n stableFrames: number\n confidenceThreshold: number\n cornerTolerance: number\n exitCornerTolerance?: number\n}\n\nexport interface FinderGuidanceOptions {\n confidenceThreshold?: number\n /** Limiting-axis fill required to enter ready. Defaults to 0.72. */\n minFillRatio?: number\n /** Limiting-axis fill allowed after ready before exiting. Defaults to 0.64. */\n exitFillRatio?: number\n /** Long-to-short side ratio that makes a document high-aspect. Defaults to 2.2. */\n highAspectRatio?: number\n /** Long-side fill required to enter ready on a high-aspect document. Defaults to 0.8. */\n highAspectFillRatio?: number\n /** Long-side fill allowed after ready on a high-aspect document. Defaults to 0.72. */\n highAspectExitFillRatio?: number\n /** Edge clearance required to enter ready. Defaults to 0.015. */\n edgeMarginRatio?: number\n /** Edge clearance allowed after ready. Defaults to 0.005. */\n exitEdgeMarginRatio?: number\n /** Opposite-edge ratio required to enter ready. Defaults to 0.48. */\n minPerspectiveRatio?: number\n /** Opposite-edge ratio allowed after ready. Defaults to 0.4. */\n exitMinPerspectiveRatio?: number\n}\n\nexport const DEFAULT_FINDER_STABLE_FRAMES = 4\nexport const DEFAULT_FINDER_CONFIDENCE_THRESHOLD = 0.72\nexport const DEFAULT_FINDER_CORNER_TOLERANCE = 0.024\nexport const DEFAULT_FINDER_EXIT_CORNER_TOLERANCE = 0.036\nexport const DEFAULT_FINDER_MIN_FILL_RATIO = 0.72\nexport const DEFAULT_FINDER_EXIT_FILL_RATIO = 0.64\nexport const DEFAULT_FINDER_HIGH_ASPECT_RATIO = 2.2\n/** Extra long-side fill asked of a high-aspect document, above the base target. */\nexport const DEFAULT_FINDER_HIGH_ASPECT_FILL_MARGIN = 0.08\nexport const DEFAULT_FINDER_EDGE_MARGIN_RATIO = 0.015\nexport const DEFAULT_FINDER_EXIT_EDGE_MARGIN_RATIO = 0.005\nexport const DEFAULT_FINDER_MIN_PERSPECTIVE_RATIO = 0.48\nexport const DEFAULT_FINDER_EXIT_MIN_PERSPECTIVE_RATIO = 0.40\n\nfunction polygonArea(points: Point[]) {\n let area = 0\n for (let index = 0; index < points.length; index += 1) {\n const current = points[index]\n const next = points[(index + 1) % points.length]\n area += current.x * next.y - next.x * current.y\n }\n return Math.abs(area) / 2\n}\n\nfunction distance(first: Point, second: Point) {\n return Math.hypot(first.x - second.x, first.y - second.y)\n}\n\nconst EMPTY_FILL: QuadFill = {\n widthFill: 0,\n heightFill: 0,\n limitingFill: 0,\n areaFill: 0,\n aspectRatio: 1,\n}\n\n/**\n * Measures how much of each frame axis the raw quad occupies. A document can\n * only grow until its limiting axis reaches a frame edge, so the larger of the\n * two axis fills — not the bounding-box area — describes how well it is framed.\n */\nexport function measureQuadFill(\n quad: DocumentQuad,\n frameWidth: number,\n frameHeight: number,\n): QuadFill {\n const points = cornerList(quad)\n const xs = points.map(({ x }) => x)\n const ys = points.map(({ y }) => y)\n const widthFill = (Math.max(...xs) - Math.min(...xs)) / Math.max(1, frameWidth)\n const heightFill = (Math.max(...ys) - Math.min(...ys)) / Math.max(1, frameHeight)\n const [topLeft, topRight, bottomRight, bottomLeft] = points\n const horizontal = Math.max(\n distance(topLeft, topRight),\n distance(bottomLeft, bottomRight),\n )\n const vertical = Math.max(\n distance(topLeft, bottomLeft),\n distance(topRight, bottomRight),\n )\n return {\n widthFill,\n heightFill,\n limitingFill: Math.max(widthFill, heightFill),\n areaFill: polygonArea(points) / Math.max(1, frameWidth * frameHeight),\n aspectRatio: Math.max(horizontal, vertical) /\n Math.max(1, Math.min(horizontal, vertical)),\n }\n}\n\n/**\n * Fill the limiting axis must reach. High-aspect documents are asked for a\n * little more of the long side, because their short side can never fill and\n * the long side is the only axis carrying resolution. The target never exceeds\n * what the edge margin physically allows.\n */\nexport function limitingFillTarget(\n fill: QuadFill,\n previouslyReady: boolean,\n edgeMarginRatio: number,\n options: FinderGuidanceOptions = {},\n) {\n const base = previouslyReady\n ? options.exitFillRatio ?? DEFAULT_FINDER_EXIT_FILL_RATIO\n : options.minFillRatio ?? DEFAULT_FINDER_MIN_FILL_RATIO\n const highAspectRatio = options.highAspectRatio ?? DEFAULT_FINDER_HIGH_ASPECT_RATIO\n if (fill.aspectRatio < highAspectRatio) return base\n const configured = previouslyReady\n ? options.highAspectExitFillRatio\n : options.highAspectFillRatio\n return Math.min(\n configured ?? base + DEFAULT_FINDER_HIGH_ASPECT_FILL_MARGIN,\n 1 - edgeMarginRatio * 2,\n )\n}\n\nexport function selectFinderGuidance(\n detection: DocumentDetectionResult,\n stability: { ready: boolean; previouslyReady?: boolean },\n options: FinderGuidanceOptions = {},\n): FinderGuidance {\n const confidenceThreshold =\n options.confidenceThreshold ?? DEFAULT_FINDER_CONFIDENCE_THRESHOLD\n if (\n detection.status !== 'success' ||\n !detection.quad ||\n detection.confidence < confidenceThreshold ||\n !detection.sourceWidth ||\n !detection.sourceHeight\n ) {\n return {\n hint: 'Place the document in the frame',\n reason: 'place-document',\n fillRatio: 0,\n fill: EMPTY_FILL,\n readyForAutoCapture: false,\n }\n }\n\n const points = cornerList(detection.quad)\n const fill = measureQuadFill(\n detection.quad,\n detection.sourceWidth,\n detection.sourceHeight,\n )\n const fillRatio = fill.limitingFill\n const edgeMarginRatio = stability.previouslyReady\n ? options.exitEdgeMarginRatio ?? DEFAULT_FINDER_EXIT_EDGE_MARGIN_RATIO\n : options.edgeMarginRatio ?? DEFAULT_FINDER_EDGE_MARGIN_RATIO\n const marginX = detection.sourceWidth * edgeMarginRatio\n const marginY = detection.sourceHeight * edgeMarginRatio\n const clippingRisk = points.some(({ x, y }) =>\n x <= marginX ||\n x >= detection.sourceWidth - marginX ||\n y <= marginY ||\n y >= detection.sourceHeight - marginY,\n )\n if (clippingRisk) {\n return {\n hint: 'Move farther away',\n reason: 'move-farther-away',\n fillRatio,\n fill,\n readyForAutoCapture: false,\n }\n }\n\n const [topLeft, topRight, bottomRight, bottomLeft] = points\n const top = distance(topLeft, topRight)\n const right = distance(topRight, bottomRight)\n const bottom = distance(bottomRight, bottomLeft)\n const left = distance(bottomLeft, topLeft)\n const oppositeRatio = Math.min(\n Math.min(top, bottom) / Math.max(1, Math.max(top, bottom)),\n Math.min(left, right) / Math.max(1, Math.max(left, right)),\n )\n const minPerspectiveRatio = stability.previouslyReady\n ? options.exitMinPerspectiveRatio ?? DEFAULT_FINDER_EXIT_MIN_PERSPECTIVE_RATIO\n : options.minPerspectiveRatio ?? DEFAULT_FINDER_MIN_PERSPECTIVE_RATIO\n if (oppositeRatio < minPerspectiveRatio) {\n return {\n hint: 'Hold the camera straight',\n reason: 'straighten-camera',\n fillRatio,\n fill,\n readyForAutoCapture: false,\n }\n }\n\n // Both axes have slack only when the limiting one does, so a skinny document\n // that already fills its long axis is never told to move closer.\n const fillTarget = limitingFillTarget(\n fill,\n stability.previouslyReady === true,\n edgeMarginRatio,\n options,\n )\n if (fillRatio < fillTarget) {\n return {\n hint: 'Move closer',\n reason: 'move-closer',\n fillRatio,\n fill,\n readyForAutoCapture: false,\n }\n }\n\n return {\n hint: 'Hold still',\n reason: stability.ready ? 'ready' : 'hold-still',\n fillRatio,\n fill,\n readyForAutoCapture: stability.ready,\n }\n}\n\nexport class QuadStabilityTracker {\n private previous?: DocumentQuad\n private count = 0\n private ready = false\n private readonly options: StabilityOptions\n\n constructor(options: StabilityOptions) {\n this.options = options\n }\n\n reset() {\n this.previous = undefined\n this.count = 0\n this.ready = false\n }\n\n update(detection: DocumentDetectionResult) {\n if (\n detection.status !== 'success' ||\n !detection.quad ||\n detection.confidence < this.options.confidenceThreshold\n ) {\n this.reset()\n return { stableFrames: 0, ready: false, movement: Infinity }\n }\n const diagonal = Math.hypot(detection.sourceWidth, detection.sourceHeight)\n const movement = this.previous\n ? Math.max(...cornerList(detection.quad).map((point, index) => {\n const previous = cornerList(this.previous!)[index]\n return Math.hypot(point.x - previous.x, point.y - previous.y) / Math.max(1, diagonal)\n }))\n : Infinity\n const exitTolerance = this.options.exitCornerTolerance ??\n Math.max(this.options.cornerTolerance, DEFAULT_FINDER_EXIT_CORNER_TOLERANCE)\n if (this.ready && this.previous && movement <= exitTolerance) {\n this.count = Math.max(this.options.stableFrames, this.count + 1)\n } else {\n this.ready = false\n this.count = this.previous && movement <= this.options.cornerTolerance\n ? this.count + 1\n : 1\n if (this.count >= this.options.stableFrames) this.ready = true\n }\n this.previous = detection.quad\n return {\n stableFrames: this.count,\n ready: this.ready,\n movement,\n }\n }\n}\n\nfunction cloneCanvas(source: HTMLCanvasElement, maxDimension: number) {\n const scale = Math.min(1, maxDimension / Math.max(source.width, source.height))\n const output = document.createElement('canvas')\n output.width = Math.max(1, Math.round(source.width * scale))\n output.height = Math.max(1, Math.round(source.height * scale))\n const context = output.getContext('2d')\n if (!context) throw new Error('Canvas 2D is unavailable in this browser.')\n context.drawImage(source, 0, 0, output.width, output.height)\n return output\n}\n\nfunction playShutter() {\n const AudioContextClass = window.AudioContext ??\n (window as typeof window & { webkitAudioContext?: typeof AudioContext }).webkitAudioContext\n if (!AudioContextClass) return\n const context = new AudioContextClass()\n const length = Math.round(context.sampleRate * 0.09)\n const buffer = context.createBuffer(1, length, context.sampleRate)\n const channel = buffer.getChannelData(0)\n for (let index = 0; index < length; index += 1) {\n const envelope = Math.exp(-index / (context.sampleRate * 0.018))\n channel[index] = (Math.random() * 2 - 1) * envelope\n }\n const source = context.createBufferSource()\n const filter = context.createBiquadFilter()\n const gain = context.createGain()\n filter.type = 'bandpass'\n filter.frequency.value = 1400\n gain.gain.value = 0.42\n source.buffer = buffer\n source.connect(filter).connect(gain).connect(context.destination)\n source.start()\n source.onended = () => void context.close()\n}\n\nasync function videoForStream(stream: MediaStream) {\n const video = document.createElement('video')\n video.muted = true\n video.autoplay = true\n video.playsInline = true\n video.srcObject = stream\n await video.play()\n return video\n}\n\nexport async function startFinder(options: FinderOptions): Promise<FinderSession> {\n await assertLicense('scan')\n const control = autoCaptureControl(options.autoCapture)\n const tracker = new QuadStabilityTracker({\n stableFrames: options.stableFrames ?? DEFAULT_FINDER_STABLE_FRAMES,\n confidenceThreshold:\n options.confidenceThreshold ?? DEFAULT_FINDER_CONFIDENCE_THRESHOLD,\n cornerTolerance: options.cornerTolerance ?? DEFAULT_FINDER_CORNER_TOLERANCE,\n exitCornerTolerance:\n options.exitCornerTolerance ?? DEFAULT_FINDER_EXIT_CORNER_TOLERANCE,\n })\n const maxDimension = options.maxFrameDimension ?? 1600\n const interval = options.intervalMs ?? 140\n const detectionOptions: ScanOptions = {\n minDimension: 220,\n maxAnalysisDimension: 520,\n temporalEdgeWindow: 3,\n ...options.detection,\n }\n const source: HTMLVideoElement | HTMLCanvasElement =\n typeof MediaStream !== 'undefined' && options.source instanceof MediaStream\n ? await videoForStream(options.source)\n : options.source as HTMLVideoElement | HTMLCanvasElement\n let running = true\n let captureStarted = false\n let guidanceReady = false\n let timer = 0\n let latestDetection: DocumentDetectionResult | undefined\n let status: FinderStatus = {\n state: 'detecting',\n confidence: 0,\n guidance: {\n hint: 'Place the document in the frame',\n reason: 'place-document',\n fillRatio: 0,\n fill: EMPTY_FILL,\n readyForAutoCapture: false,\n },\n lighting: { castShadow: false, strength: 0 },\n stableFrames: 0,\n requiredStableFrames: options.stableFrames ?? DEFAULT_FINDER_STABLE_FRAMES,\n autoCapture: { ...control },\n }\n\n const frame = () => {\n if (source instanceof HTMLCanvasElement) return cloneCanvas(source, maxDimension)\n return captureVideoFrame(source, maxDimension)\n }\n const emit = (next: FinderStatus) => {\n status = next\n options.onStatus?.(next)\n }\n const stop = () => {\n running = false\n window.clearTimeout(timer)\n if (source instanceof HTMLVideoElement && source !== options.source) source.srcObject = null\n }\n const capture = async (reason: FinderCapture['reason'] = 'manual') => {\n if (captureStarted) throw new Error('A finder capture is already in progress.')\n captureStarted = true\n let capturedFrame: HTMLCanvasElement\n try {\n capturedFrame = await snapshotBeforeCaptureFeedback(\n options.captureFrame ?? frame,\n () => {\n emit({ ...status, state: 'captured' })\n if (options.playShutterSound !== false) playShutter()\n stop()\n },\n )\n } catch (error) {\n // Leave the finder usable so the end user can retake after a blank frame.\n captureStarted = false\n throw error instanceof Error ? error : new Error('The camera frame could not be captured.')\n }\n const result: FinderCapture = { frame: capturedFrame, detection: latestDetection, reason }\n await options.onCapture?.(result)\n return result\n }\n const tick = async () => {\n if (!running || captureStarted) return\n try {\n const current = frame()\n const detection = await detectDocument(current, detectionOptions)\n latestDetection = detection\n const shadow = detection.quad\n ? analyzeCanvasCastShadow(current, detection.quad)\n : { strong: false, strength: 0 }\n const lighting: FinderLighting = shadow.strong\n ? {\n castShadow: true,\n strength: shadow.strength,\n hint: 'Tilt to move the shadow off the page',\n }\n : { castShadow: false, strength: shadow.strength }\n const stability = tracker.update(detection)\n const guidance = selectFinderGuidance(detection, {\n ...stability,\n previouslyReady: guidanceReady,\n }, {\n confidenceThreshold:\n options.confidenceThreshold ?? DEFAULT_FINDER_CONFIDENCE_THRESHOLD,\n ...options.guidance,\n })\n guidanceReady = guidance.readyForAutoCapture\n const nextState: FinderState =\n detection.status !== 'success' || guidance.reason === 'place-document'\n ? 'seeking'\n : guidance.readyForAutoCapture\n ? 'ready'\n : 'unstable'\n emit({\n state: nextState,\n confidence: detection.confidence,\n quad: detection.quad,\n guidance,\n lighting,\n stableFrames: stability.stableFrames,\n requiredStableFrames: status.requiredStableFrames,\n autoCapture: { ...control },\n sourceWidth: detection.sourceWidth,\n sourceHeight: detection.sourceHeight,\n detector: detection.detector,\n modelStatus: detection.modelStatus,\n modelProvider: detection.modelProvider,\n modelError: detection.modelError,\n inferenceMs: detection.inferenceMs,\n })\n if (guidance.readyForAutoCapture && control.checked) {\n try {\n await capture('auto')\n return\n } catch (error) {\n tracker.reset()\n guidanceReady = false\n options.onCaptureError?.(\n error instanceof Error ? error : new Error('Automatic capture failed.'),\n )\n }\n }\n } catch {\n tracker.reset()\n guidanceReady = false\n emit({\n state: 'seeking',\n confidence: 0,\n guidance: {\n hint: 'Place the document in the frame',\n reason: 'place-document',\n fillRatio: 0,\n fill: EMPTY_FILL,\n readyForAutoCapture: false,\n },\n lighting: { castShadow: false, strength: 0 },\n stableFrames: 0,\n requiredStableFrames: status.requiredStableFrames,\n autoCapture: { ...control },\n })\n }\n if (running) timer = window.setTimeout(() => void tick(), interval)\n }\n\n options.onStatus?.(status)\n void tick()\n return {\n stop,\n capture: () => capture('manual'),\n setAutoCapture(enabled) {\n if (!control.mutable || captureStarted) return false\n control.checked = enabled\n emit({ ...status, autoCapture: { ...control } })\n return true\n },\n getStatus: () => status,\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export { assertLicense, DEV_LICENSE_HOSTS, getLicense, LicenseError, setLicenseKey, } from './sdk/license';
2
+ export type { LicenseClaims, LicenseErrorCode, LicenseFeature, LicenseFeatures, } from './sdk/license';
3
+ export { cropDocument, DEFAULT_DOCUMENT_MODEL_URL, detectDocument, resolveDocumentModelUrl, scanDocument, } from './sdk/scan';
4
+ export type { ScanOptions } from './sdk/scan';
5
+ export { AutoTorchController, captureVideoFrame, detectBrowserEngine, formatCaptureDiagnosticsReport, isNearBlackFrame, meanFrameLuminance, mobileCameraConstraints, NEAR_BLACK_LUMINANCE, startCamera, torchControl, } from './sdk/camera';
6
+ export type { AutoTorchOptions, BrowserEngine, CameraDiagnostics, CameraOptions, CameraPhoto, CameraSession, CaptureDiagnosticsReport, CapturePath, TorchMode, TorchStatus, } from './sdk/camera';
7
+ export { autoCaptureControl, DEFAULT_FINDER_CONFIDENCE_THRESHOLD, DEFAULT_FINDER_CORNER_TOLERANCE, DEFAULT_FINDER_EDGE_MARGIN_RATIO, DEFAULT_FINDER_EXIT_CORNER_TOLERANCE, DEFAULT_FINDER_EXIT_EDGE_MARGIN_RATIO, DEFAULT_FINDER_EXIT_FILL_RATIO, DEFAULT_FINDER_EXIT_MIN_PERSPECTIVE_RATIO, DEFAULT_FINDER_HIGH_ASPECT_FILL_MARGIN, DEFAULT_FINDER_HIGH_ASPECT_RATIO, DEFAULT_FINDER_MIN_FILL_RATIO, DEFAULT_FINDER_MIN_PERSPECTIVE_RATIO, DEFAULT_FINDER_STABLE_FRAMES, limitingFillTarget, measureQuadFill, QuadStabilityTracker, selectFinderHint, selectFinderGuidance, startFinder, } from './sdk/finder';
8
+ export { mapDocumentCornersToFrame } from './sdk/frame-geometry';
9
+ export type { FrameSize } from './sdk/frame-geometry';
10
+ export type { AutoCaptureControl, AutoCaptureMode, FinderCapture, FinderGuidance, FinderGuidanceOptions, FinderGuidanceReason, FinderLighting, FinderOptions, FinderSession, FinderSource, FinderState, FinderStatus, QuadFill, StabilityOptions, } from './sdk/finder';
11
+ export { createFinderSimulator, simulatorPose, simulatorQuad } from './sdk/finder-simulator';
12
+ export type { FinderSimulator, SimulatorPose } from './sdk/finder-simulator';
13
+ export { recognizeText } from './sdk/ocr';
14
+ export type { OcrOptions } from './sdk/ocr';
15
+ export { detectVehicles, detectPlates } from './sdk/detect';
16
+ export { applyRedactions } from './sdk/redact';
17
+ export type { RedactResult } from './sdk/redact';
18
+ export { matchRedactionRules, redactProgrammatically } from './sdk/programmatic-redaction';
19
+ export type { LabelDirection, LabelRedactionRule, MatchRedactionOptions, NormalizedRect, ProgrammaticRedactionOptions, ProgrammaticRedactionResult, ProgrammaticRedactionRule, RedactionMatch, RedactionMatchResult, RedactionTemplate, RedactionTemplateField, SemanticField, SemanticModelDetection, SemanticRedactionRule, StringMatchMode, StringRedactionRule, TemplateAnchorField, TemplateRectField, } from './sdk/programmatic-redaction';
20
+ export type { Box, DetectOptions, Detection, DocumentCorners, DocumentDetectionResult, DocumentDetectionStatus, DocumentDetectorMode, DocumentEdge, DocumentModelStatus, DocumentQuad, ImageSource, OcrBox, OcrDiagnostics, OcrResult, Point, RedactionRegion, RedactOptions, ScanResult, } from './sdk/types';
@@ -0,0 +1,11 @@
1
+ import type { Point } from './sdk/types';
2
+ export type LivePreviewFit = 'contain' | 'cover';
3
+ export interface LiveOverlayTransform {
4
+ viewBox: string;
5
+ preserveAspectRatio: 'none' | 'xMidYMid meet';
6
+ scale: number;
7
+ offsetX: number;
8
+ offsetY: number;
9
+ }
10
+ export declare function liveOverlayTransform(sourceWidth: number, sourceHeight: number, renderedWidth: number, renderedHeight: number, fit: LivePreviewFit): LiveOverlayTransform;
11
+ export declare function mapLiveSourcePoint(point: Point, transform: LiveOverlayTransform): Point;
@@ -0,0 +1,2 @@
1
+ export { ScannerCameraOverlay, type ScannerCameraOverlayCapture, type ScannerCameraOverlayProps, } from './components/ScannerCameraOverlay';
2
+ export type { LivePreviewFit } from './live-overlay-geometry';