@ekyc_qoobiss/qbs-ect-cmp 4.7.23 → 4.7.25

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.
@@ -80,87 +80,93 @@ export class IdAutoCapture {
80
80
  // Method for continuous video frame processing with OpenCV
81
81
  this.processVideoFrame = () => {
82
82
  if (this.videoElement && this.processingCanvasElement && this.opencvReady && this.isDetecting) {
83
- const video = this.videoElement;
84
- const processingCanvas = this.processingCanvasElement;
85
- const context = processingCanvas.getContext('2d');
86
- processingCanvas.width = video.videoWidth;
87
- processingCanvas.height = video.videoHeight;
88
- context.drawImage(video, 0, 0, processingCanvas.width, processingCanvas.height);
89
- const imageData = context.getImageData(0, 0, processingCanvas.width, processingCanvas.height);
90
- // --- OpenCV.js processing starts here ---
91
- let src = new cv.Mat(processingCanvas.height, processingCanvas.width, cv.CV_8UC4);
92
- src.data.set(imageData.data);
93
- let gray = new cv.Mat();
94
- let blurred = new cv.Mat();
95
- let edges = new cv.Mat();
96
- let contours = new cv.MatVector();
97
- let hierarchy = new cv.Mat();
98
83
  try {
99
- cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
100
- cv.GaussianBlur(gray, blurred, new cv.Size(5, 5), 0, 0, cv.BORDER_DEFAULT);
101
- cv.Canny(blurred, edges, 75, 200, 3, false);
102
- cv.findContours(edges, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);
103
- let idDetected = false;
104
- let maxArea = 0;
105
- //let bestRect = null;
106
- for (let i = 0; i < contours.size(); ++i) {
107
- let contour = contours.get(i);
108
- let area = cv.contourArea(contour);
109
- if (area > 1000 && area > maxArea) {
110
- let peri = cv.arcLength(contour, true);
111
- let approx = new cv.Mat();
112
- cv.approxPolyDP(contour, approx, 0.02 * peri, true);
113
- if (approx.rows === 4) {
114
- let rect = cv.boundingRect(approx);
115
- const aspectRatio = rect.width / rect.height;
116
- if (aspectRatio > 1.4 && aspectRatio < 1.8) {
117
- if (rect.width > video.videoWidth * 0.3 && rect.height > video.videoHeight * 0.3) {
118
- idDetected = true;
119
- maxArea = area;
120
- //bestRect = rect;
84
+ console.log('Processing frame. cv.Mat is a constructor:', typeof cv.Mat === 'function');
85
+ const video = this.videoElement;
86
+ const processingCanvas = this.processingCanvasElement;
87
+ const context = processingCanvas.getContext('2d');
88
+ processingCanvas.width = video.videoWidth;
89
+ processingCanvas.height = video.videoHeight;
90
+ context.drawImage(video, 0, 0, processingCanvas.width, processingCanvas.height);
91
+ const imageData = context.getImageData(0, 0, processingCanvas.width, processingCanvas.height);
92
+ // --- OpenCV.js processing starts here ---
93
+ let src = new cv.Mat(processingCanvas.height, processingCanvas.width, cv.CV_8UC4);
94
+ src.data.set(imageData.data);
95
+ let gray = new cv.Mat();
96
+ let blurred = new cv.Mat();
97
+ let edges = new cv.Mat();
98
+ let contours = new cv.MatVector();
99
+ let hierarchy = new cv.Mat();
100
+ try {
101
+ cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
102
+ cv.GaussianBlur(gray, blurred, new cv.Size(5, 5), 0, 0, cv.BORDER_DEFAULT);
103
+ cv.Canny(blurred, edges, 75, 200, 3, false);
104
+ cv.findContours(edges, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);
105
+ let idDetected = false;
106
+ let maxArea = 0;
107
+ //let bestRect = null;
108
+ for (let i = 0; i < contours.size(); ++i) {
109
+ let contour = contours.get(i);
110
+ let area = cv.contourArea(contour);
111
+ if (area > 1000 && area > maxArea) {
112
+ let peri = cv.arcLength(contour, true);
113
+ let approx = new cv.Mat();
114
+ cv.approxPolyDP(contour, approx, 0.02 * peri, true);
115
+ if (approx.rows === 4) {
116
+ let rect = cv.boundingRect(approx);
117
+ const aspectRatio = rect.width / rect.height;
118
+ if (aspectRatio > 1.4 && aspectRatio < 1.8) {
119
+ if (rect.width > video.videoWidth * 0.3 && rect.height > video.videoHeight * 0.3) {
120
+ idDetected = true;
121
+ maxArea = area;
122
+ //bestRect = rect;
123
+ }
121
124
  }
122
125
  }
126
+ approx.delete();
123
127
  }
124
- approx.delete();
128
+ contour.delete();
129
+ }
130
+ if (idDetected) {
131
+ console.log('ID document detected! Starting countdown...');
132
+ this.countdown = 3;
133
+ if (this.animationFrameId !== null) {
134
+ cancelAnimationFrame(this.animationFrameId); // Stop continuous frame processing
135
+ this.animationFrameId = null;
136
+ }
137
+ const timer = setInterval(() => {
138
+ this.countdown--;
139
+ if (this.countdown <= 0) {
140
+ clearInterval(timer);
141
+ this.capture();
142
+ this.stopRecording();
143
+ this.isDetecting = false;
144
+ console.log('Picture taken. You can now stop recording.');
145
+ this.countdown = 0; // Ensure countdown is 0
146
+ }
147
+ }, 1000);
125
148
  }
126
- contour.delete();
127
149
  }
128
- if (idDetected) {
129
- console.log('ID document detected! Starting countdown...');
130
- this.countdown = 3;
150
+ catch (error) {
151
+ console.error('OpenCV processing error:', error);
152
+ this.isDetecting = false; // Stop detection on error
131
153
  if (this.animationFrameId !== null) {
132
- cancelAnimationFrame(this.animationFrameId); // Stop continuous frame processing
154
+ cancelAnimationFrame(this.animationFrameId);
133
155
  this.animationFrameId = null;
134
156
  }
135
- const timer = setInterval(() => {
136
- this.countdown--;
137
- if (this.countdown <= 0) {
138
- clearInterval(timer);
139
- this.capture();
140
- this.stopRecording();
141
- this.isDetecting = false;
142
- console.log('Picture taken. You can now stop recording.');
143
- this.countdown = 0; // Ensure countdown is 0
144
- }
145
- }, 1000);
146
157
  }
147
- }
148
- catch (error) {
149
- console.error('OpenCV processing error:', error);
150
- this.isDetecting = false; // Stop detection on error
151
- if (this.animationFrameId !== null) {
152
- cancelAnimationFrame(this.animationFrameId);
153
- this.animationFrameId = null;
158
+ finally {
159
+ // Crucial: Release memory allocated by OpenCV Mat objects
160
+ src.delete();
161
+ gray.delete();
162
+ blurred.delete();
163
+ edges.delete();
164
+ contours.delete();
165
+ hierarchy.delete();
154
166
  }
155
167
  }
156
- finally {
157
- // Crucial: Release memory allocated by OpenCV Mat objects
158
- src.delete();
159
- gray.delete();
160
- blurred.delete();
161
- edges.delete();
162
- contours.delete();
163
- hierarchy.delete();
168
+ catch (error) {
169
+ console.error('Error processing video frame with OpenCV:', error);
164
170
  }
165
171
  // --- OpenCV.js processing ends here ---
166
172
  }
@@ -222,10 +228,6 @@ export class IdAutoCapture {
222
228
  this.loadOpenCVScript();
223
229
  // Listen for the custom event dispatched by global.ts (ensures global.ts sets up window.Module)
224
230
  document.addEventListener('opencv:ready', this.handleOpencvReady);
225
- // Initial check in case opencv.js loads very fast and event was already dispatched
226
- if (typeof cv !== 'undefined' && cv.Mat) {
227
- this.handleOpencvReady();
228
- }
229
231
  }
230
232
  disconnectedCallback() {
231
233
  if (this.mediaStream) {
@@ -246,7 +248,7 @@ export class IdAutoCapture {
246
248
  }
247
249
  }
248
250
  loadOpenCVScript() {
249
- if (!this.opencvScriptElement) {
251
+ if (!document.querySelector('script[src="https://docs.opencv.org/4.x/opencv.js"]')) {
250
252
  // Only load if not already loaded
251
253
  this.opencvScriptElement = document.createElement('script');
252
254
  this.opencvScriptElement.type = 'text/javascript';
@@ -255,6 +257,9 @@ export class IdAutoCapture {
255
257
  document.body.appendChild(this.opencvScriptElement); // Append to body or head
256
258
  console.log('Dynamically loaded opencv.js');
257
259
  }
260
+ else {
261
+ console.log('OpenCV.js script already present in the DOM.');
262
+ }
258
263
  }
259
264
  // Method to get user media (camera stream)
260
265
  async getMedia() {
@@ -279,7 +284,7 @@ export class IdAutoCapture {
279
284
  if (store.device.isDesktop) {
280
285
  cameraVideoClass = 'cameraVideoSelfieDesk';
281
286
  }
282
- return (h("div", { key: '32fa99f679fbbc0009608aeb2eeb26645dbadb59', class: "container flex center" }, h("div", { key: '08ee0848724b359253d27120fe5e2751372cab1e', class: "px-2 w-100" }, h("h1", { key: '570154c491f44b72f5a6794f17b1a19c964a55e5', class: this.titleStyle, innerHTML: this.titleMesage }), h("div", { key: '2a626737524f5748e4d6faeb109f3dc59fe3388b', hidden: this.verified }, h("div", { key: 'f38962922b06f902790d9d549c3d1c507cafb8b8', class: "w-100 h-100 rounded" }, h("div", { key: '7c69f659183dfdfab7ea759c1a5a574af19df679', class: "camera rounded" }, h("video", { key: '7f378deee95b9821715add1f9b66e9299b6e4380', id: "video", loop: true, autoplay: true, playsinline: true, muted: true, class: cameraVideoClass, ref: el => (this.videoElement = el) }), h("canvas", { key: '8150fbc30e908e011f415b73a0e3f2d8711f2d20', id: "output", ref: el => (this.canvasElement = el), style: { display: 'none' } }), h("canvas", { key: '54887d1f9266d32f653760ff6e70971e2d525c0a', id: "processingCanvasElement", ref: el => (this.processingCanvasElement = el), style: { display: 'none' } }), h("div", { key: 'cf656641dcb1cf1bf845c28a97630c72f7da8fe6', class: "id-guide-rectangle" }), this.isCapturing && h("div", { key: 'eabb935e014eb3966940a27a5aa100477249dbba', class: "capture-flash-overlay" }), this.countdown > 0 && (h("div", { key: 'e8a05e21e03673637e0194b3d967ed0044891a01', class: "absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center" }, h("span", { key: 'f6996d51686b935aa4aaa6f2abe4062d5782c116', class: "text-white text-9xl font-bold animate-bounce" }, this.countdown)))))), h("div", { key: 'd4fc6a0ff5951767a43f9166fcf47f98b4d209a7', class: "footer text-center" }, h("img", { key: 'a84cc0c65a6684807abf314d9839babe16768494', src: logoOntrace })))));
287
+ return (h("div", { key: 'deb2d35a50823fa5c222c6049a4119a371194870', class: "container flex center" }, h("div", { key: '449a0fef911f14d3611a1d7e83ed1bfc02c0553f', class: "px-2 w-100" }, h("h1", { key: '8d9f8b3684e58ba57f4ec0467efa0d9af62c5a98', class: this.titleStyle, innerHTML: this.titleMesage }), h("div", { key: '701aeecc148bdd00ef9cd38b165f0628adfe827c', hidden: this.verified }, h("div", { key: 'cbe89cf4ddc15c46b595929ecaf4fb8cc20136b5', class: "w-100 h-100 rounded" }, h("div", { key: '78f52a0a77c3dd8218115253bbcb79ee0a9a6d4b', class: "camera rounded" }, h("video", { key: '6ee76764205ce855fedd7b8c86be4394b2cad7bb', id: "video", loop: true, autoplay: true, playsinline: true, muted: true, class: cameraVideoClass, ref: el => (this.videoElement = el) }), h("canvas", { key: '5574b79a997d3ca06afa99faa61cb9bace755e91', id: "output", ref: el => (this.canvasElement = el), style: { display: 'none' } }), h("canvas", { key: 'e25df7ef70206d5544adade008cd612f1fee550a', id: "processingCanvasElement", ref: el => (this.processingCanvasElement = el), style: { display: 'none' } }), h("div", { key: '8ac6db08f2d1e44d04f2827f29e08787b853812e', class: "id-guide-rectangle" }), this.isCapturing && h("div", { key: '900ddcc0d2bf371d7ad4e593eaf0e9b60b6d2810', class: "capture-flash-overlay" }), this.countdown > 0 && (h("div", { key: 'd5f05c1b3dcbd02977462c6b9d816c2835698c2f', class: "absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center" }, h("span", { key: '7b85d36f1b609360c8214a29e220f6f80effffca', class: "text-white text-9xl font-bold animate-bounce" }, this.countdown)))))), h("div", { key: '9b653ebb92ce731ddb235d85db4a7fa99aaa4c64', class: "footer text-center" }, h("img", { key: 'f085d8f1698e66448cf749ec4cc45b496fbd55a1', src: logoOntrace })))));
283
288
  }
284
289
  static get is() { return "id-auto-capture"; }
285
290
  static get originalStyleUrls() {
@@ -1 +1 @@
1
- {"version":3,"file":"id-auto-capture.js","sourceRoot":"","sources":["../../../../../src/components/common/id-auto-capture/id-auto-capture.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAgB,KAAK,EAAE,MAAM,eAAe,CAAC;AAElF,OAAO,WAAW,MAAM,kCAAkC,CAAC;AAC3D,OAAO,KAAK,MAAM,wBAAwB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAS5D,MAAM,OAAO,aAAa;IAgCxB;QA3BQ,kBAAa,GAAyB,IAAI,CAAC;QAC3C,gBAAW,GAAuB,IAAI,CAAC;QACvC,qBAAgB,GAAkB,IAAI,CAAC,CAAC,kCAAkC;QAC1E,wBAAmB,GAA6B,IAAI,CAAC;QAKpD,mBAAc,GAAW,EAAE,CAAC;QAC5B,cAAS,GAAW,CAAC,CAAC;QACtB,kBAAa,GAAkB,IAAI,CAAC;QACpC,gBAAW,GAAY,KAAK,CAAC;QAC7B,qBAAgB,GAAkB,IAAI,CAAC;QACvC,gBAAW,GAAY,KAAK,CAAC;QAC7B,gBAAW,GAAY,KAAK,CAAC;QAC7B,gBAAW,GAAY,KAAK,CAAC;QAqE9B,sBAAiB,GAAG,KAAK,IAAI,EAAE;YACrC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;YAC3D,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,wCAAwC;YAC/D,MAAM,IAAI,CAAC,oBAAoB,EAAE,CAAC,CAAC,gCAAgC;QACrE,CAAC,CAAC;QAqBF,kCAAkC;QAC1B,mBAAc,GAAG,GAAG,EAAE;YAC5B,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBAC1C,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,CAAC,wBAAwB;gBAElD,IAAI,OAAO,GAAG,EAAE,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,CAAC;gBAEnF,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACrD,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,IAAI,QAAQ,CAAC,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM;wBAAE,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;gBACnI,CAAC;gBAED,IAAI,CAAC,aAAa,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,CAAC;gBAErF,IAAI,CAAC,aAAa,CAAC,eAAe,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;oBAChD,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;wBAClB,IAAI,CAAC,cAAc,GAAG,CAAC,GAAG,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;oBACvD,CAAC;gBACH,CAAC,CAAC;gBAEF,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,GAAG,EAAE;oBAC/B,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACnC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;wBACnE,IAAI,CAAC,gBAAgB,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;oBACpD,CAAC;gBACH,CAAC,CAAC;gBAEF,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;gBAC3B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;gBACxB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;YACtC,CAAC;QACH,CAAC,CAAC;QAEF,iCAAiC;QACzB,kBAAa,GAAG,GAAG,EAAE;YAC3B,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,aAAa,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;gBACnE,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;gBAC1B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;gBAClC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACzD,CAAC;QACH,CAAC,CAAC;QAEF,mDAAmD;QAC3C,YAAO,GAAG,GAAG,EAAE;YACrB,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;gBAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC;gBAChC,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC;gBAClC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBAExC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC;gBAChC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC;gBAElC,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;gBAE5D,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;gBACnD,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;gBAC/B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBAErB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;gBACxB,UAAU,CAAC,GAAG,EAAE;oBACd,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;gBAC3B,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,kBAAkB;gBAE3B,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAClD,CAAC;QACH,CAAC,CAAC;QAEF,2DAA2D;QACnD,sBAAiB,GAAG,GAAG,EAAE;YAC/B,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,uBAAuB,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC9F,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC;gBAChC,MAAM,gBAAgB,GAAG,IAAI,CAAC,uBAAuB,CAAC;gBACtD,MAAM,OAAO,GAAG,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBAElD,gBAAgB,CAAC,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC;gBAC1C,gBAAgB,CAAC,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC;gBAE5C,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;gBAEhF,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;gBAE9F,2CAA2C;gBAC3C,IAAI,GAAG,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;gBAClF,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;gBAC7B,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;gBACxB,IAAI,OAAO,GAAG,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;gBAC3B,IAAI,KAAK,GAAG,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;gBACzB,IAAI,QAAQ,GAAG,IAAI,EAAE,CAAC,SAAS,EAAE,CAAC;gBAClC,IAAI,SAAS,GAAG,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;gBAE7B,IAAI,CAAC;oBACH,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;oBAC9C,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC;oBAC3E,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;oBAC5C,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,mBAAmB,CAAC,CAAC;oBAEtF,IAAI,UAAU,GAAG,KAAK,CAAC;oBACvB,IAAI,OAAO,GAAG,CAAC,CAAC;oBAChB,sBAAsB;oBAEtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;wBACzC,IAAI,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;wBAC9B,IAAI,IAAI,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;wBAEnC,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,OAAO,EAAE,CAAC;4BAClC,IAAI,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;4BACvC,IAAI,MAAM,GAAG,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;4BAC1B,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC;4BAEpD,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;gCACtB,IAAI,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;gCACnC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;gCAE7C,IAAI,WAAW,GAAG,GAAG,IAAI,WAAW,GAAG,GAAG,EAAE,CAAC;oCAC3C,IAAI,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,UAAU,GAAG,GAAG,IAAI,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,WAAW,GAAG,GAAG,EAAE,CAAC;wCACjF,UAAU,GAAG,IAAI,CAAC;wCAClB,OAAO,GAAG,IAAI,CAAC;wCACf,kBAAkB;oCACpB,CAAC;gCACH,CAAC;4BACH,CAAC;4BACD,MAAM,CAAC,MAAM,EAAE,CAAC;wBAClB,CAAC;wBACD,OAAO,CAAC,MAAM,EAAE,CAAC;oBACnB,CAAC;oBAED,IAAI,UAAU,EAAE,CAAC;wBACf,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;wBAC3D,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;wBACnB,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;4BACnC,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,mCAAmC;4BAChF,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;wBAC/B,CAAC;wBAED,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;4BAC7B,IAAI,CAAC,SAAS,EAAE,CAAC;4BACjB,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,EAAE,CAAC;gCACxB,aAAa,CAAC,KAAK,CAAC,CAAC;gCACrB,IAAI,CAAC,OAAO,EAAE,CAAC;gCACf,IAAI,CAAC,aAAa,EAAE,CAAC;gCACrB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;gCACzB,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;gCAC1D,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,wBAAwB;4BAC9C,CAAC;wBACH,CAAC,EAAE,IAAI,CAAC,CAAC;oBACX,CAAC;gBACH,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;oBACjD,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,CAAC,0BAA0B;oBACpD,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;wBACnC,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;wBAC5C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;oBAC/B,CAAC;gBACH,CAAC;wBAAS,CAAC;oBACT,0DAA0D;oBAC1D,GAAG,CAAC,MAAM,EAAE,CAAC;oBACb,IAAI,CAAC,MAAM,EAAE,CAAC;oBACd,OAAO,CAAC,MAAM,EAAE,CAAC;oBACjB,KAAK,CAAC,MAAM,EAAE,CAAC;oBACf,QAAQ,CAAC,MAAM,EAAE,CAAC;oBAClB,SAAS,CAAC,MAAM,EAAE,CAAC;gBACrB,CAAC;gBACD,yCAAyC;YAC3C,CAAC;YAED,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;gBACvD,gDAAgD;gBAChD,IAAI,CAAC,gBAAgB,GAAG,qBAAqB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YACxE,CAAC;QACH,CAAC,CAAC;QAEF,mDAAmD;QAC3C,yBAAoB,GAAG,GAAG,EAAE;YAClC,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC;gBAC/E,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;oBACnC,oCAAoC;oBACpC,IAAI,CAAC,gBAAgB,GAAG,qBAAqB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBACxE,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QAEF,gDAAgD;QACxC,yBAAoB,GAAG,KAAK,IAAI,EAAE;YACxC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACtB,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;gBAC7D,OAAO;YACT,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACtB,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;gBACzD,OAAO;YACT,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;YACxC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC,uBAAuB;YAClD,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,CAAC,8BAA8B;YACxD,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC,2BAA2B;YAEzD,IAAI,CAAC,cAAc,EAAE,CAAC;YAEtB,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;gBAC1D,wFAAwF;gBACxF,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;gBACzD,MAAM,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE;oBAChC,MAAM,gBAAgB,GAAG,GAAG,EAAE;wBAC5B,IAAI,CAAC,YAAY,CAAC,mBAAmB,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;wBAC1E,OAAO,EAAE,CAAC;oBACZ,CAAC,CAAC;oBACF,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;gBACzE,CAAC,CAAC,CAAC;gBACH,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;YACzD,CAAC;YAED,IAAI,CAAC,oBAAoB,EAAE,CAAC,CAAC,yCAAyC;QACxE,CAAC,CAAC;QAxSA,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;KACvB;IAED,kFAAkF;IAClF,KAAK,CAAC,iBAAiB;QACrB,wEAAwE;QACxE,8EAA8E;QAC9E,gEAAgE;IAClE,CAAC;IAED,4EAA4E;IAC5E,KAAK,CAAC,gBAAgB;QACpB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACpC,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAExB,gGAAgG;QAChG,QAAQ,CAAC,gBAAgB,CAAC,cAAc,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAElE,mFAAmF;QACnF,IAAI,OAAO,EAAE,KAAK,WAAW,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;YACxC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,oBAAoB;QAClB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;YACnC,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAC5C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC/B,CAAC;QACD,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC7C,CAAC;QACD,QAAQ,CAAC,mBAAmB,CAAC,cAAc,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAErE,qDAAqD;QACrD,IAAI,IAAI,CAAC,mBAAmB,IAAI,IAAI,CAAC,mBAAmB,CAAC,UAAU,EAAE,CAAC;YACpE,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YAC1E,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;QAClC,CAAC;IACH,CAAC;IAEO,gBAAgB;QACtB,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC9B,kCAAkC;YAClC,IAAI,CAAC,mBAAmB,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAC5D,IAAI,CAAC,mBAAmB,CAAC,IAAI,GAAG,iBAAiB,CAAC;YAClD,IAAI,CAAC,mBAAmB,CAAC,KAAK,GAAG,IAAI,CAAC;YACtC,IAAI,CAAC,mBAAmB,CAAC,GAAG,GAAG,uCAAuC,CAAC;YACvE,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,yBAAyB;YAC9E,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IASD,2CAA2C;IACnC,KAAK,CAAC,QAAQ;QACpB,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACpB,MAAM,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAC1C,CAAC;YACD,MAAM,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;YAEzE,MAAM,WAAW,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;YAC3E,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBACtB,IAAI,CAAC,YAAY,CAAC,SAAS,GAAG,WAAW,CAAC;gBAC1C,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;YAC3B,CAAC;YACD,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IA0ND,MAAM;QACJ,IAAI,gBAAgB,GAAG,aAAa,CAAC;QAErC,IAAI,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YAC3B,gBAAgB,GAAG,uBAAuB,CAAC;QAC7C,CAAC;QAED,OAAO,CACL,4DAAK,KAAK,EAAC,uBAAuB;YAChC,4DAAK,KAAK,EAAC,YAAY;gBACrB,2DAAI,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,CAAC,WAAW,GAAO;gBAE9D,4DAAK,MAAM,EAAE,IAAI,CAAC,QAAQ;oBACxB,4DAAK,KAAK,EAAC,qBAAqB;wBAC9B,4DAAK,KAAK,EAAC,gBAAgB;4BACzB,8DAAO,EAAE,EAAC,OAAO,EAAC,IAAI,QAAC,QAAQ,QAAC,WAAW,QAAC,KAAK,QAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC,GAAI;4BAClH,+DAAQ,EAAE,EAAC,QAAQ,EAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAI;4BACxF,+DAAQ,EAAE,EAAC,yBAAyB,EAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,uBAAuB,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAI;4BACnH,4DAAK,KAAK,EAAC,oBAAoB,GAAO;4BACrC,IAAI,CAAC,WAAW,IAAI,4DAAK,KAAK,EAAC,uBAAuB,GAAO;4BAC7D,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,CACrB,4DAAK,KAAK,EAAC,0EAA0E;gCACnF,6DAAM,KAAK,EAAC,8CAA8C,IAAE,IAAI,CAAC,SAAS,CAAQ,CAC9E,CACP,CACG,CACF,CACF;gBACN,4DAAK,KAAK,EAAC,oBAAoB;oBAC7B,4DAAK,GAAG,EAAE,WAAW,GAAQ,CACzB,CACF,CACF,CACP,CAAC;IACJ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CACF","sourcesContent":["import { Component, h, Element, Event, EventEmitter, State } from '@stencil/core';\r\n\r\nimport logoOntrace from '../../../assets/logo-ontrace.svg';\r\nimport store from '../../../helpers/store';\r\nimport { Cameras } from '../../../helpers/Cameras';\r\nimport { Browser, MobileOS } from '../../../models/IDevice';\r\n\r\ndeclare const cv: any;\r\n\r\n@Component({\r\n tag: 'id-auto-capture',\r\n styleUrl: 'id-auto-capture.css',\r\n shadow: false,\r\n})\r\nexport class IdAutoCapture {\r\n @Element() el: HTMLElement;\r\n private videoElement: HTMLVideoElement;\r\n private canvasElement: HTMLCanvasElement;\r\n private processingCanvasElement: HTMLCanvasElement; // For OpenCV frame processing\r\n private mediaRecorder: MediaRecorder | null = null;\r\n private mediaStream: MediaStream | null = null;\r\n private animationFrameId: number | null = null; // To manage requestAnimationFrame\r\n private opencvScriptElement: HTMLScriptElement | null = null;\r\n\r\n @State() private verified: boolean;\r\n @State() private titleMesage: string;\r\n @State() private titleStyle: string;\r\n @State() recordedChunks: Blob[] = [];\r\n @State() countdown: number = 0;\r\n @State() capturedImage: string | null = null;\r\n @State() isRecording: boolean = false;\r\n @State() recordedVideoUrl: string | null = null;\r\n @State() isDetecting: boolean = false;\r\n @State() opencvReady: boolean = false;\r\n @State() isCapturing: boolean = false;\r\n\r\n @Event({\r\n eventName: 'photoIdCapture',\r\n })\r\n eventPhotoCapture: EventEmitter;\r\n\r\n @Event({\r\n eventName: 'recordingIdCapture',\r\n })\r\n eventRecordingIdReady: EventEmitter;\r\n\r\n constructor() {\r\n this.verified = false;\r\n }\r\n\r\n // Lifecycle method: Called once after the component is first connected to the DOM\r\n async componentWillLoad() {\r\n // Initialize DOM element references after the component's render method\r\n // has placed them in the DOM. This should ideally be done in componentDidLoad\r\n // but can be set up to ensure elements are available for setup.\r\n }\r\n\r\n // Lifecycle method: Called once after the component has loaded and rendered\r\n async componentDidLoad() {\r\n console.log('Loading OpenCV.js...');\r\n this.loadOpenCVScript();\r\n\r\n // Listen for the custom event dispatched by global.ts (ensures global.ts sets up window.Module)\r\n document.addEventListener('opencv:ready', this.handleOpencvReady);\r\n\r\n // Initial check in case opencv.js loads very fast and event was already dispatched\r\n if (typeof cv !== 'undefined' && cv.Mat) {\r\n this.handleOpencvReady();\r\n }\r\n }\r\n\r\n disconnectedCallback() {\r\n if (this.mediaStream) {\r\n this.mediaStream.getTracks().forEach(track => track.stop());\r\n }\r\n if (this.animationFrameId !== null) {\r\n cancelAnimationFrame(this.animationFrameId);\r\n this.animationFrameId = null;\r\n }\r\n if (this.recordedVideoUrl) {\r\n URL.revokeObjectURL(this.recordedVideoUrl);\r\n }\r\n document.removeEventListener('opencv:ready', this.handleOpencvReady);\r\n\r\n // NEW: Clean up the dynamically added script element\r\n if (this.opencvScriptElement && this.opencvScriptElement.parentNode) {\r\n this.opencvScriptElement.parentNode.removeChild(this.opencvScriptElement);\r\n this.opencvScriptElement = null;\r\n }\r\n }\r\n\r\n private loadOpenCVScript() {\r\n if (!this.opencvScriptElement) {\r\n // Only load if not already loaded\r\n this.opencvScriptElement = document.createElement('script');\r\n this.opencvScriptElement.type = 'text/javascript';\r\n this.opencvScriptElement.async = true;\r\n this.opencvScriptElement.src = 'https://docs.opencv.org/4.x/opencv.js';\r\n document.body.appendChild(this.opencvScriptElement); // Append to body or head\r\n console.log('Dynamically loaded opencv.js');\r\n }\r\n }\r\n\r\n private handleOpencvReady = async () => {\r\n this.opencvReady = true;\r\n console.log('OpenCV.js loaded. Ready to start detection.');\r\n await this.getMedia(); // Get camera media once OpenCV is ready\r\n await this.handleStartDetection(); // Start processing video frames\r\n };\r\n\r\n // Method to get user media (camera stream)\r\n private async getMedia() {\r\n try {\r\n if (!store.cameraId) {\r\n await Cameras.InitCameras(store.device);\r\n }\r\n const constraints = Cameras.GetConstraints(store.cameraId, store.device);\r\n\r\n const mediaStream = await navigator.mediaDevices.getUserMedia(constraints);\r\n if (this.videoElement) {\r\n this.videoElement.srcObject = mediaStream;\r\n this.videoElement.play();\r\n }\r\n this.mediaStream = mediaStream;\r\n } catch (err) {\r\n console.error('Error accessing camera:', err);\r\n }\r\n }\r\n\r\n // Method to start video recording\r\n private startRecording = () => {\r\n if (this.mediaStream && this.videoElement) {\r\n this.recordedChunks = []; // Clear previous chunks\r\n\r\n var options = { mimeType: Cameras.webmMimeType.mime, videoBitsPerSecond: 1300000 };\r\n\r\n if (!MediaRecorder.isTypeSupported(options.mimeType)) {\r\n if (store.device.mobileOS == MobileOS.iOS || store.device.browser == Browser.Safari) options.mimeType = Cameras.mp4MimeType.mime;\r\n }\r\n\r\n this.mediaRecorder = new MediaRecorder(this.mediaStream, { mimeType: 'video/webm' });\r\n\r\n this.mediaRecorder.ondataavailable = ({ data }) => {\r\n if (data.size > 0) {\r\n this.recordedChunks = [...this.recordedChunks, data];\r\n }\r\n };\r\n\r\n this.mediaRecorder.onstop = () => {\r\n if (this.recordedChunks.length > 0) {\r\n const blob = new Blob(this.recordedChunks, { type: 'video/webm' });\r\n this.recordedVideoUrl = URL.createObjectURL(blob);\r\n }\r\n };\r\n\r\n this.mediaRecorder.start();\r\n this.isRecording = true;\r\n console.log('Recording started...');\r\n }\r\n };\r\n\r\n // Method to stop video recording\r\n private stopRecording = () => {\r\n if (this.mediaRecorder && this.mediaRecorder.state === 'recording') {\r\n this.mediaRecorder.stop();\r\n this.isRecording = false;\r\n console.log('Recording stopped.');\r\n this.eventRecordingIdReady.emit(this.recordedVideoUrl);\r\n }\r\n };\r\n\r\n // Method to capture an image from the video stream\r\n private capture = () => {\r\n if (this.videoElement && this.canvasElement) {\r\n const video = this.videoElement;\r\n const canvas = this.canvasElement;\r\n const context = canvas.getContext('2d');\r\n\r\n canvas.width = video.videoWidth;\r\n canvas.height = video.videoHeight;\r\n\r\n context.drawImage(video, 0, 0, canvas.width, canvas.height);\r\n\r\n this.capturedImage = canvas.toDataURL('image/png');\r\n console.log('Image captured!');\r\n this.verified = true;\r\n\r\n this.isCapturing = true;\r\n setTimeout(() => {\r\n this.isCapturing = false;\r\n }, 200); // Flash for 200ms\r\n\r\n this.eventPhotoCapture.emit(this.capturedImage);\r\n }\r\n };\r\n\r\n // Method for continuous video frame processing with OpenCV\r\n private processVideoFrame = () => {\r\n if (this.videoElement && this.processingCanvasElement && this.opencvReady && this.isDetecting) {\r\n const video = this.videoElement;\r\n const processingCanvas = this.processingCanvasElement;\r\n const context = processingCanvas.getContext('2d');\r\n\r\n processingCanvas.width = video.videoWidth;\r\n processingCanvas.height = video.videoHeight;\r\n\r\n context.drawImage(video, 0, 0, processingCanvas.width, processingCanvas.height);\r\n\r\n const imageData = context.getImageData(0, 0, processingCanvas.width, processingCanvas.height);\r\n\r\n // --- OpenCV.js processing starts here ---\r\n let src = new cv.Mat(processingCanvas.height, processingCanvas.width, cv.CV_8UC4);\r\n src.data.set(imageData.data);\r\n let gray = new cv.Mat();\r\n let blurred = new cv.Mat();\r\n let edges = new cv.Mat();\r\n let contours = new cv.MatVector();\r\n let hierarchy = new cv.Mat();\r\n\r\n try {\r\n cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);\r\n cv.GaussianBlur(gray, blurred, new cv.Size(5, 5), 0, 0, cv.BORDER_DEFAULT);\r\n cv.Canny(blurred, edges, 75, 200, 3, false);\r\n cv.findContours(edges, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);\r\n\r\n let idDetected = false;\r\n let maxArea = 0;\r\n //let bestRect = null;\r\n\r\n for (let i = 0; i < contours.size(); ++i) {\r\n let contour = contours.get(i);\r\n let area = cv.contourArea(contour);\r\n\r\n if (area > 1000 && area > maxArea) {\r\n let peri = cv.arcLength(contour, true);\r\n let approx = new cv.Mat();\r\n cv.approxPolyDP(contour, approx, 0.02 * peri, true);\r\n\r\n if (approx.rows === 4) {\r\n let rect = cv.boundingRect(approx);\r\n const aspectRatio = rect.width / rect.height;\r\n\r\n if (aspectRatio > 1.4 && aspectRatio < 1.8) {\r\n if (rect.width > video.videoWidth * 0.3 && rect.height > video.videoHeight * 0.3) {\r\n idDetected = true;\r\n maxArea = area;\r\n //bestRect = rect;\r\n }\r\n }\r\n }\r\n approx.delete();\r\n }\r\n contour.delete();\r\n }\r\n\r\n if (idDetected) {\r\n console.log('ID document detected! Starting countdown...');\r\n this.countdown = 3;\r\n if (this.animationFrameId !== null) {\r\n cancelAnimationFrame(this.animationFrameId); // Stop continuous frame processing\r\n this.animationFrameId = null;\r\n }\r\n\r\n const timer = setInterval(() => {\r\n this.countdown--;\r\n if (this.countdown <= 0) {\r\n clearInterval(timer);\r\n this.capture();\r\n this.stopRecording();\r\n this.isDetecting = false;\r\n console.log('Picture taken. You can now stop recording.');\r\n this.countdown = 0; // Ensure countdown is 0\r\n }\r\n }, 1000);\r\n }\r\n } catch (error) {\r\n console.error('OpenCV processing error:', error);\r\n this.isDetecting = false; // Stop detection on error\r\n if (this.animationFrameId !== null) {\r\n cancelAnimationFrame(this.animationFrameId);\r\n this.animationFrameId = null;\r\n }\r\n } finally {\r\n // Crucial: Release memory allocated by OpenCV Mat objects\r\n src.delete();\r\n gray.delete();\r\n blurred.delete();\r\n edges.delete();\r\n contours.delete();\r\n hierarchy.delete();\r\n }\r\n // --- OpenCV.js processing ends here ---\r\n }\r\n\r\n if (this.isDetecting && this.animationFrameId !== null) {\r\n // Ensure loop continues only if still detecting\r\n this.animationFrameId = requestAnimationFrame(this.processVideoFrame);\r\n }\r\n };\r\n\r\n // Method to start the OpenCV frame processing loop\r\n private startFrameProcessing = () => {\r\n if (this.opencvReady && this.videoElement && this.videoElement.readyState >= 2) {\r\n if (this.animationFrameId === null) {\r\n // Only start if not already running\r\n this.animationFrameId = requestAnimationFrame(this.processVideoFrame);\r\n }\r\n }\r\n };\r\n\r\n // Handler for starting the ID detection process\r\n private handleStartDetection = async () => {\r\n if (!this.mediaStream) {\r\n console.log('Camera not ready. Please allow camera access.');\r\n return;\r\n }\r\n if (!this.opencvReady) {\r\n console.log('OpenCV.js is not loaded yet. Please wait.');\r\n return;\r\n }\r\n\r\n console.log('Starting ID detection...');\r\n this.isDetecting = true;\r\n this.capturedImage = null; // Clear previous image\r\n this.recordedChunks = []; // Clear previous video chunks\r\n this.recordedVideoUrl = null; // Clear previous video URL\r\n\r\n this.startRecording();\r\n\r\n if (this.videoElement && this.videoElement.readyState < 3) {\r\n // Use readyState 3 (HAVE_FUTURE_DATA) or 4 (HAVE_ENOUGH_DATA) for more robust readiness\r\n console.log('Waiting for video stream to fully load...');\r\n await new Promise<void>(resolve => {\r\n const onCanPlayThrough = () => {\r\n this.videoElement.removeEventListener('canplaythrough', onCanPlayThrough);\r\n resolve();\r\n };\r\n this.videoElement.addEventListener('canplaythrough', onCanPlayThrough);\r\n });\r\n console.log('Video stream ready. Starting detection.');\r\n }\r\n\r\n this.startFrameProcessing(); // Start the OpenCV frame processing loop\r\n };\r\n\r\n render() {\r\n let cameraVideoClass = 'cameraVideo';\r\n\r\n if (store.device.isDesktop) {\r\n cameraVideoClass = 'cameraVideoSelfieDesk';\r\n }\r\n\r\n return (\r\n <div class=\"container flex center\">\r\n <div class=\"px-2 w-100\">\r\n <h1 class={this.titleStyle} innerHTML={this.titleMesage}></h1>\r\n\r\n <div hidden={this.verified}>\r\n <div class=\"w-100 h-100 rounded\">\r\n <div class=\"camera rounded\">\r\n <video id=\"video\" loop autoplay playsinline muted class={cameraVideoClass} ref={el => (this.videoElement = el)} />\r\n <canvas id=\"output\" ref={el => (this.canvasElement = el)} style={{ display: 'none' }} />\r\n <canvas id=\"processingCanvasElement\" ref={el => (this.processingCanvasElement = el)} style={{ display: 'none' }} />\r\n <div class=\"id-guide-rectangle\"></div>\r\n {this.isCapturing && <div class=\"capture-flash-overlay\"></div>}\r\n {this.countdown > 0 && (\r\n <div class=\"absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center\">\r\n <span class=\"text-white text-9xl font-bold animate-bounce\">{this.countdown}</span>\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"footer text-center\">\r\n <img src={logoOntrace}></img>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"id-auto-capture.js","sourceRoot":"","sources":["../../../../../src/components/common/id-auto-capture/id-auto-capture.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAgB,KAAK,EAAE,MAAM,eAAe,CAAC;AAElF,OAAO,WAAW,MAAM,kCAAkC,CAAC;AAC3D,OAAO,KAAK,MAAM,wBAAwB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAS5D,MAAM,OAAO,aAAa;IAgCxB;QA3BQ,kBAAa,GAAyB,IAAI,CAAC;QAC3C,gBAAW,GAAuB,IAAI,CAAC;QACvC,qBAAgB,GAAkB,IAAI,CAAC,CAAC,kCAAkC;QAC1E,wBAAmB,GAA6B,IAAI,CAAC;QAKpD,mBAAc,GAAW,EAAE,CAAC;QAC5B,cAAS,GAAW,CAAC,CAAC;QACtB,kBAAa,GAAkB,IAAI,CAAC;QACpC,gBAAW,GAAY,KAAK,CAAC;QAC7B,qBAAgB,GAAkB,IAAI,CAAC;QACvC,gBAAW,GAAY,KAAK,CAAC;QAC7B,gBAAW,GAAY,KAAK,CAAC;QAC7B,gBAAW,GAAY,KAAK,CAAC;QAkE9B,sBAAiB,GAAG,KAAK,IAAI,EAAE;YACrC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;YAC3D,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,wCAAwC;YAC/D,MAAM,IAAI,CAAC,oBAAoB,EAAE,CAAC,CAAC,gCAAgC;QACrE,CAAC,CAAC;QAqBF,kCAAkC;QAC1B,mBAAc,GAAG,GAAG,EAAE;YAC5B,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBAC1C,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,CAAC,wBAAwB;gBAElD,IAAI,OAAO,GAAG,EAAE,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,CAAC;gBAEnF,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACrD,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,IAAI,QAAQ,CAAC,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM;wBAAE,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;gBACnI,CAAC;gBAED,IAAI,CAAC,aAAa,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,CAAC;gBAErF,IAAI,CAAC,aAAa,CAAC,eAAe,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;oBAChD,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;wBAClB,IAAI,CAAC,cAAc,GAAG,CAAC,GAAG,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;oBACvD,CAAC;gBACH,CAAC,CAAC;gBAEF,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,GAAG,EAAE;oBAC/B,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACnC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;wBACnE,IAAI,CAAC,gBAAgB,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;oBACpD,CAAC;gBACH,CAAC,CAAC;gBAEF,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;gBAC3B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;gBACxB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;YACtC,CAAC;QACH,CAAC,CAAC;QAEF,iCAAiC;QACzB,kBAAa,GAAG,GAAG,EAAE;YAC3B,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,aAAa,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;gBACnE,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;gBAC1B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;gBAClC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACzD,CAAC;QACH,CAAC,CAAC;QAEF,mDAAmD;QAC3C,YAAO,GAAG,GAAG,EAAE;YACrB,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;gBAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC;gBAChC,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC;gBAClC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBAExC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC;gBAChC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC;gBAElC,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;gBAE5D,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;gBACnD,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;gBAC/B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBAErB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;gBACxB,UAAU,CAAC,GAAG,EAAE;oBACd,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;gBAC3B,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,kBAAkB;gBAE3B,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAClD,CAAC;QACH,CAAC,CAAC;QAEF,2DAA2D;QACnD,sBAAiB,GAAG,GAAG,EAAE;YAC/B,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,uBAAuB,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC9F,IAAI,CAAC;oBACH,OAAO,CAAC,GAAG,CAAC,4CAA4C,EAAE,OAAO,EAAE,CAAC,GAAG,KAAK,UAAU,CAAC,CAAC;oBACxF,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC;oBAChC,MAAM,gBAAgB,GAAG,IAAI,CAAC,uBAAuB,CAAC;oBACtD,MAAM,OAAO,GAAG,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;oBAElD,gBAAgB,CAAC,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC;oBAC1C,gBAAgB,CAAC,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC;oBAE5C,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;oBAEhF,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;oBAE9F,2CAA2C;oBAC3C,IAAI,GAAG,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;oBAClF,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;oBAC7B,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;oBACxB,IAAI,OAAO,GAAG,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;oBAC3B,IAAI,KAAK,GAAG,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;oBACzB,IAAI,QAAQ,GAAG,IAAI,EAAE,CAAC,SAAS,EAAE,CAAC;oBAClC,IAAI,SAAS,GAAG,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;oBAE7B,IAAI,CAAC;wBACH,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;wBAC9C,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC;wBAC3E,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;wBAC5C,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,mBAAmB,CAAC,CAAC;wBAEtF,IAAI,UAAU,GAAG,KAAK,CAAC;wBACvB,IAAI,OAAO,GAAG,CAAC,CAAC;wBAChB,sBAAsB;wBAEtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;4BACzC,IAAI,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;4BAC9B,IAAI,IAAI,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;4BAEnC,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,OAAO,EAAE,CAAC;gCAClC,IAAI,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;gCACvC,IAAI,MAAM,GAAG,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC;gCAC1B,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,CAAC,CAAC;gCAEpD,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;oCACtB,IAAI,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;oCACnC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;oCAE7C,IAAI,WAAW,GAAG,GAAG,IAAI,WAAW,GAAG,GAAG,EAAE,CAAC;wCAC3C,IAAI,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,UAAU,GAAG,GAAG,IAAI,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,WAAW,GAAG,GAAG,EAAE,CAAC;4CACjF,UAAU,GAAG,IAAI,CAAC;4CAClB,OAAO,GAAG,IAAI,CAAC;4CACf,kBAAkB;wCACpB,CAAC;oCACH,CAAC;gCACH,CAAC;gCACD,MAAM,CAAC,MAAM,EAAE,CAAC;4BAClB,CAAC;4BACD,OAAO,CAAC,MAAM,EAAE,CAAC;wBACnB,CAAC;wBAED,IAAI,UAAU,EAAE,CAAC;4BACf,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;4BAC3D,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;4BACnB,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;gCACnC,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,mCAAmC;gCAChF,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;4BAC/B,CAAC;4BAED,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;gCAC7B,IAAI,CAAC,SAAS,EAAE,CAAC;gCACjB,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,EAAE,CAAC;oCACxB,aAAa,CAAC,KAAK,CAAC,CAAC;oCACrB,IAAI,CAAC,OAAO,EAAE,CAAC;oCACf,IAAI,CAAC,aAAa,EAAE,CAAC;oCACrB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;oCACzB,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;oCAC1D,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,wBAAwB;gCAC9C,CAAC;4BACH,CAAC,EAAE,IAAI,CAAC,CAAC;wBACX,CAAC;oBACH,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;wBACjD,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,CAAC,0BAA0B;wBACpD,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;4BACnC,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;4BAC5C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;wBAC/B,CAAC;oBACH,CAAC;4BAAS,CAAC;wBACT,0DAA0D;wBAC1D,GAAG,CAAC,MAAM,EAAE,CAAC;wBACb,IAAI,CAAC,MAAM,EAAE,CAAC;wBACd,OAAO,CAAC,MAAM,EAAE,CAAC;wBACjB,KAAK,CAAC,MAAM,EAAE,CAAC;wBACf,QAAQ,CAAC,MAAM,EAAE,CAAC;wBAClB,SAAS,CAAC,MAAM,EAAE,CAAC;oBACrB,CAAC;gBACH,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,KAAK,CAAC,CAAC;gBACpE,CAAC;gBACD,yCAAyC;YAC3C,CAAC;YAED,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;gBACvD,gDAAgD;gBAChD,IAAI,CAAC,gBAAgB,GAAG,qBAAqB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YACxE,CAAC;QACH,CAAC,CAAC;QAEF,mDAAmD;QAC3C,yBAAoB,GAAG,GAAG,EAAE;YAClC,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC;gBAC/E,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;oBACnC,oCAAoC;oBACpC,IAAI,CAAC,gBAAgB,GAAG,qBAAqB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBACxE,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QAEF,gDAAgD;QACxC,yBAAoB,GAAG,KAAK,IAAI,EAAE;YACxC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACtB,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;gBAC7D,OAAO;YACT,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACtB,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;gBACzD,OAAO;YACT,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;YACxC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC,uBAAuB;YAClD,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,CAAC,8BAA8B;YACxD,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC,2BAA2B;YAEzD,IAAI,CAAC,cAAc,EAAE,CAAC;YAEtB,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;gBAC1D,wFAAwF;gBACxF,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;gBACzD,MAAM,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE;oBAChC,MAAM,gBAAgB,GAAG,GAAG,EAAE;wBAC5B,IAAI,CAAC,YAAY,CAAC,mBAAmB,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;wBAC1E,OAAO,EAAE,CAAC;oBACZ,CAAC,CAAC;oBACF,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;gBACzE,CAAC,CAAC,CAAC;gBACH,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;YACzD,CAAC;YAED,IAAI,CAAC,oBAAoB,EAAE,CAAC,CAAC,yCAAyC;QACxE,CAAC,CAAC;QA1SA,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;KACvB;IAED,kFAAkF;IAClF,KAAK,CAAC,iBAAiB;QACrB,wEAAwE;QACxE,8EAA8E;QAC9E,gEAAgE;IAClE,CAAC;IAED,4EAA4E;IAC5E,KAAK,CAAC,gBAAgB;QACpB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACpC,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAExB,gGAAgG;QAChG,QAAQ,CAAC,gBAAgB,CAAC,cAAc,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACpE,CAAC;IAED,oBAAoB;QAClB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;YACnC,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAC5C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC/B,CAAC;QACD,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC7C,CAAC;QACD,QAAQ,CAAC,mBAAmB,CAAC,cAAc,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAErE,qDAAqD;QACrD,IAAI,IAAI,CAAC,mBAAmB,IAAI,IAAI,CAAC,mBAAmB,CAAC,UAAU,EAAE,CAAC;YACpE,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YAC1E,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;QAClC,CAAC;IACH,CAAC;IAEO,gBAAgB;QACtB,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,qDAAqD,CAAC,EAAE,CAAC;YACnF,kCAAkC;YAClC,IAAI,CAAC,mBAAmB,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAC5D,IAAI,CAAC,mBAAmB,CAAC,IAAI,GAAG,iBAAiB,CAAC;YAClD,IAAI,CAAC,mBAAmB,CAAC,KAAK,GAAG,IAAI,CAAC;YACtC,IAAI,CAAC,mBAAmB,CAAC,GAAG,GAAG,uCAAuC,CAAC;YACvE,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,yBAAyB;YAC9E,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IASD,2CAA2C;IACnC,KAAK,CAAC,QAAQ;QACpB,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACpB,MAAM,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAC1C,CAAC;YACD,MAAM,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;YAEzE,MAAM,WAAW,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;YAC3E,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBACtB,IAAI,CAAC,YAAY,CAAC,SAAS,GAAG,WAAW,CAAC;gBAC1C,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;YAC3B,CAAC;YACD,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IA+ND,MAAM;QACJ,IAAI,gBAAgB,GAAG,aAAa,CAAC;QAErC,IAAI,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YAC3B,gBAAgB,GAAG,uBAAuB,CAAC;QAC7C,CAAC;QAED,OAAO,CACL,4DAAK,KAAK,EAAC,uBAAuB;YAChC,4DAAK,KAAK,EAAC,YAAY;gBACrB,2DAAI,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,CAAC,WAAW,GAAO;gBAE9D,4DAAK,MAAM,EAAE,IAAI,CAAC,QAAQ;oBACxB,4DAAK,KAAK,EAAC,qBAAqB;wBAC9B,4DAAK,KAAK,EAAC,gBAAgB;4BACzB,8DAAO,EAAE,EAAC,OAAO,EAAC,IAAI,QAAC,QAAQ,QAAC,WAAW,QAAC,KAAK,QAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC,GAAI;4BAClH,+DAAQ,EAAE,EAAC,QAAQ,EAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAI;4BACxF,+DAAQ,EAAE,EAAC,yBAAyB,EAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,uBAAuB,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAI;4BACnH,4DAAK,KAAK,EAAC,oBAAoB,GAAO;4BACrC,IAAI,CAAC,WAAW,IAAI,4DAAK,KAAK,EAAC,uBAAuB,GAAO;4BAC7D,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,CACrB,4DAAK,KAAK,EAAC,0EAA0E;gCACnF,6DAAM,KAAK,EAAC,8CAA8C,IAAE,IAAI,CAAC,SAAS,CAAQ,CAC9E,CACP,CACG,CACF,CACF;gBACN,4DAAK,KAAK,EAAC,oBAAoB;oBAC7B,4DAAK,GAAG,EAAE,WAAW,GAAQ,CACzB,CACF,CACF,CACP,CAAC;IACJ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CACF","sourcesContent":["import { Component, h, Element, Event, EventEmitter, State } from '@stencil/core';\r\n\r\nimport logoOntrace from '../../../assets/logo-ontrace.svg';\r\nimport store from '../../../helpers/store';\r\nimport { Cameras } from '../../../helpers/Cameras';\r\nimport { Browser, MobileOS } from '../../../models/IDevice';\r\n\r\ndeclare const cv: any;\r\n\r\n@Component({\r\n tag: 'id-auto-capture',\r\n styleUrl: 'id-auto-capture.css',\r\n shadow: false,\r\n})\r\nexport class IdAutoCapture {\r\n @Element() el: HTMLElement;\r\n private videoElement: HTMLVideoElement;\r\n private canvasElement: HTMLCanvasElement;\r\n private processingCanvasElement: HTMLCanvasElement; // For OpenCV frame processing\r\n private mediaRecorder: MediaRecorder | null = null;\r\n private mediaStream: MediaStream | null = null;\r\n private animationFrameId: number | null = null; // To manage requestAnimationFrame\r\n private opencvScriptElement: HTMLScriptElement | null = null;\r\n\r\n @State() private verified: boolean;\r\n @State() private titleMesage: string;\r\n @State() private titleStyle: string;\r\n @State() recordedChunks: Blob[] = [];\r\n @State() countdown: number = 0;\r\n @State() capturedImage: string | null = null;\r\n @State() isRecording: boolean = false;\r\n @State() recordedVideoUrl: string | null = null;\r\n @State() isDetecting: boolean = false;\r\n @State() opencvReady: boolean = false;\r\n @State() isCapturing: boolean = false;\r\n\r\n @Event({\r\n eventName: 'photoIdCapture',\r\n })\r\n eventPhotoCapture: EventEmitter;\r\n\r\n @Event({\r\n eventName: 'recordingIdCapture',\r\n })\r\n eventRecordingIdReady: EventEmitter;\r\n\r\n constructor() {\r\n this.verified = false;\r\n }\r\n\r\n // Lifecycle method: Called once after the component is first connected to the DOM\r\n async componentWillLoad() {\r\n // Initialize DOM element references after the component's render method\r\n // has placed them in the DOM. This should ideally be done in componentDidLoad\r\n // but can be set up to ensure elements are available for setup.\r\n }\r\n\r\n // Lifecycle method: Called once after the component has loaded and rendered\r\n async componentDidLoad() {\r\n console.log('Loading OpenCV.js...');\r\n this.loadOpenCVScript();\r\n\r\n // Listen for the custom event dispatched by global.ts (ensures global.ts sets up window.Module)\r\n document.addEventListener('opencv:ready', this.handleOpencvReady);\r\n }\r\n\r\n disconnectedCallback() {\r\n if (this.mediaStream) {\r\n this.mediaStream.getTracks().forEach(track => track.stop());\r\n }\r\n if (this.animationFrameId !== null) {\r\n cancelAnimationFrame(this.animationFrameId);\r\n this.animationFrameId = null;\r\n }\r\n if (this.recordedVideoUrl) {\r\n URL.revokeObjectURL(this.recordedVideoUrl);\r\n }\r\n document.removeEventListener('opencv:ready', this.handleOpencvReady);\r\n\r\n // NEW: Clean up the dynamically added script element\r\n if (this.opencvScriptElement && this.opencvScriptElement.parentNode) {\r\n this.opencvScriptElement.parentNode.removeChild(this.opencvScriptElement);\r\n this.opencvScriptElement = null;\r\n }\r\n }\r\n\r\n private loadOpenCVScript() {\r\n if (!document.querySelector('script[src=\"https://docs.opencv.org/4.x/opencv.js\"]')) {\r\n // Only load if not already loaded\r\n this.opencvScriptElement = document.createElement('script');\r\n this.opencvScriptElement.type = 'text/javascript';\r\n this.opencvScriptElement.async = true;\r\n this.opencvScriptElement.src = 'https://docs.opencv.org/4.x/opencv.js';\r\n document.body.appendChild(this.opencvScriptElement); // Append to body or head\r\n console.log('Dynamically loaded opencv.js');\r\n } else {\r\n console.log('OpenCV.js script already present in the DOM.');\r\n }\r\n }\r\n\r\n private handleOpencvReady = async () => {\r\n this.opencvReady = true;\r\n console.log('OpenCV.js loaded. Ready to start detection.');\r\n await this.getMedia(); // Get camera media once OpenCV is ready\r\n await this.handleStartDetection(); // Start processing video frames\r\n };\r\n\r\n // Method to get user media (camera stream)\r\n private async getMedia() {\r\n try {\r\n if (!store.cameraId) {\r\n await Cameras.InitCameras(store.device);\r\n }\r\n const constraints = Cameras.GetConstraints(store.cameraId, store.device);\r\n\r\n const mediaStream = await navigator.mediaDevices.getUserMedia(constraints);\r\n if (this.videoElement) {\r\n this.videoElement.srcObject = mediaStream;\r\n this.videoElement.play();\r\n }\r\n this.mediaStream = mediaStream;\r\n } catch (err) {\r\n console.error('Error accessing camera:', err);\r\n }\r\n }\r\n\r\n // Method to start video recording\r\n private startRecording = () => {\r\n if (this.mediaStream && this.videoElement) {\r\n this.recordedChunks = []; // Clear previous chunks\r\n\r\n var options = { mimeType: Cameras.webmMimeType.mime, videoBitsPerSecond: 1300000 };\r\n\r\n if (!MediaRecorder.isTypeSupported(options.mimeType)) {\r\n if (store.device.mobileOS == MobileOS.iOS || store.device.browser == Browser.Safari) options.mimeType = Cameras.mp4MimeType.mime;\r\n }\r\n\r\n this.mediaRecorder = new MediaRecorder(this.mediaStream, { mimeType: 'video/webm' });\r\n\r\n this.mediaRecorder.ondataavailable = ({ data }) => {\r\n if (data.size > 0) {\r\n this.recordedChunks = [...this.recordedChunks, data];\r\n }\r\n };\r\n\r\n this.mediaRecorder.onstop = () => {\r\n if (this.recordedChunks.length > 0) {\r\n const blob = new Blob(this.recordedChunks, { type: 'video/webm' });\r\n this.recordedVideoUrl = URL.createObjectURL(blob);\r\n }\r\n };\r\n\r\n this.mediaRecorder.start();\r\n this.isRecording = true;\r\n console.log('Recording started...');\r\n }\r\n };\r\n\r\n // Method to stop video recording\r\n private stopRecording = () => {\r\n if (this.mediaRecorder && this.mediaRecorder.state === 'recording') {\r\n this.mediaRecorder.stop();\r\n this.isRecording = false;\r\n console.log('Recording stopped.');\r\n this.eventRecordingIdReady.emit(this.recordedVideoUrl);\r\n }\r\n };\r\n\r\n // Method to capture an image from the video stream\r\n private capture = () => {\r\n if (this.videoElement && this.canvasElement) {\r\n const video = this.videoElement;\r\n const canvas = this.canvasElement;\r\n const context = canvas.getContext('2d');\r\n\r\n canvas.width = video.videoWidth;\r\n canvas.height = video.videoHeight;\r\n\r\n context.drawImage(video, 0, 0, canvas.width, canvas.height);\r\n\r\n this.capturedImage = canvas.toDataURL('image/png');\r\n console.log('Image captured!');\r\n this.verified = true;\r\n\r\n this.isCapturing = true;\r\n setTimeout(() => {\r\n this.isCapturing = false;\r\n }, 200); // Flash for 200ms\r\n\r\n this.eventPhotoCapture.emit(this.capturedImage);\r\n }\r\n };\r\n\r\n // Method for continuous video frame processing with OpenCV\r\n private processVideoFrame = () => {\r\n if (this.videoElement && this.processingCanvasElement && this.opencvReady && this.isDetecting) {\r\n try {\r\n console.log('Processing frame. cv.Mat is a constructor:', typeof cv.Mat === 'function');\r\n const video = this.videoElement;\r\n const processingCanvas = this.processingCanvasElement;\r\n const context = processingCanvas.getContext('2d');\r\n\r\n processingCanvas.width = video.videoWidth;\r\n processingCanvas.height = video.videoHeight;\r\n\r\n context.drawImage(video, 0, 0, processingCanvas.width, processingCanvas.height);\r\n\r\n const imageData = context.getImageData(0, 0, processingCanvas.width, processingCanvas.height);\r\n\r\n // --- OpenCV.js processing starts here ---\r\n let src = new cv.Mat(processingCanvas.height, processingCanvas.width, cv.CV_8UC4);\r\n src.data.set(imageData.data);\r\n let gray = new cv.Mat();\r\n let blurred = new cv.Mat();\r\n let edges = new cv.Mat();\r\n let contours = new cv.MatVector();\r\n let hierarchy = new cv.Mat();\r\n\r\n try {\r\n cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);\r\n cv.GaussianBlur(gray, blurred, new cv.Size(5, 5), 0, 0, cv.BORDER_DEFAULT);\r\n cv.Canny(blurred, edges, 75, 200, 3, false);\r\n cv.findContours(edges, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);\r\n\r\n let idDetected = false;\r\n let maxArea = 0;\r\n //let bestRect = null;\r\n\r\n for (let i = 0; i < contours.size(); ++i) {\r\n let contour = contours.get(i);\r\n let area = cv.contourArea(contour);\r\n\r\n if (area > 1000 && area > maxArea) {\r\n let peri = cv.arcLength(contour, true);\r\n let approx = new cv.Mat();\r\n cv.approxPolyDP(contour, approx, 0.02 * peri, true);\r\n\r\n if (approx.rows === 4) {\r\n let rect = cv.boundingRect(approx);\r\n const aspectRatio = rect.width / rect.height;\r\n\r\n if (aspectRatio > 1.4 && aspectRatio < 1.8) {\r\n if (rect.width > video.videoWidth * 0.3 && rect.height > video.videoHeight * 0.3) {\r\n idDetected = true;\r\n maxArea = area;\r\n //bestRect = rect;\r\n }\r\n }\r\n }\r\n approx.delete();\r\n }\r\n contour.delete();\r\n }\r\n\r\n if (idDetected) {\r\n console.log('ID document detected! Starting countdown...');\r\n this.countdown = 3;\r\n if (this.animationFrameId !== null) {\r\n cancelAnimationFrame(this.animationFrameId); // Stop continuous frame processing\r\n this.animationFrameId = null;\r\n }\r\n\r\n const timer = setInterval(() => {\r\n this.countdown--;\r\n if (this.countdown <= 0) {\r\n clearInterval(timer);\r\n this.capture();\r\n this.stopRecording();\r\n this.isDetecting = false;\r\n console.log('Picture taken. You can now stop recording.');\r\n this.countdown = 0; // Ensure countdown is 0\r\n }\r\n }, 1000);\r\n }\r\n } catch (error) {\r\n console.error('OpenCV processing error:', error);\r\n this.isDetecting = false; // Stop detection on error\r\n if (this.animationFrameId !== null) {\r\n cancelAnimationFrame(this.animationFrameId);\r\n this.animationFrameId = null;\r\n }\r\n } finally {\r\n // Crucial: Release memory allocated by OpenCV Mat objects\r\n src.delete();\r\n gray.delete();\r\n blurred.delete();\r\n edges.delete();\r\n contours.delete();\r\n hierarchy.delete();\r\n }\r\n } catch (error) {\r\n console.error('Error processing video frame with OpenCV:', error);\r\n }\r\n // --- OpenCV.js processing ends here ---\r\n }\r\n\r\n if (this.isDetecting && this.animationFrameId !== null) {\r\n // Ensure loop continues only if still detecting\r\n this.animationFrameId = requestAnimationFrame(this.processVideoFrame);\r\n }\r\n };\r\n\r\n // Method to start the OpenCV frame processing loop\r\n private startFrameProcessing = () => {\r\n if (this.opencvReady && this.videoElement && this.videoElement.readyState >= 2) {\r\n if (this.animationFrameId === null) {\r\n // Only start if not already running\r\n this.animationFrameId = requestAnimationFrame(this.processVideoFrame);\r\n }\r\n }\r\n };\r\n\r\n // Handler for starting the ID detection process\r\n private handleStartDetection = async () => {\r\n if (!this.mediaStream) {\r\n console.log('Camera not ready. Please allow camera access.');\r\n return;\r\n }\r\n if (!this.opencvReady) {\r\n console.log('OpenCV.js is not loaded yet. Please wait.');\r\n return;\r\n }\r\n\r\n console.log('Starting ID detection...');\r\n this.isDetecting = true;\r\n this.capturedImage = null; // Clear previous image\r\n this.recordedChunks = []; // Clear previous video chunks\r\n this.recordedVideoUrl = null; // Clear previous video URL\r\n\r\n this.startRecording();\r\n\r\n if (this.videoElement && this.videoElement.readyState < 3) {\r\n // Use readyState 3 (HAVE_FUTURE_DATA) or 4 (HAVE_ENOUGH_DATA) for more robust readiness\r\n console.log('Waiting for video stream to fully load...');\r\n await new Promise<void>(resolve => {\r\n const onCanPlayThrough = () => {\r\n this.videoElement.removeEventListener('canplaythrough', onCanPlayThrough);\r\n resolve();\r\n };\r\n this.videoElement.addEventListener('canplaythrough', onCanPlayThrough);\r\n });\r\n console.log('Video stream ready. Starting detection.');\r\n }\r\n\r\n this.startFrameProcessing(); // Start the OpenCV frame processing loop\r\n };\r\n\r\n render() {\r\n let cameraVideoClass = 'cameraVideo';\r\n\r\n if (store.device.isDesktop) {\r\n cameraVideoClass = 'cameraVideoSelfieDesk';\r\n }\r\n\r\n return (\r\n <div class=\"container flex center\">\r\n <div class=\"px-2 w-100\">\r\n <h1 class={this.titleStyle} innerHTML={this.titleMesage}></h1>\r\n\r\n <div hidden={this.verified}>\r\n <div class=\"w-100 h-100 rounded\">\r\n <div class=\"camera rounded\">\r\n <video id=\"video\" loop autoplay playsinline muted class={cameraVideoClass} ref={el => (this.videoElement = el)} />\r\n <canvas id=\"output\" ref={el => (this.canvasElement = el)} style={{ display: 'none' }} />\r\n <canvas id=\"processingCanvasElement\" ref={el => (this.processingCanvasElement = el)} style={{ display: 'none' }} />\r\n <div class=\"id-guide-rectangle\"></div>\r\n {this.isCapturing && <div class=\"capture-flash-overlay\"></div>}\r\n {this.countdown > 0 && (\r\n <div class=\"absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center\">\r\n <span class=\"text-white text-9xl font-bold animate-bounce\">{this.countdown}</span>\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"footer text-center\">\r\n <img src={logoOntrace}></img>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n }\r\n}\r\n"]}
@@ -590,87 +590,93 @@ const IdAutoCapture = class {
590
590
  // Method for continuous video frame processing with OpenCV
591
591
  this.processVideoFrame = () => {
592
592
  if (this.videoElement && this.processingCanvasElement && this.opencvReady && this.isDetecting) {
593
- const video = this.videoElement;
594
- const processingCanvas = this.processingCanvasElement;
595
- const context = processingCanvas.getContext('2d');
596
- processingCanvas.width = video.videoWidth;
597
- processingCanvas.height = video.videoHeight;
598
- context.drawImage(video, 0, 0, processingCanvas.width, processingCanvas.height);
599
- const imageData = context.getImageData(0, 0, processingCanvas.width, processingCanvas.height);
600
- // --- OpenCV.js processing starts here ---
601
- let src = new cv.Mat(processingCanvas.height, processingCanvas.width, cv.CV_8UC4);
602
- src.data.set(imageData.data);
603
- let gray = new cv.Mat();
604
- let blurred = new cv.Mat();
605
- let edges = new cv.Mat();
606
- let contours = new cv.MatVector();
607
- let hierarchy = new cv.Mat();
608
593
  try {
609
- cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
610
- cv.GaussianBlur(gray, blurred, new cv.Size(5, 5), 0, 0, cv.BORDER_DEFAULT);
611
- cv.Canny(blurred, edges, 75, 200, 3, false);
612
- cv.findContours(edges, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);
613
- let idDetected = false;
614
- let maxArea = 0;
615
- //let bestRect = null;
616
- for (let i = 0; i < contours.size(); ++i) {
617
- let contour = contours.get(i);
618
- let area = cv.contourArea(contour);
619
- if (area > 1000 && area > maxArea) {
620
- let peri = cv.arcLength(contour, true);
621
- let approx = new cv.Mat();
622
- cv.approxPolyDP(contour, approx, 0.02 * peri, true);
623
- if (approx.rows === 4) {
624
- let rect = cv.boundingRect(approx);
625
- const aspectRatio = rect.width / rect.height;
626
- if (aspectRatio > 1.4 && aspectRatio < 1.8) {
627
- if (rect.width > video.videoWidth * 0.3 && rect.height > video.videoHeight * 0.3) {
628
- idDetected = true;
629
- maxArea = area;
630
- //bestRect = rect;
594
+ console.log('Processing frame. cv.Mat is a constructor:', typeof cv.Mat === 'function');
595
+ const video = this.videoElement;
596
+ const processingCanvas = this.processingCanvasElement;
597
+ const context = processingCanvas.getContext('2d');
598
+ processingCanvas.width = video.videoWidth;
599
+ processingCanvas.height = video.videoHeight;
600
+ context.drawImage(video, 0, 0, processingCanvas.width, processingCanvas.height);
601
+ const imageData = context.getImageData(0, 0, processingCanvas.width, processingCanvas.height);
602
+ // --- OpenCV.js processing starts here ---
603
+ let src = new cv.Mat(processingCanvas.height, processingCanvas.width, cv.CV_8UC4);
604
+ src.data.set(imageData.data);
605
+ let gray = new cv.Mat();
606
+ let blurred = new cv.Mat();
607
+ let edges = new cv.Mat();
608
+ let contours = new cv.MatVector();
609
+ let hierarchy = new cv.Mat();
610
+ try {
611
+ cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
612
+ cv.GaussianBlur(gray, blurred, new cv.Size(5, 5), 0, 0, cv.BORDER_DEFAULT);
613
+ cv.Canny(blurred, edges, 75, 200, 3, false);
614
+ cv.findContours(edges, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);
615
+ let idDetected = false;
616
+ let maxArea = 0;
617
+ //let bestRect = null;
618
+ for (let i = 0; i < contours.size(); ++i) {
619
+ let contour = contours.get(i);
620
+ let area = cv.contourArea(contour);
621
+ if (area > 1000 && area > maxArea) {
622
+ let peri = cv.arcLength(contour, true);
623
+ let approx = new cv.Mat();
624
+ cv.approxPolyDP(contour, approx, 0.02 * peri, true);
625
+ if (approx.rows === 4) {
626
+ let rect = cv.boundingRect(approx);
627
+ const aspectRatio = rect.width / rect.height;
628
+ if (aspectRatio > 1.4 && aspectRatio < 1.8) {
629
+ if (rect.width > video.videoWidth * 0.3 && rect.height > video.videoHeight * 0.3) {
630
+ idDetected = true;
631
+ maxArea = area;
632
+ //bestRect = rect;
633
+ }
631
634
  }
632
635
  }
636
+ approx.delete();
637
+ }
638
+ contour.delete();
639
+ }
640
+ if (idDetected) {
641
+ console.log('ID document detected! Starting countdown...');
642
+ this.countdown = 3;
643
+ if (this.animationFrameId !== null) {
644
+ cancelAnimationFrame(this.animationFrameId); // Stop continuous frame processing
645
+ this.animationFrameId = null;
633
646
  }
634
- approx.delete();
647
+ const timer = setInterval(() => {
648
+ this.countdown--;
649
+ if (this.countdown <= 0) {
650
+ clearInterval(timer);
651
+ this.capture();
652
+ this.stopRecording();
653
+ this.isDetecting = false;
654
+ console.log('Picture taken. You can now stop recording.');
655
+ this.countdown = 0; // Ensure countdown is 0
656
+ }
657
+ }, 1000);
635
658
  }
636
- contour.delete();
637
659
  }
638
- if (idDetected) {
639
- console.log('ID document detected! Starting countdown...');
640
- this.countdown = 3;
660
+ catch (error) {
661
+ console.error('OpenCV processing error:', error);
662
+ this.isDetecting = false; // Stop detection on error
641
663
  if (this.animationFrameId !== null) {
642
- cancelAnimationFrame(this.animationFrameId); // Stop continuous frame processing
664
+ cancelAnimationFrame(this.animationFrameId);
643
665
  this.animationFrameId = null;
644
666
  }
645
- const timer = setInterval(() => {
646
- this.countdown--;
647
- if (this.countdown <= 0) {
648
- clearInterval(timer);
649
- this.capture();
650
- this.stopRecording();
651
- this.isDetecting = false;
652
- console.log('Picture taken. You can now stop recording.');
653
- this.countdown = 0; // Ensure countdown is 0
654
- }
655
- }, 1000);
656
667
  }
657
- }
658
- catch (error) {
659
- console.error('OpenCV processing error:', error);
660
- this.isDetecting = false; // Stop detection on error
661
- if (this.animationFrameId !== null) {
662
- cancelAnimationFrame(this.animationFrameId);
663
- this.animationFrameId = null;
668
+ finally {
669
+ // Crucial: Release memory allocated by OpenCV Mat objects
670
+ src.delete();
671
+ gray.delete();
672
+ blurred.delete();
673
+ edges.delete();
674
+ contours.delete();
675
+ hierarchy.delete();
664
676
  }
665
677
  }
666
- finally {
667
- // Crucial: Release memory allocated by OpenCV Mat objects
668
- src.delete();
669
- gray.delete();
670
- blurred.delete();
671
- edges.delete();
672
- contours.delete();
673
- hierarchy.delete();
678
+ catch (error) {
679
+ console.error('Error processing video frame with OpenCV:', error);
674
680
  }
675
681
  // --- OpenCV.js processing ends here ---
676
682
  }
@@ -732,10 +738,6 @@ const IdAutoCapture = class {
732
738
  this.loadOpenCVScript();
733
739
  // Listen for the custom event dispatched by global.ts (ensures global.ts sets up window.Module)
734
740
  document.addEventListener('opencv:ready', this.handleOpencvReady);
735
- // Initial check in case opencv.js loads very fast and event was already dispatched
736
- if (typeof cv !== 'undefined' && cv.Mat) {
737
- this.handleOpencvReady();
738
- }
739
741
  }
740
742
  disconnectedCallback() {
741
743
  if (this.mediaStream) {
@@ -756,7 +758,7 @@ const IdAutoCapture = class {
756
758
  }
757
759
  }
758
760
  loadOpenCVScript() {
759
- if (!this.opencvScriptElement) {
761
+ if (!document.querySelector('script[src="https://docs.opencv.org/4.x/opencv.js"]')) {
760
762
  // Only load if not already loaded
761
763
  this.opencvScriptElement = document.createElement('script');
762
764
  this.opencvScriptElement.type = 'text/javascript';
@@ -765,6 +767,9 @@ const IdAutoCapture = class {
765
767
  document.body.appendChild(this.opencvScriptElement); // Append to body or head
766
768
  console.log('Dynamically loaded opencv.js');
767
769
  }
770
+ else {
771
+ console.log('OpenCV.js script already present in the DOM.');
772
+ }
768
773
  }
769
774
  // Method to get user media (camera stream)
770
775
  async getMedia() {
@@ -789,7 +794,7 @@ const IdAutoCapture = class {
789
794
  if (state.device.isDesktop) {
790
795
  cameraVideoClass = 'cameraVideoSelfieDesk';
791
796
  }
792
- return (h("div", { key: '32fa99f679fbbc0009608aeb2eeb26645dbadb59', class: "container flex center" }, h("div", { key: '08ee0848724b359253d27120fe5e2751372cab1e', class: "px-2 w-100" }, h("h1", { key: '570154c491f44b72f5a6794f17b1a19c964a55e5', class: this.titleStyle, innerHTML: this.titleMesage }), h("div", { key: '2a626737524f5748e4d6faeb109f3dc59fe3388b', hidden: this.verified }, h("div", { key: 'f38962922b06f902790d9d549c3d1c507cafb8b8', class: "w-100 h-100 rounded" }, h("div", { key: '7c69f659183dfdfab7ea759c1a5a574af19df679', class: "camera rounded" }, h("video", { key: '7f378deee95b9821715add1f9b66e9299b6e4380', id: "video", loop: true, autoplay: true, playsinline: true, muted: true, class: cameraVideoClass, ref: el => (this.videoElement = el) }), h("canvas", { key: '8150fbc30e908e011f415b73a0e3f2d8711f2d20', id: "output", ref: el => (this.canvasElement = el), style: { display: 'none' } }), h("canvas", { key: '54887d1f9266d32f653760ff6e70971e2d525c0a', id: "processingCanvasElement", ref: el => (this.processingCanvasElement = el), style: { display: 'none' } }), h("div", { key: 'cf656641dcb1cf1bf845c28a97630c72f7da8fe6', class: "id-guide-rectangle" }), this.isCapturing && h("div", { key: 'eabb935e014eb3966940a27a5aa100477249dbba', class: "capture-flash-overlay" }), this.countdown > 0 && (h("div", { key: 'e8a05e21e03673637e0194b3d967ed0044891a01', class: "absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center" }, h("span", { key: 'f6996d51686b935aa4aaa6f2abe4062d5782c116', class: "text-white text-9xl font-bold animate-bounce" }, this.countdown)))))), h("div", { key: 'd4fc6a0ff5951767a43f9166fcf47f98b4d209a7', class: "footer text-center" }, h("img", { key: 'a84cc0c65a6684807abf314d9839babe16768494', src: logoOntraceSvg })))));
797
+ return (h("div", { key: 'deb2d35a50823fa5c222c6049a4119a371194870', class: "container flex center" }, h("div", { key: '449a0fef911f14d3611a1d7e83ed1bfc02c0553f', class: "px-2 w-100" }, h("h1", { key: '8d9f8b3684e58ba57f4ec0467efa0d9af62c5a98', class: this.titleStyle, innerHTML: this.titleMesage }), h("div", { key: '701aeecc148bdd00ef9cd38b165f0628adfe827c', hidden: this.verified }, h("div", { key: 'cbe89cf4ddc15c46b595929ecaf4fb8cc20136b5', class: "w-100 h-100 rounded" }, h("div", { key: '78f52a0a77c3dd8218115253bbcb79ee0a9a6d4b', class: "camera rounded" }, h("video", { key: '6ee76764205ce855fedd7b8c86be4394b2cad7bb', id: "video", loop: true, autoplay: true, playsinline: true, muted: true, class: cameraVideoClass, ref: el => (this.videoElement = el) }), h("canvas", { key: '5574b79a997d3ca06afa99faa61cb9bace755e91', id: "output", ref: el => (this.canvasElement = el), style: { display: 'none' } }), h("canvas", { key: 'e25df7ef70206d5544adade008cd612f1fee550a', id: "processingCanvasElement", ref: el => (this.processingCanvasElement = el), style: { display: 'none' } }), h("div", { key: '8ac6db08f2d1e44d04f2827f29e08787b853812e', class: "id-guide-rectangle" }), this.isCapturing && h("div", { key: '900ddcc0d2bf371d7ad4e593eaf0e9b60b6d2810', class: "capture-flash-overlay" }), this.countdown > 0 && (h("div", { key: 'd5f05c1b3dcbd02977462c6b9d816c2835698c2f', class: "absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center" }, h("span", { key: '7b85d36f1b609360c8214a29e220f6f80effffca', class: "text-white text-9xl font-bold animate-bounce" }, this.countdown)))))), h("div", { key: '9b653ebb92ce731ddb235d85db4a7fa99aaa4c64', class: "footer text-center" }, h("img", { key: 'f085d8f1698e66448cf749ec4cc45b496fbd55a1', src: logoOntraceSvg })))));
793
798
  }
794
799
  get el() { return getElement(this); }
795
800
  };
@@ -854,7 +859,7 @@ const IdSelection = class {
854
859
  };
855
860
  IdSelection.style = idSelectionCss;
856
861
 
857
- const version$1 = "4.7.23";
862
+ const version$1 = "4.7.25";
858
863
  var packageJson = {
859
864
  version: version$1};
860
865