@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.
- package/README.md +288 -0
- package/dist/assets/document-worker-QjcJjl9-.js +2 -0
- package/dist/assets/document-worker-QjcJjl9-.js.map +1 -0
- package/dist/assets/ort.min-CA5AZ7mL.js +2937 -0
- package/dist/assets/ort.min-CA5AZ7mL.js.map +1 -0
- package/dist/components/ScannerCameraOverlay.d.ts +36 -0
- package/dist/components/scanner-camera-overlay.css +2 -0
- package/dist/finder-Clo7f2gN.js +1447 -0
- package/dist/finder-Clo7f2gN.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/live-overlay-geometry.d.ts +11 -0
- package/dist/react.d.ts +2 -0
- package/dist/react.js +448 -0
- package/dist/react.js.map +1 -0
- package/dist/scanner-sdk.js +921 -0
- package/dist/scanner-sdk.js.map +1 -0
- package/dist/sdk/camera.d.ts +142 -0
- package/dist/sdk/detect.d.ts +3 -0
- package/dist/sdk/display-quad.d.ts +23 -0
- package/dist/sdk/document-analysis.d.ts +14 -0
- package/dist/sdk/document-geometry.d.ts +21 -0
- package/dist/sdk/field-model.d.ts +4 -0
- package/dist/sdk/finder-simulator.d.ts +17 -0
- package/dist/sdk/finder.d.ts +166 -0
- package/dist/sdk/frame-geometry.d.ts +6 -0
- package/dist/sdk/image.d.ts +18 -0
- package/dist/sdk/license-codec.d.ts +2 -0
- package/dist/sdk/license-public-key.d.ts +9 -0
- package/dist/sdk/license-runtime.d.ts +2 -0
- package/dist/sdk/license.d.ts +76 -0
- package/dist/sdk/lighting.d.ts +22 -0
- package/dist/sdk/ocr.d.ts +75 -0
- package/dist/sdk/programmatic-redaction.d.ts +102 -0
- package/dist/sdk/redact.d.ts +12 -0
- package/dist/sdk/scan.d.ts +32 -0
- package/dist/sdk/types.d.ts +92 -0
- package/package.json +74 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ImageSource } from './types';
|
|
2
|
+
export interface CanvasSourceOptions {
|
|
3
|
+
cloneCanvas?: boolean;
|
|
4
|
+
maxDimension?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare function sourceToCanvas(source: ImageSource, options?: CanvasSourceOptions): Promise<HTMLCanvasElement>;
|
|
7
|
+
export declare function canvasToBlob(canvas: HTMLCanvasElement, type?: string, quality?: number): Promise<Blob>;
|
|
8
|
+
export declare function clampBox(box: {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
}, width: number, height: number): {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raw Ed25519 public key: 32 bytes, base64url, no padding.
|
|
3
|
+
*
|
|
4
|
+
* The license portal signs with `LICENSE_SIGNING_PRIVATE_KEY`.
|
|
5
|
+
* Generate a pair with `npm run generate-keypair --prefix license-portal`,
|
|
6
|
+
* then replace this constant with the printed public key and rebuild the
|
|
7
|
+
* library. Never commit the private key.
|
|
8
|
+
*/
|
|
9
|
+
export declare const LICENSE_PUBLIC_KEY_BASE64 = "uFpA_UXGk-1AjjG31cFP6cqXOQX0w2TnuR7Bl-msZ6I";
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hosts that may use the SDK before a paid license exists.
|
|
3
|
+
* Add a production hostname here when it should run without a signed key.
|
|
4
|
+
*
|
|
5
|
+
* An entry is either an exact hostname or a single `*.suffix` pattern.
|
|
6
|
+
* `*.exige.io` matches `exige.io` and any host that ends with `.exige.io`.
|
|
7
|
+
* It does not match `exige.io.evil.com`. Other entries are exact:
|
|
8
|
+
* `exige-park-app.ngrok.io` does not allow the rest of ngrok, and nothing
|
|
9
|
+
* here allows `*.vercel.app`. Paid license `domains` stay exact hostnames.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEV_LICENSE_HOSTS: readonly ["localhost", "127.0.0.1", "exige-scanner-sdk.vercel.app", "exige-park-app.ngrok.io", "*.exige.io"];
|
|
12
|
+
export declare const LICENSE_FEATURES: readonly ["scan", "ocr", "redaction", "vehicles", "torch"];
|
|
13
|
+
export type LicenseFeature = (typeof LICENSE_FEATURES)[number];
|
|
14
|
+
export type LicenseErrorCode = 'missing' | 'malformed' | 'invalid-signature' | 'expired' | 'domain' | 'feature';
|
|
15
|
+
export interface LicenseFeatures {
|
|
16
|
+
scan: boolean;
|
|
17
|
+
ocr: boolean;
|
|
18
|
+
redaction: boolean;
|
|
19
|
+
vehicles: boolean;
|
|
20
|
+
torch: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface LicenseClaims {
|
|
23
|
+
customerId: string;
|
|
24
|
+
/** Exact hostnames. `localhost` and `127.0.0.1` are included only when listed. */
|
|
25
|
+
domains: string[];
|
|
26
|
+
/** Unix expiry in seconds. The key is valid while `now < exp`. */
|
|
27
|
+
exp: number;
|
|
28
|
+
features: LicenseFeatures;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Compact signed payload: `base64url(json).base64url(ed25519 signature)`.
|
|
32
|
+
* The signature covers the raw JSON bytes. Public APIs do not accept a
|
|
33
|
+
* caller-supplied public key or hostname.
|
|
34
|
+
*/
|
|
35
|
+
export interface LicenseVerification {
|
|
36
|
+
publicKey: Uint8Array;
|
|
37
|
+
/** Injected only for Node tests. Browsers use `location.hostname`. */
|
|
38
|
+
hostname: string;
|
|
39
|
+
/** Unix time in seconds. */
|
|
40
|
+
now: number;
|
|
41
|
+
}
|
|
42
|
+
export declare class LicenseError extends Error {
|
|
43
|
+
readonly code: LicenseErrorCode;
|
|
44
|
+
constructor(code: LicenseErrorCode, message: string);
|
|
45
|
+
}
|
|
46
|
+
export declare function normalizeHostname(value: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* Canonical JSON signed by the license portal. Key order is part of the
|
|
49
|
+
* signature bytes. Keep this in lockstep with `license-portal/lib/license-token.ts`.
|
|
50
|
+
*/
|
|
51
|
+
export declare function canonicalLicensePayload(claims: LicenseClaims): string;
|
|
52
|
+
/**
|
|
53
|
+
* Verifies a compact license. Hostname and public key are explicit so Node
|
|
54
|
+
* tests can inject them. Published entry points call `assertLicense`, which
|
|
55
|
+
* always uses the embedded public key and `location.hostname`.
|
|
56
|
+
*/
|
|
57
|
+
export declare function verifyLicenseToken(licenseKey: string, verification: LicenseVerification): Promise<LicenseClaims>;
|
|
58
|
+
/**
|
|
59
|
+
* Verifies `licenseKey` for the current page and keeps it for later calls.
|
|
60
|
+
* Throws `LicenseError` when the key is missing, malformed, badly signed,
|
|
61
|
+
* expired, or not issued for `location.hostname`.
|
|
62
|
+
*/
|
|
63
|
+
export declare function setLicenseKey(licenseKey: string): Promise<LicenseClaims>;
|
|
64
|
+
/**
|
|
65
|
+
* Feature flags from the key most recently accepted by `setLicenseKey`.
|
|
66
|
+
* Returns null when no key is loaded, the key is expired, or this hostname
|
|
67
|
+
* is not on the key. Enforcement still re-checks the signature in `assertLicense`.
|
|
68
|
+
*/
|
|
69
|
+
export declare function getLicense(): LicenseClaims | null;
|
|
70
|
+
/**
|
|
71
|
+
* Fail-closed gate used by the public camera, finder, scan, OCR, redaction,
|
|
72
|
+
* and vehicle entry points. Throws before those APIs do any work.
|
|
73
|
+
*/
|
|
74
|
+
export declare function assertLicense(feature: LicenseFeature): Promise<LicenseClaims>;
|
|
75
|
+
/** Drops the in-memory key. Not part of the published package entry. */
|
|
76
|
+
export declare function clearLicenseForTests(): void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DocumentQuad } from './types';
|
|
2
|
+
export interface CastShadowRegion {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
}
|
|
8
|
+
export interface CastShadowAnalysis {
|
|
9
|
+
strong: boolean;
|
|
10
|
+
strength: number;
|
|
11
|
+
darkness: number;
|
|
12
|
+
areaRatio: number;
|
|
13
|
+
region?: CastShadowRegion;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Finds a connected, page-sized dark blob in any direction. A component must
|
|
17
|
+
* cover meaningful area and contain local contrast, distinguishing cast
|
|
18
|
+
* shadows over printed paper from a dark border or isolated illustration.
|
|
19
|
+
*/
|
|
20
|
+
export declare function analyzeCastShadowLuminance(luminance: Uint8Array, width: number, height: number, gridSize?: number): CastShadowAnalysis;
|
|
21
|
+
export declare function flattenIlluminationLuminance(luminance: Uint8Array, width: number, height: number, radius?: number): Uint8Array<ArrayBuffer>;
|
|
22
|
+
export declare function analyzeCanvasCastShadow(canvas: HTMLCanvasElement, quad: DocumentQuad): CastShadowAnalysis;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { type CastShadowAnalysis } from './lighting';
|
|
2
|
+
import type { ImageSource, OcrBox, OcrResult } from './types';
|
|
3
|
+
export interface OcrOptions {
|
|
4
|
+
language?: string;
|
|
5
|
+
/**
|
|
6
|
+
* Minimum normalized confidence accepted for OCR tokens, from 0 to 1.
|
|
7
|
+
* Defaults to 0.5. Words and characters are filtered independently.
|
|
8
|
+
*/
|
|
9
|
+
minConfidence?: number;
|
|
10
|
+
/**
|
|
11
|
+
* Re-reads one low-yield phone/hand cast-shadow tile after local
|
|
12
|
+
* illumination normalization. Defaults to true.
|
|
13
|
+
*/
|
|
14
|
+
shadowPass?: boolean;
|
|
15
|
+
includeWords?: boolean;
|
|
16
|
+
includeCharacters?: boolean;
|
|
17
|
+
onProgress?: (progress: number, status: string) => void;
|
|
18
|
+
}
|
|
19
|
+
interface TesseractBbox {
|
|
20
|
+
x0: number;
|
|
21
|
+
y0: number;
|
|
22
|
+
x1: number;
|
|
23
|
+
y1: number;
|
|
24
|
+
}
|
|
25
|
+
interface TesseractSymbol {
|
|
26
|
+
text: string;
|
|
27
|
+
confidence: number;
|
|
28
|
+
bbox: TesseractBbox;
|
|
29
|
+
}
|
|
30
|
+
interface TesseractWord {
|
|
31
|
+
text: string;
|
|
32
|
+
confidence: number;
|
|
33
|
+
bbox: TesseractBbox;
|
|
34
|
+
symbols: TesseractSymbol[];
|
|
35
|
+
}
|
|
36
|
+
interface TesseractBlock {
|
|
37
|
+
paragraphs: Array<{
|
|
38
|
+
lines: Array<{
|
|
39
|
+
words: TesseractWord[];
|
|
40
|
+
}>;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
export interface OcrPass {
|
|
44
|
+
blocks: TesseractBlock[] | null;
|
|
45
|
+
/** Maps pass coordinates back into the original input image. */
|
|
46
|
+
scaleX?: number;
|
|
47
|
+
scaleY?: number;
|
|
48
|
+
offsetX?: number;
|
|
49
|
+
offsetY?: number;
|
|
50
|
+
}
|
|
51
|
+
export declare function mergeOcrPasses(passes: OcrPass[], options: Pick<OcrOptions, 'minConfidence' | 'includeWords' | 'includeCharacters'>, imageSize?: {
|
|
52
|
+
width: number;
|
|
53
|
+
height: number;
|
|
54
|
+
}, inkDensity?: (box: OcrBox['bbox']) => number): {
|
|
55
|
+
text: string;
|
|
56
|
+
confidence: number;
|
|
57
|
+
words: OcrBox[];
|
|
58
|
+
characters: OcrBox[];
|
|
59
|
+
};
|
|
60
|
+
export declare function extractOcrLayout(blocks: TesseractBlock[] | null, options: Pick<OcrOptions, 'minConfidence' | 'includeWords' | 'includeCharacters'>): {
|
|
61
|
+
text: string;
|
|
62
|
+
confidence: number;
|
|
63
|
+
words: OcrBox[];
|
|
64
|
+
characters: OcrBox[];
|
|
65
|
+
};
|
|
66
|
+
export declare function extractOcrBoxes(blocks: TesseractBlock[] | null, options: Pick<OcrOptions, 'minConfidence' | 'includeWords' | 'includeCharacters'>): {
|
|
67
|
+
words: OcrBox[];
|
|
68
|
+
characters: OcrBox[];
|
|
69
|
+
};
|
|
70
|
+
export declare function shadowRegionNeedsOcr(analysis: CastShadowAnalysis, words: OcrBox[], imageSize: {
|
|
71
|
+
width: number;
|
|
72
|
+
height: number;
|
|
73
|
+
}): boolean;
|
|
74
|
+
export declare function recognizeText(source: ImageSource, options?: OcrOptions): Promise<OcrResult>;
|
|
75
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { Box, ImageSource, OcrResult, RedactOptions } from './types';
|
|
2
|
+
export type StringMatchMode = 'exact' | 'case-insensitive' | 'regex';
|
|
3
|
+
export type LabelDirection = 'above' | 'below' | 'left' | 'right' | 'any';
|
|
4
|
+
export interface StringRedactionRule {
|
|
5
|
+
id: string;
|
|
6
|
+
strategy: 'string';
|
|
7
|
+
mode: StringMatchMode;
|
|
8
|
+
values?: string[];
|
|
9
|
+
pattern?: string;
|
|
10
|
+
flags?: string;
|
|
11
|
+
scope?: 'word' | 'line';
|
|
12
|
+
}
|
|
13
|
+
export interface LabelRedactionRule {
|
|
14
|
+
id: string;
|
|
15
|
+
strategy: 'label';
|
|
16
|
+
label: string;
|
|
17
|
+
direction: LabelDirection;
|
|
18
|
+
labelMode?: 'exact' | 'case-insensitive';
|
|
19
|
+
valuePattern?: string;
|
|
20
|
+
patternFlags?: string;
|
|
21
|
+
window?: {
|
|
22
|
+
distance?: number;
|
|
23
|
+
crossAxis?: number;
|
|
24
|
+
};
|
|
25
|
+
redactLabel?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export type SemanticField = 'person_name' | 'date_of_birth' | 'address' | 'document_number' | 'expiration_date' | 'postal_code' | 'state';
|
|
28
|
+
export interface SemanticRedactionRule {
|
|
29
|
+
id: string;
|
|
30
|
+
strategy: 'semantic';
|
|
31
|
+
field: SemanticField;
|
|
32
|
+
}
|
|
33
|
+
export interface SemanticModelDetection {
|
|
34
|
+
field: SemanticField;
|
|
35
|
+
bbox: Box;
|
|
36
|
+
confidence: number;
|
|
37
|
+
}
|
|
38
|
+
export type ProgrammaticRedactionRule = StringRedactionRule | LabelRedactionRule | SemanticRedactionRule;
|
|
39
|
+
export interface NormalizedRect {
|
|
40
|
+
x: number;
|
|
41
|
+
y: number;
|
|
42
|
+
width: number;
|
|
43
|
+
height: number;
|
|
44
|
+
}
|
|
45
|
+
export interface TemplateRectField {
|
|
46
|
+
id: string;
|
|
47
|
+
strategy: 'rect';
|
|
48
|
+
rect: NormalizedRect;
|
|
49
|
+
}
|
|
50
|
+
export interface TemplateAnchorField extends Omit<LabelRedactionRule, 'id' | 'strategy'> {
|
|
51
|
+
id: string;
|
|
52
|
+
strategy: 'anchor';
|
|
53
|
+
}
|
|
54
|
+
export type RedactionTemplateField = TemplateRectField | TemplateAnchorField;
|
|
55
|
+
export interface RedactionTemplate {
|
|
56
|
+
id: string;
|
|
57
|
+
fields: RedactionTemplateField[];
|
|
58
|
+
}
|
|
59
|
+
export interface MatchRedactionOptions {
|
|
60
|
+
rules: ProgrammaticRedactionRule[];
|
|
61
|
+
template?: RedactionTemplate;
|
|
62
|
+
imageWidth?: number;
|
|
63
|
+
imageHeight?: number;
|
|
64
|
+
semanticDetections?: SemanticModelDetection[];
|
|
65
|
+
modelRequested?: boolean;
|
|
66
|
+
}
|
|
67
|
+
export interface RedactionMatch {
|
|
68
|
+
ruleId: string;
|
|
69
|
+
strategy: 'string' | 'label' | 'template-rect' | 'template-anchor' | 'semantic';
|
|
70
|
+
source?: 'string' | 'label' | 'template' | 'alias' | 'mrz' | 'layout' | 'model';
|
|
71
|
+
bbox: Box;
|
|
72
|
+
text?: string;
|
|
73
|
+
confidence: number;
|
|
74
|
+
}
|
|
75
|
+
export interface RedactionMatchResult {
|
|
76
|
+
matches: RedactionMatch[];
|
|
77
|
+
unmatchedRuleIds: string[];
|
|
78
|
+
complete: boolean;
|
|
79
|
+
confidence: number;
|
|
80
|
+
}
|
|
81
|
+
export interface ProgrammaticRedactionOptions extends MatchRedactionOptions {
|
|
82
|
+
ocr?: OcrResult;
|
|
83
|
+
style?: RedactOptions;
|
|
84
|
+
requireAll?: boolean;
|
|
85
|
+
models?: {
|
|
86
|
+
fields?: string;
|
|
87
|
+
fieldClasses?: SemanticField[];
|
|
88
|
+
confidence?: number;
|
|
89
|
+
allowHeuristicFallback?: boolean;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
export interface ProgrammaticRedactionResult extends RedactionMatchResult {
|
|
93
|
+
status: 'success' | 'partial' | 'unmatched';
|
|
94
|
+
ocr?: OcrResult;
|
|
95
|
+
canvas?: HTMLCanvasElement;
|
|
96
|
+
blob?: Blob;
|
|
97
|
+
modelStatus: 'not-requested' | 'loaded' | 'fallback' | 'failed';
|
|
98
|
+
modelError?: string;
|
|
99
|
+
}
|
|
100
|
+
export declare function matchRedactionRules(ocr: OcrResult | undefined, options: MatchRedactionOptions): RedactionMatchResult;
|
|
101
|
+
export declare function redactionStatus(summary: RedactionMatchResult, requireAll?: boolean): ProgrammaticRedactionResult['status'];
|
|
102
|
+
export declare function redactProgrammatically(image: ImageSource, options: ProgrammaticRedactionOptions): Promise<ProgrammaticRedactionResult>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ImageSource, RedactionRegion, RedactOptions } from './types';
|
|
2
|
+
export interface RedactResult {
|
|
3
|
+
canvas: HTMLCanvasElement;
|
|
4
|
+
blob: Blob;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Applies redaction regions to a copy of an image and encodes the result.
|
|
8
|
+
*
|
|
9
|
+
* The source is not mutated. Regions use source-image pixel coordinates and
|
|
10
|
+
* are clipped to the image bounds.
|
|
11
|
+
*/
|
|
12
|
+
export declare function applyRedactions(source: ImageSource, regions: RedactionRegion[], options?: RedactOptions): Promise<RedactResult>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { DocumentCorners, DocumentDetectionResult, DocumentDetectorMode, ImageSource, ScanResult } from './types';
|
|
2
|
+
export interface ScanOptions {
|
|
3
|
+
minDimension?: number;
|
|
4
|
+
edgeThreshold?: number;
|
|
5
|
+
minConfidence?: number;
|
|
6
|
+
maxAnalysisDimension?: number;
|
|
7
|
+
maxOutputDimension?: number;
|
|
8
|
+
useWorker?: boolean;
|
|
9
|
+
/** OR the current edge map with recent frames; useful for live finder input. */
|
|
10
|
+
temporalEdgeWindow?: number;
|
|
11
|
+
/** Enables experimental Hough line assembly when no connected contour survives. */
|
|
12
|
+
lineFallback?: boolean;
|
|
13
|
+
/** Selects zero-download classical detection, strict ML, or ML with classical fallback. */
|
|
14
|
+
detector?: DocumentDetectorMode;
|
|
15
|
+
/** URL of a DocAligner-compatible [1,3,256,256] ONNX heatmap model. */
|
|
16
|
+
modelUrl?: string;
|
|
17
|
+
/** Heatmap threshold used before largest-component corner centroids. */
|
|
18
|
+
heatmapThreshold?: number;
|
|
19
|
+
/** Reuse model bytes through the browser HTTP cache. */
|
|
20
|
+
cacheModel?: boolean;
|
|
21
|
+
/** Base URL for ONNX Runtime WASM files when WebGPU is unavailable. */
|
|
22
|
+
ortWasmPaths?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare const DEFAULT_DOCUMENT_MODEL_URL = "https://exige-scanner-sdk.vercel.app/models/docaligner-lcnet100-f4117b78.onnx";
|
|
25
|
+
export declare function resolveDocumentModelUrl(detector?: DocumentDetectorMode, modelUrl?: string): string | undefined;
|
|
26
|
+
export declare function perspectiveOutputSize(corners: DocumentCorners, maxDimension: number): {
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
};
|
|
30
|
+
export declare function detectDocument(source: ImageSource, options?: ScanOptions): Promise<DocumentDetectionResult>;
|
|
31
|
+
export declare function cropDocument(source: ImageSource, corners: DocumentCorners, options?: Pick<ScanOptions, 'maxOutputDimension'>): Promise<ScanResult>;
|
|
32
|
+
export declare function scanDocument(source: ImageSource, options?: ScanOptions): Promise<ScanResult>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export type ImageSource = Blob | HTMLImageElement | HTMLCanvasElement | ImageBitmap;
|
|
2
|
+
export interface Point {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
}
|
|
6
|
+
export interface Box {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
}
|
|
12
|
+
export interface DocumentCorners {
|
|
13
|
+
topLeft: Point;
|
|
14
|
+
topRight: Point;
|
|
15
|
+
bottomRight: Point;
|
|
16
|
+
bottomLeft: Point;
|
|
17
|
+
}
|
|
18
|
+
export interface DocumentEdge {
|
|
19
|
+
start: Point;
|
|
20
|
+
end: Point;
|
|
21
|
+
}
|
|
22
|
+
export interface DocumentQuad extends DocumentCorners {
|
|
23
|
+
edges: {
|
|
24
|
+
top: DocumentEdge;
|
|
25
|
+
right: DocumentEdge;
|
|
26
|
+
bottom: DocumentEdge;
|
|
27
|
+
left: DocumentEdge;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export type DocumentDetectionStatus = 'success' | 'no-document' | 'low-confidence' | 'low-quality';
|
|
31
|
+
export type DocumentDetectorMode = 'classical' | 'ml' | 'auto';
|
|
32
|
+
export type DocumentModelStatus = 'not-requested' | 'loading' | 'ready' | 'fallback' | 'failed';
|
|
33
|
+
export interface DocumentDetectionResult {
|
|
34
|
+
status: DocumentDetectionStatus;
|
|
35
|
+
quad?: DocumentQuad;
|
|
36
|
+
corners?: DocumentCorners;
|
|
37
|
+
confidence: number;
|
|
38
|
+
message: string;
|
|
39
|
+
sourceWidth: number;
|
|
40
|
+
sourceHeight: number;
|
|
41
|
+
detector?: 'classical' | 'ml';
|
|
42
|
+
modelStatus?: DocumentModelStatus;
|
|
43
|
+
modelProvider?: 'webgpu' | 'wasm';
|
|
44
|
+
modelError?: string;
|
|
45
|
+
inferenceMs?: number;
|
|
46
|
+
}
|
|
47
|
+
export interface ScanResult extends DocumentDetectionResult {
|
|
48
|
+
canvas?: HTMLCanvasElement;
|
|
49
|
+
}
|
|
50
|
+
export interface OcrResult {
|
|
51
|
+
/** Text rebuilt from words that meet OcrOptions.minConfidence. */
|
|
52
|
+
text: string;
|
|
53
|
+
/** Arithmetic mean of retained word confidence, normalized 0–1; 0 when empty. */
|
|
54
|
+
confidence: number;
|
|
55
|
+
language: string;
|
|
56
|
+
imageWidth: number;
|
|
57
|
+
imageHeight: number;
|
|
58
|
+
diagnostics?: OcrDiagnostics;
|
|
59
|
+
words?: OcrBox[];
|
|
60
|
+
characters?: OcrBox[];
|
|
61
|
+
}
|
|
62
|
+
export interface OcrDiagnostics {
|
|
63
|
+
shadowPassUsed: boolean;
|
|
64
|
+
castShadowStrength: number;
|
|
65
|
+
shadowRegion?: Box;
|
|
66
|
+
}
|
|
67
|
+
export interface OcrBox {
|
|
68
|
+
text: string;
|
|
69
|
+
/** Token confidence normalized to 0–1. */
|
|
70
|
+
confidence: number;
|
|
71
|
+
bbox: Box;
|
|
72
|
+
}
|
|
73
|
+
export interface Detection extends Box {
|
|
74
|
+
id: string;
|
|
75
|
+
label: string;
|
|
76
|
+
confidence: number;
|
|
77
|
+
source: 'model' | 'heuristic';
|
|
78
|
+
}
|
|
79
|
+
export interface DetectOptions {
|
|
80
|
+
modelUrl?: string;
|
|
81
|
+
confidence?: number;
|
|
82
|
+
allowFallback?: boolean;
|
|
83
|
+
}
|
|
84
|
+
export interface RedactionRegion extends Box {
|
|
85
|
+
mode?: 'blackout' | 'blur';
|
|
86
|
+
}
|
|
87
|
+
export interface RedactOptions {
|
|
88
|
+
mode?: 'blackout' | 'blur';
|
|
89
|
+
blurRadius?: number;
|
|
90
|
+
mimeType?: 'image/png' | 'image/jpeg' | 'image/webp';
|
|
91
|
+
quality?: number;
|
|
92
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@exige/web-scanner-sdk",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Client-side document scanning, OCR, YOLO inference, and visual redaction for web apps.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"sideEffects": [
|
|
8
|
+
"**/*.css"
|
|
9
|
+
],
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"main": "./dist/scanner-sdk.js",
|
|
17
|
+
"module": "./dist/scanner-sdk.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/scanner-sdk.js"
|
|
23
|
+
},
|
|
24
|
+
"./react": {
|
|
25
|
+
"types": "./dist/react.d.ts",
|
|
26
|
+
"import": "./dist/react.js"
|
|
27
|
+
},
|
|
28
|
+
"./camera-overlay.css": "./dist/components/scanner-camera-overlay.css"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"dev": "vite --config vite.config.app.ts",
|
|
32
|
+
"build": "npm run build:lib && npm run build:demo",
|
|
33
|
+
"build:lib": "tsc -b && vite build && tsc -p tsconfig.lib.json",
|
|
34
|
+
"build:demo": "tsc -b && vite build --config vite.config.app.ts",
|
|
35
|
+
"vercel-build": "npm run build:demo",
|
|
36
|
+
"typecheck": "tsc -b",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"lint": "oxlint",
|
|
39
|
+
"preview": "vite preview --config vite.config.app.ts",
|
|
40
|
+
"docs:api": "typedoc",
|
|
41
|
+
"docs:dev": "npm run docs:api && vitepress dev site --host 0.0.0.0 --port 43261",
|
|
42
|
+
"docs:build": "npm run docs:api && vitepress build site",
|
|
43
|
+
"docs:preview": "vitepress preview site --host 0.0.0.0 --port 43261",
|
|
44
|
+
"dev:portal": "npm --prefix license-portal run dev",
|
|
45
|
+
"test:portal": "npm --prefix license-portal test"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"onnxruntime-web": "^1.30.0",
|
|
49
|
+
"tesseract.js": "^7.0.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"react": ">=18"
|
|
53
|
+
},
|
|
54
|
+
"peerDependenciesMeta": {
|
|
55
|
+
"react": {
|
|
56
|
+
"optional": true
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/node": "^24.13.3",
|
|
61
|
+
"@types/react": "^19.2.18",
|
|
62
|
+
"@types/react-dom": "^19.2.7",
|
|
63
|
+
"@vitejs/plugin-react": "^6.1.1",
|
|
64
|
+
"oxlint": "^1.81.0",
|
|
65
|
+
"react": "^19.2.8",
|
|
66
|
+
"react-dom": "^19.2.8",
|
|
67
|
+
"typedoc": "^0.28.20",
|
|
68
|
+
"typedoc-plugin-markdown": "^4.13.1",
|
|
69
|
+
"typescript": "~6.0.2",
|
|
70
|
+
"vite": "^8.3.0",
|
|
71
|
+
"vitepress": "^1.6.4",
|
|
72
|
+
"vitest": "^5.0.1"
|
|
73
|
+
}
|
|
74
|
+
}
|