@jaak.ai/stamps 2.0.0-beta.4 → 2.0.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +660 -510
- package/dist/cjs/jaak-stamps-webcomponent.cjs.js +1 -1
- package/dist/cjs/jaak-stamps.cjs.entry.js +241 -41
- package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
- package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/components/my-component/my-component.css +54 -24
- package/dist/collection/components/my-component/my-component.js +91 -5
- package/dist/collection/components/my-component/my-component.js.map +1 -1
- package/dist/collection/services/CameraService.js +158 -21
- package/dist/collection/services/CameraService.js.map +1 -1
- package/dist/collection/services/DetectionService.js +34 -16
- package/dist/collection/services/DetectionService.js.map +1 -1
- package/dist/components/jaak-stamps.js +244 -41
- package/dist/components/jaak-stamps.js.map +1 -1
- package/dist/esm/jaak-stamps-webcomponent.js +1 -1
- package/dist/esm/jaak-stamps.entry.js +241 -41
- package/dist/esm/jaak-stamps.entry.js.map +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js +1 -1
- package/dist/jaak-stamps-webcomponent/jaak-stamps.entry.esm.js.map +1 -1
- package/dist/jaak-stamps-webcomponent/p-65990bdd.entry.js +2 -0
- package/dist/jaak-stamps-webcomponent/p-65990bdd.entry.js.map +1 -0
- package/dist/types/components/my-component/my-component.d.ts +6 -0
- package/dist/types/components.d.ts +18 -2
- package/dist/types/services/CameraService.d.ts +1 -0
- package/package.json +2 -2
- package/dist/jaak-stamps-webcomponent/p-10ee2dab.entry.js +0 -2
- package/dist/jaak-stamps-webcomponent/p-10ee2dab.entry.js.map +0 -1
|
@@ -199,6 +199,7 @@ class CameraService {
|
|
|
199
199
|
deviceType = 'desktop';
|
|
200
200
|
preferredCameraFacing = null;
|
|
201
201
|
preferredCamera = 'auto';
|
|
202
|
+
isManuallySelected = false;
|
|
202
203
|
constructor(logger, eventBus, preferredCamera = 'auto') {
|
|
203
204
|
this.logger = logger;
|
|
204
205
|
this.eventBus = eventBus;
|
|
@@ -245,6 +246,11 @@ class CameraService {
|
|
|
245
246
|
}))
|
|
246
247
|
});
|
|
247
248
|
this.setInitialCameraPreference();
|
|
249
|
+
this.logger.state('PREFERENCIA_INICIAL_APLICADA', {
|
|
250
|
+
selectedCameraId: this.selectedCameraId,
|
|
251
|
+
preferredCameraFacing: this.preferredCameraFacing,
|
|
252
|
+
preferredCamera: this.preferredCamera
|
|
253
|
+
});
|
|
248
254
|
this.eventBus.emit('camera-changed', this.selectedCameraId);
|
|
249
255
|
return this.availableCameras;
|
|
250
256
|
}
|
|
@@ -270,6 +276,7 @@ class CameraService {
|
|
|
270
276
|
}
|
|
271
277
|
this.selectedCameraId = cameraId;
|
|
272
278
|
this.updatePreferredFacing(camera);
|
|
279
|
+
this.isManuallySelected = true; // Mark as manually selected
|
|
273
280
|
this.savePreference();
|
|
274
281
|
this.eventBus.emit('camera-changed', cameraId);
|
|
275
282
|
}
|
|
@@ -277,12 +284,31 @@ class CameraService {
|
|
|
277
284
|
return this.preferredCameraFacing;
|
|
278
285
|
}
|
|
279
286
|
async setupCamera(constraints) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
287
|
+
try {
|
|
288
|
+
const finalConstraints = constraints || await this.getMaxResolution();
|
|
289
|
+
const stream = await navigator.mediaDevices.getUserMedia({
|
|
290
|
+
video: finalConstraints,
|
|
291
|
+
audio: false
|
|
292
|
+
});
|
|
293
|
+
return stream;
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
this.logger.error('Error en setupCamera, intentando con restricciones básicas:', error);
|
|
297
|
+
// Fallback to basic constraints if getMaxResolution fails
|
|
298
|
+
const basicConstraints = {
|
|
299
|
+
width: { ideal: 1280 },
|
|
300
|
+
height: { ideal: 720 }
|
|
301
|
+
};
|
|
302
|
+
// Only add facingMode if not on desktop to avoid OverconstrainedError
|
|
303
|
+
if (this.deviceType !== 'desktop' && this.preferredCameraFacing) {
|
|
304
|
+
basicConstraints.facingMode = this.preferredCameraFacing;
|
|
305
|
+
}
|
|
306
|
+
this.logger.state('USANDO_RESTRICCIONES_BASICAS', { constraints: basicConstraints });
|
|
307
|
+
return await navigator.mediaDevices.getUserMedia({
|
|
308
|
+
video: basicConstraints,
|
|
309
|
+
audio: false
|
|
310
|
+
});
|
|
311
|
+
}
|
|
286
312
|
}
|
|
287
313
|
async switchCamera(cameraId) {
|
|
288
314
|
const selectedCamera = this.availableCameras.find(cam => cam.deviceId === cameraId);
|
|
@@ -294,7 +320,8 @@ class CameraService {
|
|
|
294
320
|
await this.setSelectedCamera(cameraId);
|
|
295
321
|
this.logger.state('CAMARA_CAMBIADA', {
|
|
296
322
|
label: selectedCamera.label,
|
|
297
|
-
deviceId: selectedCamera.deviceId
|
|
323
|
+
deviceId: selectedCamera.deviceId,
|
|
324
|
+
isManuallySelected: this.isManuallySelected
|
|
298
325
|
});
|
|
299
326
|
}
|
|
300
327
|
async flipToNextCamera() {
|
|
@@ -376,6 +403,13 @@ class CameraService {
|
|
|
376
403
|
setInitialCameraPreference() {
|
|
377
404
|
if (this.availableCameras.length === 0)
|
|
378
405
|
return;
|
|
406
|
+
// Clear any existing localStorage preferences to ensure fresh start
|
|
407
|
+
localStorage.removeItem('jaak-stamps-camera-preference');
|
|
408
|
+
this.logger.state('APLICANDO_PREFERENCIA_INICIAL', {
|
|
409
|
+
preferredCamera: this.preferredCamera,
|
|
410
|
+
availableCamerasCount: this.availableCameras.length
|
|
411
|
+
});
|
|
412
|
+
this.isManuallySelected = false; // Reset manual selection flag
|
|
379
413
|
if (this.preferredCamera === 'front') {
|
|
380
414
|
this.selectFrontCamera();
|
|
381
415
|
}
|
|
@@ -388,23 +422,56 @@ class CameraService {
|
|
|
388
422
|
}
|
|
389
423
|
selectFrontCamera() {
|
|
390
424
|
this.preferredCameraFacing = 'user';
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
425
|
+
this.logger.state('BUSCANDO_CAMARA_FRONTAL', {
|
|
426
|
+
availableCameras: this.availableCameras.map(cam => ({
|
|
427
|
+
id: cam.deviceId,
|
|
428
|
+
label: cam.label
|
|
429
|
+
}))
|
|
430
|
+
});
|
|
431
|
+
const frontCamera = this.availableCameras.find(camera => {
|
|
432
|
+
const label = camera.label.toLowerCase();
|
|
433
|
+
return label.includes('front') ||
|
|
434
|
+
label.includes('user') ||
|
|
435
|
+
label.includes('selfie') ||
|
|
436
|
+
label.includes('frontal') ||
|
|
437
|
+
(!label.includes('back') && !label.includes('rear') && !label.includes('environment'));
|
|
438
|
+
});
|
|
439
|
+
// If not found, use the first camera (usually front on mobile)
|
|
395
440
|
this.selectedCameraId = frontCamera ? frontCamera.deviceId : this.availableCameras[0].deviceId;
|
|
396
441
|
this.logger.state('CAMARA_FRONTAL_SELECCIONADA', {
|
|
442
|
+
found: !!frontCamera,
|
|
397
443
|
label: frontCamera?.label || this.availableCameras[0].label,
|
|
398
444
|
deviceId: this.selectedCameraId
|
|
399
445
|
});
|
|
400
446
|
}
|
|
401
447
|
selectBackCamera() {
|
|
402
448
|
this.preferredCameraFacing = 'environment';
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
449
|
+
this.logger.state('BUSCANDO_CAMARA_TRASERA', {
|
|
450
|
+
availableCameras: this.availableCameras.map(cam => ({
|
|
451
|
+
id: cam.deviceId,
|
|
452
|
+
label: cam.label
|
|
453
|
+
}))
|
|
454
|
+
});
|
|
455
|
+
// Try to find rear camera with multiple detection methods
|
|
456
|
+
let backCamera = this.availableCameras.find(camera => {
|
|
457
|
+
const label = camera.label.toLowerCase();
|
|
458
|
+
return label.includes('back') ||
|
|
459
|
+
label.includes('rear') ||
|
|
460
|
+
label.includes('environment') ||
|
|
461
|
+
label.includes('trasera') ||
|
|
462
|
+
label.includes('posterior');
|
|
463
|
+
});
|
|
464
|
+
// If not found by label, try to use the last camera (usually rear on mobile)
|
|
465
|
+
if (!backCamera && this.availableCameras.length > 1) {
|
|
466
|
+
backCamera = this.availableCameras[this.availableCameras.length - 1];
|
|
467
|
+
this.logger.state('USANDO_ULTIMA_CAMARA_COMO_TRASERA', {
|
|
468
|
+
label: backCamera.label,
|
|
469
|
+
deviceId: backCamera.deviceId
|
|
470
|
+
});
|
|
471
|
+
}
|
|
406
472
|
this.selectedCameraId = backCamera ? backCamera.deviceId : this.availableCameras[0].deviceId;
|
|
407
473
|
this.logger.state('CAMARA_TRASERA_SELECCIONADA', {
|
|
474
|
+
found: !!backCamera,
|
|
408
475
|
label: backCamera?.label || this.availableCameras[0].label,
|
|
409
476
|
deviceId: this.selectedCameraId
|
|
410
477
|
});
|
|
@@ -415,8 +482,10 @@ class CameraService {
|
|
|
415
482
|
this.logger.state('CAMARA_AUTO_SELECCIONADA_MOBILE', { type: 'rear' });
|
|
416
483
|
}
|
|
417
484
|
else {
|
|
418
|
-
|
|
485
|
+
// For desktop, prefer front camera (usually built-in webcam)
|
|
486
|
+
this.selectFrontCamera();
|
|
419
487
|
this.logger.state('CAMARA_AUTO_SELECCIONADA_DESKTOP', {
|
|
488
|
+
type: 'front',
|
|
420
489
|
label: this.availableCameras[0].label,
|
|
421
490
|
deviceId: this.selectedCameraId
|
|
422
491
|
});
|
|
@@ -430,15 +499,60 @@ class CameraService {
|
|
|
430
499
|
}
|
|
431
500
|
async getMaxResolution() {
|
|
432
501
|
try {
|
|
502
|
+
// Ensure device type is detected before determining constraints
|
|
503
|
+
if (!this.deviceType || this.deviceType === 'desktop') {
|
|
504
|
+
await this.detectDeviceType();
|
|
505
|
+
}
|
|
433
506
|
const videoConstraints = {};
|
|
434
|
-
|
|
507
|
+
this.logger.state('CONFIGURANDO_CONSTRAINS_CAMARA', {
|
|
508
|
+
selectedCameraId: this.selectedCameraId,
|
|
509
|
+
preferredCameraFacing: this.preferredCameraFacing,
|
|
510
|
+
preferredCamera: this.preferredCamera,
|
|
511
|
+
deviceType: this.deviceType,
|
|
512
|
+
isManuallySelected: this.isManuallySelected
|
|
513
|
+
});
|
|
514
|
+
if (this.isManuallySelected && this.selectedCameraId) {
|
|
515
|
+
// When manually selected, use deviceId for exact camera selection
|
|
435
516
|
videoConstraints.deviceId = { exact: this.selectedCameraId };
|
|
517
|
+
this.logger.state('USANDO_CAMARA_MANUAL', {
|
|
518
|
+
deviceId: this.selectedCameraId
|
|
519
|
+
});
|
|
436
520
|
}
|
|
437
521
|
else if (this.preferredCameraFacing) {
|
|
438
|
-
|
|
522
|
+
// Use facingMode for initial preference-based selection
|
|
523
|
+
// Use 'ideal' instead of 'exact' to avoid OverconstrainedError on desktop
|
|
524
|
+
const facingConstraint = this.deviceType === 'desktop'
|
|
525
|
+
? { ideal: this.preferredCameraFacing }
|
|
526
|
+
: { exact: this.preferredCameraFacing };
|
|
527
|
+
videoConstraints.facingMode = facingConstraint;
|
|
528
|
+
this.logger.state('USANDO_FACING_CONSTRAINT', {
|
|
529
|
+
facingMode: this.preferredCameraFacing,
|
|
530
|
+
constraintType: this.deviceType === 'desktop' ? 'ideal' : 'exact'
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
else if (this.selectedCameraId) {
|
|
534
|
+
videoConstraints.deviceId = { exact: this.selectedCameraId };
|
|
535
|
+
this.logger.state('USANDO_CAMARA_SELECCIONADA', {
|
|
536
|
+
deviceId: this.selectedCameraId
|
|
537
|
+
});
|
|
439
538
|
}
|
|
440
539
|
else {
|
|
441
|
-
|
|
540
|
+
// Use preferredCamera setting to determine default facing mode
|
|
541
|
+
if (this.preferredCamera === 'front') {
|
|
542
|
+
videoConstraints.facingMode = "user";
|
|
543
|
+
}
|
|
544
|
+
else if (this.preferredCamera === 'back') {
|
|
545
|
+
videoConstraints.facingMode = "environment";
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
// Auto mode: use environment for mobile/tablet, user for desktop
|
|
549
|
+
videoConstraints.facingMode = (this.deviceType === 'mobile' || this.deviceType === 'tablet') ? "environment" : "user";
|
|
550
|
+
}
|
|
551
|
+
this.logger.state('USANDO_PREFERENCIA_CONFIGURADA', {
|
|
552
|
+
facingMode: videoConstraints.facingMode,
|
|
553
|
+
preferredCamera: this.preferredCamera,
|
|
554
|
+
deviceType: this.deviceType
|
|
555
|
+
});
|
|
442
556
|
}
|
|
443
557
|
const tempStream = await navigator.mediaDevices.getUserMedia({
|
|
444
558
|
video: videoConstraints
|
|
@@ -470,6 +584,10 @@ class CameraService {
|
|
|
470
584
|
}
|
|
471
585
|
catch (err) {
|
|
472
586
|
this.logger.warn('No se pudieron obtener capacidades de cámara, usando configuración de respaldo');
|
|
587
|
+
// Ensure device type is detected before determining constraints
|
|
588
|
+
if (!this.deviceType || this.deviceType === 'desktop') {
|
|
589
|
+
await this.detectDeviceType();
|
|
590
|
+
}
|
|
473
591
|
const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;
|
|
474
592
|
const fallbackConstraints = {
|
|
475
593
|
width: { ideal: isTablet ? 1280 : 1920 },
|
|
@@ -477,14 +595,33 @@ class CameraService {
|
|
|
477
595
|
};
|
|
478
596
|
// Apply basic focus settings even for fallback
|
|
479
597
|
this.applyBasicFocusSettings(fallbackConstraints);
|
|
480
|
-
if (this.selectedCameraId) {
|
|
598
|
+
if (this.isManuallySelected && this.selectedCameraId) {
|
|
599
|
+
// When manually selected, use deviceId for exact camera selection
|
|
481
600
|
fallbackConstraints.deviceId = { exact: this.selectedCameraId };
|
|
482
601
|
}
|
|
483
602
|
else if (this.preferredCameraFacing) {
|
|
484
|
-
|
|
603
|
+
// Use facingMode for initial preference-based selection
|
|
604
|
+
// Use 'ideal' instead of 'exact' to avoid OverconstrainedError on desktop
|
|
605
|
+
const facingConstraint = this.deviceType === 'desktop'
|
|
606
|
+
? { ideal: this.preferredCameraFacing }
|
|
607
|
+
: { exact: this.preferredCameraFacing };
|
|
608
|
+
fallbackConstraints.facingMode = facingConstraint;
|
|
609
|
+
}
|
|
610
|
+
else if (this.selectedCameraId) {
|
|
611
|
+
fallbackConstraints.deviceId = { exact: this.selectedCameraId };
|
|
485
612
|
}
|
|
486
613
|
else {
|
|
487
|
-
|
|
614
|
+
// Use preferredCamera setting to determine default facing mode
|
|
615
|
+
if (this.preferredCamera === 'front') {
|
|
616
|
+
fallbackConstraints.facingMode = "user";
|
|
617
|
+
}
|
|
618
|
+
else if (this.preferredCamera === 'back') {
|
|
619
|
+
fallbackConstraints.facingMode = "environment";
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
// Auto mode: use environment for mobile/tablet, user for desktop
|
|
623
|
+
fallbackConstraints.facingMode = (this.deviceType === 'mobile' || this.deviceType === 'tablet') ? "environment" : "user";
|
|
624
|
+
}
|
|
488
625
|
}
|
|
489
626
|
return fallbackConstraints;
|
|
490
627
|
}
|
|
@@ -728,7 +865,7 @@ class DetectionService {
|
|
|
728
865
|
modelLoaded = false;
|
|
729
866
|
deviceStrategy;
|
|
730
867
|
MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/ddmyp-v2.onnx";
|
|
731
|
-
MOBILENET_MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/
|
|
868
|
+
MOBILENET_MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/squeezenet_new_fp32.onnx";
|
|
732
869
|
MOBILENET_CLASSES_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.json";
|
|
733
870
|
INPUT_SIZE = 320;
|
|
734
871
|
CONFIDENCE_THRESHOLD = 0.6;
|
|
@@ -790,15 +927,27 @@ class DetectionService {
|
|
|
790
927
|
}
|
|
791
928
|
try {
|
|
792
929
|
this.logger.state('CARGANDO_MODELO_MOBILENET', { path: this.MOBILENET_MODEL_PATH });
|
|
793
|
-
//
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
930
|
+
// Try to load class map (optional - SqueezeNet may not need it for basic classification)
|
|
931
|
+
try {
|
|
932
|
+
const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);
|
|
933
|
+
if (classResponse.ok) {
|
|
934
|
+
this.mobileNetClassMap = await classResponse.json();
|
|
935
|
+
this.logger.state('CLASES_MOBILENET_CARGADAS', {
|
|
936
|
+
classCount: Object.keys(this.mobileNetClassMap).length
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
catch (error) {
|
|
941
|
+
this.logger.warn('No se pudo cargar el mapa de clases de MobileNet, usando clasificación básica');
|
|
942
|
+
// Create a basic class map for document types
|
|
943
|
+
this.mobileNetClassMap = {
|
|
944
|
+
"0": "document",
|
|
945
|
+
"1": "id_card",
|
|
946
|
+
"2": "passport",
|
|
947
|
+
"3": "license",
|
|
948
|
+
"4": "other"
|
|
949
|
+
};
|
|
797
950
|
}
|
|
798
|
-
this.mobileNetClassMap = await classResponse.json();
|
|
799
|
-
this.logger.state('CLASES_MOBILENET_CARGADAS', {
|
|
800
|
-
classCount: Object.keys(this.mobileNetClassMap).length
|
|
801
|
-
});
|
|
802
951
|
// Load model
|
|
803
952
|
const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);
|
|
804
953
|
try {
|
|
@@ -887,7 +1036,7 @@ class DetectionService {
|
|
|
887
1036
|
try {
|
|
888
1037
|
this.logger.state('CLASIFICANDO_DOCUMENTO', { timestamp: Date.now() });
|
|
889
1038
|
const inputTensor = this.preprocessMobileNet(canvas);
|
|
890
|
-
const feeds = {
|
|
1039
|
+
const feeds = { [this.mobileNetSession.inputNames[0]]: inputTensor };
|
|
891
1040
|
const results = await this.mobileNetSession.run(feeds);
|
|
892
1041
|
const output = results[Object.keys(results)[0]].data;
|
|
893
1042
|
const maxIdx = output.reduce((bestIdx, val, idx, arr) => val > arr[bestIdx] ? idx : bestIdx, 0);
|
|
@@ -897,7 +1046,8 @@ class DetectionService {
|
|
|
897
1046
|
class: className,
|
|
898
1047
|
confidence: confidence.toFixed(3),
|
|
899
1048
|
classIndex: maxIdx,
|
|
900
|
-
timestamp: Date.now()
|
|
1049
|
+
timestamp: Date.now(),
|
|
1050
|
+
results
|
|
901
1051
|
});
|
|
902
1052
|
return {
|
|
903
1053
|
class: className,
|
|
@@ -936,7 +1086,7 @@ class DetectionService {
|
|
|
936
1086
|
displayedVideoHeight = INPUT_SIZE / videoAspectRatio;
|
|
937
1087
|
}
|
|
938
1088
|
else {
|
|
939
|
-
// Video is taller - pillarboxed in display
|
|
1089
|
+
// Video is taller - pillarboxed in display
|
|
940
1090
|
displayedVideoHeight = INPUT_SIZE;
|
|
941
1091
|
displayedVideoWidth = INPUT_SIZE * videoAspectRatio;
|
|
942
1092
|
}
|
|
@@ -987,7 +1137,7 @@ class DetectionService {
|
|
|
987
1137
|
const leftAligned = Math.abs(docLeft - maskLeft) <= tolerance;
|
|
988
1138
|
return {
|
|
989
1139
|
top: topAligned && leftAligned, // Esquina superior izquierda: borde top Y left alineados
|
|
990
|
-
right: topAligned && rightAligned, // Esquina superior derecha: borde top Y right alineados
|
|
1140
|
+
right: topAligned && rightAligned, // Esquina superior derecha: borde top Y right alineados
|
|
991
1141
|
bottom: bottomAligned && leftAligned, // Esquina inferior izquierda: borde bottom Y left alineados
|
|
992
1142
|
left: bottomAligned && rightAligned // Esquina inferior derecha: borde bottom Y right alineados
|
|
993
1143
|
};
|
|
@@ -1072,15 +1222,20 @@ class DetectionService {
|
|
|
1072
1222
|
tempCanvas.width = 224;
|
|
1073
1223
|
tempCanvas.height = 224;
|
|
1074
1224
|
const tempCtx = tempCanvas.getContext('2d');
|
|
1225
|
+
// Resize image to 224x224 for SqueezeNet (using MobileNet interface)
|
|
1075
1226
|
tempCtx.drawImage(canvas, 0, 0, 224, 224);
|
|
1076
1227
|
const imageData = tempCtx.getImageData(0, 0, 224, 224);
|
|
1077
1228
|
const data = imageData.data;
|
|
1078
1229
|
const hw = 224 * 224;
|
|
1079
1230
|
const arr = new Float32Array(3 * hw);
|
|
1231
|
+
// SqueezeNet preprocessing: normalize to [0,1] range and arrange in CHW format
|
|
1080
1232
|
for (let i = 0; i < hw; i++) {
|
|
1081
|
-
|
|
1082
|
-
arr[
|
|
1083
|
-
|
|
1233
|
+
// Red channel
|
|
1234
|
+
arr[i] = data[i * 4 + 0] / 255.0;
|
|
1235
|
+
// Green channel
|
|
1236
|
+
arr[hw + i] = data[i * 4 + 1] / 255.0;
|
|
1237
|
+
// Blue channel
|
|
1238
|
+
arr[2 * hw + i] = data[i * 4 + 2] / 255.0;
|
|
1084
1239
|
}
|
|
1085
1240
|
return new window.ort.Tensor('float32', arr, [1, 3, 224, 224]);
|
|
1086
1241
|
}
|
|
@@ -1141,7 +1296,7 @@ class ServiceContainer {
|
|
|
1141
1296
|
}
|
|
1142
1297
|
}
|
|
1143
1298
|
|
|
1144
|
-
const myComponentCss = ":host{display:block;width:100%;height:100%;font-family:system-ui, -apple-system, sans-serif;color:#1a1a1a}.detector-container{display:flex;flex-direction:column;align-items:center;width:100%;height:100%}h1{font-size:24px;font-weight:500;color:#333;margin:0 0 24px 0}.video-container{position:relative;width:100%;height:100%;background:#333;border:1px solid #e0e0e0;border-radius:8px;overflow:hidden}video,.detection-overlay{position:absolute;width:100%;height:100%;border-radius:8px}video.mirror,.detection-overlay.mirror{transform:rotateY(180deg)}.detection-overlay{z-index:1;pointer-events:none}video{z-index:0}.detection-box{transition:opacity 0.2s ease}.status{margin-top:16px;font-size:12px;color:#666}.overlay-mask{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;display:block;pointer-events:none}.card-outline{position:absolute;top:var(--mask-center-y, 50%);left:var(--mask-center-x, 50%);transform:translate(-50%, -50%);width:var(--mask-width, 88%);height:var(--mask-height, 55%);border:none;border-radius:4px;background:transparent;opacity:0.8}.side{position:absolute;background:#999;transition:background-color 0.3s ease;border-radius:1px}.side-top.aligned{border-left-color:#28a745;border-top-color:#28a745}.side-right.aligned{border-right-color:#28a745;border-top-color:#28a745}.side-bottom.aligned{border-left-color:#28a745;border-bottom-color:#28a745}.side-left.aligned{border-right-color:#28a745;border-bottom-color:#28a745}.side-top{top:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-right{top:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-bottom{bottom:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.side-left{bottom:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.guide-text{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);color:#fff;font-size:14px;font-weight:600;text-align:center;white-space:normal;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px;z-index:20}.quality-indicator{position:absolute;top:20px;right:20px;display:flex;align-items:center;gap:8px;background:rgba(0, 0, 0, 0.8);padding:8px 12px;border-radius:20px;z-index:25;transition:all 0.3s ease}.quality-indicator.warning{background:rgba(255, 152, 0, 0.9)}.quality-indicator.good{background:rgba(76, 175, 80, 0.9)}.quality-score{color:#fff;font-size:12px;font-weight:600;min-width:30px;text-align:center}.quality-status{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:bold;color:#fff;transition:all 0.3s ease}.quality-status.ready{background:#4CAF50}.quality-status.not-ready{background:#f44336}.card-outline.quality-warning{animation:qualityWarning 1s ease-in-out infinite alternate}@keyframes qualityWarning{0%{box-shadow:0 0 0 3px rgba(255, 152, 0, 0.6)}100%{box-shadow:0 0 0 6px rgba(255, 152, 0, 0.3)}}.capture-animation{position:absolute;top:0;left:0;width:100%;height:100%;background:#fff;opacity:0;z-index:30;pointer-events:none;animation:captureFlash 0.6s ease-out}@keyframes captureFlash{0%{opacity:0}15%{opacity:0.8}30%{opacity:0}45%{opacity:0.4}60%{opacity:0}100%{opacity:0}}.card-outline.capturing{animation:pulseGreen 0.6s ease-out}@keyframes pulseGreen{0%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}50%{border-color:#28a745;box-shadow:0 0 0 8px rgba(40, 167, 69, 0.6)}100%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}}.flip-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showFlipInstruction 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.id-card-icon{width:80px;height:50px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:8px;position:relative;animation:flipCard 2s ease-in-out infinite;box-shadow:0 4px 12px rgba(0, 0, 0, 0.3)}.id-card-icon::before{content:'';position:absolute;top:8px;left:8px;width:16px;height:12px;background:rgba(255, 255, 255, 0.9);border-radius:2px}.id-card-icon::after{content:'';position:absolute;top:25px;left:8px;width:64px;height:3px;background:rgba(255, 255, 255, 0.7);border-radius:1px;box-shadow:0 6px 0 rgba(255, 255, 255, 0.7), 0 12px 0 rgba(255, 255, 255, 0.7)}.flip-text{margin-top:12px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px}@keyframes showFlipInstruction{0%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}}@keyframes flipCard{0%{transform:rotateY(0deg)}50%{transform:rotateY(180deg)}100%{transform:rotateY(360deg)}}.success-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showSuccessMessage 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.check-icon{width:80px;height:80px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:50%;position:relative;animation:bounceSuccess 0.6s ease-out;box-shadow:0 4px 16px rgba(108, 117, 125, 0.4);display:flex;align-items:center;justify-content:center}.check-icon::before{content:'';position:absolute;width:20px;height:35px;border:4px solid #fff;border-top:none;border-left:none;transform:rotate(45deg);animation:drawCheck 0.4s ease-out 0.2s both}.success-text{margin-top:16px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px;animation:fadeInUp 0.5s ease-out 0.4s both}@keyframes showSuccessMessage{0%{opacity:0;transform:translate(-50%, -50%) scale(0.5)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.9)}}@keyframes bounceSuccess{0%{transform:scale(0)}50%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes drawCheck{0%{width:0;height:0}50%{width:20px;height:0}100%{width:20px;height:35px}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}100%{opacity:1;transform:translateY(0)}}.skip-button{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.skip-button:hover{background:#f8f9fa}.skip-button:active{background:#e9ecef;transform:translateX(-50%) translateY(0)}.camera-controls{position:absolute;top:16px;right:16px;z-index:25;display:flex;gap:8px;pointer-events:auto}.camera-selector-button{height:32px;padding:0 10px;border:none;border-radius:8px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(12px);color:#ffffff;font-size:12px;font-weight:500;cursor:pointer;transition:all 0.2s ease;display:flex;align-items:center;justify-content:center;border:1px solid rgba(255, 255, 255, 0.1);white-space:nowrap;min-width:fit-content}.camera-selector-button:hover{background:rgba(0, 0, 0, 0.8);border-color:rgba(255, 255, 255, 0.2);transform:translateY(-1px)}.camera-selector-button:active{transform:translateY(0);background:rgba(0, 0, 0, 0.9)}.camera-selector-button:disabled,.camera-selector-button.loading{opacity:0.7;cursor:not-allowed;pointer-events:none}.camera-selector-button:disabled:hover,.camera-selector-button.loading:hover{transform:none;background:rgba(0, 0, 0, 0.6);border-color:rgba(255, 255, 255, 0.1)}.button-spinner{width:16px;height:16px;border:2px solid rgba(255, 255, 255, 0.3);border-top:2px solid #ffffff;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.camera-selector-dropdown{position:absolute;top:56px;right:16px;z-index:30;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;min-width:260px;max-width:300px;border:1px solid rgba(255, 255, 255, 0.1);overflow:hidden;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}@keyframes slideInFromTop{0%{opacity:0;transform:translateY(-8px) scale(0.95)}100%{opacity:1;transform:translateY(0) scale(1)}}.camera-selector-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-bottom:1px solid rgba(255, 255, 255, 0.1)}.camera-selector-header span{font-weight:500;color:#ffffff;font-size:13px;opacity:0.9}.close-selector{width:20px;height:20px;border:none;background:none;color:rgba(255, 255, 255, 0.7);font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all 0.2s ease}.close-selector:hover{background:rgba(255, 255, 255, 0.1);color:#ffffff}.camera-list{padding:4px 0;max-height:240px;overflow-y:auto}.camera-option{width:100%;padding:8px 12px;border:none;background:none;text-align:left;cursor:pointer;transition:all 0.2s ease;display:flex;justify-content:space-between;align-items:center;color:rgba(255, 255, 255, 0.9)}.camera-option:hover{background:rgba(255, 255, 255, 0.08)}.camera-option.selected{background:rgba(255, 255, 255, 0.12);color:#ffffff}.camera-label{font-size:13px;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-right:8px;font-weight:400}.selected-indicator{font-size:14px;color:#ffffff;opacity:0.9}.device-info{padding:6px 12px;border-top:1px solid rgba(255, 255, 255, 0.1);background:rgba(255, 255, 255, 0.05)}.device-info small{color:rgba(255, 255, 255, 0.6);font-size:11px;text-transform:capitalize;font-weight:400}@media (max-width: 480px){.camera-controls{top:12px;right:12px;gap:6px}.camera-selector-button{height:36px;padding:0 12px;font-size:11px;border-radius:6px}.camera-selector-dropdown{right:12px;top:48px;min-width:240px;max-width:calc(100vw - 24px)}.camera-selector-header{padding:6px 10px}.camera-option{padding:6px 10px}.device-info{padding:4px 10px}}.watermark{position:absolute;bottom:12px;right:12px;z-index:15;pointer-events:none;opacity:0.7}.watermark img{height:24px;width:auto;filter:drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))}.component-status{position:absolute;top:16px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);display:flex;align-items:center;gap:6px;padding:6px 10px;z-index:40;height:32px;width:fit-content;animation:slideInFromTop 0.3s ease-out}.status-spinner{width:16px;height:16px;border:1px solid rgba(255, 255, 255, 0.3);border-top:1px solid #ffffff;border-radius:50%;animation:statusSpin 1s linear infinite;flex-shrink:0}.status-content{display:flex;flex-direction:column;gap:1px}.status-message{color:#ffffff;font-size:12px;font-weight:500;margin:0}.status-description{color:rgba(255, 255, 255, 0.7);font-size:10px;line-height:1.2;margin:0}@keyframes statusSpin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@media (max-width: 480px){.component-status{top:12px;left:12px;padding:4px 8px;gap:4px;height:28px;border-radius:8px}.status-spinner{width:14px;height:14px}.status-message{font-size:11px}.status-description{font-size:9px}}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.85);backdrop-filter:blur(4px);display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:30;border-radius:8px}.loading-spinner{width:50px;height:50px;border:3px solid rgba(255, 255, 255, 0.15);border-top:3px solid #28a745;border-radius:50%;animation:spin 1s ease-in-out infinite;margin-bottom:16px}.loading-text{color:#ffffff;font-size:14px;font-weight:500;text-align:center;opacity:0.9;margin-bottom:4px}.loading-description{color:rgba(255, 255, 255, 0.7);font-size:12px;text-align:center;opacity:0.8}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.performance-monitor{position:absolute;top:70px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromLeft 0.3s ease-out;transition:all 0.3s ease}@keyframes slideInFromLeft{0%{opacity:0;transform:translateX(-20px) scale(0.95)}100%{opacity:1;transform:translateX(0) scale(1)}}.performance-expanded{padding:6px 10px}.metrics-row{display:flex;gap:8px;margin-bottom:4px}.metrics-row:last-child{margin-bottom:0}.metric-compact{display:flex;flex-direction:column;align-items:center;gap:2px;min-width:50px}.metric-label{font-size:9px;color:rgba(255, 255, 255, 0.6);font-weight:500;text-transform:uppercase;letter-spacing:0.3px}.metric-value{font-size:10px;font-weight:600;font-family:'Monaco', 'Menlo', 'Consolas', monospace;padding:2px 4px;border-radius:3px;text-align:center;white-space:nowrap}.metric-value.good{color:#4ade80;background:rgba(74, 222, 128, 0.1);border:1px solid rgba(74, 222, 128, 0.2)}.metric-value.warning{color:#fbbf24;background:rgba(251, 191, 36, 0.1);border:1px solid rgba(251, 191, 36, 0.2)}.metric-value.danger{color:#f87171;background:rgba(248, 113, 113, 0.1);border:1px solid rgba(248, 113, 113, 0.2)}@media (max-width: 480px){.performance-monitor{top:60px;left:12px;width:fit-content}.performance-expanded{padding:4px 8px}.metrics-row{gap:6px;margin-bottom:3px}.metric-compact{min-width:45px;gap:1px}.metric-label{font-size:8px}.metric-value{font-size:9px;padding:1px 3px}}.quality-monitor{position:absolute;top:200px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromLeft 0.3s ease-out;transition:all 0.3s ease}.quality-text{padding:6px 10px;font-size:11px;color:white;font-family:'Monaco', 'Menlo', 'Consolas', monospace;line-height:1.4}.quality-fail{color:#ff9999}@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.7}}.metric-value.danger{animation:pulse 2s infinite}@media (max-width: 480px){.quality-monitor{top:160px;left:12px}.quality-text{padding:4px 8px;font-size:10px}}";
|
|
1299
|
+
const myComponentCss = ":host{display:block;width:100%;height:100%;font-family:system-ui, -apple-system, sans-serif;color:#1a1a1a}.detector-container{display:flex;flex-direction:column;align-items:center;width:100%;height:100%}h1{font-size:24px;font-weight:500;color:#333;margin:0 0 24px 0}.video-container{position:relative;width:100%;height:100%;background:#333;border:1px solid #e0e0e0;border-radius:8px;overflow:hidden}video,.detection-overlay{position:absolute;width:100%;height:100%;border-radius:8px}video.mirror,.detection-overlay.mirror{transform:rotateY(180deg)}.detection-overlay{z-index:1;pointer-events:none}video{z-index:0}.detection-box{transition:opacity 0.2s ease}.status{margin-top:16px;font-size:12px;color:#666}.overlay-mask{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;display:block;pointer-events:none}.card-outline{position:absolute;top:var(--mask-center-y, 50%);left:var(--mask-center-x, 50%);transform:translate(-50%, -50%);width:var(--mask-width, 88%);height:var(--mask-height, 55%);border:none;border-radius:4px;background:transparent;opacity:0.8}.side{position:absolute;background:#999;transition:background-color 0.3s ease;border-radius:1px}.side-top.aligned{border-left-color:#28a745;border-top-color:#28a745}.side-right.aligned{border-right-color:#28a745;border-top-color:#28a745}.side-bottom.aligned{border-left-color:#28a745;border-bottom-color:#28a745}.side-left.aligned{border-right-color:#28a745;border-bottom-color:#28a745}.side-top{top:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-right{top:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-bottom{bottom:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.side-left{bottom:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.guide-text{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);color:#fff;font-size:14px;font-weight:600;text-align:center;white-space:normal;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(12px);padding:12px 20px;border-radius:8px;max-width:300px;z-index:20;border:1px solid rgba(255, 255, 255, 0.1)}.quality-indicator{position:absolute;top:20px;right:20px;display:flex;align-items:center;gap:8px;background:rgba(0, 0, 0, 0.8);padding:8px 12px;border-radius:20px;z-index:25;transition:all 0.3s ease}.quality-indicator.warning{background:rgba(255, 152, 0, 0.9)}.quality-indicator.good{background:rgba(76, 175, 80, 0.9)}.quality-score{color:#fff;font-size:12px;font-weight:600;min-width:30px;text-align:center}.quality-status{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:bold;color:#fff;transition:all 0.3s ease}.quality-status.ready{background:#4CAF50}.quality-status.not-ready{background:#f44336}.card-outline.quality-warning{animation:qualityWarning 1s ease-in-out infinite alternate}@keyframes qualityWarning{0%{box-shadow:0 0 0 3px rgba(255, 152, 0, 0.6)}100%{box-shadow:0 0 0 6px rgba(255, 152, 0, 0.3)}}.capture-animation{position:absolute;top:0;left:0;width:100%;height:100%;background:#fff;opacity:0;z-index:30;pointer-events:none;animation:captureFlash 0.6s ease-out}@keyframes captureFlash{0%{opacity:0}15%{opacity:0.8}30%{opacity:0}45%{opacity:0.4}60%{opacity:0}100%{opacity:0}}.card-outline.capturing{animation:pulseGreen 0.6s ease-out}@keyframes pulseGreen{0%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}50%{border-color:#28a745;box-shadow:0 0 0 8px rgba(40, 167, 69, 0.6)}100%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}}.flip-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showFlipInstruction 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.id-card-icon{width:80px;height:50px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:8px;position:relative;animation:flipCard 2s ease-in-out infinite;box-shadow:0 4px 12px rgba(0, 0, 0, 0.3)}.id-card-icon::before{content:'';position:absolute;top:8px;left:8px;width:16px;height:12px;background:rgba(255, 255, 255, 0.9);border-radius:2px}.id-card-icon::after{content:'';position:absolute;top:25px;left:8px;width:64px;height:3px;background:rgba(255, 255, 255, 0.7);border-radius:1px;box-shadow:0 6px 0 rgba(255, 255, 255, 0.7), 0 12px 0 rgba(255, 255, 255, 0.7)}.flip-text{margin-top:12px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px}@keyframes showFlipInstruction{0%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}}@keyframes flipCard{0%{transform:rotateY(0deg)}50%{transform:rotateY(180deg)}100%{transform:rotateY(360deg)}}.success-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showSuccessMessage 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.check-icon{width:80px;height:80px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:50%;position:relative;animation:bounceSuccess 0.6s ease-out;box-shadow:0 4px 16px rgba(108, 117, 125, 0.4);display:flex;align-items:center;justify-content:center}.check-icon::before{content:'';position:absolute;width:20px;height:35px;border:4px solid #fff;border-top:none;border-left:none;transform:rotate(45deg);animation:drawCheck 0.4s ease-out 0.2s both}.success-text{margin-top:16px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px;animation:fadeInUp 0.5s ease-out 0.4s both}@keyframes showSuccessMessage{0%{opacity:0;transform:translate(-50%, -50%) scale(0.5)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.9)}}@keyframes bounceSuccess{0%{transform:scale(0)}50%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes drawCheck{0%{width:0;height:0}50%{width:20px;height:0}100%{width:20px;height:35px}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}100%{opacity:1;transform:translateY(0)}}.skip-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.skip-explanation{background:rgba(0, 0, 0, 0.5);color:#ffffff;padding:10px 16px;border-radius:8px;font-size:14px;font-weight:500;text-align:center;margin-bottom:12px;box-shadow:0 2px 8px rgba(0, 0, 0, 0.2);backdrop-filter:blur(12px);border:1px solid rgba(255, 255, 255, 0.1);animation:fadeIn 0.3s ease-in-out}@keyframes fadeIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.skip-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.skip-button:hover{background:#f8f9fa}.skip-button:active{background:#e9ecef;transform:translateY(1px)}.camera-controls{position:absolute;top:16px;right:16px;z-index:25;display:flex;gap:8px;pointer-events:auto}.camera-selector-button{height:32px;padding:0 10px;border:none;border-radius:8px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(12px);color:#ffffff;font-size:12px;font-weight:500;cursor:pointer;transition:all 0.2s ease;display:flex;align-items:center;justify-content:center;border:1px solid rgba(255, 255, 255, 0.1);white-space:nowrap;min-width:fit-content}.camera-selector-button:hover{background:rgba(0, 0, 0, 0.8);border-color:rgba(255, 255, 255, 0.2);transform:translateY(-1px)}.camera-selector-button:active{transform:translateY(0);background:rgba(0, 0, 0, 0.9)}.camera-selector-button:disabled,.camera-selector-button.loading{opacity:0.7;cursor:not-allowed;pointer-events:none}.camera-selector-button:disabled:hover,.camera-selector-button.loading:hover{transform:none;background:rgba(0, 0, 0, 0.6);border-color:rgba(255, 255, 255, 0.1)}.button-spinner{width:16px;height:16px;border:2px solid rgba(255, 255, 255, 0.3);border-top:2px solid #ffffff;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.camera-selector-dropdown{position:absolute;top:56px;right:16px;z-index:30;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;min-width:260px;max-width:300px;border:1px solid rgba(255, 255, 255, 0.1);overflow:hidden;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}@keyframes slideInFromTop{0%{opacity:0;transform:translateY(-8px) scale(0.95)}100%{opacity:1;transform:translateY(0) scale(1)}}.camera-selector-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-bottom:1px solid rgba(255, 255, 255, 0.1)}.camera-selector-header span{font-weight:500;color:#ffffff;font-size:13px;opacity:0.9}.close-selector{width:20px;height:20px;border:none;background:none;color:rgba(255, 255, 255, 0.7);font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all 0.2s ease}.close-selector:hover{background:rgba(255, 255, 255, 0.1);color:#ffffff}.camera-list{padding:4px 0;max-height:240px;overflow-y:auto}.camera-option{width:100%;padding:8px 12px;border:none;background:none;text-align:left;cursor:pointer;transition:all 0.2s ease;display:flex;justify-content:space-between;align-items:center;color:rgba(255, 255, 255, 0.9)}.camera-option:hover{background:rgba(255, 255, 255, 0.08)}.camera-option.selected{background:rgba(255, 255, 255, 0.12);color:#ffffff}.camera-label{font-size:13px;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-right:8px;font-weight:400}.selected-indicator{font-size:14px;color:#ffffff;opacity:0.9}.device-info{padding:6px 12px;border-top:1px solid rgba(255, 255, 255, 0.1);background:rgba(255, 255, 255, 0.05)}.device-info small{color:rgba(255, 255, 255, 0.6);font-size:11px;text-transform:capitalize;font-weight:400}@media (max-width: 480px){.camera-controls{top:12px;right:12px;gap:6px}.camera-selector-button{height:36px;padding:0 12px;font-size:11px;border-radius:6px}.camera-selector-dropdown{right:12px;top:48px;min-width:240px;max-width:calc(100vw - 24px)}.camera-selector-header{padding:6px 10px}.camera-option{padding:6px 10px}.device-info{padding:4px 10px}}.watermark{position:absolute;bottom:12px;right:12px;z-index:15;pointer-events:none;opacity:0.7}.watermark img{height:24px;width:auto;filter:drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))}.component-status{position:absolute;top:16px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);display:flex;align-items:center;gap:6px;padding:6px 10px;z-index:40;height:32px;width:fit-content;animation:slideInFromTop 0.3s ease-out}.status-spinner{width:16px;height:16px;border:1px solid rgba(255, 255, 255, 0.3);border-top:1px solid #ffffff;border-radius:50%;animation:statusSpin 1s linear infinite;flex-shrink:0}.status-content{display:flex;flex-direction:column;gap:1px}.status-message{color:#ffffff;font-size:12px;font-weight:500;margin:0}.status-description{color:rgba(255, 255, 255, 0.7);font-size:10px;line-height:1.2;margin:0}@keyframes statusSpin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@media (max-width: 480px){.component-status{top:12px;left:12px;padding:4px 8px;gap:4px;height:28px;border-radius:8px}.status-spinner{width:14px;height:14px}.status-message{font-size:11px}.status-description{font-size:9px}}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.85);backdrop-filter:blur(4px);display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:30;border-radius:8px}.loading-spinner{width:50px;height:50px;border:3px solid rgba(255, 255, 255, 0.15);border-top:3px solid #28a745;border-radius:50%;animation:spin 1s ease-in-out infinite;margin-bottom:16px}.loading-text{color:#ffffff;font-size:14px;font-weight:500;text-align:center;opacity:0.9;margin-bottom:4px}.loading-description{color:rgba(255, 255, 255, 0.7);font-size:12px;text-align:center;opacity:0.8}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.performance-monitor{position:absolute;top:70px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromLeft 0.3s ease-out;transition:all 0.3s ease}@keyframes slideInFromLeft{0%{opacity:0;transform:translateX(-20px) scale(0.95)}100%{opacity:1;transform:translateX(0) scale(1)}}.performance-expanded{padding:6px 10px}.metrics-row{display:flex;gap:8px;margin-bottom:4px}.metrics-row:last-child{margin-bottom:0}.metric-compact{display:flex;flex-direction:column;align-items:center;gap:2px;min-width:50px}.metric-label{font-size:9px;color:rgba(255, 255, 255, 0.6);font-weight:500;text-transform:uppercase;letter-spacing:0.3px}.metric-value{font-size:10px;font-weight:600;font-family:'Monaco', 'Menlo', 'Consolas', monospace;padding:2px 4px;border-radius:3px;text-align:center;white-space:nowrap}.metric-value.good{color:#4ade80;background:rgba(74, 222, 128, 0.1);border:1px solid rgba(74, 222, 128, 0.2)}.metric-value.warning{color:#fbbf24;background:rgba(251, 191, 36, 0.1);border:1px solid rgba(251, 191, 36, 0.2)}.metric-value.danger{color:#f87171;background:rgba(248, 113, 113, 0.1);border:1px solid rgba(248, 113, 113, 0.2)}@media (max-width: 480px){.performance-monitor{top:60px;left:12px;width:fit-content}.performance-expanded{padding:4px 8px}.metrics-row{gap:6px;margin-bottom:3px}.metric-compact{min-width:45px;gap:1px}.metric-label{font-size:8px}.metric-value{font-size:9px;padding:1px 3px}}.quality-monitor{position:absolute;top:200px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromLeft 0.3s ease-out;transition:all 0.3s ease}.quality-text{padding:6px 10px;font-size:11px;color:white;font-family:'Monaco', 'Menlo', 'Consolas', monospace;line-height:1.4}.quality-fail{color:#ff9999}@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.7}}.metric-value.danger{animation:pulse 2s infinite}@media (max-width: 480px){.quality-monitor{top:160px;left:12px}.quality-text{padding:4px 8px;font-size:10px}}";
|
|
1145
1300
|
|
|
1146
1301
|
const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H {
|
|
1147
1302
|
constructor() {
|
|
@@ -1154,11 +1309,13 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
1154
1309
|
get el() { return this; }
|
|
1155
1310
|
debug = false;
|
|
1156
1311
|
alignmentTolerance = 15;
|
|
1157
|
-
maskSize =
|
|
1312
|
+
maskSize = 90;
|
|
1158
1313
|
cropMargin = 20;
|
|
1159
1314
|
useDocumentClassification = false;
|
|
1160
1315
|
preferredCamera = 'auto';
|
|
1161
1316
|
captureDelay = 1500;
|
|
1317
|
+
enableBackDocumentTimer = false;
|
|
1318
|
+
backDocumentTimerDuration = 20;
|
|
1162
1319
|
captureCompleted;
|
|
1163
1320
|
isReady;
|
|
1164
1321
|
// State derived from services
|
|
@@ -1187,6 +1344,7 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
1187
1344
|
successfulDetections: 0,
|
|
1188
1345
|
detectionRate: 0
|
|
1189
1346
|
};
|
|
1347
|
+
backDocumentTimerRemaining = 0;
|
|
1190
1348
|
// Services
|
|
1191
1349
|
serviceContainer;
|
|
1192
1350
|
logger;
|
|
@@ -1205,6 +1363,7 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
1205
1363
|
hasScreenshotTaken = false;
|
|
1206
1364
|
alignmentStartTime;
|
|
1207
1365
|
alignmentTimer;
|
|
1366
|
+
backDocumentTimer;
|
|
1208
1367
|
// Performance monitoring
|
|
1209
1368
|
performanceMetrics = {
|
|
1210
1369
|
fps: 0,
|
|
@@ -1670,7 +1829,13 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
1670
1829
|
});
|
|
1671
1830
|
}
|
|
1672
1831
|
// Update document detection state
|
|
1832
|
+
const wasDocumentDetected = this.hasDocumentDetected;
|
|
1673
1833
|
this.hasDocumentDetected = detections.length > 0;
|
|
1834
|
+
// Restart timer if document detected during back capture
|
|
1835
|
+
if (!wasDocumentDetected && this.hasDocumentDetected &&
|
|
1836
|
+
captureState.step === 'back' && this.enableBackDocumentTimer) {
|
|
1837
|
+
this.startBackDocumentTimer();
|
|
1838
|
+
}
|
|
1674
1839
|
// Adaptive frame rate
|
|
1675
1840
|
if (detections.length === 0) {
|
|
1676
1841
|
this.consecutiveFailures++;
|
|
@@ -1747,7 +1912,7 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
1747
1912
|
availableCameras: [],
|
|
1748
1913
|
selectedCameraId: null,
|
|
1749
1914
|
deviceType: 'desktop'};
|
|
1750
|
-
return (h("div", { key: '
|
|
1915
|
+
return (h("div", { key: '9d4d77042218ab3d0bc4fb1ce879db09dc3e78b4', class: "detector-container" }, h("div", { key: '51ac8ccb1275637282b038ad8364d19f14ef61b1', class: "video-container" }, h("video", { key: 'a34f0481da20ec5b7b62b21aa275ec5f6dfec5d1', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), h("div", { key: '43b71dfe3eaf20ffa66a4139e24b1af6a2074631', ref: el => this.detectionContainer = el, class: `detection-overlay ${this.shouldMirrorVideo ? 'mirror' : ''}` }, this.debug && this.detectionBoxes.map((box, index) => (h("div", { key: index, class: "detection-box", style: {
|
|
1751
1916
|
position: 'absolute',
|
|
1752
1917
|
left: `${box.x}px`,
|
|
1753
1918
|
top: `${box.y}px`,
|
|
@@ -1756,7 +1921,9 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
1756
1921
|
border: '2px solid #32406C',
|
|
1757
1922
|
pointerEvents: 'none',
|
|
1758
1923
|
boxSizing: 'border-box'
|
|
1759
|
-
} })))), this.isMaskReady && (h("div", { key: '
|
|
1924
|
+
} })))), this.isMaskReady && (h("div", { key: 'c2596f8cabb227e3ea3b082495f52b141cb1690f', class: "overlay-mask" }, h("div", { key: 'ba1ea39b5df1cd312a9bd9410b7225a29cfb8a29', class: "card-outline" }, h("div", { key: '6ce4d4d969d5f3fbcf75a4eb285f61d434c5633b', class: "side side-top" }), h("div", { key: '36653ecc4fcda25dfc84bc4d1f4c4c5dfb71ced7', class: "side side-right" }), h("div", { key: '8b108fa8fb370b229a0d1a77cb1ff044319a8f75', class: "side side-bottom" }), h("div", { key: 'a7aa3b45c065a50445aafd5c3ccefb57b0c9c769', class: "side side-left" }), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'b94b92273e12a019238e11ae57f21e140f13c3f1', class: "guide-text" }, "Alinee su identificaci\u00F3n con el marco"))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '144c3741003ec0cc148bb6ce92012d7b3cd110c8', class: "skip-section" }, h("div", { key: 'f0a984a6b75afa374c5d47da9d53e39f98071da0', class: "skip-explanation" }, "Si tu documento no tiene lado trasero, da clic en el bot\u00F3n para continuar con el proceso"), h("button", { key: '57ac30d776e30709aab6e0a621cef889da3cc677', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button" }, this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
|
|
1925
|
+
? `Saltar reverso (${this.backDocumentTimerRemaining}s)`
|
|
1926
|
+
: 'Saltar reverso'))), captureState.isVideoActive && (h("div", { key: 'bd45628707e0169317ed3dd4247e1056d7046104', class: "camera-controls" }, h("button", { key: 'e750fbf4d5d76d9e9596823bb2b86801ef19e485', class: `camera-selector-button ${this.isSwitchingCamera ? 'loading' : ''}`, onClick: () => this.toggleCameraSelector(), type: "button", title: "Seleccionar c\u00E1mara", disabled: this.isSwitchingCamera }, this.isSwitchingCamera ? (h("div", { class: "button-spinner" })) : ('Cámaras')))), this.showCameraSelector && cameraInfo.availableCameras.length > 0 && (h("div", { key: '40ada780a8ea13aeeaee9cb39bc6496f69f2679d', class: "camera-selector-dropdown" }, h("div", { key: '3a920bb02ba024f0359513f10544bf0528ecee6d', class: "camera-selector-header" }, h("span", { key: 'e5efd478a602b13821ba53cb9a7a59d1b4a71178' }, "Seleccionar C\u00E1mara"), h("button", { key: '2df6cc11e162be74862029e33815927e3fa8f2f8', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: '06934642dff134c9e1a6872f935a5892a9c7b835', class: "camera-list" }, cameraInfo.availableCameras.map((camera) => (h("button", { key: camera.id, class: `camera-option ${cameraInfo.selectedCameraId === camera.id ? 'selected' : ''}`, onClick: () => this.handleCameraSwitch(camera.id), type: "button" }, h("span", { class: "camera-label" }, camera.label || `Cámara ${cameraInfo.availableCameras.indexOf(camera) + 1}`), cameraInfo.selectedCameraId === camera.id && (h("span", { class: "selected-indicator" }, "\u2713")))))), h("div", { key: '8d5ede287c2efb0ebe418bee8dc7fb310443c991', class: "device-info" }, h("small", { key: 'b7dd10565113694b09f01ab28ffa29262ae1d2bc' }, "Dispositivo: ", cameraInfo.deviceType)))))), captureState.isCapturing && (h("div", { key: '2f9e549e6c0c56d4db5835e58361fb17bba6cf90', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: 'a6ef0ed127f23e9d764896ed743ca8d8454851a6', class: "flip-animation" }, h("div", { key: '0b04411f88a634bb3243b00ca2d5a45fd6962dea', class: "id-card-icon" }), h("div", { key: '9327be58879b407cea87f455989406e58302e9d1', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: 'bd268578b5003e99256e3340b4a9a6fb7656be64', class: "success-animation" }, h("div", { key: '064e0a5b9851de14bc6829f028e7ea7161fd1633', class: "check-icon" }), h("div", { key: 'bdcd94a8806399e396e218a359c10b11d05f38d6', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: '3d9af617376c16e44e065873919c3d90ff46110a', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: 'be7b56decfd6f12dcca46b2a9456480e3d5ac00e', class: "status-spinner" })), h("div", { key: '5fe9850883cb749cebaa18c3e9c13ca21325e373', class: "status-content" }, h("div", { key: '43fdb50691e4b98e56126af1a129f625061128bf', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: 'b76cbfa4a0349421fcd535d3fd8bf40c89ca3aef', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: 'eddefb464af0487ab9ab2a0f76dccbb6a2092e51', class: "performance-monitor" }, h("div", { key: '7b7d93b56cb4cd4fbb1bdde89c6150b282fa805e', class: "performance-expanded" }, h("div", { key: 'f302e8b9d985fb8cad53c4c4e0d37a3bf5a63261', class: "metrics-row" }, h("div", { key: 'e8d8f2420ee8643a7f454d38065c75b5be598f77', class: "metric-compact" }, h("span", { key: '6e52eb5bb06e0df57e61774de38c31349f45e22b', class: "metric-label" }, "FPS"), h("span", { key: '6636f9cea20c49b49c17db86188e2f6b214c45c3', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: 'afa1d9dec05b14256a1b1fcec8638b8c21a56e37', class: "metric-compact" }, h("span", { key: '9c55e30f5d01582648bacc1fb38ca1990485a591', class: "metric-label" }, "MEM"), h("span", { key: 'ca263601e8715027f95ffb2d5413a643dc570cf2', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: '03caf19961fd01b7781484d49d8121b1e78c161f', class: "metrics-row" }, h("div", { key: 'bffb08f01f703411f7c8605e4f8d95b1c37b5c0f', class: "metric-compact" }, h("span", { key: '9b92279b3253cc669412733facb3751f4344d69f', class: "metric-label" }, "INF"), h("span", { key: '3234d4150e2e1479e3b552767af8123e69911d6c', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: '77082d2669db53f19fb50b3bbfa1ebefb0b86ff4', class: "metric-compact" }, h("span", { key: 'cc6ef96c72c800ba36dab2a388f1de863b2dacd5', class: "metric-label" }, "FRAME"), h("span", { key: 'e2bb4b7351869a76e810f8bbf20d805154495e35', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: '5700d7ef839fa77686299d79445203090dc8079f', class: "metrics-row" }, h("div", { key: 'a2999a035fccb7f250c01b084075490678513c87', class: "metric-compact" }, h("span", { key: '3677d58665996fa5969507dbaff9e956b2ea54ee', class: "metric-label" }, "DET"), h("span", { key: 'c584312438b339c82a3bdc33f00fb985ff2a6f55', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: '58866219f213bf8607083f30be2d5ca5d0515cea', class: "metric-compact" }, h("span", { key: 'd90b450051331347f219b6c0f197536d0dcee9b7', class: "metric-label" }, "RATE"), h("span", { key: 'f6e6cd7948e06014e5a0416e4e81394fa36ec61d', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: 'c1d0194f181a0082cc1aa5452de382908da61b65', class: "watermark" }, h("img", { key: 'e04d35f3c79a2b4a3922ab5b0f102220171fa7c0', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
|
|
1760
1927
|
}
|
|
1761
1928
|
// Utility methods
|
|
1762
1929
|
updateDetectionBoxes(boxes) {
|
|
@@ -1825,6 +1992,15 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
1825
1992
|
bottomSide?.classList.toggle('aligned', currentAlignment.bottom);
|
|
1826
1993
|
leftSide?.classList.toggle('aligned', currentAlignment.left);
|
|
1827
1994
|
const allSidesAligned = this.detectionService.areAllSidesAligned(currentAlignment);
|
|
1995
|
+
// Restart back document timer if any border is aligned during back capture
|
|
1996
|
+
const captureState = this.stateManager.getCaptureState();
|
|
1997
|
+
if (captureState.step === 'back' && this.enableBackDocumentTimer && bestBox) {
|
|
1998
|
+
const anyBorderAligned = currentAlignment.top || currentAlignment.right ||
|
|
1999
|
+
currentAlignment.bottom || currentAlignment.left;
|
|
2000
|
+
if (anyBorderAligned) {
|
|
2001
|
+
this.startBackDocumentTimer();
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
1828
2004
|
if (allSidesAligned && bestBox) {
|
|
1829
2005
|
cardOutline?.classList.add('perfect-match');
|
|
1830
2006
|
corners?.forEach(corner => corner.classList.add('perfect-match'));
|
|
@@ -1939,6 +2115,7 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
1939
2115
|
showFlipAnimation: false,
|
|
1940
2116
|
isDetectionPaused: false
|
|
1941
2117
|
});
|
|
2118
|
+
this.startBackDocumentTimer();
|
|
1942
2119
|
}, 3000);
|
|
1943
2120
|
}
|
|
1944
2121
|
else if (captureState.step === 'back') {
|
|
@@ -1989,9 +2166,32 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
1989
2166
|
cancelAnimationFrame(this.animationId);
|
|
1990
2167
|
this.animationId = undefined;
|
|
1991
2168
|
}
|
|
2169
|
+
this.clearBackDocumentTimer();
|
|
1992
2170
|
this.detectionBoxes = [];
|
|
1993
2171
|
this.logger.state('DETECTOR_DETENIDO', { timestamp: Date.now() });
|
|
1994
2172
|
}
|
|
2173
|
+
startBackDocumentTimer() {
|
|
2174
|
+
if (!this.enableBackDocumentTimer)
|
|
2175
|
+
return;
|
|
2176
|
+
if (this.backDocumentTimer) {
|
|
2177
|
+
clearInterval(this.backDocumentTimer);
|
|
2178
|
+
}
|
|
2179
|
+
this.backDocumentTimerRemaining = this.backDocumentTimerDuration;
|
|
2180
|
+
this.backDocumentTimer = window.setInterval(() => {
|
|
2181
|
+
this.backDocumentTimerRemaining--;
|
|
2182
|
+
if (this.backDocumentTimerRemaining <= 0) {
|
|
2183
|
+
this.clearBackDocumentTimer();
|
|
2184
|
+
this.skipBackCapture();
|
|
2185
|
+
}
|
|
2186
|
+
}, 1000);
|
|
2187
|
+
}
|
|
2188
|
+
clearBackDocumentTimer() {
|
|
2189
|
+
if (this.backDocumentTimer) {
|
|
2190
|
+
clearInterval(this.backDocumentTimer);
|
|
2191
|
+
this.backDocumentTimer = undefined;
|
|
2192
|
+
}
|
|
2193
|
+
this.backDocumentTimerRemaining = 0;
|
|
2194
|
+
}
|
|
1995
2195
|
toggleCameraSelector() {
|
|
1996
2196
|
if (this.isSwitchingCamera)
|
|
1997
2197
|
return; // Don't toggle if switching camera
|
|
@@ -2137,6 +2337,8 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
2137
2337
|
"useDocumentClassification": [4, "use-document-classification"],
|
|
2138
2338
|
"preferredCamera": [1, "preferred-camera"],
|
|
2139
2339
|
"captureDelay": [2, "capture-delay"],
|
|
2340
|
+
"enableBackDocumentTimer": [4, "enable-back-document-timer"],
|
|
2341
|
+
"backDocumentTimerDuration": [2, "back-document-timer-duration"],
|
|
2140
2342
|
"detectionBoxes": [32],
|
|
2141
2343
|
"sideAlignment": [32],
|
|
2142
2344
|
"isMaskReady": [32],
|
|
@@ -2146,6 +2348,7 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
2146
2348
|
"hasDocumentDetected": [32],
|
|
2147
2349
|
"currentStatus": [32],
|
|
2148
2350
|
"performanceData": [32],
|
|
2351
|
+
"backDocumentTimerRemaining": [32],
|
|
2149
2352
|
"getCapturedImages": [64],
|
|
2150
2353
|
"isProcessCompleted": [64],
|
|
2151
2354
|
"startCapture": [64],
|