@andresxid/xid_camera_ocr_sdk_react 0.1.1 → 0.3.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/CHANGELOG.md +38 -0
- package/README.md +83 -16
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -14
- package/dist/index.d.ts +61 -14
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -19,7 +19,7 @@ interface CornerPoint {
|
|
|
19
19
|
}
|
|
20
20
|
/** User-facing guidance for the current frame. */
|
|
21
21
|
type FrameHint = 'no_document' | 'too_small' | 'too_dark' | 'glare' | 'blurry' | 'hold_still' | 'ready'
|
|
22
|
-
/** OpenCV failed to load or the worker crashed: auto-capture is off, `captureNow()`
|
|
22
|
+
/** OpenCV failed to load or the worker crashed: auto-capture is off, `captureNow()` still crops the guide region. */
|
|
23
23
|
| 'detector_unavailable';
|
|
24
24
|
interface XidCameraOcrSessionOptions {
|
|
25
25
|
/** `<video>` element that renders the camera stream. */
|
|
@@ -27,16 +27,26 @@ interface XidCameraOcrSessionOptions {
|
|
|
27
27
|
/**
|
|
28
28
|
* Shape hints the host is interested in. Detection and capture are NOT
|
|
29
29
|
* filtered by this list (any quadrilateral in [1.25, 1.75] aspect is
|
|
30
|
-
* capturable)
|
|
30
|
+
* capturable). The first entry fixes the guide ratio (PASSPORT_MX → TD3,
|
|
31
|
+
* otherwise ID-1) for both the on-screen guide and the captured crop.
|
|
31
32
|
*/
|
|
32
33
|
documentTypes?: DocumentType[];
|
|
33
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* When `true`, the capture is cropped to the guide rectangle (cover math over the video
|
|
36
|
+
* element's client box). Only enable it when the video is `object-fit: cover` filling its
|
|
37
|
+
* box and a centered guide is drawn with `guideBox`. Default `false`: full-frame snapshot.
|
|
38
|
+
* `<XidCameraOcr />` turns it on whenever it draws the guide.
|
|
39
|
+
*/
|
|
40
|
+
cropToGuide?: boolean;
|
|
41
|
+
/** Live guide ratio (width / height) read at capture time. Default: derived from `documentTypes`. */
|
|
42
|
+
guideRatio?: () => number;
|
|
43
|
+
/** When `true`, captures automatically once a stable, good-quality quad is seen. Default `false`: the user takes the photo manually. */
|
|
34
44
|
autoCapture?: boolean;
|
|
35
45
|
/** Consecutive stable frames required before auto-capture. Default 10 (≈ 1 s at 10 fps). */
|
|
36
46
|
stableFramesRequired?: number;
|
|
37
47
|
/** JPEG quality of the captured image (0–1). Default 0.92. */
|
|
38
48
|
captureQuality?: number;
|
|
39
|
-
/**
|
|
49
|
+
/** Max long side of the captured guide crop (never upscaled): `standard` = 1024 px, `high` = 1600 px. Default `standard`. */
|
|
40
50
|
captureResolution?: 'standard' | 'high';
|
|
41
51
|
/**
|
|
42
52
|
* URL of the OpenCV.js asset the worker loads lazily. Defaults to the
|
|
@@ -204,7 +214,25 @@ declare class CVWorkerClient {
|
|
|
204
214
|
private request;
|
|
205
215
|
}
|
|
206
216
|
|
|
207
|
-
|
|
217
|
+
interface BoxSize {
|
|
218
|
+
width: number;
|
|
219
|
+
height: number;
|
|
220
|
+
}
|
|
221
|
+
interface PixelRect {
|
|
222
|
+
x: number;
|
|
223
|
+
y: number;
|
|
224
|
+
width: number;
|
|
225
|
+
height: number;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Fixed guide ratio from the configured document types: TD3 when the first accepted
|
|
229
|
+
* type is PASSPORT_MX, ID-1 otherwise. Detection never changes it.
|
|
230
|
+
*/
|
|
231
|
+
declare function guideRatioFor(documentTypes: readonly DocumentType[] | undefined): number;
|
|
232
|
+
/** Guide size in container px: at most 85% of the width and 70% of the height, keeping `ratio`. */
|
|
233
|
+
declare function guideBox(container: BoxSize, ratio: number): BoxSize;
|
|
234
|
+
|
|
235
|
+
type WorkerClient = Pick<CVWorkerClient, 'init' | 'isReady' | 'analyze' | 'terminate'>;
|
|
208
236
|
/**
|
|
209
237
|
* @internal Test seam (second constructor argument). Not part of the public,
|
|
210
238
|
* documented API and may change without notice.
|
|
@@ -216,8 +244,8 @@ interface XidCameraOcrSessionDeps {
|
|
|
216
244
|
attachCamera(video: HTMLVideoElement): Promise<MediaStream>;
|
|
217
245
|
detachCamera(video: HTMLVideoElement, stream: MediaStream | null): void;
|
|
218
246
|
sampleFrame(video: HTMLVideoElement, targetWidth: number): ImageDataLike | null;
|
|
219
|
-
|
|
220
|
-
|
|
247
|
+
/** Draws `rect` (video px) of the current frame scaled to `out` and encodes it as JPEG. */
|
|
248
|
+
cropFrame(video: HTMLVideoElement, rect: PixelRect, out: BoxSize, quality: number): Promise<Blob>;
|
|
221
249
|
snapshotToBlob(video: HTMLVideoElement, quality: number): Promise<Blob>;
|
|
222
250
|
supportsTorch(track: MediaStreamTrack): boolean;
|
|
223
251
|
setTorch(track: MediaStreamTrack, on: boolean): Promise<boolean>;
|
|
@@ -233,8 +261,6 @@ declare class XidCameraOcrSession {
|
|
|
233
261
|
private generation;
|
|
234
262
|
private timer;
|
|
235
263
|
private frameCallback;
|
|
236
|
-
/** The in-flight analyze request, so a manual capture never overlaps it. */
|
|
237
|
-
private inFlight;
|
|
238
264
|
/** 0 = not armed yet (armed on the first analysed frame and after each capture). */
|
|
239
265
|
private warmupUntil;
|
|
240
266
|
private capturing;
|
|
@@ -267,8 +293,15 @@ declare class XidCameraOcrSession {
|
|
|
267
293
|
private updateTorch;
|
|
268
294
|
/** Reprojects a sample-frame quad onto the full video frame; null when degenerate. */
|
|
269
295
|
private fullFrameQuad;
|
|
270
|
-
/** `
|
|
296
|
+
/** `typeHint` is the stable detection hint (null when nothing stable was tracked). */
|
|
271
297
|
private doCapture;
|
|
298
|
+
/**
|
|
299
|
+
* With `cropToGuide` off, takes the plain full-frame snapshot. Otherwise crops the guide region out of the current full frame. The rect is computed now, from
|
|
300
|
+
* the live element sizes, so a rotation mid-session is handled. The video element fills
|
|
301
|
+
* the root with `object-fit: cover`, so its client box is the guide's container. Without
|
|
302
|
+
* a usable rect (no layout / no frame) or when the crop fails, the full-frame snapshot
|
|
303
|
+
* is used and the type is null.
|
|
304
|
+
*/
|
|
272
305
|
private captureBlob;
|
|
273
306
|
/** Clears every timer and frame callback, turns the torch off, closes the camera and drops the worker. */
|
|
274
307
|
private release;
|
|
@@ -342,7 +375,8 @@ declare function measureQuality(gray: GrayFrame, quad: Quad): FrameQuality;
|
|
|
342
375
|
/**
|
|
343
376
|
* Camera helpers — getUserMedia + video element wiring.
|
|
344
377
|
*/
|
|
345
|
-
|
|
378
|
+
type ViewportOrientation = 'portrait' | 'landscape';
|
|
379
|
+
declare function attachCamera(videoElement: HTMLVideoElement, constraints?: MediaStreamConstraints, orientation?: ViewportOrientation): Promise<MediaStream>;
|
|
346
380
|
declare function detachCamera(videoElement: HTMLVideoElement, stream: MediaStream | null): void;
|
|
347
381
|
/** Captura un snapshot del video y devuelve un Blob JPEG. */
|
|
348
382
|
declare function snapshotToBlob(videoElement: HTMLVideoElement, quality?: number): Promise<Blob>;
|
|
@@ -438,7 +472,7 @@ interface UseXidCameraOcrReturn {
|
|
|
438
472
|
start: () => Promise<void>;
|
|
439
473
|
stop: () => void;
|
|
440
474
|
captureNow: () => Promise<void>;
|
|
441
|
-
/** Stops the current run and starts a new one (re-arms the auto-shutter). */
|
|
475
|
+
/** Stops the current run and starts a new one (re-arms the auto-shutter when `autoCapture` is on). */
|
|
442
476
|
retake: () => Promise<void>;
|
|
443
477
|
}
|
|
444
478
|
declare function useXidCameraOcr(options: UseXidCameraOcrOptions): UseXidCameraOcrReturn;
|
|
@@ -453,7 +487,20 @@ interface XidCameraOcrProps extends UseXidCameraOcrOptions {
|
|
|
453
487
|
theme?: XidCameraOcrTheme;
|
|
454
488
|
/** Show the capture tips card. Default `true`. */
|
|
455
489
|
showTips?: boolean;
|
|
490
|
+
/** Hide the built-in shutter button; drive capture with the `ref` handle instead. Default `false`. */
|
|
491
|
+
hideShutter?: boolean;
|
|
492
|
+
/** Called with the initial status and again on every status change. */
|
|
493
|
+
onStatusChange?: (status: SessionState['status']) => void;
|
|
494
|
+
}
|
|
495
|
+
/** Imperative handle exposed through the component `ref`. */
|
|
496
|
+
interface XidCameraOcrHandle {
|
|
497
|
+
/** Same as the built-in shutter: ignored unless the camera is live; errors reach `onError`. */
|
|
498
|
+
capture(): Promise<void>;
|
|
499
|
+
/** Same as the built-in retake: ignored unless the run is `done` or `error`. */
|
|
500
|
+
retake(): void;
|
|
501
|
+
/** Starts the camera (needed only with `autoStart={false}` or after `stop`). */
|
|
502
|
+
start(): Promise<void>;
|
|
456
503
|
}
|
|
457
|
-
declare
|
|
504
|
+
declare const XidCameraOcr: react.ForwardRefExoticComponent<XidCameraOcrProps & react.RefAttributes<XidCameraOcrHandle>>;
|
|
458
505
|
|
|
459
|
-
export { CVWorkerClient, type CornerPoint, type CvDetectionResult, DEFAULT_TEXTS_EN, DEFAULT_TEXTS_ES, type DocumentType, type ExtractResult, type FrameHint, type FrameQuality, type FrameState, type HintCopy, type HintCopyKey, ID1_RATIO, type Point, QUALITY_THRESHOLDS, type Quad, type SessionState, type SessionStatus, StabilityTracker, TD3_RATIO, type UseXidCameraOcrOptions, type UseXidCameraOcrReturn, XCO_VARS, type XcoThemeKey, XidCameraOcr, type XidCameraOcrProps, XidCameraOcrSession, type XidCameraOcrSessionOptions, type XidCameraOcrTheme, attachCamera, copyFor, decideHint, defaultOpencvUrl, detachCamera, detectDocumentCV, isCapturableAspect, measureQuality, orderCorners, rectifiedAspect, resolveTexts, sampleFrame, setTorch, snapshotToBlob, supportsTorch, typeHintFromAspect, useXidCameraOcr, warpDocument, warpDocumentImageData, warpedSnapshotToBlob };
|
|
506
|
+
export { type BoxSize, CVWorkerClient, type CornerPoint, type CvDetectionResult, DEFAULT_TEXTS_EN, DEFAULT_TEXTS_ES, type DocumentType, type ExtractResult, type FrameHint, type FrameQuality, type FrameState, type HintCopy, type HintCopyKey, ID1_RATIO, type Point, QUALITY_THRESHOLDS, type Quad, type SessionState, type SessionStatus, StabilityTracker, TD3_RATIO, type UseXidCameraOcrOptions, type UseXidCameraOcrReturn, XCO_VARS, type XcoThemeKey, XidCameraOcr, type XidCameraOcrHandle, type XidCameraOcrProps, XidCameraOcrSession, type XidCameraOcrSessionOptions, type XidCameraOcrTheme, attachCamera, copyFor, decideHint, defaultOpencvUrl, detachCamera, detectDocumentCV, guideBox, guideRatioFor, isCapturableAspect, measureQuality, orderCorners, rectifiedAspect, resolveTexts, sampleFrame, setTorch, snapshotToBlob, supportsTorch, typeHintFromAspect, useXidCameraOcr, warpDocument, warpDocumentImageData, warpedSnapshotToBlob };
|
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ interface CornerPoint {
|
|
|
19
19
|
}
|
|
20
20
|
/** User-facing guidance for the current frame. */
|
|
21
21
|
type FrameHint = 'no_document' | 'too_small' | 'too_dark' | 'glare' | 'blurry' | 'hold_still' | 'ready'
|
|
22
|
-
/** OpenCV failed to load or the worker crashed: auto-capture is off, `captureNow()`
|
|
22
|
+
/** OpenCV failed to load or the worker crashed: auto-capture is off, `captureNow()` still crops the guide region. */
|
|
23
23
|
| 'detector_unavailable';
|
|
24
24
|
interface XidCameraOcrSessionOptions {
|
|
25
25
|
/** `<video>` element that renders the camera stream. */
|
|
@@ -27,16 +27,26 @@ interface XidCameraOcrSessionOptions {
|
|
|
27
27
|
/**
|
|
28
28
|
* Shape hints the host is interested in. Detection and capture are NOT
|
|
29
29
|
* filtered by this list (any quadrilateral in [1.25, 1.75] aspect is
|
|
30
|
-
* capturable)
|
|
30
|
+
* capturable). The first entry fixes the guide ratio (PASSPORT_MX → TD3,
|
|
31
|
+
* otherwise ID-1) for both the on-screen guide and the captured crop.
|
|
31
32
|
*/
|
|
32
33
|
documentTypes?: DocumentType[];
|
|
33
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* When `true`, the capture is cropped to the guide rectangle (cover math over the video
|
|
36
|
+
* element's client box). Only enable it when the video is `object-fit: cover` filling its
|
|
37
|
+
* box and a centered guide is drawn with `guideBox`. Default `false`: full-frame snapshot.
|
|
38
|
+
* `<XidCameraOcr />` turns it on whenever it draws the guide.
|
|
39
|
+
*/
|
|
40
|
+
cropToGuide?: boolean;
|
|
41
|
+
/** Live guide ratio (width / height) read at capture time. Default: derived from `documentTypes`. */
|
|
42
|
+
guideRatio?: () => number;
|
|
43
|
+
/** When `true`, captures automatically once a stable, good-quality quad is seen. Default `false`: the user takes the photo manually. */
|
|
34
44
|
autoCapture?: boolean;
|
|
35
45
|
/** Consecutive stable frames required before auto-capture. Default 10 (≈ 1 s at 10 fps). */
|
|
36
46
|
stableFramesRequired?: number;
|
|
37
47
|
/** JPEG quality of the captured image (0–1). Default 0.92. */
|
|
38
48
|
captureQuality?: number;
|
|
39
|
-
/**
|
|
49
|
+
/** Max long side of the captured guide crop (never upscaled): `standard` = 1024 px, `high` = 1600 px. Default `standard`. */
|
|
40
50
|
captureResolution?: 'standard' | 'high';
|
|
41
51
|
/**
|
|
42
52
|
* URL of the OpenCV.js asset the worker loads lazily. Defaults to the
|
|
@@ -204,7 +214,25 @@ declare class CVWorkerClient {
|
|
|
204
214
|
private request;
|
|
205
215
|
}
|
|
206
216
|
|
|
207
|
-
|
|
217
|
+
interface BoxSize {
|
|
218
|
+
width: number;
|
|
219
|
+
height: number;
|
|
220
|
+
}
|
|
221
|
+
interface PixelRect {
|
|
222
|
+
x: number;
|
|
223
|
+
y: number;
|
|
224
|
+
width: number;
|
|
225
|
+
height: number;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Fixed guide ratio from the configured document types: TD3 when the first accepted
|
|
229
|
+
* type is PASSPORT_MX, ID-1 otherwise. Detection never changes it.
|
|
230
|
+
*/
|
|
231
|
+
declare function guideRatioFor(documentTypes: readonly DocumentType[] | undefined): number;
|
|
232
|
+
/** Guide size in container px: at most 85% of the width and 70% of the height, keeping `ratio`. */
|
|
233
|
+
declare function guideBox(container: BoxSize, ratio: number): BoxSize;
|
|
234
|
+
|
|
235
|
+
type WorkerClient = Pick<CVWorkerClient, 'init' | 'isReady' | 'analyze' | 'terminate'>;
|
|
208
236
|
/**
|
|
209
237
|
* @internal Test seam (second constructor argument). Not part of the public,
|
|
210
238
|
* documented API and may change without notice.
|
|
@@ -216,8 +244,8 @@ interface XidCameraOcrSessionDeps {
|
|
|
216
244
|
attachCamera(video: HTMLVideoElement): Promise<MediaStream>;
|
|
217
245
|
detachCamera(video: HTMLVideoElement, stream: MediaStream | null): void;
|
|
218
246
|
sampleFrame(video: HTMLVideoElement, targetWidth: number): ImageDataLike | null;
|
|
219
|
-
|
|
220
|
-
|
|
247
|
+
/** Draws `rect` (video px) of the current frame scaled to `out` and encodes it as JPEG. */
|
|
248
|
+
cropFrame(video: HTMLVideoElement, rect: PixelRect, out: BoxSize, quality: number): Promise<Blob>;
|
|
221
249
|
snapshotToBlob(video: HTMLVideoElement, quality: number): Promise<Blob>;
|
|
222
250
|
supportsTorch(track: MediaStreamTrack): boolean;
|
|
223
251
|
setTorch(track: MediaStreamTrack, on: boolean): Promise<boolean>;
|
|
@@ -233,8 +261,6 @@ declare class XidCameraOcrSession {
|
|
|
233
261
|
private generation;
|
|
234
262
|
private timer;
|
|
235
263
|
private frameCallback;
|
|
236
|
-
/** The in-flight analyze request, so a manual capture never overlaps it. */
|
|
237
|
-
private inFlight;
|
|
238
264
|
/** 0 = not armed yet (armed on the first analysed frame and after each capture). */
|
|
239
265
|
private warmupUntil;
|
|
240
266
|
private capturing;
|
|
@@ -267,8 +293,15 @@ declare class XidCameraOcrSession {
|
|
|
267
293
|
private updateTorch;
|
|
268
294
|
/** Reprojects a sample-frame quad onto the full video frame; null when degenerate. */
|
|
269
295
|
private fullFrameQuad;
|
|
270
|
-
/** `
|
|
296
|
+
/** `typeHint` is the stable detection hint (null when nothing stable was tracked). */
|
|
271
297
|
private doCapture;
|
|
298
|
+
/**
|
|
299
|
+
* With `cropToGuide` off, takes the plain full-frame snapshot. Otherwise crops the guide region out of the current full frame. The rect is computed now, from
|
|
300
|
+
* the live element sizes, so a rotation mid-session is handled. The video element fills
|
|
301
|
+
* the root with `object-fit: cover`, so its client box is the guide's container. Without
|
|
302
|
+
* a usable rect (no layout / no frame) or when the crop fails, the full-frame snapshot
|
|
303
|
+
* is used and the type is null.
|
|
304
|
+
*/
|
|
272
305
|
private captureBlob;
|
|
273
306
|
/** Clears every timer and frame callback, turns the torch off, closes the camera and drops the worker. */
|
|
274
307
|
private release;
|
|
@@ -342,7 +375,8 @@ declare function measureQuality(gray: GrayFrame, quad: Quad): FrameQuality;
|
|
|
342
375
|
/**
|
|
343
376
|
* Camera helpers — getUserMedia + video element wiring.
|
|
344
377
|
*/
|
|
345
|
-
|
|
378
|
+
type ViewportOrientation = 'portrait' | 'landscape';
|
|
379
|
+
declare function attachCamera(videoElement: HTMLVideoElement, constraints?: MediaStreamConstraints, orientation?: ViewportOrientation): Promise<MediaStream>;
|
|
346
380
|
declare function detachCamera(videoElement: HTMLVideoElement, stream: MediaStream | null): void;
|
|
347
381
|
/** Captura un snapshot del video y devuelve un Blob JPEG. */
|
|
348
382
|
declare function snapshotToBlob(videoElement: HTMLVideoElement, quality?: number): Promise<Blob>;
|
|
@@ -438,7 +472,7 @@ interface UseXidCameraOcrReturn {
|
|
|
438
472
|
start: () => Promise<void>;
|
|
439
473
|
stop: () => void;
|
|
440
474
|
captureNow: () => Promise<void>;
|
|
441
|
-
/** Stops the current run and starts a new one (re-arms the auto-shutter). */
|
|
475
|
+
/** Stops the current run and starts a new one (re-arms the auto-shutter when `autoCapture` is on). */
|
|
442
476
|
retake: () => Promise<void>;
|
|
443
477
|
}
|
|
444
478
|
declare function useXidCameraOcr(options: UseXidCameraOcrOptions): UseXidCameraOcrReturn;
|
|
@@ -453,7 +487,20 @@ interface XidCameraOcrProps extends UseXidCameraOcrOptions {
|
|
|
453
487
|
theme?: XidCameraOcrTheme;
|
|
454
488
|
/** Show the capture tips card. Default `true`. */
|
|
455
489
|
showTips?: boolean;
|
|
490
|
+
/** Hide the built-in shutter button; drive capture with the `ref` handle instead. Default `false`. */
|
|
491
|
+
hideShutter?: boolean;
|
|
492
|
+
/** Called with the initial status and again on every status change. */
|
|
493
|
+
onStatusChange?: (status: SessionState['status']) => void;
|
|
494
|
+
}
|
|
495
|
+
/** Imperative handle exposed through the component `ref`. */
|
|
496
|
+
interface XidCameraOcrHandle {
|
|
497
|
+
/** Same as the built-in shutter: ignored unless the camera is live; errors reach `onError`. */
|
|
498
|
+
capture(): Promise<void>;
|
|
499
|
+
/** Same as the built-in retake: ignored unless the run is `done` or `error`. */
|
|
500
|
+
retake(): void;
|
|
501
|
+
/** Starts the camera (needed only with `autoStart={false}` or after `stop`). */
|
|
502
|
+
start(): Promise<void>;
|
|
456
503
|
}
|
|
457
|
-
declare
|
|
504
|
+
declare const XidCameraOcr: react.ForwardRefExoticComponent<XidCameraOcrProps & react.RefAttributes<XidCameraOcrHandle>>;
|
|
458
505
|
|
|
459
|
-
export { CVWorkerClient, type CornerPoint, type CvDetectionResult, DEFAULT_TEXTS_EN, DEFAULT_TEXTS_ES, type DocumentType, type ExtractResult, type FrameHint, type FrameQuality, type FrameState, type HintCopy, type HintCopyKey, ID1_RATIO, type Point, QUALITY_THRESHOLDS, type Quad, type SessionState, type SessionStatus, StabilityTracker, TD3_RATIO, type UseXidCameraOcrOptions, type UseXidCameraOcrReturn, XCO_VARS, type XcoThemeKey, XidCameraOcr, type XidCameraOcrProps, XidCameraOcrSession, type XidCameraOcrSessionOptions, type XidCameraOcrTheme, attachCamera, copyFor, decideHint, defaultOpencvUrl, detachCamera, detectDocumentCV, isCapturableAspect, measureQuality, orderCorners, rectifiedAspect, resolveTexts, sampleFrame, setTorch, snapshotToBlob, supportsTorch, typeHintFromAspect, useXidCameraOcr, warpDocument, warpDocumentImageData, warpedSnapshotToBlob };
|
|
506
|
+
export { type BoxSize, CVWorkerClient, type CornerPoint, type CvDetectionResult, DEFAULT_TEXTS_EN, DEFAULT_TEXTS_ES, type DocumentType, type ExtractResult, type FrameHint, type FrameQuality, type FrameState, type HintCopy, type HintCopyKey, ID1_RATIO, type Point, QUALITY_THRESHOLDS, type Quad, type SessionState, type SessionStatus, StabilityTracker, TD3_RATIO, type UseXidCameraOcrOptions, type UseXidCameraOcrReturn, XCO_VARS, type XcoThemeKey, XidCameraOcr, type XidCameraOcrHandle, type XidCameraOcrProps, XidCameraOcrSession, type XidCameraOcrSessionOptions, type XidCameraOcrTheme, attachCamera, copyFor, decideHint, defaultOpencvUrl, detachCamera, detectDocumentCV, guideBox, guideRatioFor, isCapturableAspect, measureQuality, orderCorners, rectifiedAspect, resolveTexts, sampleFrame, setTorch, snapshotToBlob, supportsTorch, typeHintFromAspect, useXidCameraOcr, warpDocument, warpDocumentImageData, warpedSnapshotToBlob };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {useRef,useState,useCallback,useEffect,useMemo,useId,useLayoutEffect}from'react';import {jsx,jsxs}from'react/jsx-runtime';async function ue(e,t){let r={audio:false,video:{facingMode:{ideal:"environment"},width:{ideal:1920,min:640},height:{ideal:1080,min:480},aspectRatio:{ideal:1.7777777777777777}}};if(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia)throw new Error("Camera unavailable: getUserMedia requires a secure context (HTTPS or localhost) and a browser with MediaDevices support.");let n;try{n=await navigator.mediaDevices.getUserMedia(t??r);}catch(s){if(!t)n=await navigator.mediaDevices.getUserMedia({audio:false,video:true});else throw s}e.srcObject=n,e.muted=true,e.playsInline=true,e.autoplay=true;let o=n.getVideoTracks()[0],i=o.getCapabilities?.();return i&&"focusMode"in i&&i.focusMode?.includes("continuous")&&o.applyConstraints({advanced:[{focusMode:"continuous"}]}).catch(()=>{}),await e.play().catch(()=>{}),n}function de(e,t){e.srcObject===t&&(e.srcObject=null),t?.getTracks().forEach(r=>r.stop());}async function pe(e,t=.92){let r=e.videoWidth,n=e.videoHeight;if(!r||!n)throw new Error("Video stream not ready (videoWidth=0)");let o=document.createElement("canvas");o.width=r,o.height=n;let i=o.getContext("2d");if(!i)throw new Error("2D canvas context unavailable");return i.drawImage(e,0,0,r,n),new Promise((s,a)=>{o.toBlob(l=>l?s(l):a(new Error("Canvas toBlob returned null")),"image/jpeg",t);})}var Q=null;function me(e,t=640){let r=e.videoWidth,n=e.videoHeight;if(!r||!n)return null;let o=Math.round(t),i=Math.round(n*t/r);Q??=document.createElement("canvas"),(Q.width!==o||Q.height!==i)&&(Q.width=o,Q.height=i);let s=Q.getContext("2d",{willReadFrequently:true});return s?(s.drawImage(e,0,0,o,i),s.getImageData(0,0,o,i)):null}function Ae(e){let t=e.videoWidth,r=e.videoHeight;if(!t||!r)return null;let n=document.createElement("canvas");n.width=t,n.height=r;let o=n.getContext("2d",{willReadFrequently:true});return o?(o.drawImage(e,0,0,t,r),o.getImageData(0,0,t,r)):null}function Fe(e,t=.92){let r=document.createElement("canvas");r.width=e.width,r.height=e.height;let n=r.getContext("2d");return n?(n.putImageData(e,0,0),new Promise((o,i)=>r.toBlob(s=>s?o(s):i(new Error("Canvas toBlob returned null")),"image/jpeg",t))):Promise.reject(new Error("2D canvas context unavailable"))}function he(e){let t=e.getCapabilities;return typeof t!="function"?false:t.call(e).torch===true}async function ye(e,t){try{return await e.applyConstraints({advanced:[{torch:t}]}),!0}catch{return false}}var bt="@andresxid/xid_camera_ocr_sdk_react";function Pe(e,t){return e.pathname.endsWith(`/${bt}/${t}`)}function De(e){return new URL(e,import.meta.url)}function Ie(){return new URL("@andresxid/xid_camera_ocr_sdk_react/opencv.js",import.meta.url)}function fe(){let e=Ie();return Pe(e,"opencv.js")?De("./opencv.js").href:e.href}function Oe(e){return e!==void 0?new Worker(e,{type:"module"}):Pe(Ie(),"opencv.js")?new Worker(De("./cv-worker.js"),{type:"module"}):new Worker(new URL("@andresxid/xid_camera_ocr_sdk_react/cv-worker.js",import.meta.url),{type:"module"})}function He(e){if(!e||typeof e!="object")return null;let t=e;switch(t.type){case "ready":return {type:"ready"};case "init-error":return typeof t.error=="string"?{type:"init-error",error:t.error}:null;case "error":return typeof t.id=="number"&&typeof t.error=="string"?{type:"error",id:t.id,error:t.error}:null;case "analyze-result":return typeof t.id=="number"&&t.result&&typeof t.result=="object"?{type:"analyze-result",id:t.id,result:t.result}:null;case "warp-result":return typeof t.id=="number"&&typeof t.width=="number"&&typeof t.height=="number"&&t.buffer instanceof ArrayBuffer?{type:"warp-result",id:t.id,width:t.width,height:t.height,buffer:t.buffer}:null;default:return null}}function Le(e){let t=new Uint8ClampedArray(e.data.byteLength);return t.set(e.data),t.buffer}var xt=e=>e instanceof Error?e:new Error(String(e)),W=class{initTimeoutMs;worker=null;readyPromise=null;rejectInit=null;initTimer=null;ready=false;pending=new Map;nextId=1;constructor(t={}){this.initTimeoutMs=t.initTimeoutMs??3e4;}init(t=fe(),r){if(this.readyPromise)return this.readyPromise;let n;try{n=Oe(r);}catch(i){return Promise.reject(xt(i))}this.worker=n;let o=new Promise((i,s)=>{this.rejectInit=s,this.initTimer=setTimeout(()=>this.fail(new Error(`OpenCV worker not ready within ${this.initTimeoutMs} ms`)),this.initTimeoutMs),n.addEventListener("message",a=>{if(this.worker!==n)return;let l=He(a.data);if(!l)return;if(l.type==="ready"){this.clearInitTimer(),this.rejectInit=null,this.ready=true,i();return}if(l.type==="init-error"){this.fail(new Error(l.error));return}let c=this.pending.get(l.id);c&&(this.pending.delete(l.id),l.type==="error"?c.reject(new Error(l.error)):c.resolve(l));}),n.addEventListener("error",a=>{this.worker===n&&this.fail(new Error(a.message||"Worker error"));}),n.addEventListener("messageerror",a=>{if(this.worker!==n)return;let l=new Error("Worker message could not be deserialized"),c=a.data?.id,d=typeof c=="number"?this.pending.get(c):void 0;if(typeof c=="number"&&d){this.pending.delete(c),d.reject(l);return}this.fail(l);});});return this.readyPromise=o,n.postMessage({type:"init",opencvUrl:t}),o}isReady(){return this.ready&&this.worker!==null}async analyze(t,r={}){let n=Le(t),o=r.prior,i=await this.request(s=>({type:"analyze",id:s,width:t.width,height:t.height,buffer:n,...o?{prior:o}:{}}),[n]);if(i.type!=="analyze-result")throw new Error(`Unexpected worker response: ${i.type}`);return i.result}async warp(t,r,n,o=1024){let i=Le(t),s=await this.request(a=>({type:"warp",id:a,width:t.width,height:t.height,buffer:i,corners:r,docType:n,longSide:o}),[i]);if(s.type!=="warp-result")throw new Error(`Unexpected worker response: ${s.type}`);return new ImageData(new Uint8ClampedArray(s.buffer),s.width,s.height)}terminate(){this.rejectInit=null,this.shutdown(new Error("Worker terminated"));}fail(t){let r=this.rejectInit;this.rejectInit=null,this.shutdown(t),r?.(t);}clearInitTimer(){this.initTimer!==null&&clearTimeout(this.initTimer),this.initTimer=null;}shutdown(t){this.clearInitTimer(),this.worker?.terminate(),this.worker=null,this.readyPromise=null,this.ready=false;let r=[...this.pending.values()];this.pending.clear();for(let n of r)n.reject(t);}request(t,r){let n=this.worker;if(!n||!this.ready)return Promise.reject(new Error("CVWorkerClient not ready"));let o=t(this.nextId++),i=new Promise((s,a)=>this.pending.set(o.id,{resolve:s,reject:a}));return n.postMessage(o,r),i}};var D=1.585772508336421,O=125/88,St=1.503,Ct=.05,te=1.25,be=1.75,wt=.25;function ge(e){if(e.length!==4)throw new Error(`orderCorners expects 4 points, got ${e.length}`);let t=(e[0].x+e[1].x+e[2].x+e[3].x)/4,r=(e[0].y+e[1].y+e[2].y+e[3].y)/4,n=[...e].sort((i,s)=>Math.atan2(i.y-r,i.x-t)-Math.atan2(s.y-r,s.x-t)),o=0;for(let i=1;i<4;i++){let s=n[i],a=n[o];(s.x+s.y<a.x+a.y||s.x+s.y===a.x+a.y&&s.y<a.y)&&(o=i);}return [0,1,2,3].map(i=>n[(o+i)%4])}function H(e){let t=0;for(let r=0;r<e.length;r++){let n=e[r],o=e[(r+1)%e.length];t+=n.x*o.y-o.x*n.y;}return Math.abs(t)/2}function re(e){let[t,r,n,o]=e;return {top:Math.hypot(r.x-t.x,r.y-t.y),right:Math.hypot(n.x-r.x,n.y-r.y),bottom:Math.hypot(n.x-o.x,n.y-o.y),left:Math.hypot(o.x-t.x,o.y-t.y)}}function Rt(e){let t=[0,0,0,0];for(let r=0;r<4;r++){let n=e[(r+3)%4],o=e[r],i=e[(r+1)%4],s=n.x-o.x,a=n.y-o.y,l=i.x-o.x,c=i.y-o.y,d=Math.hypot(s,a),p=Math.hypot(l,c);if(d===0||p===0){t[r]=0;continue}let m=Math.min(1,Math.max(-1,(s*l+a*c)/(d*p)));t[r]=Math.acos(m)*180/Math.PI;}return t}function ne(e,t=70,r=110){let n=re(e);return n.top<=0||n.right<=0||n.bottom<=0||n.left<=0||!Tt(e)||H(e)<=0?false:Rt(e).every(o=>o>=t&&o<=r)}function Tt(e){let t=0;for(let r=0;r<4;r++){let n=e[r],o=e[(r+1)%4],i=e[(r+2)%4],s=(o.x-n.x)*(i.y-o.y)-(o.y-n.y)*(i.x-o.x);if(s===0)return false;let a=Math.sign(s);if(t===0)t=a;else if(a!==t)return false}return true}function j(e){let t=re(e),r=(t.top+t.bottom)/2,n=(t.left+t.right)/2,o=Math.min(r,n);return o<=0?0:Math.max(r,n)/o}function vt(e){if(!Number.isFinite(e))return 0;let t=Math.min(Math.abs(e-D),Math.abs(e-O));return Math.max(0,1-t/wt)}function Ue(e){return .5*e.areaRatio+.3*e.rectangularity+.2*vt(e.aspect)}function oe(e){let t=e>=St?D:O;return Math.abs(e-t)/t<=Ct?t===D?"INE":"PASSPORT_MX":"OTHER"}function xe(e){return e>=te&&e<=be}function Qe(e,t){return e==="INE"?D:e==="PASSPORT_MX"?O:t}var z=1024,Ne=1600;function qe(e,t,r,n,o=z){let i=Mt(Qe(n,j(r))),s=Math.max(1,Math.round(o/i)),a=re(r),l=a.top+a.bottom<a.left+a.right,c=n==="INE"||n==="PASSPORT_MX",d=l&&c?[r[3],r[0],r[1],r[2]]:r,p=!l||c,m=p?o:s,u=p?s:o,x=null,S=null,y=null,g=null,h=null,f=null;try{return x=e.matFromImageData(t),S=new e.Mat,y=e.matFromArray(4,1,e.CV_32FC2,[d[0].x,d[0].y,d[1].x,d[1].y,d[2].x,d[2].y,d[3].x,d[3].y]),g=e.matFromArray(4,1,e.CV_32FC2,[0,0,m,0,m,u,0,u]),h=e.getPerspectiveTransform(y,g),e.warpPerspective(x,S,h,new e.Size(m,u),e.INTER_LINEAR,e.BORDER_CONSTANT,new e.Scalar(0,0,0,255)),S.channels()!==4&&(f=new e.Mat,e.cvtColor(S,f,e.COLOR_BGR2RGBA)),Et(new Uint8ClampedArray((f??S).data),m,u)}finally{for(let v of [f,h,g,y,S,x])v?.delete();}}function Be(e,t,r,n,o=z){let i=t.getContext("2d",{willReadFrequently:true});if(!i)throw new Error("2D canvas context unavailable");let s=i.getImageData(0,0,t.width,t.height),a=qe(e,s,r,n,o),l=document.createElement("canvas");l.width=a.width,l.height=a.height;let c=l.getContext("2d");if(!c)throw new Error("2D canvas context unavailable (output)");return c.putImageData(a,0,0),l}async function kt(e,t,r,n,o=.92,i=z){let s=r?Be(e,t,r,n,i):t;return new Promise((a,l)=>{s.toBlob(c=>c?a(c):l(new Error("Canvas toBlob returned null")),"image/jpeg",o);})}function Mt(e){return Number.isFinite(e)?Math.min(be,Math.max(te,e)):te}function Et(e,t,r){return typeof globalThis.ImageData=="function"?new ImageData(e,t,r):{data:e,width:t,height:r,colorSpace:"srgb"}}var _={brightnessMin:.18,brightnessMax:.9,blurMin:60,glareMax:.04,fillMin:.25,glarePixel:248};function V(e,t,r){let n=new Int32Array(r*2);for(let o=0;o<r;o++){let i=o+.5,s=1/0,a=-1/0;for(let l=0;l<4;l++){let c=e[l],d=e[(l+1)%4],p=Math.min(c.y,d.y),m=Math.max(c.y,d.y);if(i<p||i>m||m===p)continue;let u=c.x+(i-c.y)*(d.x-c.x)/(d.y-c.y);u<s&&(s=u),u>a&&(a=u);}if(s===1/0){n[o*2]=0,n[o*2+1]=0;continue}n[o*2]=Math.max(0,Math.ceil(s-.5)),n[o*2+1]=Math.min(t,Math.floor(a+.5));}return n}function Se(e,t){let{data:r,width:n,height:o}=e,i=V(t,n,o),s=_.glarePixel,a=0,l=0,c=0,d=0,p=0,m=0;for(let f=0;f<o;f++){let v=i[f*2],k=i[f*2+1];if(v>=k)continue;let E=0,M=0;f>0&&f<o-1&&(E=Math.max(v,i[(f-1)*2],i[(f+1)*2])+1,M=Math.min(k,i[(f-1)*2+1],i[(f+1)*2+1])-1);let w=f*n;for(let T=v;T<k;T++){let A=w+T,F=r[A];if(a+=F,F>=s&&l++,c++,T>=E&&T<M){let C=4*F-r[A-n]-r[A+n]-r[A-1]-r[A+1];d+=C,p+=C*C,m++;}}}let u=c>0?a/c/255:0,x=c>0?l/c:0,S=m>0?Math.max(0,p/m-(d/m)**2):0,y=n*o,g=y>0?H(t)/y:0,h=u>=_.brightnessMin&&u<=_.brightnessMax&&S>=_.blurMin&&x<=_.glareMax&&g>=_.fillMin;return {brightness:u,blurScore:S,glareRatio:x,docFillRatio:g,ok:h}}function Xe(e){let{data:t}=e;if(t.length===0)return 0;let r=0;for(let n=0;n<t.length;n++)r+=t[n];return r/t.length/255}function Ce(e){if(!e.detected||!e.quality)return "no_document";let t=e.quality;return !Number.isFinite(t.docFillRatio)||t.docFillRatio<_.fillMin?"too_small":!Number.isFinite(t.brightness)||t.brightness<_.brightnessMin?"too_dark":!Number.isFinite(t.glareRatio)||t.glareRatio>_.glareMax||t.brightness>_.brightnessMax?"glare":!Number.isFinite(t.blurScore)||t.blurScore<_.blurMin?"blurry":e.stableFrames<e.stableFramesRequired?"hold_still":"ready"}var _t=_.brightnessMin;function We(e){return !e.torchSupported||e.torchOn?false:(e.quality?e.quality.brightness:e.frameBrightness)<_t}var we=Object.freeze({idle:"Toca para activar la c\xE1mara",starting:"Abriendo la c\xE1mara\u2026",loading_detector:"Preparando la c\xE1mara\u2026",no_document:"Coloca tu identificaci\xF3n dentro del recuadro",too_small:"Acerca m\xE1s tu identificaci\xF3n",too_dark:"Hay poca luz, busca un lugar m\xE1s iluminado",glare:"Hay un reflejo, inclina un poco tu identificaci\xF3n",blurry:"Espera a que la c\xE1mara enfoque",hold_still:"No te muevas\u2026",ready:"\xA1Perfecto! No te muevas",capturing:"Tomando la foto\u2026",uploading:"Revisando tu identificaci\xF3n\u2026",done:"\xA1Listo!",error:"Algo sali\xF3 mal, int\xE9ntalo de nuevo",detector_unavailable:"Toma la foto con el bot\xF3n blanco",retake:"Tomar otra vez",capture:"Tomar foto",tip_light:"Busca un lugar con buena luz",tip_glare:"Evita reflejos: no apuntes una l\xE1mpara directo a tu identificaci\xF3n",tip_focus:"Espera a que la c\xE1mara enfoque; la foto se toma sola",tips_dismiss:"Entendido"}),At=Object.freeze({idle:"Ready to start",starting:"Starting camera\u2026",loading_detector:"Loading detector\u2026",no_document:"Place the document inside the frame",too_small:"Move closer to the document",too_dark:"Find more light",glare:"Tilt the document to avoid glare",blurry:"Hold still to focus",hold_still:"Hold still\u2026",ready:"Ready \u2014 hold still",capturing:"Capturing\u2026",uploading:"Processing document\u2026",done:"Done",error:"Something went wrong \u2014 try again",detector_unavailable:"Detector unavailable \u2014 capture manually",retake:"Capture again",capture:"Capture now",tip_light:"Find a well-lit place",tip_glare:"Avoid glare: don't point a lamp straight at your ID",tip_focus:"Wait for the camera to focus; the photo is taken automatically",tips_dismiss:"Got it"}),Ft=["loading_detector","capturing","uploading","done","error"];function Pt(e){return Ft.includes(e)}function G(e,t){return t?.[e]??we[e]}function Re(e){let t={...we};for(let r of Object.keys(t))t[r]=G(r,e);return t}function ae(e,t,r){return e==="idle"||e==="stopped"?G("idle",r):e==="starting"?G("starting",r):Pt(e)?G(e,r):G(t??"no_document",r)}var Dt=.05;function It(e,t,r){let n=r.width/t.width,o=r.height/t.height;return e.map(i=>({x:i.x*n,y:i.y*o}))}function Ot(e,t){return e.map(r=>({x:Math.min(t.width,Math.max(0,r.x)),y:Math.min(t.height,Math.max(0,r.y))}))}function je(e,t,r){let n=Ot(It(e,t,r),r);return !ne(n)||H(n)<Dt*r.width*r.height?null:n}var ze={stableFrames:0,isStable:false,quad:null,typeHint:null},Y=class{required;maxRatio;switchFrames;current=ze;candidate=null;constructor(t={}){this.required=t.stableFramesRequired??10,this.maxRatio=t.maxDisplacementRatio??.015,this.switchFrames=Math.max(1,t.hintSwitchFrames??3);}get snapshot(){return this.current}reset(){this.current=ze,this.candidate=null;}update(t,r){if(!t)return this.reset(),this.current;let n=Math.hypot(r.width,r.height)*this.maxRatio,o=this.current,i=o.quad!==null&&o.quad.every((l,c)=>Math.hypot(t.quad[c].x-l.x,t.quad[c].y-l.y)<=n),s=o.typeHint??t.typeHint,a=i?o.stableFrames+1:1;if(t.typeHint===s)this.candidate=null;else {let l=this.candidate?.typeHint===t.typeHint?this.candidate.frames+1:1;this.candidate={typeHint:t.typeHint,frames:l},l>=this.switchFrames&&(s=t.typeHint,a=1,this.candidate=null);}return this.current={stableFrames:a,isStable:a>=this.required,quad:t.quad,typeHint:s},this.current}};var Lt=640,Ut=10,Ve=1500,Qt=35e3,Nt=5,qt={createWorkerClient:e=>new W(e),attachCamera:e=>ue(e),detachCamera:de,sampleFrame:me,grabFrame:Ae,encodeJpeg:Fe,snapshotToBlob:pe,supportsTorch:he,setTorch:ye,now:()=>performance.now()},Ge=e=>e.provenance==="reduced"||e.provenance==="lowres",Ye=e=>e instanceof Error?e:new Error(String(e)),$e=e=>e.map(t=>({x:t.x,y:t.y})),$=class{opts;deps;stream=null;track=null;cv=null;generation=0;timer=null;frameCallback=null;inFlight=null;warmupUntil=0;capturing=false;autoShutterSpent=false;torchSupported=false;torchOn=false;torchRejected=false;weakRun=false;prior=null;stability;state={status:"idle",lastFrame:null,lastResult:null,lastError:null};constructor(t,r={}){this.opts={videoElement:t.videoElement,documentTypes:t.documentTypes??["INE","PASSPORT_MX"],autoCapture:t.autoCapture??true,stableFramesRequired:t.stableFramesRequired??10,captureQuality:t.captureQuality??.92,captureResolution:t.captureResolution??"standard",opencvUrl:t.opencvUrl,workerUrl:t.workerUrl,onUpload:t.onUpload,onFrameAnalyzed:t.onFrameAnalyzed,onCaptured:t.onCaptured,onResult:t.onResult,onError:t.onError},this.deps={...qt,...r},this.stability=new Y({stableFramesRequired:this.opts.stableFramesRequired});}async start(){if(!["idle","stopped","error"].includes(this.state.status))throw new Error(`Cannot start session from status=${this.state.status}`);this.release();let t=++this.generation;this.setStatus("starting"),this.state.lastError=null;try{let r=await this.deps.attachCamera(this.opts.videoElement);if(t!==this.generation){this.deps.detachCamera(this.opts.videoElement,r);return}this.stream=r,this.track=r.getVideoTracks()[0]??null,this.torchSupported=this.track?this.deps.supportsTorch(this.track):!1,this.warmupUntil=0,this.setStatus("loading_detector");let n=this.deps.createWorkerClient({initTimeoutMs:Qt});this.cv=n,n.init(this.opts.opencvUrl,this.opts.workerUrl).then(()=>{t!==this.generation||this.cv!==n||(this.state.status==="loading_detector"&&this.setStatus("streaming"),this.scheduleNext(t,0));},o=>this.detectorUnavailable(t,n,o));}catch(r){throw t===this.generation&&this.emitError(r),r}}stop(){this.generation++,this.release(),this.setStatus("stopped");}async captureNow(){if(this.capturing)return;let t=this.state.status;if(t!=="streaming"&&t!=="loading_detector"&&!(t==="done"&&this.stream))throw new Error(`Cannot capture from status=${this.state.status}`);let r=this.stability.snapshot,n=this.state.lastFrame?.frameSize??null,o=r.quad&&n?this.fullFrameQuad(r.quad,n):null;await this.doCapture(this.generation,o?r.typeHint:null,o);}getState(){return {...this.state}}scheduleNext(t,r){this.timer=setTimeout(()=>{if(this.timer=null,t!==this.generation)return;let n=this.opts.videoElement;typeof n.requestVideoFrameCallback=="function"?this.frameCallback=n.requestVideoFrameCallback(()=>{this.frameCallback=null,this.tick(t);}):this.tick(t);},r);}async tick(t){if(t!==this.generation)return;let r=this.deps.now();try{await this.analyzeFrame(t);}catch(n){t===this.generation&&console.warn("[xid-camera-ocr] analyzeFrame error:",n);}t!==this.generation||!this.cv||this.scheduleNext(t,Math.max(0,1e3/Ut-(this.deps.now()-r)));}async analyzeFrame(t){let r=this.cv;if(this.capturing||!r?.isReady())return;let n=this.deps.sampleFrame(this.opts.videoElement,Lt);if(!n)return;let o={width:n.width,height:n.height};this.warmupUntil===0&&(this.warmupUntil=this.deps.now()+Ve);let i=this.prior&&this.prior.width===n.width&&this.prior.height===n.height?this.prior.quad:null,s=r.analyze(n,i?{prior:i}:{});this.inFlight=s;let a;try{a=await s;}catch(u){if(t===this.generation&&this.cv===r&&!r.isReady()){this.detectorUnavailable(t,r,u);return}throw u}finally{this.inFlight===s&&(this.inFlight=null);}if(t!==this.generation||this.capturing)return;this.prior=a.detected&&a.corners?{quad:$e(a.corners),...o}:null;let c=!(this.deps.now()<this.warmupUntil)&&a.detected&&a.corners&&a.documentType?{quad:a.corners,typeHint:a.documentType}:null,d=this.stability.update(c,o);this.weakRun=d.stableFrames<=1?c!==null&&Ge(a):this.weakRun||Ge(a);let p=this.opts.stableFramesRequired+(this.weakRun?Nt:0);if(await this.updateTorch(t,a),t!==this.generation)return;let m={detected:a.detected,documentType:a.documentType,confidence:Math.min(d.stableFrames/p,1),aspectRatio:a.aspectRatio,quality:a.quality,corners:a.corners?$e(a.corners):null,frameSize:o,hint:Ce({detected:a.detected,quality:a.quality,stableFrames:d.stableFrames,stableFramesRequired:p}),...this.torchSupported?{torch:this.torchOn}:{}};if(this.state.lastFrame=m,this.opts.onFrameAnalyzed?.(m),t===this.generation&&this.opts.autoCapture&&!this.autoShutterSpent&&d.quad&&d.stableFrames>=p&&a.quality?.ok){let u=this.fullFrameQuad(d.quad,o);if(!u){this.stability.reset(),this.weakRun=false;return}await this.doCapture(t,d.typeHint,u);}}detectorUnavailable(t,r,n){if(t!==this.generation||this.cv!==r)return;r.terminate(),this.cv=null,this.inFlight=null,this.prior=null,this.stability.reset(),this.weakRun=false,this.autoShutterSpent=true,this.state.status==="loading_detector"&&this.setStatus("streaming");let o=Ye(n);this.state.lastError=o;let i={detected:false,documentType:null,confidence:0,aspectRatio:null,quality:null,corners:null,frameSize:null,hint:"detector_unavailable",...this.torchSupported?{torch:this.torchOn}:{}};this.state.lastFrame=i,this.opts.onFrameAnalyzed?.(i),t===this.generation&&this.opts.onError?.(o);}async updateTorch(t,r){if(!this.track||this.torchRejected||!We({torchSupported:this.torchSupported,torchOn:this.torchOn,quality:r.quality,frameBrightness:r.frameBrightness}))return;let n=await this.deps.setTorch(this.track,true);t===this.generation&&(this.torchOn=n,n||(this.torchRejected=true));}fullFrameQuad(t,r){let n=this.opts.videoElement;return !n.videoWidth||!n.videoHeight?null:je(t,r,{width:n.videoWidth,height:n.videoHeight})}async doCapture(t,r,n){if(!this.capturing){this.capturing=true,this.autoShutterSpent=true,this.prior=null,this.stability.reset(),this.weakRun=false,this.setStatus("capturing");try{let{blob:o,type:i}=await this.captureBlob(t,r,n);if(t!==this.generation)return;this.opts.onCaptured?.(o,i),this.setStatus("uploading");let s=await this.opts.onUpload(o,i);if(t!==this.generation)return;this.state.lastResult=s,this.setStatus("done"),this.opts.onResult?.(s);}catch(o){t===this.generation&&this.emitError(o);}finally{t===this.generation&&(this.stability.reset(),this.weakRun=false,this.warmupUntil=this.deps.now()+Ve,this.capturing=false);}}}async captureBlob(t,r,n){let o=this.opts.videoElement,i=async()=>({blob:await this.deps.snapshotToBlob(o,this.opts.captureQuality),type:null}),s=this.cv;if(!s?.isReady()||!n)return i();try{await this.inFlight?.catch(()=>{});let a=this.deps.grabFrame(o);if(!a||!s.isReady())return i();let l=this.opts.captureResolution==="high"?Ne:z,c=await s.warp(a,n,r,l);return {blob:await this.deps.encodeJpeg(c,this.opts.captureQuality),type:r}}catch(a){if(t!==this.generation)throw a;return console.warn("[xid-camera-ocr] warp failed, using plain snapshot:",a),i()}}release(){this.prior=null,this.timer!==null&&clearTimeout(this.timer),this.timer=null,this.frameCallback!==null&&(this.opts.videoElement.cancelVideoFrameCallback?.(this.frameCallback),this.frameCallback=null),this.track&&this.torchOn&&this.deps.setTorch(this.track,false),this.torchOn=false,this.torchRejected=false,this.stream&&this.deps.detachCamera(this.opts.videoElement,this.stream),this.stream=null,this.track=null,this.cv?.terminate(),this.cv=null,this.inFlight=null,this.stability.reset(),this.weakRun=false,this.capturing=false,this.autoShutterSpent=false;}setStatus(t){this.state.status=t;}emitError(t){let r=Ye(t);this.state.lastError=r,this.setStatus("error"),this.opts.onError?.(r);}};var Ke=.08,Bt=.95,Xt=.02,N=8,Wt=2,Je=8,Ze=.33,ie=2,jt=2,zt=1,Vt=jt+ie,Gt=2,Yt=2*(ie+1),$t=10,et=1.1,ot=ie+1,Kt=6,at=.92,Jt=1/at,Zt=.85,er=2,tr=.05,tt=2,rt=64;function it(e){return {detected:false,documentType:null,aspectRatio:null,corners:null,boundingBox:null,quality:null,frameBrightness:e,score:null}}function rr(e,t,r,n={}){let o={brightness:0};try{return nr(e,t,o,n.prior??null)}catch(i){return console.warn("[xid-camera-ocr] detectDocumentCV failed:",i),it(o.brightness)}}function nr(e,t,r,n){let{width:o,height:i}=t,s=[],a=l=>(s.push(l),l);try{let l=a(e.matFromImageData(t)),c=a(new e.Mat),d=a(new e.Mat),p={equalized:a(new e.Mat),filtered:a(new e.Mat),padded:a(new e.Mat),edges:a(new e.Mat),dilated:a(new e.Mat),kernel:a(e.Mat.ones(3,3,e.CV_8U)),contours:a(new e.MatVector),hierarchy:a(new e.Mat),hull:a(new e.Mat),approx:a(new e.Mat),clahe:a(new e.CLAHE(Wt,new e.Size(Je,Je)))};e.cvtColor(l,c,e.COLOR_RGBA2GRAY),r.brightness=Xe(Te(c,o,i));let m=[],u=nt(e,c,p,o,i,m,n),x=!1,S=Math.round(o/tt),y=Math.round(i/tt);if(!u&&S>=rt&&y>=rt&&(e.resize(c,d,new e.Size(S,y),0,0,e.INTER_AREA),u=nt(e,d,p,o,i,m,n),x=u!==null),u&&cr(u,m,Te(c,o,i))&&(u=null),!u)return it(r.brightness);let g=x?"lowres":u.reduced?"reduced":"direct",h=u.quad.map(w=>w.x),f=u.quad.map(w=>w.y),v=Math.min(...h),k=Math.max(...h),E=Math.min(...f),M=Math.max(...f);return {detected:!0,documentType:oe(u.aspect),aspectRatio:u.aspect,corners:u.quad,boundingBox:{x:v/o,y:E/i,width:(k-v)/o,height:(M-E)/i},quality:Se(Te(c,o,i),ct(u.quad,ot*u.scale)),frameBrightness:r.brightness,score:g==="direct"?u.score:u.score*Zt,provenance:g}}finally{for(let l of s)l.delete();}}function nt(e,t,r,n,o,i,s){let a=t.cols,l=t.rows,c=n/a,d=o/l,p=a*l,m=h=>({x:h.x*c,y:h.y*d}),{hull:u,approx:x,contours:S}=r;r.clahe.apply(t,r.equalized),e.bilateralFilter(r.equalized,r.filtered,9,75,75,e.BORDER_DEFAULT),e.copyMakeBorder(r.filtered,r.padded,N,N,N,N,e.BORDER_CONSTANT,new e.Scalar(0));let y=mr(r.padded.data);e.Canny(r.padded,r.edges,Math.max(10,(1-Ze)*y),Math.min(255,(1+Ze)*y)),e.dilate(r.edges,r.dilated,r.kernel,new e.Point(-1,-1),ie),e.findContours(r.dilated,S,r.hierarchy,e.RETR_LIST,e.CHAIN_APPROX_SIMPLE);let g=null;for(let h=0;h<S.size();h++){let f=S.get(h);try{let v=e.boundingRect(f);if(v.width*v.height<p*Ke)continue;e.convexHull(f,u,!1,!0);let k=e.contourArea(u);if(k<p*Ke||k>p*Bt||(e.approxPolyDP(u,x,Xt*e.arcLength(u,!0),!0),x.rows<4||x.rows>Kt||!e.isContourConvex(x)))continue;let E=x.rows!==4,M;if(!E)M=ar(x,a,l);else {let X=ir(st(x));if(!X)continue;M=X.map(U=>lt(U,a,l));let L=k/H(M);if(!(L>=at&&L<=Jt))continue}let w=k*c*d,T=M.map(m),A=Vt*c;if(pr(T,n,o,A)>zt){lr(T,n,o,A)||i.push({pts:T,area:w});continue}let F=ge(T);if(!ne(F))continue;let C=e.minAreaRect(E?u:x),I=C.size.width*C.size.height,Z=I>0?Math.min(1,k/I):0,q=j(F);if(!xe(q))continue;let B=Ue({areaRatio:k/p,rectangularity:Z,aspect:q}),ee=s?B-or(F,s,n,o):B;(!g||ee>g.rank)&&(g={quad:F,score:B,rank:ee,aspect:q,area:w,scale:c,reduced:E});}finally{f.delete();}}return g}function or(e,t,r,n){let o=1/0;for(let i=0;i<4;i++){let s=0;for(let a=0;a<4;a++){let l=e[(a+i)%4];s=Math.max(s,Math.hypot(l.x-t[a].x,l.y-t[a].y));}o=Math.min(o,s);}return er*Math.min(o/Math.hypot(r,n),tr)}function Te(e,t,r){return {data:e.data,width:t,height:r}}function st(e){let t=e.data32S,r=[];for(let n=0;n<e.rows;n++)r.push({x:t[n*2]-N,y:t[n*2+1]-N});return r}function lt(e,t,r){return {x:Math.min(t,Math.max(0,e.x)),y:Math.min(r,Math.max(0,e.y))}}function ar(e,t,r){return st(e).map(n=>lt(n,t,r))}function ir(e){let t=e;for(;t.length>4;){let r=t.length,n=-1,o=1/0,i=null;for(let a=0;a<r;a++){let l=t[(a+r-1)%r],c=t[a],d=t[(a+1)%r],p=t[(a+2)%r],m=sr(l,c,p,d);if(!m)continue;let u=Math.abs((m.x-c.x)*(d.y-c.y)-(m.y-c.y)*(d.x-c.x))/2;u<o&&(o=u,n=a,i=m);}if(n<0||!i)return null;let s=[];for(let a=0;a<r;a++)a===n?s.push(i):a!==(n+1)%r&&s.push(t[a]);t=s;}return t}function sr(e,t,r,n){let o=t.x-e.x,i=t.y-e.y,s=n.x-r.x,a=n.y-r.y,l=o*a-i*s;if(Math.abs(l)<1e-9)return null;let c=((r.x-e.x)*a-(r.y-e.y)*s)/l,d=((r.x-e.x)*i-(r.y-e.y)*o)/l;return c<1||d<1?null:{x:e.x+c*o,y:e.y+c*i}}function lr(e,t,r,n){let o=e.map(s=>s.x),i=e.map(s=>s.y);return Math.min(...o)<=n&&Math.max(...o)>=t-n||Math.min(...i)<=n&&Math.max(...i)>=r-n}function cr(e,t,r){let n=Yt*e.scale;if(!t.some(a=>a.area>=Gt*e.area&&e.quad.every(l=>dr(a.pts,l,n))))return false;if(oe(e.aspect)==="OTHER")return true;let{inner:i,ring:s}=ur(r,ct(e.quad,ot*e.scale),e.quad);return i<s-$t}function ur(e,t,r){let{data:n,width:o,height:i}=e,s=(r[0].x+r[1].x+r[2].x+r[3].x)/4,a=(r[0].y+r[1].y+r[2].y+r[3].y)/4,l=r.map(y=>({x:s+(y.x-s)*et,y:a+(y.y-a)*et})),c=V(l,o,i),d=V(r,o,i),p=V(t,o,i),m=0,u=0,x=0,S=0;for(let y=0;y<i;y++){let g=c[y*2],h=c[y*2+1];if(g>=h)continue;let f=d[y*2],v=d[y*2+1],k=p[y*2],E=p[y*2+1],M=y*o;for(let w=g;w<h;w++){let T=n[M+w];w>=k&&w<E?(m+=T,u++):(w<f||w>=v)&&(x+=T,S++);}}return {inner:u>0?m/u:0,ring:S>0?x/S:0}}function dr(e,t,r){let n=0;for(let i=0;i<e.length;i++){let s=e[i],a=e[(i+1)%e.length];n+=s.x*a.y-a.x*s.y;}let o=Math.sign(n);if(o===0)return false;for(let i=0;i<e.length;i++){let s=e[i],a=e[(i+1)%e.length],l=Math.hypot(a.x-s.x,a.y-s.y);if(l===0)continue;if(o*((a.x-s.x)*(t.y-s.y)-(a.y-s.y)*(t.x-s.x))/l<r)return false}return true}function ct(e,t){return e.map((r,n)=>{let o=e[(n+3)%4],i=e[(n+1)%4],s=o.x-r.x,a=o.y-r.y,l=i.x-r.x,c=i.y-r.y,d=Math.hypot(s,a),p=Math.hypot(l,c),m=s/d+l/p,u=a/d+c/p,x=Math.hypot(m,u),S=Math.sin(Math.acos(Math.min(1,Math.max(-1,(s*l+a*c)/(d*p))))/2),y=t/S/x;return {x:r.x+m*y,y:r.y+u*y}})}function pr(e,t,r,n){let o=0;for(let i of e)(i.x<=n||i.x>=t-n||i.y<=n||i.y>=r-n)&&o++;return o}function mr(e){let t=new Uint32Array(256);for(let n=0;n<e.length;n++)t[e[n]]++;let r=0;for(let n=0;n<256;n++)if(r+=t[n],r>=e.length/2)return n;return 128}function ke(e){let t=useRef(null),r=useRef(null),[n,o]=useState("idle"),[i,s]=useState(null),[a,l]=useState(null),[c,d]=useState(null),p=useRef(e);p.current=e;let m=useCallback(()=>{if(r.current)return r.current;if(!t.current)throw new Error("videoRef not attached yet");let g=new $({videoElement:t.current,documentTypes:p.current.documentTypes,autoCapture:p.current.autoCapture,stableFramesRequired:p.current.stableFramesRequired,captureQuality:p.current.captureQuality,captureResolution:p.current.captureResolution,opencvUrl:p.current.opencvUrl,workerUrl:p.current.workerUrl,onUpload:(h,f)=>p.current.onUpload(h,f),onFrameAnalyzed:h=>{s(h),r.current===g&&o(g.getState().status),p.current.onFrameAnalyzed?.(h);},onCaptured:(h,f)=>{o("capturing"),p.current.onCaptured?.(h,f);},onResult:h=>{l(h),o("done"),p.current.onResult?.(h);},onError:h=>{d(h),r.current===g&&o(g.getState().status),p.current.onError?.(h);}});return r.current=g,g},[]),u=useCallback(async()=>{let g=m();await g.start(),r.current===g&&o(g.getState().status);},[m]),x=useCallback(()=>{r.current?.stop(),o("stopped");},[]),S=useCallback(async()=>{await r.current?.captureNow();},[]),y=useCallback(async()=>{x(),l(null),d(null),s(null),await u();},[x,u]);return useEffect(()=>(e.autoStart!==false&&t.current&&u().catch(()=>{}),()=>{r.current?.stop(),r.current=null;}),[]),{videoRef:t,status:n,frame:i,result:a,error:c,start:u,stop:x,captureNow:S,retake:y}}function fr({status:e,showTips:t,dismissed:r,completedOnce:n}){return t&&!r&&(e==="error"||!n&&(e==="starting"||e==="loading_detector"))}function ut(e,t){let[r,n]=useState(false),[o,i]=useState(e==="done"),[s,a]=useState(e),l=r,c=o;s!==e&&(a(e),e==="error"&&(l=false,n(false)),e==="done"&&(c=true,i(true)));let d=useCallback(()=>n(true),[]);return {visible:fr({status:e,showTips:t,dismissed:l,completedOnce:c}),dismiss:d}}var le={accent:{name:"--xco-accent",fallback:"#22c55e"},warning:{name:"--xco-warning",fallback:"#eab308"},danger:{name:"--xco-danger",fallback:"#ef4444"},background:{name:"--xco-background",fallback:"#000"},mask:{name:"--xco-mask",fallback:"rgba(0,0,0,0.4)"},hintBg:{name:"--xco-hint-bg",fallback:"rgba(0,0,0,0.7)"},hintFg:{name:"--xco-hint-fg",fallback:"white"},buttonBg:{name:"--xco-button-bg",fallback:"rgba(255,255,255,0.92)"},buttonFg:{name:"--xco-button-fg",fallback:"#111"},shutter:{name:"--xco-shutter",fallback:"rgba(255,255,255,0.9)"},overlayBg:{name:"--xco-overlay-bg",fallback:"rgba(0,0,0,0.78)"},overlayFg:{name:"--xco-overlay-fg",fallback:"white"},fontFamily:{name:"--xco-font-family",fallback:"system-ui, -apple-system, sans-serif"},radius:{name:"--xco-radius",fallback:"12px"}};function b(e){let{name:t,fallback:r}=le[e];return `var(${t}, ${r})`}function dt(e){let t={};if(!e)return t;for(let r of Object.keys(e)){if(!Object.prototype.hasOwnProperty.call(le,r))continue;let n=e[r];typeof n!="string"||n===""||(t[le[r].name]=n);}return t}function pt(e,t){return e==="done"?b("accent"):e==="error"?b("danger"):e==="uploading"||e==="capturing"?b("accent"):t?.detected?t.confidence>=1?b("accent"):b("warning"):b("danger")}var Ee={width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",focusable:"false",style:{flex:"0 0 auto"}},br=()=>jsxs("svg",{...Ee,children:[jsx("circle",{cx:"12",cy:"12",r:"4"}),jsx("path",{d:"M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"})]}),gr=()=>jsxs("svg",{...Ee,children:[jsx("rect",{x:"3",y:"5",width:"18",height:"14",rx:"2"}),jsx("path",{d:"M14 5l-6 14M18 5l-6 14"})]}),xr=()=>jsxs("svg",{...Ee,children:[jsx("path",{d:"M4 8V5a1 1 0 0 1 1-1h3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3"}),jsx("circle",{cx:"12",cy:"12",r:"2"})]});function mt({texts:e,onDismiss:t}){let r=[{Icon:br,text:e.tip_light},{Icon:gr,text:e.tip_glare},{Icon:xr,text:e.tip_focus}];return jsxs("div",{className:"xco-tips",style:Sr,children:[jsx("ul",{style:Cr,children:r.map(({Icon:n,text:o})=>jsxs("li",{style:wr,children:[jsx(n,{}),jsx("span",{children:o})]},o))}),jsx("button",{type:"button",className:"xco-tips-dismiss",onClick:t,style:Rr,children:e.tips_dismiss})]})}var Sr={position:"absolute",top:"calc(16px + env(safe-area-inset-top, 0px))",left:"50%",transform:"translateX(-50%)",boxSizing:"border-box",width:"calc(100% - 32px)",maxWidth:360,padding:16,background:b("overlayBg"),color:b("overlayFg"),borderRadius:b("radius"),fontFamily:b("fontFamily"),fontSize:15,lineHeight:1.35,display:"flex",flexDirection:"column",gap:12,pointerEvents:"auto",zIndex:5},Cr={listStyle:"none",margin:0,padding:0,display:"flex",flexDirection:"column",gap:10},wr={display:"flex",alignItems:"center",gap:12},Rr={alignSelf:"flex-end",minHeight:44,padding:"10px 20px",borderRadius:b("radius"),background:b("buttonBg"),color:b("buttonFg"),border:"none",fontFamily:b("fontFamily"),fontSize:15,fontWeight:600,cursor:"pointer",WebkitTapHighlightColor:"transparent"};var _r=typeof window>"u"?useEffect:useLayoutEffect;function ht({videoRef:e,status:t,frame:r,texts:n,documentTypes:o,theme:i,className:s,style:a,hideStatusOverlay:l,tipsVisible:c,onCapture:d,onRetake:p,onStart:m,onDismissTips:u}){let x=t==="streaming"||t==="loading_detector",S=t==="done"||t==="error",y=t==="idle"||t==="stopped",g=t==="capturing"||t==="uploading",h="xco-doc-mask-"+useId().replace(/[^A-Za-z0-9_-]/g,""),f=useRef(null),[v,k]=useState({width:0,height:0}),E=r?.documentType,M=E==="PASSPORT_MX"?O:E==="INE"?D:o[0]==="PASSPORT_MX"?O:D;_r(()=>{let C=f.current;if(!C)return;let I=()=>{let q=C.clientWidth,B=C.clientHeight,ee=q*.85,X=B*.7,L=ee,U=L/M;U>X&&(U=X,L=U*M),k({width:L,height:U});};I();let Z=new ResizeObserver(I);return Z.observe(C),()=>Z.disconnect()},[M]);let w=!!(r?.corners&&r?.frameSize),T=pt(t,r),A=ae(t,r?.hint,n),F=s?`xid-camera-ocr ${s}`:"xid-camera-ocr";return jsxs("div",{ref:f,className:F,"data-status":t,"data-hint":r?.hint??"",style:{...Ar,...dt(i),...a},children:[jsx("style",{children:"@keyframes xco-spin { to { transform: rotate(360deg); } }"}),jsx("video",{ref:e,playsInline:true,muted:true,autoPlay:true,style:Fr}),!l&&!w&&jsx("div",{style:Dr,children:jsx("div",{className:"xco-guide",style:{...Ir,width:v.width,height:v.height,borderColor:T}})}),!l&&w&&r&&r.corners&&r.frameSize&&jsxs("svg",{style:Pr,viewBox:`0 0 ${r.frameSize.width} ${r.frameSize.height}`,preserveAspectRatio:"xMidYMid slice",children:[jsx("defs",{children:jsxs("mask",{id:h,children:[jsx("rect",{x:"0",y:"0",width:r.frameSize.width,height:r.frameSize.height,fill:"white"}),jsx("polygon",{points:r.corners.map(C=>`${C.x},${C.y}`).join(" "),fill:"black"})]})}),jsx("rect",{x:"0",y:"0",width:r.frameSize.width,height:r.frameSize.height,style:{fill:b("mask")},mask:`url(#${h})`}),jsx("polygon",{points:r.corners.map(C=>`${C.x},${C.y}`).join(" "),style:{fill:"none",stroke:T},strokeWidth:Math.max(2,r.frameSize.width*.006),strokeLinejoin:"round"}),r.corners.map((C,I)=>jsx("circle",{cx:C.x,cy:C.y,r:Math.max(4,r.frameSize.width*.012),style:{fill:T}},I))]}),!l&&(y?jsx("button",{type:"button",className:"xco-hint",onClick:m,style:qr,children:A}):jsx("p",{className:"xco-hint",style:ft,role:"status","aria-live":"polite",children:A})),!l&&x&&jsx("button",{type:"button",className:"xco-shutter",onClick:d,"aria-label":n.capture,style:Ur,children:jsx("span",{style:Qr})}),!l&&S&&jsx("button",{type:"button",className:"xco-retake",onClick:p,"aria-label":n.retake,style:Nr,children:n.retake}),!l&&g&&jsxs("div",{className:"xco-loader",style:Or,"aria-busy":"true","aria-live":"polite",children:[jsx("div",{style:Hr}),jsx("p",{style:Lr,children:ae(t,void 0,n)})]}),c&&!l&&jsx(mt,{texts:n,onDismiss:u})]})}var yt="calc(104px + env(safe-area-inset-bottom, 0px))",Ar={position:"relative",width:"100%",height:"100%",overflow:"hidden",background:b("background"),fontFamily:b("fontFamily"),touchAction:"none"},Fr={position:"absolute",inset:0,width:"100%",height:"100%",objectFit:"cover",display:"block"},Pr={position:"absolute",inset:0,width:"100%",height:"100%",pointerEvents:"none"},Dr={position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",pointerEvents:"none"},Ir={borderRadius:b("radius"),borderWidth:4,borderStyle:"solid",boxShadow:`0 0 0 9999px ${b("mask")}`,transition:"border-color 200ms ease-in-out, width 200ms ease-in-out, height 200ms ease-in-out"},Or={position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:20,background:b("overlayBg"),backdropFilter:"blur(6px)",WebkitBackdropFilter:"blur(6px)",pointerEvents:"auto",zIndex:10},Hr={width:56,height:56,borderRadius:"50%",border:"5px solid rgba(255, 255, 255, 0.18)",borderTopColor:b("accent"),animation:"xco-spin 0.85s linear infinite"},Lr={color:b("overlayFg"),fontFamily:b("fontFamily"),fontSize:15,fontWeight:500,margin:0,textAlign:"center",padding:"0 24px"},Ur={position:"absolute",bottom:yt,left:"50%",transform:"translateX(-50%)",width:68,height:68,borderRadius:"50%",background:"rgba(255,255,255,0.18)",border:`4px solid ${b("shutter")}`,cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"auto",WebkitTapHighlightColor:"transparent",padding:0},Qr={width:52,height:52,borderRadius:"50%",background:"white",display:"block"},Nr={position:"absolute",bottom:yt,left:"50%",transform:"translateX(-50%)",minHeight:44,padding:"10px 20px",borderRadius:22,background:b("buttonBg"),color:b("buttonFg"),border:"none",fontFamily:b("fontFamily"),fontSize:15,fontWeight:600,cursor:"pointer",pointerEvents:"auto",WebkitTapHighlightColor:"transparent"},ft={position:"absolute",bottom:"calc(16px + env(safe-area-inset-bottom, 0px))",left:"50%",transform:"translateX(-50%)",boxSizing:"border-box",width:"max-content",maxWidth:"calc(100% - 32px)",background:b("hintBg"),color:b("hintFg"),padding:"10px 16px",borderRadius:b("radius"),fontFamily:b("fontFamily"),fontSize:16,lineHeight:1.35,margin:0,whiteSpace:"normal",textAlign:"center"},qr={...ft,border:"none",minHeight:44,cursor:"pointer",pointerEvents:"auto",WebkitTapHighlightColor:"transparent"};var Xr=["INE","PASSPORT_MX"],_e=()=>{};function Wr({className:e,style:t,hideStatusOverlay:r,texts:n,theme:o,showTips:i,...s}){let{videoRef:a,status:l,frame:c,start:d,captureNow:p,retake:m}=ke(s),u=ut(l,i??true),x=useMemo(()=>Re(n),[n]),S=l==="streaming"||l==="loading_detector",y=l==="done"||l==="error",g=()=>{S&&p().catch(_e);},h=()=>{y&&m().catch(_e);},f=()=>{d().catch(_e);};return jsx(ht,{videoRef:a,status:l,frame:c,texts:x,documentTypes:s.documentTypes??Xr,theme:o,className:e,style:t,hideStatusOverlay:r,tipsVisible:u.visible,onCapture:g,onRetake:h,onStart:f,onDismissTips:u.dismiss})}export{W as CVWorkerClient,At as DEFAULT_TEXTS_EN,we as DEFAULT_TEXTS_ES,D as ID1_RATIO,_ as QUALITY_THRESHOLDS,Y as StabilityTracker,O as TD3_RATIO,le as XCO_VARS,Wr as XidCameraOcr,$ as XidCameraOcrSession,ue as attachCamera,ae as copyFor,Ce as decideHint,fe as defaultOpencvUrl,de as detachCamera,rr as detectDocumentCV,xe as isCapturableAspect,Se as measureQuality,ge as orderCorners,j as rectifiedAspect,Re as resolveTexts,me as sampleFrame,ye as setTorch,pe as snapshotToBlob,he as supportsTorch,oe as typeHintFromAspect,ke as useXidCameraOcr,Be as warpDocument,qe as warpDocumentImageData,kt as warpedSnapshotToBlob};//# sourceMappingURL=index.js.map
|
|
1
|
+
import {forwardRef,useMemo,useImperativeHandle,useRef,useEffect,useState,useCallback,useLayoutEffect}from'react';import {jsx,jsxs}from'react/jsx-runtime';function Rt(e=typeof window>"u"?void 0:window){return e?typeof e.matchMedia=="function"?e.matchMedia("(orientation: portrait)").matches?"portrait":"landscape":e.innerHeight>e.innerWidth?"portrait":"landscape":"landscape"}function Tt(e){return {audio:false,video:{facingMode:{ideal:"environment"},...e==="portrait"?{width:{ideal:1080},height:{ideal:1920},aspectRatio:{ideal:9/16}}:{width:{ideal:1920,min:640},height:{ideal:1080,min:480},aspectRatio:{ideal:16/9}}}}}async function ae(e,t,r=Rt()){let n=Tt(r);if(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia)throw new Error("Camera unavailable: getUserMedia requires a secure context (HTTPS or localhost) and a browser with MediaDevices support.");let o;try{o=await navigator.mediaDevices.getUserMedia(t??n);}catch(s){if(!t)o=await navigator.mediaDevices.getUserMedia({audio:false,video:true});else throw s}e.srcObject=o,e.muted=true,e.playsInline=true,e.autoplay=true;let a=o.getVideoTracks()[0],i=a.getCapabilities?.();return i&&"focusMode"in i&&i.focusMode?.includes("continuous")&&a.applyConstraints({advanced:[{focusMode:"continuous"}]}).catch(()=>{}),await e.play().catch(()=>{}),o}function ie(e,t){e.srcObject===t&&(e.srcObject=null),t?.getTracks().forEach(r=>r.stop());}async function se(e,t=.92){let r=e.videoWidth,n=e.videoHeight;if(!r||!n)throw new Error("Video stream not ready (videoWidth=0)");let o=document.createElement("canvas");o.width=r,o.height=n;let a=o.getContext("2d");if(!a)throw new Error("2D canvas context unavailable");return a.drawImage(e,0,0,r,n),new Promise((i,s)=>{o.toBlob(u=>u?i(u):s(new Error("Canvas toBlob returned null")),"image/jpeg",t);})}function Ae(e,t,r,n=.92){let o=document.createElement("canvas");o.width=r.width,o.height=r.height;let a=o.getContext("2d");return a?(a.imageSmoothingEnabled=true,a.imageSmoothingQuality="high",a.drawImage(e,t.x,t.y,t.width,t.height,0,0,r.width,r.height),new Promise((i,s)=>o.toBlob(u=>u?i(u):s(new Error("Canvas toBlob returned null")),"image/jpeg",n))):Promise.reject(new Error("2D canvas context unavailable"))}var H=null;function ue(e,t=640){let r=e.videoWidth,n=e.videoHeight;if(!r||!n)return null;let o=Math.round(t),a=Math.round(n*t/r);H??=document.createElement("canvas"),(H.width!==o||H.height!==a)&&(H.width=o,H.height=a);let i=H.getContext("2d",{willReadFrequently:true});return i?(i.drawImage(e,0,0,o,a),i.getImageData(0,0,o,a)):null}function ce(e){let t=e.getCapabilities;return typeof t!="function"?false:t.call(e).torch===true}async function le(e,t){try{return await e.applyConstraints({advanced:[{torch:t}]}),!0}catch{return false}}var Mt="@andresxid/xid_camera_ocr_sdk_react";function Pe(e,t){return e.pathname.endsWith(`/${Mt}/${t}`)}function Fe(e){return new URL(e,import.meta.url)}function Oe(){return new URL("@andresxid/xid_camera_ocr_sdk_react/opencv.js",import.meta.url)}function de(){let e=Oe();return Pe(e,"opencv.js")?Fe("./opencv.js").href:e.href}function De(e){return e!==void 0?new Worker(e,{type:"module"}):Pe(Oe(),"opencv.js")?new Worker(Fe("./cv-worker.js"),{type:"module"}):new Worker(new URL("@andresxid/xid_camera_ocr_sdk_react/cv-worker.js",import.meta.url),{type:"module"})}function Ie(e){if(!e||typeof e!="object")return null;let t=e;switch(t.type){case "ready":return {type:"ready"};case "init-error":return typeof t.error=="string"?{type:"init-error",error:t.error}:null;case "error":return typeof t.id=="number"&&typeof t.error=="string"?{type:"error",id:t.id,error:t.error}:null;case "analyze-result":return typeof t.id=="number"&&t.result&&typeof t.result=="object"?{type:"analyze-result",id:t.id,result:t.result}:null;case "warp-result":return typeof t.id=="number"&&typeof t.width=="number"&&typeof t.height=="number"&&t.buffer instanceof ArrayBuffer?{type:"warp-result",id:t.id,width:t.width,height:t.height,buffer:t.buffer}:null;default:return null}}function He(e){let t=new Uint8ClampedArray(e.data.byteLength);return t.set(e.data),t.buffer}var Et=e=>e instanceof Error?e:new Error(String(e)),B=class{initTimeoutMs;worker=null;readyPromise=null;rejectInit=null;initTimer=null;ready=false;pending=new Map;nextId=1;constructor(t={}){this.initTimeoutMs=t.initTimeoutMs??3e4;}init(t=de(),r){if(this.readyPromise)return this.readyPromise;let n;try{n=De(r);}catch(a){return Promise.reject(Et(a))}this.worker=n;let o=new Promise((a,i)=>{this.rejectInit=i,this.initTimer=setTimeout(()=>this.fail(new Error(`OpenCV worker not ready within ${this.initTimeoutMs} ms`)),this.initTimeoutMs),n.addEventListener("message",s=>{if(this.worker!==n)return;let u=Ie(s.data);if(!u)return;if(u.type==="ready"){this.clearInitTimer(),this.rejectInit=null,this.ready=true,a();return}if(u.type==="init-error"){this.fail(new Error(u.error));return}let c=this.pending.get(u.id);c&&(this.pending.delete(u.id),u.type==="error"?c.reject(new Error(u.error)):c.resolve(u));}),n.addEventListener("error",s=>{this.worker===n&&this.fail(new Error(s.message||"Worker error"));}),n.addEventListener("messageerror",s=>{if(this.worker!==n)return;let u=new Error("Worker message could not be deserialized"),c=s.data?.id,d=typeof c=="number"?this.pending.get(c):void 0;if(typeof c=="number"&&d){this.pending.delete(c),d.reject(u);return}this.fail(u);});});return this.readyPromise=o,n.postMessage({type:"init",opencvUrl:t}),o}isReady(){return this.ready&&this.worker!==null}async analyze(t,r={}){let n=He(t),o=r.prior,a=await this.request(i=>({type:"analyze",id:i,width:t.width,height:t.height,buffer:n,...o?{prior:o}:{}}),[n]);if(a.type!=="analyze-result")throw new Error(`Unexpected worker response: ${a.type}`);return a.result}async warp(t,r,n,o=1024){let a=He(t),i=await this.request(s=>({type:"warp",id:s,width:t.width,height:t.height,buffer:a,corners:r,docType:n,longSide:o}),[a]);if(i.type!=="warp-result")throw new Error(`Unexpected worker response: ${i.type}`);return new ImageData(new Uint8ClampedArray(i.buffer),i.width,i.height)}terminate(){this.rejectInit=null,this.shutdown(new Error("Worker terminated"));}fail(t){let r=this.rejectInit;this.rejectInit=null,this.shutdown(t),r?.(t);}clearInitTimer(){this.initTimer!==null&&clearTimeout(this.initTimer),this.initTimer=null;}shutdown(t){this.clearInitTimer(),this.worker?.terminate(),this.worker=null,this.readyPromise=null,this.ready=false;let r=[...this.pending.values()];this.pending.clear();for(let n of r)n.reject(t);}request(t,r){let n=this.worker;if(!n||!this.ready)return Promise.reject(new Error("CVWorkerClient not ready"));let o=t(this.nextId++),a=new Promise((i,s)=>this.pending.set(o.id,{resolve:i,reject:s}));return n.postMessage(o,r),a}};var O=1.585772508336421,L=125/88,kt=1.503,_t=.05,Y=1.25,pe=1.75,At=.25;function me(e){if(e.length!==4)throw new Error(`orderCorners expects 4 points, got ${e.length}`);let t=(e[0].x+e[1].x+e[2].x+e[3].x)/4,r=(e[0].y+e[1].y+e[2].y+e[3].y)/4,n=[...e].sort((a,i)=>Math.atan2(a.y-r,a.x-t)-Math.atan2(i.y-r,i.x-t)),o=0;for(let a=1;a<4;a++){let i=n[a],s=n[o];(i.x+i.y<s.x+s.y||i.x+i.y===s.x+s.y&&i.y<s.y)&&(o=a);}return [0,1,2,3].map(a=>n[(o+a)%4])}function D(e){let t=0;for(let r=0;r<e.length;r++){let n=e[r],o=e[(r+1)%e.length];t+=n.x*o.y-o.x*n.y;}return Math.abs(t)/2}function K(e){let[t,r,n,o]=e;return {top:Math.hypot(r.x-t.x,r.y-t.y),right:Math.hypot(n.x-r.x,n.y-r.y),bottom:Math.hypot(n.x-o.x,n.y-o.y),left:Math.hypot(o.x-t.x,o.y-t.y)}}function Pt(e){let t=[0,0,0,0];for(let r=0;r<4;r++){let n=e[(r+3)%4],o=e[r],a=e[(r+1)%4],i=n.x-o.x,s=n.y-o.y,u=a.x-o.x,c=a.y-o.y,d=Math.hypot(i,s),p=Math.hypot(u,c);if(d===0||p===0){t[r]=0;continue}let m=Math.min(1,Math.max(-1,(i*u+s*c)/(d*p)));t[r]=Math.acos(m)*180/Math.PI;}return t}function $(e,t=70,r=110){let n=K(e);return n.top<=0||n.right<=0||n.bottom<=0||n.left<=0||!Ft(e)||D(e)<=0?false:Pt(e).every(o=>o>=t&&o<=r)}function Ft(e){let t=0;for(let r=0;r<4;r++){let n=e[r],o=e[(r+1)%4],a=e[(r+2)%4],i=(o.x-n.x)*(a.y-o.y)-(o.y-n.y)*(a.x-o.x);if(i===0)return false;let s=Math.sign(i);if(t===0)t=s;else if(s!==t)return false}return true}function Q(e){let t=K(e),r=(t.top+t.bottom)/2,n=(t.left+t.right)/2,o=Math.min(r,n);return o<=0?0:Math.max(r,n)/o}function Ot(e){if(!Number.isFinite(e))return 0;let t=Math.min(Math.abs(e-O),Math.abs(e-L));return Math.max(0,1-t/At)}function Le(e){return .5*e.areaRatio+.3*e.rectangularity+.2*Ot(e.aspect)}function Z(e){let t=e>=kt?O:L;return Math.abs(e-t)/t<=_t?t===O?"INE":"PASSPORT_MX":"OTHER"}function he(e){return e>=Y&&e<=pe}function Ue(e,t){return e==="INE"?O:e==="PASSPORT_MX"?L:t}var X=1024,Be=1600;function Qe(e,t,r,n,o=X){let a=It(Ue(n,Q(r))),i=Math.max(1,Math.round(o/a)),s=K(r),u=s.top+s.bottom<s.left+s.right,c=n==="INE"||n==="PASSPORT_MX",d=u&&c?[r[3],r[0],r[1],r[2]]:r,p=!u||c,m=p?o:i,l=p?i:o,x=null,S=null,y=null,b=null,h=null,f=null;try{return x=e.matFromImageData(t),S=new e.Mat,y=e.matFromArray(4,1,e.CV_32FC2,[d[0].x,d[0].y,d[1].x,d[1].y,d[2].x,d[2].y,d[3].x,d[3].y]),b=e.matFromArray(4,1,e.CV_32FC2,[0,0,m,0,m,l,0,l]),h=e.getPerspectiveTransform(y,b),e.warpPerspective(x,S,h,new e.Size(m,l),e.INTER_LINEAR,e.BORDER_CONSTANT,new e.Scalar(0,0,0,255)),S.channels()!==4&&(f=new e.Mat,e.cvtColor(S,f,e.COLOR_BGR2RGBA)),Ht(new Uint8ClampedArray((f??S).data),m,l)}finally{for(let R of [f,h,b,y,S,x])R?.delete();}}function Xe(e,t,r,n,o=X){let a=t.getContext("2d",{willReadFrequently:true});if(!a)throw new Error("2D canvas context unavailable");let i=a.getImageData(0,0,t.width,t.height),s=Qe(e,i,r,n,o),u=document.createElement("canvas");u.width=s.width,u.height=s.height;let c=u.getContext("2d");if(!c)throw new Error("2D canvas context unavailable (output)");return c.putImageData(s,0,0),u}async function Dt(e,t,r,n,o=.92,a=X){let i=r?Xe(e,t,r,n,a):t;return new Promise((s,u)=>{i.toBlob(c=>c?s(c):u(new Error("Canvas toBlob returned null")),"image/jpeg",o);})}function It(e){return Number.isFinite(e)?Math.min(pe,Math.max(Y,e)):Y}function Ht(e,t,r){return typeof globalThis.ImageData=="function"?new ImageData(e,t,r):{data:e,width:t,height:r,colorSpace:"srgb"}}var Lt=.85,Ut=.7;function I(e){return e?.[0]==="PASSPORT_MX"?L:O}function q(e,t){let r=e.width*Lt,n=e.height*Ut,o=r,a=o/t;return a>n&&(a=n,o=a*t),{width:o,height:a}}var qe=e=>Number.isFinite(e)&&e>0,ye=e=>qe(e.width)&&qe(e.height);function Ne(e,t,r){if(!ye(e)||!ye(t)||!ye(r))return null;let n=Math.max(t.width/e.width,t.height/e.height),o=(t.width-e.width*n)/2,a=(t.height-e.height*n)/2,i=Math.round(((t.width-r.width)/2-o)/n),s=Math.round(((t.height-r.height)/2-a)/n),u=i+Math.round(r.width/n),c=s+Math.round(r.height/n),d=Math.max(0,i),p=Math.max(0,s),m=Math.min(e.width,u),l=Math.min(e.height,c);return m<=d||l<=p?null:{x:d,y:p,width:m-d,height:l-p}}function We(e,t){let r=Math.max(e.width,e.height);if(r<=t)return {width:e.width,height:e.height};let n=t/r;return {width:Math.max(1,Math.round(e.width*n)),height:Math.max(1,Math.round(e.height*n))}}var E={brightnessMin:.18,brightnessMax:.9,blurMin:60,glareMax:.04,fillMin:.25,glarePixel:248};function N(e,t,r){let n=new Int32Array(r*2);for(let o=0;o<r;o++){let a=o+.5,i=1/0,s=-1/0;for(let u=0;u<4;u++){let c=e[u],d=e[(u+1)%4],p=Math.min(c.y,d.y),m=Math.max(c.y,d.y);if(a<p||a>m||m===p)continue;let l=c.x+(a-c.y)*(d.x-c.x)/(d.y-c.y);l<i&&(i=l),l>s&&(s=l);}if(i===1/0){n[o*2]=0,n[o*2+1]=0;continue}n[o*2]=Math.max(0,Math.ceil(i-.5)),n[o*2+1]=Math.min(t,Math.floor(s+.5));}return n}function fe(e,t){let{data:r,width:n,height:o}=e,a=N(t,n,o),i=E.glarePixel,s=0,u=0,c=0,d=0,p=0,m=0;for(let f=0;f<o;f++){let R=a[f*2],C=a[f*2+1];if(R>=C)continue;let T=0,M=0;f>0&&f<o-1&&(T=Math.max(R,a[(f-1)*2],a[(f+1)*2])+1,M=Math.min(C,a[(f-1)*2+1],a[(f+1)*2+1])-1);let w=f*n;for(let v=R;v<C;v++){let k=w+v,A=r[k];if(s+=A,A>=i&&u++,c++,v>=T&&v<M){let F=4*A-r[k-n]-r[k+n]-r[k-1]-r[k+1];d+=F,p+=F*F,m++;}}}let l=c>0?s/c/255:0,x=c>0?u/c:0,S=m>0?Math.max(0,p/m-(d/m)**2):0,y=n*o,b=y>0?D(t)/y:0,h=l>=E.brightnessMin&&l<=E.brightnessMax&&S>=E.blurMin&&x<=E.glareMax&&b>=E.fillMin;return {brightness:l,blurScore:S,glareRatio:x,docFillRatio:b,ok:h}}function je(e){let{data:t}=e;if(t.length===0)return 0;let r=0;for(let n=0;n<t.length;n++)r+=t[n];return r/t.length/255}function be(e){if(!e.detected||!e.quality)return "no_document";let t=e.quality;return !Number.isFinite(t.docFillRatio)||t.docFillRatio<E.fillMin?"too_small":!Number.isFinite(t.brightness)||t.brightness<E.brightnessMin?"too_dark":!Number.isFinite(t.glareRatio)||t.glareRatio>E.glareMax||t.brightness>E.brightnessMax?"glare":!Number.isFinite(t.blurScore)||t.blurScore<E.blurMin?"blurry":e.stableFrames<e.stableFramesRequired?"hold_still":"ready"}var Bt=E.brightnessMin;function ze(e){return !e.torchSupported||e.torchOn?false:(e.quality?e.quality.brightness:e.frameBrightness)<Bt}var ge=Object.freeze({idle:"Toca para activar la c\xE1mara",starting:"Abriendo la c\xE1mara\u2026",loading_detector:"Preparando la c\xE1mara\u2026",no_document:"Coloca tu identificaci\xF3n dentro del recuadro",too_small:"Acerca m\xE1s tu identificaci\xF3n",too_dark:"Hay poca luz, busca un lugar m\xE1s iluminado",glare:"Hay un reflejo, inclina un poco tu identificaci\xF3n",blurry:"Espera a que la c\xE1mara enfoque",hold_still:"Mant\xE9n la c\xE1mara quieta",ready:"\xA1Perfecto! Toma la foto",capturing:"Tomando la foto\u2026",uploading:"Revisando tu identificaci\xF3n\u2026",done:"\xA1Listo!",error:"Algo sali\xF3 mal, int\xE9ntalo de nuevo",detector_unavailable:"Toma la foto con el bot\xF3n",retake:"Tomar otra vez",capture:"Tomar foto",tip_light:"Busca un lugar con buena luz",tip_glare:"Evita reflejos: no apuntes una l\xE1mpara directo a tu identificaci\xF3n",tip_focus:"Espera a que la c\xE1mara enfoque y luego toca el bot\xF3n",tips_dismiss:"Entendido"}),Qt=Object.freeze({idle:"Ready to start",starting:"Starting camera\u2026",loading_detector:"Loading detector\u2026",no_document:"Place the document inside the frame",too_small:"Move closer to the document",too_dark:"Find more light",glare:"Tilt the document to avoid glare",blurry:"Hold still to focus",hold_still:"Hold the camera steady",ready:"Perfect! Take the photo",capturing:"Capturing\u2026",uploading:"Processing document\u2026",done:"Done",error:"Something went wrong \u2014 try again",detector_unavailable:"Detector unavailable \u2014 capture manually",retake:"Capture again",capture:"Capture now",tip_light:"Find a well-lit place",tip_glare:"Avoid glare: don't point a lamp straight at your ID",tip_focus:"Wait for the camera to focus, then tap the button",tips_dismiss:"Got it"}),Xt=["loading_detector","capturing","uploading","done","error"];function qt(e){return Xt.includes(e)}function W(e,t){return t?.[e]??ge[e]}function xe(e){let t={...ge};for(let r of Object.keys(t))t[r]=W(r,e);return t}function J(e,t,r){return e==="idle"||e==="stopped"?W("idle",r):e==="starting"?W("starting",r):qt(e)?W(e,r):W(t??"no_document",r)}var Nt=.05;function Wt(e,t,r){let n=r.width/t.width,o=r.height/t.height;return e.map(a=>({x:a.x*n,y:a.y*o}))}function jt(e,t){return e.map(r=>({x:Math.min(t.width,Math.max(0,r.x)),y:Math.min(t.height,Math.max(0,r.y))}))}function Ve(e,t,r){let n=jt(Wt(e,t,r),r);return !$(n)||D(n)<Nt*r.width*r.height?null:n}var Ge={stableFrames:0,isStable:false,quad:null,typeHint:null},j=class{required;maxRatio;switchFrames;current=Ge;candidate=null;constructor(t={}){this.required=t.stableFramesRequired??10,this.maxRatio=t.maxDisplacementRatio??.015,this.switchFrames=Math.max(1,t.hintSwitchFrames??3);}get snapshot(){return this.current}reset(){this.current=Ge,this.candidate=null;}update(t,r){if(!t)return this.reset(),this.current;let n=Math.hypot(r.width,r.height)*this.maxRatio,o=this.current,a=o.quad!==null&&o.quad.every((u,c)=>Math.hypot(t.quad[c].x-u.x,t.quad[c].y-u.y)<=n),i=o.typeHint??t.typeHint,s=a?o.stableFrames+1:1;if(t.typeHint===i)this.candidate=null;else {let u=this.candidate?.typeHint===t.typeHint?this.candidate.frames+1:1;this.candidate={typeHint:t.typeHint,frames:u},u>=this.switchFrames&&(i=t.typeHint,s=1,this.candidate=null);}return this.current={stableFrames:s,isStable:s>=this.required,quad:t.quad,typeHint:i},this.current}};var Vt=640,Gt=10,Ye=1500,Yt=35e3,Kt=5,$t={createWorkerClient:e=>new B(e),attachCamera:e=>ae(e),detachCamera:ie,sampleFrame:ue,cropFrame:Ae,snapshotToBlob:se,supportsTorch:ce,setTorch:le,now:()=>performance.now()},Ke=e=>e.provenance==="reduced"||e.provenance==="lowres",$e=e=>e instanceof Error?e:new Error(String(e)),Ze=e=>e.map(t=>({x:t.x,y:t.y})),z=class{opts;deps;stream=null;track=null;cv=null;generation=0;timer=null;frameCallback=null;warmupUntil=0;capturing=false;autoShutterSpent=false;torchSupported=false;torchOn=false;torchRejected=false;weakRun=false;prior=null;stability;state={status:"idle",lastFrame:null,lastResult:null,lastError:null};constructor(t,r={}){this.opts={videoElement:t.videoElement,documentTypes:t.documentTypes??["INE","PASSPORT_MX"],cropToGuide:t.cropToGuide??false,guideRatio:t.guideRatio,autoCapture:t.autoCapture??false,stableFramesRequired:t.stableFramesRequired??10,captureQuality:t.captureQuality??.92,captureResolution:t.captureResolution??"standard",opencvUrl:t.opencvUrl,workerUrl:t.workerUrl,onUpload:t.onUpload,onFrameAnalyzed:t.onFrameAnalyzed,onCaptured:t.onCaptured,onResult:t.onResult,onError:t.onError},this.deps={...$t,...r},this.stability=new j({stableFramesRequired:this.opts.stableFramesRequired});}async start(){if(!["idle","stopped","error"].includes(this.state.status))throw new Error(`Cannot start session from status=${this.state.status}`);this.release();let t=++this.generation;this.setStatus("starting"),this.state.lastError=null;try{let r=await this.deps.attachCamera(this.opts.videoElement);if(t!==this.generation){this.deps.detachCamera(this.opts.videoElement,r);return}this.stream=r,this.track=r.getVideoTracks()[0]??null,this.torchSupported=this.track?this.deps.supportsTorch(this.track):!1,this.warmupUntil=0,this.setStatus("loading_detector");let n=this.deps.createWorkerClient({initTimeoutMs:Yt});this.cv=n,n.init(this.opts.opencvUrl,this.opts.workerUrl).then(()=>{t!==this.generation||this.cv!==n||(this.state.status==="loading_detector"&&this.setStatus("streaming"),this.scheduleNext(t,0));},o=>this.detectorUnavailable(t,n,o));}catch(r){throw t===this.generation&&this.emitError(r),r}}stop(){this.generation++,this.release(),this.setStatus("stopped");}async captureNow(){if(this.capturing)return;let t=this.state.status;if(t!=="streaming"&&t!=="loading_detector"&&!(t==="done"&&this.stream))throw new Error(`Cannot capture from status=${this.state.status}`);let r=this.stability.snapshot,n=this.state.lastFrame?.frameSize??null,o=r.quad&&n?this.fullFrameQuad(r.quad,n):null;await this.doCapture(this.generation,o?r.typeHint:null);}getState(){return {...this.state}}scheduleNext(t,r){this.timer=setTimeout(()=>{if(this.timer=null,t!==this.generation)return;let n=this.opts.videoElement;typeof n.requestVideoFrameCallback=="function"?this.frameCallback=n.requestVideoFrameCallback(()=>{this.frameCallback=null,this.tick(t);}):this.tick(t);},r);}async tick(t){if(t!==this.generation)return;let r=this.deps.now();try{await this.analyzeFrame(t);}catch(n){t===this.generation&&console.warn("[xid-camera-ocr] analyzeFrame error:",n);}t!==this.generation||!this.cv||this.scheduleNext(t,Math.max(0,1e3/Gt-(this.deps.now()-r)));}async analyzeFrame(t){let r=this.cv;if(this.capturing||!r?.isReady())return;let n=this.deps.sampleFrame(this.opts.videoElement,Vt);if(!n)return;let o={width:n.width,height:n.height};this.warmupUntil===0&&(this.warmupUntil=this.deps.now()+Ye);let a=this.prior&&this.prior.width===n.width&&this.prior.height===n.height?this.prior.quad:null,i;try{i=await r.analyze(n,a?{prior:a}:{});}catch(m){if(t===this.generation&&this.cv===r&&!r.isReady()){this.detectorUnavailable(t,r,m);return}throw m}if(t!==this.generation||this.capturing)return;this.prior=i.detected&&i.corners?{quad:Ze(i.corners),...o}:null;let u=!(this.deps.now()<this.warmupUntil)&&i.detected&&i.corners&&i.documentType?{quad:i.corners,typeHint:i.documentType}:null,c=this.stability.update(u,o);this.weakRun=c.stableFrames<=1?u!==null&&Ke(i):this.weakRun||Ke(i);let d=this.opts.stableFramesRequired+(this.weakRun?Kt:0);if(await this.updateTorch(t,i),t!==this.generation)return;let p={detected:i.detected,documentType:i.documentType,confidence:Math.min(c.stableFrames/d,1),aspectRatio:i.aspectRatio,quality:i.quality,corners:i.corners?Ze(i.corners):null,frameSize:o,hint:be({detected:i.detected,quality:i.quality,stableFrames:c.stableFrames,stableFramesRequired:d}),...this.torchSupported?{torch:this.torchOn}:{}};if(this.state.lastFrame=p,this.opts.onFrameAnalyzed?.(p),t===this.generation&&this.opts.autoCapture&&!this.autoShutterSpent&&c.quad&&c.stableFrames>=d&&i.quality?.ok){if(!this.fullFrameQuad(c.quad,o)){this.stability.reset(),this.weakRun=false;return}await this.doCapture(t,c.typeHint);}}detectorUnavailable(t,r,n){if(t!==this.generation||this.cv!==r)return;r.terminate(),this.cv=null,this.prior=null,this.stability.reset(),this.weakRun=false,this.autoShutterSpent=true,this.state.status==="loading_detector"&&this.setStatus("streaming");let o=$e(n);this.state.lastError=o;let a={detected:false,documentType:null,confidence:0,aspectRatio:null,quality:null,corners:null,frameSize:null,hint:"detector_unavailable",...this.torchSupported?{torch:this.torchOn}:{}};this.state.lastFrame=a,this.opts.onFrameAnalyzed?.(a),t===this.generation&&this.opts.onError?.(o);}async updateTorch(t,r){if(!this.track||this.torchRejected||!ze({torchSupported:this.torchSupported,torchOn:this.torchOn,quality:r.quality,frameBrightness:r.frameBrightness}))return;let n=await this.deps.setTorch(this.track,true);t===this.generation&&(this.torchOn=n,n||(this.torchRejected=true));}fullFrameQuad(t,r){let n=this.opts.videoElement;return !n.videoWidth||!n.videoHeight?null:Ve(t,r,{width:n.videoWidth,height:n.videoHeight})}async doCapture(t,r){if(!this.capturing){this.capturing=true,this.autoShutterSpent=true,this.prior=null,this.stability.reset(),this.weakRun=false,this.setStatus("capturing");try{let{blob:n,type:o}=await this.captureBlob(t,r);if(t!==this.generation)return;this.opts.onCaptured?.(n,o),this.setStatus("uploading");let a=await this.opts.onUpload(n,o);if(t!==this.generation)return;this.state.lastResult=a,this.setStatus("done"),this.opts.onResult?.(a);}catch(n){t===this.generation&&this.emitError(n);}finally{t===this.generation&&(this.stability.reset(),this.weakRun=false,this.warmupUntil=this.deps.now()+Ye,this.capturing=false);}}}async captureBlob(t,r){let n=this.opts.videoElement,o=async()=>({blob:await this.deps.snapshotToBlob(n,this.opts.captureQuality),type:null});if(!this.opts.cropToGuide)return {blob:await this.deps.snapshotToBlob(n,this.opts.captureQuality),type:r};let a={width:n.clientWidth,height:n.clientHeight},i=this.opts.guideRatio?.()??I(this.opts.documentTypes),s=Ne({width:n.videoWidth,height:n.videoHeight},a,q(a,i));if(!s)return o();try{let u=this.opts.captureResolution==="high"?Be:X;return {blob:await this.deps.cropFrame(n,s,We(s,u),this.opts.captureQuality),type:r}}catch(u){if(t!==this.generation)throw u;return console.warn("[xid-camera-ocr] guide crop failed, using plain snapshot:",u),o()}}release(){this.prior=null,this.timer!==null&&clearTimeout(this.timer),this.timer=null,this.frameCallback!==null&&(this.opts.videoElement.cancelVideoFrameCallback?.(this.frameCallback),this.frameCallback=null),this.track&&this.torchOn&&this.deps.setTorch(this.track,false),this.torchOn=false,this.torchRejected=false,this.stream&&this.deps.detachCamera(this.opts.videoElement,this.stream),this.stream=null,this.track=null,this.cv?.terminate(),this.cv=null,this.stability.reset(),this.weakRun=false,this.capturing=false,this.autoShutterSpent=false;}setStatus(t){this.state.status=t;}emitError(t){let r=$e(t);this.state.lastError=r,this.setStatus("error"),this.opts.onError?.(r);}};var Je=.08,Zt=.95,Jt=.02,U=8,er=2,et=8,tt=.33,ee=2,tr=2,rr=1,nr=tr+ee,or=2,ar=2*(ee+1),ir=10,rt=1.1,it=ee+1,sr=6,st=.92,ur=1/st,cr=.85,lr=2,dr=.05,nt=2,ot=64;function ut(e){return {detected:false,documentType:null,aspectRatio:null,corners:null,boundingBox:null,quality:null,frameBrightness:e,score:null}}function pr(e,t,r,n={}){let o={brightness:0};try{return mr(e,t,o,n.prior??null)}catch(a){return console.warn("[xid-camera-ocr] detectDocumentCV failed:",a),ut(o.brightness)}}function mr(e,t,r,n){let{width:o,height:a}=t,i=[],s=u=>(i.push(u),u);try{let u=s(e.matFromImageData(t)),c=s(new e.Mat),d=s(new e.Mat),p={equalized:s(new e.Mat),filtered:s(new e.Mat),padded:s(new e.Mat),edges:s(new e.Mat),dilated:s(new e.Mat),kernel:s(e.Mat.ones(3,3,e.CV_8U)),contours:s(new e.MatVector),hierarchy:s(new e.Mat),hull:s(new e.Mat),approx:s(new e.Mat),clahe:s(new e.CLAHE(er,new e.Size(et,et)))};e.cvtColor(u,c,e.COLOR_RGBA2GRAY),r.brightness=je(Se(c,o,a));let m=[],l=at(e,c,p,o,a,m,n),x=!1,S=Math.round(o/nt),y=Math.round(a/nt);if(!l&&S>=ot&&y>=ot&&(e.resize(c,d,new e.Size(S,y),0,0,e.INTER_AREA),l=at(e,d,p,o,a,m,n),x=l!==null),l&&xr(l,m,Se(c,o,a))&&(l=null),!l)return ut(r.brightness);let b=x?"lowres":l.reduced?"reduced":"direct",h=l.quad.map(w=>w.x),f=l.quad.map(w=>w.y),R=Math.min(...h),C=Math.max(...h),T=Math.min(...f),M=Math.max(...f);return {detected:!0,documentType:Z(l.aspect),aspectRatio:l.aspect,corners:l.quad,boundingBox:{x:R/o,y:T/a,width:(C-R)/o,height:(M-T)/a},quality:fe(Se(c,o,a),dt(l.quad,it*l.scale)),frameBrightness:r.brightness,score:b==="direct"?l.score:l.score*cr,provenance:b}}finally{for(let u of i)u.delete();}}function at(e,t,r,n,o,a,i){let s=t.cols,u=t.rows,c=n/s,d=o/u,p=s*u,m=h=>({x:h.x*c,y:h.y*d}),{hull:l,approx:x,contours:S}=r;r.clahe.apply(t,r.equalized),e.bilateralFilter(r.equalized,r.filtered,9,75,75,e.BORDER_DEFAULT),e.copyMakeBorder(r.filtered,r.padded,U,U,U,U,e.BORDER_CONSTANT,new e.Scalar(0));let y=Rr(r.padded.data);e.Canny(r.padded,r.edges,Math.max(10,(1-tt)*y),Math.min(255,(1+tt)*y)),e.dilate(r.edges,r.dilated,r.kernel,new e.Point(-1,-1),ee),e.findContours(r.dilated,S,r.hierarchy,e.RETR_LIST,e.CHAIN_APPROX_SIMPLE);let b=null;for(let h=0;h<S.size();h++){let f=S.get(h);try{let R=e.boundingRect(f);if(R.width*R.height<p*Je)continue;e.convexHull(f,l,!1,!0);let C=e.contourArea(l);if(C<p*Je||C>p*Zt||(e.approxPolyDP(l,x,Jt*e.arcLength(l,!0),!0),x.rows<4||x.rows>sr||!e.isContourConvex(x)))continue;let T=x.rows!==4,M;if(!T)M=yr(x,s,u);else {let ke=fr(ct(x));if(!ke)continue;M=ke.map(Ct=>lt(Ct,s,u));let _e=C/D(M);if(!(_e>=st&&_e<=ur))continue}let w=C*c*d,v=M.map(m),k=nr*c;if(Cr(v,n,o,k)>rr){gr(v,n,o,k)||a.push({pts:v,area:w});continue}let A=me(v);if(!$(A))continue;let F=e.minAreaRect(T?l:x),ve=F.size.width*F.size.height,wt=ve>0?Math.min(1,C/ve):0,ne=Q(A);if(!he(ne))continue;let oe=Le({areaRatio:C/p,rectangularity:wt,aspect:ne}),Ee=i?oe-hr(A,i,n,o):oe;(!b||Ee>b.rank)&&(b={quad:A,score:oe,rank:Ee,aspect:ne,area:w,scale:c,reduced:T});}finally{f.delete();}}return b}function hr(e,t,r,n){let o=1/0;for(let a=0;a<4;a++){let i=0;for(let s=0;s<4;s++){let u=e[(s+a)%4];i=Math.max(i,Math.hypot(u.x-t[s].x,u.y-t[s].y));}o=Math.min(o,i);}return lr*Math.min(o/Math.hypot(r,n),dr)}function Se(e,t,r){return {data:e.data,width:t,height:r}}function ct(e){let t=e.data32S,r=[];for(let n=0;n<e.rows;n++)r.push({x:t[n*2]-U,y:t[n*2+1]-U});return r}function lt(e,t,r){return {x:Math.min(t,Math.max(0,e.x)),y:Math.min(r,Math.max(0,e.y))}}function yr(e,t,r){return ct(e).map(n=>lt(n,t,r))}function fr(e){let t=e;for(;t.length>4;){let r=t.length,n=-1,o=1/0,a=null;for(let s=0;s<r;s++){let u=t[(s+r-1)%r],c=t[s],d=t[(s+1)%r],p=t[(s+2)%r],m=br(u,c,p,d);if(!m)continue;let l=Math.abs((m.x-c.x)*(d.y-c.y)-(m.y-c.y)*(d.x-c.x))/2;l<o&&(o=l,n=s,a=m);}if(n<0||!a)return null;let i=[];for(let s=0;s<r;s++)s===n?i.push(a):s!==(n+1)%r&&i.push(t[s]);t=i;}return t}function br(e,t,r,n){let o=t.x-e.x,a=t.y-e.y,i=n.x-r.x,s=n.y-r.y,u=o*s-a*i;if(Math.abs(u)<1e-9)return null;let c=((r.x-e.x)*s-(r.y-e.y)*i)/u,d=((r.x-e.x)*a-(r.y-e.y)*o)/u;return c<1||d<1?null:{x:e.x+c*o,y:e.y+c*a}}function gr(e,t,r,n){let o=e.map(i=>i.x),a=e.map(i=>i.y);return Math.min(...o)<=n&&Math.max(...o)>=t-n||Math.min(...a)<=n&&Math.max(...a)>=r-n}function xr(e,t,r){let n=ar*e.scale;if(!t.some(s=>s.area>=or*e.area&&e.quad.every(u=>wr(s.pts,u,n))))return false;if(Z(e.aspect)==="OTHER")return true;let{inner:a,ring:i}=Sr(r,dt(e.quad,it*e.scale),e.quad);return a<i-ir}function Sr(e,t,r){let{data:n,width:o,height:a}=e,i=(r[0].x+r[1].x+r[2].x+r[3].x)/4,s=(r[0].y+r[1].y+r[2].y+r[3].y)/4,u=r.map(y=>({x:i+(y.x-i)*rt,y:s+(y.y-s)*rt})),c=N(u,o,a),d=N(r,o,a),p=N(t,o,a),m=0,l=0,x=0,S=0;for(let y=0;y<a;y++){let b=c[y*2],h=c[y*2+1];if(b>=h)continue;let f=d[y*2],R=d[y*2+1],C=p[y*2],T=p[y*2+1],M=y*o;for(let w=b;w<h;w++){let v=n[M+w];w>=C&&w<T?(m+=v,l++):(w<f||w>=R)&&(x+=v,S++);}}return {inner:l>0?m/l:0,ring:S>0?x/S:0}}function wr(e,t,r){let n=0;for(let a=0;a<e.length;a++){let i=e[a],s=e[(a+1)%e.length];n+=i.x*s.y-s.x*i.y;}let o=Math.sign(n);if(o===0)return false;for(let a=0;a<e.length;a++){let i=e[a],s=e[(a+1)%e.length],u=Math.hypot(s.x-i.x,s.y-i.y);if(u===0)continue;if(o*((s.x-i.x)*(t.y-i.y)-(s.y-i.y)*(t.x-i.x))/u<r)return false}return true}function dt(e,t){return e.map((r,n)=>{let o=e[(n+3)%4],a=e[(n+1)%4],i=o.x-r.x,s=o.y-r.y,u=a.x-r.x,c=a.y-r.y,d=Math.hypot(i,s),p=Math.hypot(u,c),m=i/d+u/p,l=s/d+c/p,x=Math.hypot(m,l),S=Math.sin(Math.acos(Math.min(1,Math.max(-1,(i*u+s*c)/(d*p))))/2),y=t/S/x;return {x:r.x+m*y,y:r.y+l*y}})}function Cr(e,t,r,n){let o=0;for(let a of e)(a.x<=n||a.x>=t-n||a.y<=n||a.y>=r-n)&&o++;return o}function Rr(e){let t=new Uint32Array(256);for(let n=0;n<e.length;n++)t[e[n]]++;let r=0;for(let n=0;n<256;n++)if(r+=t[n],r>=e.length/2)return n;return 128}function Ce(e){let t=useRef(null),r=useRef(null),[n,o]=useState("idle"),[a,i]=useState(null),[s,u]=useState(null),[c,d]=useState(null),p=useRef(e);p.current=e;let m=useCallback(()=>{if(r.current)return r.current;if(!t.current)throw new Error("videoRef not attached yet");let b=new z({videoElement:t.current,documentTypes:p.current.documentTypes,cropToGuide:p.current.cropToGuide,guideRatio:()=>I(p.current.documentTypes),autoCapture:p.current.autoCapture,stableFramesRequired:p.current.stableFramesRequired,captureQuality:p.current.captureQuality,captureResolution:p.current.captureResolution,opencvUrl:p.current.opencvUrl,workerUrl:p.current.workerUrl,onUpload:(h,f)=>p.current.onUpload(h,f),onFrameAnalyzed:h=>{i(h),r.current===b&&o(b.getState().status),p.current.onFrameAnalyzed?.(h);},onCaptured:(h,f)=>{o("capturing"),p.current.onCaptured?.(h,f);},onResult:h=>{u(h),o("done"),p.current.onResult?.(h);},onError:h=>{d(h),r.current===b&&o(b.getState().status),p.current.onError?.(h);}});return r.current=b,b},[]),l=useCallback(async()=>{let b=m();await b.start(),r.current===b&&o(b.getState().status);},[m]),x=useCallback(()=>{r.current?.stop(),o("stopped");},[]),S=useCallback(async()=>{await r.current?.captureNow();},[]),y=useCallback(async()=>{x(),u(null),d(null),i(null),await l();},[x,l]);return useEffect(()=>(e.autoStart!==false&&t.current&&l().catch(()=>{}),()=>{r.current?.stop(),r.current=null;}),[]),{videoRef:t,status:n,frame:a,result:s,error:c,start:l,stop:x,captureNow:S,retake:y}}function vr({status:e,showTips:t,dismissed:r,completedOnce:n}){return t&&!r&&(e==="error"||!n&&(e==="starting"||e==="loading_detector"))}function pt(e,t){let[r,n]=useState(false),[o,a]=useState(e==="done"),[i,s]=useState(e),u=r,c=o;i!==e&&(s(e),e==="error"&&(u=false,n(false)),e==="done"&&(c=true,a(true)));let d=useCallback(()=>n(true),[]);return {visible:vr({status:e,showTips:t,dismissed:u,completedOnce:c}),dismiss:d}}var re={accent:{name:"--xco-accent",fallback:"#22c55e"},warning:{name:"--xco-warning",fallback:"#eab308"},danger:{name:"--xco-danger",fallback:"#ef4444"},background:{name:"--xco-background",fallback:"#000"},mask:{name:"--xco-mask",fallback:"rgba(0,0,0,0.4)"},hintBg:{name:"--xco-hint-bg",fallback:"rgba(0,0,0,0.7)"},hintFg:{name:"--xco-hint-fg",fallback:"white"},buttonBg:{name:"--xco-button-bg",fallback:"rgba(255,255,255,0.92)"},buttonFg:{name:"--xco-button-fg",fallback:"#111"},shutter:{name:"--xco-shutter",fallback:"rgba(255,255,255,0.9)"},overlayBg:{name:"--xco-overlay-bg",fallback:"rgba(0,0,0,0.78)"},overlayFg:{name:"--xco-overlay-fg",fallback:"white"},fontFamily:{name:"--xco-font-family",fallback:"system-ui, -apple-system, sans-serif"},radius:{name:"--xco-radius",fallback:"12px"}};function g(e){let{name:t,fallback:r}=re[e];return `var(${t}, ${r})`}function mt(e){let t={};if(!e)return t;for(let r of Object.keys(e)){if(!Object.prototype.hasOwnProperty.call(re,r))continue;let n=e[r];typeof n!="string"||n===""||(t[re[r].name]=n);}return t}function ht(e,t){return e==="done"?g("accent"):e==="error"?g("danger"):e==="uploading"||e==="capturing"?g("accent"):t?.detected?t.confidence>=1?g("accent"):g("warning"):g("danger")}var Te={width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",focusable:"false",style:{flex:"0 0 auto"}},Er=()=>jsxs("svg",{...Te,children:[jsx("circle",{cx:"12",cy:"12",r:"4"}),jsx("path",{d:"M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"})]}),kr=()=>jsxs("svg",{...Te,children:[jsx("rect",{x:"3",y:"5",width:"18",height:"14",rx:"2"}),jsx("path",{d:"M14 5l-6 14M18 5l-6 14"})]}),_r=()=>jsxs("svg",{...Te,children:[jsx("path",{d:"M4 8V5a1 1 0 0 1 1-1h3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3"}),jsx("circle",{cx:"12",cy:"12",r:"2"})]});function yt({texts:e,onDismiss:t}){let r=[{Icon:Er,text:e.tip_light},{Icon:kr,text:e.tip_glare},{Icon:_r,text:e.tip_focus}];return jsxs("div",{className:"xco-tips",style:Ar,children:[jsx("ul",{style:Pr,children:r.map(({Icon:n,text:o})=>jsxs("li",{style:Fr,children:[jsx(n,{}),jsx("span",{children:o})]},o))}),jsx("button",{type:"button",className:"xco-tips-dismiss",onClick:t,style:Or,children:e.tips_dismiss})]})}var Ar={position:"absolute",top:"calc(16px + env(safe-area-inset-top, 0px))",left:"50%",transform:"translateX(-50%)",boxSizing:"border-box",width:"calc(100% - 32px)",maxWidth:360,padding:16,background:g("overlayBg"),color:g("overlayFg"),borderRadius:g("radius"),fontFamily:g("fontFamily"),fontSize:15,lineHeight:1.35,display:"flex",flexDirection:"column",gap:12,pointerEvents:"auto",zIndex:5},Pr={listStyle:"none",margin:0,padding:0,display:"flex",flexDirection:"column",gap:10},Fr={display:"flex",alignItems:"center",gap:12},Or={alignSelf:"flex-end",minHeight:44,padding:"10px 20px",borderRadius:g("radius"),background:g("buttonBg"),color:g("buttonFg"),border:"none",fontFamily:g("fontFamily"),fontSize:15,fontWeight:600,cursor:"pointer",WebkitTapHighlightColor:"transparent"};var Ur=typeof window>"u"?useEffect:useLayoutEffect;function bt({videoRef:e,status:t,frame:r,texts:n,documentTypes:o,theme:a,className:i,style:s,hideStatusOverlay:u,hideShutter:c,tipsVisible:d,onCapture:p,onRetake:m,onStart:l,onDismissTips:x}){let S=t==="streaming"||t==="loading_detector",y=t==="done"||t==="error",b=t==="idle"||t==="stopped",h=t==="capturing"||t==="uploading",f=useRef(null),[R,C]=useState({width:0,height:0}),T=I(o);Ur(()=>{let k=f.current;if(!k)return;let A=()=>C(q({width:k.clientWidth,height:k.clientHeight},T));A();let F=new ResizeObserver(A);return F.observe(k),()=>F.disconnect()},[T]);let M=ht(t,r),w=J(t,r?.hint,n),v=i?`xid-camera-ocr ${i}`:"xid-camera-ocr";return jsxs("div",{ref:f,className:v,"data-status":t,"data-hint":r?.hint??"",style:{...Br,...mt(a),...s},children:[jsx("style",{children:"@keyframes xco-spin { to { transform: rotate(360deg); } }"}),jsx("video",{ref:e,playsInline:true,muted:true,autoPlay:true,style:Qr}),!u&&jsx("div",{style:Xr,children:jsx("div",{className:"xco-guide",style:{...qr,width:R.width,height:R.height,borderColor:M}})}),!u&&(b?jsx("button",{type:"button",className:"xco-hint",onClick:l,style:Yr,children:w}):jsx("p",{className:"xco-hint",style:xt,role:"status","aria-live":"polite",children:w})),!u&&!c&&S&&jsx("button",{type:"button",className:"xco-shutter",onClick:p,"aria-label":n.capture,style:zr,children:jsx("span",{style:Vr})}),!u&&y&&jsx("button",{type:"button",className:"xco-retake",onClick:m,"aria-label":n.retake,style:Gr,children:n.retake}),!u&&h&&jsxs("div",{className:"xco-loader",style:Nr,"aria-busy":"true","aria-live":"polite",children:[jsx("div",{style:Wr}),jsx("p",{style:jr,children:J(t,void 0,n)})]}),d&&!u&&jsx(yt,{texts:n,onDismiss:x})]})}var gt="calc(104px + env(safe-area-inset-bottom, 0px))",Br={position:"relative",width:"100%",height:"100%",overflow:"hidden",background:g("background"),fontFamily:g("fontFamily"),touchAction:"none"},Qr={position:"absolute",inset:0,width:"100%",height:"100%",objectFit:"cover",display:"block"},Xr={position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",pointerEvents:"none"},qr={borderRadius:g("radius"),boxSizing:"content-box",borderWidth:4,borderStyle:"solid",boxShadow:`0 0 0 9999px ${g("mask")}`,transition:"border-color 200ms ease-in-out"},Nr={position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:20,background:g("overlayBg"),backdropFilter:"blur(6px)",WebkitBackdropFilter:"blur(6px)",pointerEvents:"auto",zIndex:10},Wr={width:56,height:56,borderRadius:"50%",border:"5px solid rgba(255, 255, 255, 0.18)",borderTopColor:g("accent"),animation:"xco-spin 0.85s linear infinite"},jr={color:g("overlayFg"),fontFamily:g("fontFamily"),fontSize:15,fontWeight:500,margin:0,textAlign:"center",padding:"0 24px"},zr={position:"absolute",bottom:gt,left:"50%",transform:"translateX(-50%)",width:68,height:68,borderRadius:"50%",background:"rgba(255,255,255,0.18)",border:`4px solid ${g("shutter")}`,cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"auto",WebkitTapHighlightColor:"transparent",padding:0},Vr={width:52,height:52,borderRadius:"50%",background:"white",display:"block"},Gr={position:"absolute",bottom:gt,left:"50%",transform:"translateX(-50%)",minHeight:44,padding:"10px 20px",borderRadius:22,background:g("buttonBg"),color:g("buttonFg"),border:"none",fontFamily:g("fontFamily"),fontSize:15,fontWeight:600,cursor:"pointer",pointerEvents:"auto",WebkitTapHighlightColor:"transparent"},xt={position:"absolute",bottom:"calc(16px + env(safe-area-inset-bottom, 0px))",left:"50%",transform:"translateX(-50%)",boxSizing:"border-box",width:"max-content",maxWidth:"calc(100% - 32px)",background:g("hintBg"),color:g("hintFg"),padding:"10px 16px",borderRadius:g("radius"),fontFamily:g("fontFamily"),fontSize:16,lineHeight:1.35,margin:0,whiteSpace:"normal",textAlign:"center"},Yr={...xt,border:"none",minHeight:44,cursor:"pointer",pointerEvents:"auto",WebkitTapHighlightColor:"transparent"};var tn=["INE","PASSPORT_MX"],Me=()=>{},St=forwardRef(function({className:t,style:r,hideStatusOverlay:n,texts:o,theme:a,showTips:i,hideShutter:s,onStatusChange:u,...c},d){let{videoRef:p,status:m,frame:l,start:x,captureNow:S,retake:y}=Ce({...c,cropToGuide:!n}),b=pt(m,i??true),h=useMemo(()=>xe(o),[o]),f=m==="streaming"||m==="loading_detector",R=m==="done"||m==="error",C=async()=>{f&&await S().catch(Me);},T=()=>{R&&y().catch(Me);},M=async()=>{await x().catch(Me);};useImperativeHandle(d,()=>({capture:C,retake:T,start:M}));let w=useRef(u);return w.current=u,useEffect(()=>{w.current?.(m);},[m]),jsx(bt,{videoRef:p,status:m,frame:l,texts:h,documentTypes:c.documentTypes??tn,theme:a,className:t,style:r,hideStatusOverlay:n,hideShutter:s,tipsVisible:b.visible,onCapture:()=>{C();},onRetake:T,onStart:()=>{M();},onDismissTips:b.dismiss})});St.displayName="XidCameraOcr";export{B as CVWorkerClient,Qt as DEFAULT_TEXTS_EN,ge as DEFAULT_TEXTS_ES,O as ID1_RATIO,E as QUALITY_THRESHOLDS,j as StabilityTracker,L as TD3_RATIO,re as XCO_VARS,St as XidCameraOcr,z as XidCameraOcrSession,ae as attachCamera,J as copyFor,be as decideHint,de as defaultOpencvUrl,ie as detachCamera,pr as detectDocumentCV,q as guideBox,I as guideRatioFor,he as isCapturableAspect,fe as measureQuality,me as orderCorners,Q as rectifiedAspect,xe as resolveTexts,ue as sampleFrame,le as setTorch,se as snapshotToBlob,ce as supportsTorch,Z as typeHintFromAspect,Ce as useXidCameraOcr,Xe as warpDocument,Qe as warpDocumentImageData,Dt as warpedSnapshotToBlob};//# sourceMappingURL=index.js.map
|
|
2
2
|
//# sourceMappingURL=index.js.map
|