@andresxid/xid_camera_ocr_sdk_react 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -1
- package/LICENSE +9 -0
- package/README.md +51 -18
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -4
- package/dist/index.d.ts +17 -4
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
package/dist/index.d.cts
CHANGED
|
@@ -30,7 +30,7 @@ interface XidCameraOcrSessionOptions {
|
|
|
30
30
|
* capturable); wrappers use it to size the fallback guide rectangle.
|
|
31
31
|
*/
|
|
32
32
|
documentTypes?: DocumentType[];
|
|
33
|
-
/** When `true`, captures automatically once a stable, good-quality quad is seen. */
|
|
33
|
+
/** When `true`, captures automatically once a stable, good-quality quad is seen. Default `false`: the user takes the photo manually. */
|
|
34
34
|
autoCapture?: boolean;
|
|
35
35
|
/** Consecutive stable frames required before auto-capture. Default 10 (≈ 1 s at 10 fps). */
|
|
36
36
|
stableFramesRequired?: number;
|
|
@@ -438,7 +438,7 @@ interface UseXidCameraOcrReturn {
|
|
|
438
438
|
start: () => Promise<void>;
|
|
439
439
|
stop: () => void;
|
|
440
440
|
captureNow: () => Promise<void>;
|
|
441
|
-
/** Stops the current run and starts a new one (re-arms the auto-shutter). */
|
|
441
|
+
/** Stops the current run and starts a new one (re-arms the auto-shutter when `autoCapture` is on). */
|
|
442
442
|
retake: () => Promise<void>;
|
|
443
443
|
}
|
|
444
444
|
declare function useXidCameraOcr(options: UseXidCameraOcrOptions): UseXidCameraOcrReturn;
|
|
@@ -453,7 +453,20 @@ interface XidCameraOcrProps extends UseXidCameraOcrOptions {
|
|
|
453
453
|
theme?: XidCameraOcrTheme;
|
|
454
454
|
/** Show the capture tips card. Default `true`. */
|
|
455
455
|
showTips?: boolean;
|
|
456
|
+
/** Hide the built-in shutter button; drive capture with the `ref` handle instead. Default `false`. */
|
|
457
|
+
hideShutter?: boolean;
|
|
458
|
+
/** Called with the initial status and again on every status change. */
|
|
459
|
+
onStatusChange?: (status: SessionState['status']) => void;
|
|
456
460
|
}
|
|
457
|
-
|
|
461
|
+
/** Imperative handle exposed through the component `ref`. */
|
|
462
|
+
interface XidCameraOcrHandle {
|
|
463
|
+
/** Same as the built-in shutter: ignored unless the camera is live; errors reach `onError`. */
|
|
464
|
+
capture(): Promise<void>;
|
|
465
|
+
/** Same as the built-in retake: ignored unless the run is `done` or `error`. */
|
|
466
|
+
retake(): void;
|
|
467
|
+
/** Starts the camera (needed only with `autoStart={false}` or after `stop`). */
|
|
468
|
+
start(): Promise<void>;
|
|
469
|
+
}
|
|
470
|
+
declare const XidCameraOcr: react.ForwardRefExoticComponent<XidCameraOcrProps & react.RefAttributes<XidCameraOcrHandle>>;
|
|
458
471
|
|
|
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 };
|
|
472
|
+
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 XidCameraOcrHandle, 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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ interface XidCameraOcrSessionOptions {
|
|
|
30
30
|
* capturable); wrappers use it to size the fallback guide rectangle.
|
|
31
31
|
*/
|
|
32
32
|
documentTypes?: DocumentType[];
|
|
33
|
-
/** When `true`, captures automatically once a stable, good-quality quad is seen. */
|
|
33
|
+
/** When `true`, captures automatically once a stable, good-quality quad is seen. Default `false`: the user takes the photo manually. */
|
|
34
34
|
autoCapture?: boolean;
|
|
35
35
|
/** Consecutive stable frames required before auto-capture. Default 10 (≈ 1 s at 10 fps). */
|
|
36
36
|
stableFramesRequired?: number;
|
|
@@ -438,7 +438,7 @@ interface UseXidCameraOcrReturn {
|
|
|
438
438
|
start: () => Promise<void>;
|
|
439
439
|
stop: () => void;
|
|
440
440
|
captureNow: () => Promise<void>;
|
|
441
|
-
/** Stops the current run and starts a new one (re-arms the auto-shutter). */
|
|
441
|
+
/** Stops the current run and starts a new one (re-arms the auto-shutter when `autoCapture` is on). */
|
|
442
442
|
retake: () => Promise<void>;
|
|
443
443
|
}
|
|
444
444
|
declare function useXidCameraOcr(options: UseXidCameraOcrOptions): UseXidCameraOcrReturn;
|
|
@@ -453,7 +453,20 @@ interface XidCameraOcrProps extends UseXidCameraOcrOptions {
|
|
|
453
453
|
theme?: XidCameraOcrTheme;
|
|
454
454
|
/** Show the capture tips card. Default `true`. */
|
|
455
455
|
showTips?: boolean;
|
|
456
|
+
/** Hide the built-in shutter button; drive capture with the `ref` handle instead. Default `false`. */
|
|
457
|
+
hideShutter?: boolean;
|
|
458
|
+
/** Called with the initial status and again on every status change. */
|
|
459
|
+
onStatusChange?: (status: SessionState['status']) => void;
|
|
456
460
|
}
|
|
457
|
-
|
|
461
|
+
/** Imperative handle exposed through the component `ref`. */
|
|
462
|
+
interface XidCameraOcrHandle {
|
|
463
|
+
/** Same as the built-in shutter: ignored unless the camera is live; errors reach `onError`. */
|
|
464
|
+
capture(): Promise<void>;
|
|
465
|
+
/** Same as the built-in retake: ignored unless the run is `done` or `error`. */
|
|
466
|
+
retake(): void;
|
|
467
|
+
/** Starts the camera (needed only with `autoStart={false}` or after `stop`). */
|
|
468
|
+
start(): Promise<void>;
|
|
469
|
+
}
|
|
470
|
+
declare const XidCameraOcr: react.ForwardRefExoticComponent<XidCameraOcrProps & react.RefAttributes<XidCameraOcrHandle>>;
|
|
458
471
|
|
|
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 };
|
|
472
|
+
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 XidCameraOcrHandle, 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 };
|
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';async function le(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 a=n.getVideoTracks()[0],i=a.getCapabilities?.();return i&&"focusMode"in i&&i.focusMode?.includes("continuous")&&a.applyConstraints({advanced:[{focusMode:"continuous"}]}).catch(()=>{}),await e.play().catch(()=>{}),n}function ce(e,t){e.srcObject===t&&(e.srcObject=null),t?.getTracks().forEach(r=>r.stop());}async function ue(e,t=.92){let r=e.videoWidth,n=e.videoHeight;if(!r||!n)throw new Error("Video stream not ready (videoWidth=0)");let a=document.createElement("canvas");a.width=r,a.height=n;let i=a.getContext("2d");if(!i)throw new Error("2D canvas context unavailable");return i.drawImage(e,0,0,r,n),new Promise((s,o)=>{a.toBlob(l=>l?s(l):o(new Error("Canvas toBlob returned null")),"image/jpeg",t);})}var U=null;function de(e,t=640){let r=e.videoWidth,n=e.videoHeight;if(!r||!n)return null;let a=Math.round(t),i=Math.round(n*t/r);U??=document.createElement("canvas"),(U.width!==a||U.height!==i)&&(U.width=a,U.height=i);let s=U.getContext("2d",{willReadFrequently:true});return s?(s.drawImage(e,0,0,a,i),s.getImageData(0,0,a,i)):null}function Ee(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 a=n.getContext("2d",{willReadFrequently:true});return a?(a.drawImage(e,0,0,t,r),a.getImageData(0,0,t,r)):null}function _e(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((a,i)=>r.toBlob(s=>s?a(s):i(new Error("Canvas toBlob returned null")),"image/jpeg",t))):Promise.reject(new Error("2D canvas context unavailable"))}function pe(e){let t=e.getCapabilities;return typeof t!="function"?false:t.call(e).torch===true}async function me(e,t){try{return await e.applyConstraints({advanced:[{torch:t}]}),!0}catch{return false}}var gt="@andresxid/xid_camera_ocr_sdk_react";function Ae(e,t){return e.pathname.endsWith(`/${gt}/${t}`)}function Fe(e){return new URL(e,import.meta.url)}function Pe(){return new URL("@andresxid/xid_camera_ocr_sdk_react/opencv.js",import.meta.url)}function he(){let e=Pe();return Ae(e,"opencv.js")?Fe("./opencv.js").href:e.href}function Oe(e){return e!==void 0?new Worker(e,{type:"module"}):Ae(Pe(),"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 De(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 Ie(e){let t=new Uint8ClampedArray(e.data.byteLength);return t.set(e.data),t.buffer}var St=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=he(),r){if(this.readyPromise)return this.readyPromise;let n;try{n=Oe(r);}catch(i){return Promise.reject(St(i))}this.worker=n;let a=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",o=>{if(this.worker!==n)return;let l=De(o.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",o=>{this.worker===n&&this.fail(new Error(o.message||"Worker error"));}),n.addEventListener("messageerror",o=>{if(this.worker!==n)return;let l=new Error("Worker message could not be deserialized"),c=o.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=a,n.postMessage({type:"init",opencvUrl:t}),a}isReady(){return this.ready&&this.worker!==null}async analyze(t,r={}){let n=Ie(t),a=r.prior,i=await this.request(s=>({type:"analyze",id:s,width:t.width,height:t.height,buffer:n,...a?{prior:a}:{}}),[n]);if(i.type!=="analyze-result")throw new Error(`Unexpected worker response: ${i.type}`);return i.result}async warp(t,r,n,a=1024){let i=Ie(t),s=await this.request(o=>({type:"warp",id:o,width:t.width,height:t.height,buffer:i,corners:r,docType:n,longSide:a}),[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 a=t(this.nextId++),i=new Promise((s,o)=>this.pending.set(a.id,{resolve:s,reject:o}));return n.postMessage(a,r),i}};var O=1.585772508336421,I=125/88,Ct=1.503,wt=.05,Z=1.25,ye=1.75,Tt=.25;function fe(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)),a=0;for(let i=1;i<4;i++){let s=n[i],o=n[a];(s.x+s.y<o.x+o.y||s.x+s.y===o.x+o.y&&s.y<o.y)&&(a=i);}return [0,1,2,3].map(i=>n[(a+i)%4])}function H(e){let t=0;for(let r=0;r<e.length;r++){let n=e[r],a=e[(r+1)%e.length];t+=n.x*a.y-a.x*n.y;}return Math.abs(t)/2}function ee(e){let[t,r,n,a]=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-a.x,n.y-a.y),left:Math.hypot(a.x-t.x,a.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],a=e[r],i=e[(r+1)%4],s=n.x-a.x,o=n.y-a.y,l=i.x-a.x,c=i.y-a.y,d=Math.hypot(s,o),p=Math.hypot(l,c);if(d===0||p===0){t[r]=0;continue}let m=Math.min(1,Math.max(-1,(s*l+o*c)/(d*p)));t[r]=Math.acos(m)*180/Math.PI;}return t}function te(e,t=70,r=110){let n=ee(e);return n.top<=0||n.right<=0||n.bottom<=0||n.left<=0||!vt(e)||H(e)<=0?false:Rt(e).every(a=>a>=t&&a<=r)}function vt(e){let t=0;for(let r=0;r<4;r++){let n=e[r],a=e[(r+1)%4],i=e[(r+2)%4],s=(a.x-n.x)*(i.y-a.y)-(a.y-n.y)*(i.x-a.x);if(s===0)return false;let o=Math.sign(s);if(t===0)t=o;else if(o!==t)return false}return true}function j(e){let t=ee(e),r=(t.top+t.bottom)/2,n=(t.left+t.right)/2,a=Math.min(r,n);return a<=0?0:Math.max(r,n)/a}function kt(e){if(!Number.isFinite(e))return 0;let t=Math.min(Math.abs(e-O),Math.abs(e-I));return Math.max(0,1-t/Tt)}function He(e){return .5*e.areaRatio+.3*e.rectangularity+.2*kt(e.aspect)}function re(e){let t=e>=Ct?O:I;return Math.abs(e-t)/t<=wt?t===O?"INE":"PASSPORT_MX":"OTHER"}function be(e){return e>=Z&&e<=ye}function Le(e,t){return e==="INE"?O:e==="PASSPORT_MX"?I:t}var z=1024,Ue=1600;function Qe(e,t,r,n,a=z){let i=Et(Le(n,j(r))),s=Math.max(1,Math.round(a/i)),o=ee(r),l=o.top+o.bottom<o.left+o.right,c=n==="INE"||n==="PASSPORT_MX",d=l&&c?[r[3],r[0],r[1],r[2]]:r,p=!l||c,m=p?a:s,u=p?s:a,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,u,0,u]),h=e.getPerspectiveTransform(y,b),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)),_t(new Uint8ClampedArray((f??S).data),m,u)}finally{for(let T of [f,h,b,y,S,x])T?.delete();}}function qe(e,t,r,n,a=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),o=Qe(e,s,r,n,a),l=document.createElement("canvas");l.width=o.width,l.height=o.height;let c=l.getContext("2d");if(!c)throw new Error("2D canvas context unavailable (output)");return c.putImageData(o,0,0),l}async function Mt(e,t,r,n,a=.92,i=z){let s=r?qe(e,t,r,n,i):t;return new Promise((o,l)=>{s.toBlob(c=>c?o(c):l(new Error("Canvas toBlob returned null")),"image/jpeg",a);})}function Et(e){return Number.isFinite(e)?Math.min(ye,Math.max(Z,e)):Z}function _t(e,t,r){return typeof globalThis.ImageData=="function"?new ImageData(e,t,r):{data:e,width:t,height:r,colorSpace:"srgb"}}var M={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 a=0;a<r;a++){let i=a+.5,s=1/0,o=-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>o&&(o=u);}if(s===1/0){n[a*2]=0,n[a*2+1]=0;continue}n[a*2]=Math.max(0,Math.ceil(s-.5)),n[a*2+1]=Math.min(t,Math.floor(o+.5));}return n}function ge(e,t){let{data:r,width:n,height:a}=e,i=V(t,n,a),s=M.glarePixel,o=0,l=0,c=0,d=0,p=0,m=0;for(let f=0;f<a;f++){let T=i[f*2],w=i[f*2+1];if(T>=w)continue;let v=0,R=0;f>0&&f<a-1&&(v=Math.max(T,i[(f-1)*2],i[(f+1)*2])+1,R=Math.min(w,i[(f-1)*2+1],i[(f+1)*2+1])-1);let C=f*n;for(let k=T;k<w;k++){let A=C+k,E=r[A];if(o+=E,E>=s&&l++,c++,k>=v&&k<R){let P=4*E-r[A-n]-r[A+n]-r[A-1]-r[A+1];d+=P,p+=P*P,m++;}}}let u=c>0?o/c/255:0,x=c>0?l/c:0,S=m>0?Math.max(0,p/m-(d/m)**2):0,y=n*a,b=y>0?H(t)/y:0,h=u>=M.brightnessMin&&u<=M.brightnessMax&&S>=M.blurMin&&x<=M.glareMax&&b>=M.fillMin;return {brightness:u,blurScore:S,glareRatio:x,docFillRatio:b,ok:h}}function Ne(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 xe(e){if(!e.detected||!e.quality)return "no_document";let t=e.quality;return !Number.isFinite(t.docFillRatio)||t.docFillRatio<M.fillMin?"too_small":!Number.isFinite(t.brightness)||t.brightness<M.brightnessMin?"too_dark":!Number.isFinite(t.glareRatio)||t.glareRatio>M.glareMax||t.brightness>M.brightnessMax?"glare":!Number.isFinite(t.blurScore)||t.blurScore<M.blurMin?"blurry":e.stableFrames<e.stableFramesRequired?"hold_still":"ready"}var At=M.brightnessMin;function Xe(e){return !e.torchSupported||e.torchOn?false:(e.quality?e.quality.brightness:e.frameBrightness)<At}var Se=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"}),Ft=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"}),Pt=["loading_detector","capturing","uploading","done","error"];function Ot(e){return Pt.includes(e)}function G(e,t){return t?.[e]??Se[e]}function Ce(e){let t={...Se};for(let r of Object.keys(t))t[r]=G(r,e);return t}function ne(e,t,r){return e==="idle"||e==="stopped"?G("idle",r):e==="starting"?G("starting",r):Ot(e)?G(e,r):G(t??"no_document",r)}var Dt=.05;function It(e,t,r){let n=r.width/t.width,a=r.height/t.height;return e.map(i=>({x:i.x*n,y:i.y*a}))}function Ht(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 Be(e,t,r){let n=Ht(It(e,t,r),r);return !te(n)||H(n)<Dt*r.width*r.height?null:n}var We={stableFrames:0,isStable:false,quad:null,typeHint:null},Y=class{required;maxRatio;switchFrames;current=We;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=We,this.candidate=null;}update(t,r){if(!t)return this.reset(),this.current;let n=Math.hypot(r.width,r.height)*this.maxRatio,a=this.current,i=a.quad!==null&&a.quad.every((l,c)=>Math.hypot(t.quad[c].x-l.x,t.quad[c].y-l.y)<=n),s=a.typeHint??t.typeHint,o=i?a.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,o=1,this.candidate=null);}return this.current={stableFrames:o,isStable:o>=this.required,quad:t.quad,typeHint:s},this.current}};var Ut=640,Qt=10,je=1500,qt=35e3,Nt=5,Xt={createWorkerClient:e=>new W(e),attachCamera:e=>le(e),detachCamera:ce,sampleFrame:de,grabFrame:Ee,encodeJpeg:_e,snapshotToBlob:ue,supportsTorch:pe,setTorch:me,now:()=>performance.now()},ze=e=>e.provenance==="reduced"||e.provenance==="lowres",Ve=e=>e instanceof Error?e:new Error(String(e)),Ge=e=>e.map(t=>({x:t.x,y:t.y})),K=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??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={...Xt,...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));},a=>this.detectorUnavailable(t,n,a));}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,a=r.quad&&n?this.fullFrameQuad(r.quad,n):null;await this.doCapture(this.generation,a?r.typeHint:null,a);}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/Qt-(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,Ut);if(!n)return;let a={width:n.width,height:n.height};this.warmupUntil===0&&(this.warmupUntil=this.deps.now()+je);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 o;try{o=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=o.detected&&o.corners?{quad:Ge(o.corners),...a}:null;let c=!(this.deps.now()<this.warmupUntil)&&o.detected&&o.corners&&o.documentType?{quad:o.corners,typeHint:o.documentType}:null,d=this.stability.update(c,a);this.weakRun=d.stableFrames<=1?c!==null&&ze(o):this.weakRun||ze(o);let p=this.opts.stableFramesRequired+(this.weakRun?Nt:0);if(await this.updateTorch(t,o),t!==this.generation)return;let m={detected:o.detected,documentType:o.documentType,confidence:Math.min(d.stableFrames/p,1),aspectRatio:o.aspectRatio,quality:o.quality,corners:o.corners?Ge(o.corners):null,frameSize:a,hint:xe({detected:o.detected,quality:o.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&&o.quality?.ok){let u=this.fullFrameQuad(d.quad,a);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 a=Ve(n);this.state.lastError=a;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?.(a);}async updateTorch(t,r){if(!this.track||this.torchRejected||!Xe({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:Be(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:a,type:i}=await this.captureBlob(t,r,n);if(t!==this.generation)return;this.opts.onCaptured?.(a,i),this.setStatus("uploading");let s=await this.opts.onUpload(a,i);if(t!==this.generation)return;this.state.lastResult=s,this.setStatus("done"),this.opts.onResult?.(s);}catch(a){t===this.generation&&this.emitError(a);}finally{t===this.generation&&(this.stability.reset(),this.weakRun=false,this.warmupUntil=this.deps.now()+je,this.capturing=false);}}}async captureBlob(t,r,n){let a=this.opts.videoElement,i=async()=>({blob:await this.deps.snapshotToBlob(a,this.opts.captureQuality),type:null}),s=this.cv;if(!s?.isReady()||!n)return i();try{await this.inFlight?.catch(()=>{});let o=this.deps.grabFrame(a);if(!o||!s.isReady())return i();let l=this.opts.captureResolution==="high"?Ue:z,c=await s.warp(o,n,r,l);return {blob:await this.deps.encodeJpeg(c,this.opts.captureQuality),type:r}}catch(o){if(t!==this.generation)throw o;return console.warn("[xid-camera-ocr] warp failed, using plain snapshot:",o),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=Ve(t);this.state.lastError=r,this.setStatus("error"),this.opts.onError?.(r);}};var Ye=.08,Bt=.95,Wt=.02,Q=8,jt=2,Ke=8,$e=.33,ae=2,zt=2,Vt=1,Gt=zt+ae,Yt=2,Kt=2*(ae+1),$t=10,Je=1.1,rt=ae+1,Jt=6,nt=.92,Zt=1/nt,er=.85,tr=2,rr=.05,Ze=2,et=64;function at(e){return {detected:false,documentType:null,aspectRatio:null,corners:null,boundingBox:null,quality:null,frameBrightness:e,score:null}}function nr(e,t,r,n={}){let a={brightness:0};try{return ar(e,t,a,n.prior??null)}catch(i){return console.warn("[xid-camera-ocr] detectDocumentCV failed:",i),at(a.brightness)}}function ar(e,t,r,n){let{width:a,height:i}=t,s=[],o=l=>(s.push(l),l);try{let l=o(e.matFromImageData(t)),c=o(new e.Mat),d=o(new e.Mat),p={equalized:o(new e.Mat),filtered:o(new e.Mat),padded:o(new e.Mat),edges:o(new e.Mat),dilated:o(new e.Mat),kernel:o(e.Mat.ones(3,3,e.CV_8U)),contours:o(new e.MatVector),hierarchy:o(new e.Mat),hull:o(new e.Mat),approx:o(new e.Mat),clahe:o(new e.CLAHE(jt,new e.Size(Ke,Ke)))};e.cvtColor(l,c,e.COLOR_RGBA2GRAY),r.brightness=Ne(we(c,a,i));let m=[],u=tt(e,c,p,a,i,m,n),x=!1,S=Math.round(a/Ze),y=Math.round(i/Ze);if(!u&&S>=et&&y>=et&&(e.resize(c,d,new e.Size(S,y),0,0,e.INTER_AREA),u=tt(e,d,p,a,i,m,n),x=u!==null),u&&ur(u,m,we(c,a,i))&&(u=null),!u)return at(r.brightness);let b=x?"lowres":u.reduced?"reduced":"direct",h=u.quad.map(C=>C.x),f=u.quad.map(C=>C.y),T=Math.min(...h),w=Math.max(...h),v=Math.min(...f),R=Math.max(...f);return {detected:!0,documentType:re(u.aspect),aspectRatio:u.aspect,corners:u.quad,boundingBox:{x:T/a,y:v/i,width:(w-T)/a,height:(R-v)/i},quality:ge(we(c,a,i),st(u.quad,rt*u.scale)),frameBrightness:r.brightness,score:b==="direct"?u.score:u.score*er,provenance:b}}finally{for(let l of s)l.delete();}}function tt(e,t,r,n,a,i,s){let o=t.cols,l=t.rows,c=n/o,d=a/l,p=o*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,Q,Q,Q,Q,e.BORDER_CONSTANT,new e.Scalar(0));let y=hr(r.padded.data);e.Canny(r.padded,r.edges,Math.max(10,(1-$e)*y),Math.min(255,(1+$e)*y)),e.dilate(r.edges,r.dilated,r.kernel,new e.Point(-1,-1),ae),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 T=e.boundingRect(f);if(T.width*T.height<p*Ye)continue;e.convexHull(f,u,!1,!0);let w=e.contourArea(u);if(w<p*Ye||w>p*Bt||(e.approxPolyDP(u,x,Wt*e.arcLength(u,!0),!0),x.rows<4||x.rows>Jt||!e.isContourConvex(x)))continue;let v=x.rows!==4,R;if(!v)R=ir(x,o,l);else {let L=sr(ot(x));if(!L)continue;R=L.map(bt=>it(bt,o,l));let D=w/H(R);if(!(D>=nt&&D<=Zt))continue}let C=w*c*d,k=R.map(m),A=Gt*c;if(mr(k,n,a,A)>Vt){cr(k,n,a,A)||i.push({pts:k,area:C});continue}let E=fe(k);if(!te(E))continue;let P=e.minAreaRect(v?u:x),q=P.size.width*P.size.height,se=q>0?Math.min(1,w/q):0,N=j(E);if(!be(N))continue;let X=He({areaRatio:w/p,rectangularity:se,aspect:N}),B=s?X-or(E,s,n,a):X;(!b||B>b.rank)&&(b={quad:E,score:X,rank:B,aspect:N,area:C,scale:c,reduced:v});}finally{f.delete();}}return b}function or(e,t,r,n){let a=1/0;for(let i=0;i<4;i++){let s=0;for(let o=0;o<4;o++){let l=e[(o+i)%4];s=Math.max(s,Math.hypot(l.x-t[o].x,l.y-t[o].y));}a=Math.min(a,s);}return tr*Math.min(a/Math.hypot(r,n),rr)}function we(e,t,r){return {data:e.data,width:t,height:r}}function ot(e){let t=e.data32S,r=[];for(let n=0;n<e.rows;n++)r.push({x:t[n*2]-Q,y:t[n*2+1]-Q});return r}function it(e,t,r){return {x:Math.min(t,Math.max(0,e.x)),y:Math.min(r,Math.max(0,e.y))}}function ir(e,t,r){return ot(e).map(n=>it(n,t,r))}function sr(e){let t=e;for(;t.length>4;){let r=t.length,n=-1,a=1/0,i=null;for(let o=0;o<r;o++){let l=t[(o+r-1)%r],c=t[o],d=t[(o+1)%r],p=t[(o+2)%r],m=lr(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<a&&(a=u,n=o,i=m);}if(n<0||!i)return null;let s=[];for(let o=0;o<r;o++)o===n?s.push(i):o!==(n+1)%r&&s.push(t[o]);t=s;}return t}function lr(e,t,r,n){let a=t.x-e.x,i=t.y-e.y,s=n.x-r.x,o=n.y-r.y,l=a*o-i*s;if(Math.abs(l)<1e-9)return null;let c=((r.x-e.x)*o-(r.y-e.y)*s)/l,d=((r.x-e.x)*i-(r.y-e.y)*a)/l;return c<1||d<1?null:{x:e.x+c*a,y:e.y+c*i}}function cr(e,t,r,n){let a=e.map(s=>s.x),i=e.map(s=>s.y);return Math.min(...a)<=n&&Math.max(...a)>=t-n||Math.min(...i)<=n&&Math.max(...i)>=r-n}function ur(e,t,r){let n=Kt*e.scale;if(!t.some(o=>o.area>=Yt*e.area&&e.quad.every(l=>pr(o.pts,l,n))))return false;if(re(e.aspect)==="OTHER")return true;let{inner:i,ring:s}=dr(r,st(e.quad,rt*e.scale),e.quad);return i<s-$t}function dr(e,t,r){let{data:n,width:a,height:i}=e,s=(r[0].x+r[1].x+r[2].x+r[3].x)/4,o=(r[0].y+r[1].y+r[2].y+r[3].y)/4,l=r.map(y=>({x:s+(y.x-s)*Je,y:o+(y.y-o)*Je})),c=V(l,a,i),d=V(r,a,i),p=V(t,a,i),m=0,u=0,x=0,S=0;for(let y=0;y<i;y++){let b=c[y*2],h=c[y*2+1];if(b>=h)continue;let f=d[y*2],T=d[y*2+1],w=p[y*2],v=p[y*2+1],R=y*a;for(let C=b;C<h;C++){let k=n[R+C];C>=w&&C<v?(m+=k,u++):(C<f||C>=T)&&(x+=k,S++);}}return {inner:u>0?m/u:0,ring:S>0?x/S:0}}function pr(e,t,r){let n=0;for(let i=0;i<e.length;i++){let s=e[i],o=e[(i+1)%e.length];n+=s.x*o.y-o.x*s.y;}let a=Math.sign(n);if(a===0)return false;for(let i=0;i<e.length;i++){let s=e[i],o=e[(i+1)%e.length],l=Math.hypot(o.x-s.x,o.y-s.y);if(l===0)continue;if(a*((o.x-s.x)*(t.y-s.y)-(o.y-s.y)*(t.x-s.x))/l<r)return false}return true}function st(e,t){return e.map((r,n)=>{let a=e[(n+3)%4],i=e[(n+1)%4],s=a.x-r.x,o=a.y-r.y,l=i.x-r.x,c=i.y-r.y,d=Math.hypot(s,o),p=Math.hypot(l,c),m=s/d+l/p,u=o/d+c/p,x=Math.hypot(m,u),S=Math.sin(Math.acos(Math.min(1,Math.max(-1,(s*l+o*c)/(d*p))))/2),y=t/S/x;return {x:r.x+m*y,y:r.y+u*y}})}function mr(e,t,r,n){let a=0;for(let i of e)(i.x<=n||i.x>=t-n||i.y<=n||i.y>=r-n)&&a++;return a}function hr(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 Re(e){let t=useRef(null),r=useRef(null),[n,a]=useState("idle"),[i,s]=useState(null),[o,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 b=new K({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===b&&a(b.getState().status),p.current.onFrameAnalyzed?.(h);},onCaptured:(h,f)=>{a("capturing"),p.current.onCaptured?.(h,f);},onResult:h=>{l(h),a("done"),p.current.onResult?.(h);},onError:h=>{d(h),r.current===b&&a(b.getState().status),p.current.onError?.(h);}});return r.current=b,b},[]),u=useCallback(async()=>{let b=m();await b.start(),r.current===b&&a(b.getState().status);},[m]),x=useCallback(()=>{r.current?.stop(),a("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:o,error:c,start:u,stop:x,captureNow:S,retake:y}}function br({status:e,showTips:t,dismissed:r,completedOnce:n}){return t&&!r&&(e==="error"||!n&&(e==="starting"||e==="loading_detector"))}function lt(e,t){let[r,n]=useState(false),[a,i]=useState(e==="done"),[s,o]=useState(e),l=r,c=a;s!==e&&(o(e),e==="error"&&(l=false,n(false)),e==="done"&&(c=true,i(true)));let d=useCallback(()=>n(true),[]);return {visible:br({status:e,showTips:t,dismissed:l,completedOnce:c}),dismiss:d}}var ie={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}=ie[e];return `var(${t}, ${r})`}function ct(e){let t={};if(!e)return t;for(let r of Object.keys(e)){if(!Object.prototype.hasOwnProperty.call(ie,r))continue;let n=e[r];typeof n!="string"||n===""||(t[ie[r].name]=n);}return t}function ut(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 ke={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"}},gr=()=>jsxs("svg",{...ke,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"})]}),xr=()=>jsxs("svg",{...ke,children:[jsx("rect",{x:"3",y:"5",width:"18",height:"14",rx:"2"}),jsx("path",{d:"M14 5l-6 14M18 5l-6 14"})]}),Sr=()=>jsxs("svg",{...ke,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 dt({texts:e,onDismiss:t}){let r=[{Icon:gr,text:e.tip_light},{Icon:xr,text:e.tip_glare},{Icon:Sr,text:e.tip_focus}];return jsxs("div",{className:"xco-tips",style:Cr,children:[jsx("ul",{style:wr,children:r.map(({Icon:n,text:a})=>jsxs("li",{style:Tr,children:[jsx(n,{}),jsx("span",{children:a})]},a))}),jsx("button",{type:"button",className:"xco-tips-dismiss",onClick:t,style:Rr,children:e.tips_dismiss})]})}var Cr={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},wr={listStyle:"none",margin:0,padding:0,display:"flex",flexDirection:"column",gap:10},Tr={display:"flex",alignItems:"center",gap:12},Rr={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 _r=typeof window>"u"?useEffect:useLayoutEffect;function mt({videoRef:e,status:t,frame:r,texts:n,documentTypes:a,theme:i,className:s,style:o,hideStatusOverlay:l,hideShutter:c,tipsVisible:d,onCapture:p,onRetake:m,onStart:u,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),[T,w]=useState({width:0,height:0}),v=r?.documentType,R=v==="PASSPORT_MX"?I:v==="INE"?O:a[0]==="PASSPORT_MX"?I:O;_r(()=>{let E=f.current;if(!E)return;let P=()=>{let se=E.clientWidth,N=E.clientHeight,X=se*.85,B=N*.7,L=X,D=L/R;D>B&&(D=B,L=D*R),w({width:L,height:D});};P();let q=new ResizeObserver(P);return q.observe(E),()=>q.disconnect()},[R]);let C=ut(t,r),k=ne(t,r?.hint,n),A=s?`xid-camera-ocr ${s}`:"xid-camera-ocr";return jsxs("div",{ref:f,className:A,"data-status":t,"data-hint":r?.hint??"",style:{...Ar,...ct(i),...o},children:[jsx("style",{children:"@keyframes xco-spin { to { transform: rotate(360deg); } }"}),jsx("video",{ref:e,playsInline:true,muted:true,autoPlay:true,style:Fr}),!l&&jsx("div",{style:Pr,children:jsx("div",{className:"xco-guide",style:{...Or,width:T.width,height:T.height,borderColor:C}})}),!l&&(b?jsx("button",{type:"button",className:"xco-hint",onClick:u,style:qr,children:k}):jsx("p",{className:"xco-hint",style:yt,role:"status","aria-live":"polite",children:k})),!l&&!c&&S&&jsx("button",{type:"button",className:"xco-shutter",onClick:p,"aria-label":n.capture,style:Lr,children:jsx("span",{style:Ur})}),!l&&y&&jsx("button",{type:"button",className:"xco-retake",onClick:m,"aria-label":n.retake,style:Qr,children:n.retake}),!l&&h&&jsxs("div",{className:"xco-loader",style:Dr,"aria-busy":"true","aria-live":"polite",children:[jsx("div",{style:Ir}),jsx("p",{style:Hr,children:ne(t,void 0,n)})]}),d&&!l&&jsx(dt,{texts:n,onDismiss:x})]})}var ht="calc(104px + env(safe-area-inset-bottom, 0px))",Ar={position:"relative",width:"100%",height:"100%",overflow:"hidden",background:g("background"),fontFamily:g("fontFamily"),touchAction:"none"},Fr={position:"absolute",inset:0,width:"100%",height:"100%",objectFit:"cover",display:"block"},Pr={position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",pointerEvents:"none"},Or={borderRadius:g("radius"),borderWidth:4,borderStyle:"solid",boxShadow:`0 0 0 9999px ${g("mask")}`,transition:"border-color 200ms ease-in-out, width 200ms ease-in-out, height 200ms ease-in-out"},Dr={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},Ir={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"},Hr={color:g("overlayFg"),fontFamily:g("fontFamily"),fontSize:15,fontWeight:500,margin:0,textAlign:"center",padding:"0 24px"},Lr={position:"absolute",bottom:ht,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},Ur={width:52,height:52,borderRadius:"50%",background:"white",display:"block"},Qr={position:"absolute",bottom:ht,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"},yt={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"},qr={...yt,border:"none",minHeight:44,cursor:"pointer",pointerEvents:"auto",WebkitTapHighlightColor:"transparent"};var zr=["INE","PASSPORT_MX"],Me=()=>{},ft=forwardRef(function({className:t,style:r,hideStatusOverlay:n,texts:a,theme:i,showTips:s,hideShutter:o,onStatusChange:l,...c},d){let{videoRef:p,status:m,frame:u,start:x,captureNow:S,retake:y}=Re(c),b=lt(m,s??true),h=useMemo(()=>Ce(a),[a]),f=m==="streaming"||m==="loading_detector",T=m==="done"||m==="error",w=async()=>{f&&await S().catch(Me);},v=()=>{T&&y().catch(Me);},R=async()=>{await x().catch(Me);};useImperativeHandle(d,()=>({capture:w,retake:v,start:R}));let C=useRef(l);return C.current=l,useEffect(()=>{C.current?.(m);},[m]),jsx(mt,{videoRef:p,status:m,frame:u,texts:h,documentTypes:c.documentTypes??zr,theme:i,className:t,style:r,hideStatusOverlay:n,hideShutter:o,tipsVisible:b.visible,onCapture:()=>{w();},onRetake:v,onStart:()=>{R();},onDismissTips:b.dismiss})});ft.displayName="XidCameraOcr";export{W as CVWorkerClient,Ft as DEFAULT_TEXTS_EN,Se as DEFAULT_TEXTS_ES,O as ID1_RATIO,M as QUALITY_THRESHOLDS,Y as StabilityTracker,I as TD3_RATIO,ie as XCO_VARS,ft as XidCameraOcr,K as XidCameraOcrSession,le as attachCamera,ne as copyFor,xe as decideHint,he as defaultOpencvUrl,ce as detachCamera,nr as detectDocumentCV,be as isCapturableAspect,ge as measureQuality,fe as orderCorners,j as rectifiedAspect,Ce as resolveTexts,de as sampleFrame,me as setTorch,ue as snapshotToBlob,pe as supportsTorch,re as typeHintFromAspect,Re as useXidCameraOcr,qe as warpDocument,Qe as warpDocumentImageData,Mt as warpedSnapshotToBlob};//# sourceMappingURL=index.js.map
|
|
2
2
|
//# sourceMappingURL=index.js.map
|