@jaak.ai/stamps 2.1.0-dev.6 → 2.1.0-dev.7
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/dist/cjs/jaak-stamps-webcomponent.cjs.js +1 -1
- package/dist/cjs/jaak-stamps.cjs.entry.js +264 -25
- 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 +36 -11
- package/dist/collection/components/my-component/my-component.js +233 -21
- package/dist/collection/components/my-component/my-component.js.map +1 -1
- package/dist/collection/services/DetectionService.js +32 -4
- package/dist/collection/services/DetectionService.js.map +1 -1
- package/dist/components/jaak-stamps.js +265 -25
- 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 +264 -25
- 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-be6b6ca3.entry.js +2 -0
- package/dist/jaak-stamps-webcomponent/p-be6b6ca3.entry.js.map +1 -0
- package/dist/types/components/my-component/my-component.d.ts +5 -0
- package/package.json +1 -1
- package/dist/jaak-stamps-webcomponent/p-d05dc382.entry.js +0 -2
- package/dist/jaak-stamps-webcomponent/p-d05dc382.entry.js.map +0 -1
package/dist/cjs/loader.cjs.js
CHANGED
|
@@ -5,7 +5,7 @@ var index = require('./index-BfhtOB0D.js');
|
|
|
5
5
|
const defineCustomElements = async (win, options) => {
|
|
6
6
|
if (typeof window === 'undefined') return undefined;
|
|
7
7
|
await index.globalScripts();
|
|
8
|
-
return index.bootstrapLazy([["jaak-stamps.cjs",[[1,"jaak-stamps",{"debug":[4],"alignmentTolerance":[2,"alignment-tolerance"],"maskSize":[2,"mask-size"],"cropMargin":[2,"crop-margin"],"useDocumentClassification":[4,"use-document-classification"],"useDocumentDetector":[4,"use-document-detector"],"preferredCamera":[1,"preferred-camera"],"captureDelay":[2,"capture-delay"],"enableBackDocumentTimer":[4,"enable-back-document-timer"],"backDocumentTimerDuration":[2,"back-document-timer-duration"],"detectionBoxes":[32],"sideAlignment":[32],"isMaskReady":[32],"shouldMirrorVideo":[32],"showCameraSelector":[32],"isSwitchingCamera":[32],"hasDocumentDetected":[32],"cameraInfoWithAutofocus":[32],"currentStatus":[32],"performanceData":[32],"backDocumentTimerRemaining":[32],"showManualCaptureButton":[32],"performanceDegradedMode":[32],"showPerformanceMessage":[32],"captureStateVersion":[32],"getCapturedImages":[64],"isProcessCompleted":[64],"startCapture":[64],"stopCapture":[64],"resetCapture":[64],"skipBackCapture":[64],"getStatus":[64],"preloadModel":[64],"getCameraInfo":[64],"setPreferredCamera":[64],"setCaptureDelay":[64],"getCaptureDelay":[64]}]]]], options);
|
|
8
|
+
return index.bootstrapLazy([["jaak-stamps.cjs",[[1,"jaak-stamps",{"debug":[4],"alignmentTolerance":[2,"alignment-tolerance"],"maskSize":[2,"mask-size"],"cropMargin":[2,"crop-margin"],"useDocumentClassification":[4,"use-document-classification"],"useDocumentDetector":[4,"use-document-detector"],"preferredCamera":[1,"preferred-camera"],"captureDelay":[2,"capture-delay"],"enableBackDocumentTimer":[4,"enable-back-document-timer"],"backDocumentTimerDuration":[2,"back-document-timer-duration"],"detectionBoxes":[32],"sideAlignment":[32],"isMaskReady":[32],"shouldMirrorVideo":[32],"showCameraSelector":[32],"isSwitchingCamera":[32],"hasDocumentDetected":[32],"cameraInfoWithAutofocus":[32],"currentStatus":[32],"performanceData":[32],"backDocumentTimerRemaining":[32],"showManualCaptureButton":[32],"performanceDegradedMode":[32],"showPerformanceMessage":[32],"captureStateVersion":[32],"processingButton":[32],"getCapturedImages":[64],"isProcessCompleted":[64],"startCapture":[64],"stopCapture":[64],"resetCapture":[64],"skipBackCapture":[64],"getStatus":[64],"preloadModel":[64],"getCameraInfo":[64],"setPreferredCamera":[64],"setCaptureDelay":[64],"getCaptureDelay":[64]}]]]], options);
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
exports.setNonce = index.setNonce;
|
|
@@ -571,11 +571,12 @@ video {
|
|
|
571
571
|
transform: translateY(1px);
|
|
572
572
|
}
|
|
573
573
|
|
|
574
|
-
.capture-button:disabled
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
574
|
+
.capture-button:disabled,
|
|
575
|
+
.capture-button.primary-button:disabled {
|
|
576
|
+
cursor: not-allowed !important;
|
|
577
|
+
transform: none !important;
|
|
578
|
+
opacity: 0.7 !important;
|
|
579
|
+
transition: none !important;
|
|
579
580
|
}
|
|
580
581
|
|
|
581
582
|
/* Responsive para móviles */
|
|
@@ -599,6 +600,14 @@ video {
|
|
|
599
600
|
padding: 10px 20px;
|
|
600
601
|
font-size: 13px;
|
|
601
602
|
}
|
|
603
|
+
|
|
604
|
+
/* Ensure disabled styles work on mobile too */
|
|
605
|
+
.capture-button:disabled,
|
|
606
|
+
.capture-button.primary-button:disabled,
|
|
607
|
+
.skip-button:disabled {
|
|
608
|
+
opacity: 0.7 !important;
|
|
609
|
+
cursor: not-allowed !important;
|
|
610
|
+
}
|
|
602
611
|
}
|
|
603
612
|
|
|
604
613
|
.skip-explanation {
|
|
@@ -663,6 +672,13 @@ video {
|
|
|
663
672
|
transform: translateY(1px);
|
|
664
673
|
}
|
|
665
674
|
|
|
675
|
+
.skip-button:disabled {
|
|
676
|
+
cursor: not-allowed !important;
|
|
677
|
+
transform: none !important;
|
|
678
|
+
opacity: 0.7 !important;
|
|
679
|
+
transition: none !important;
|
|
680
|
+
}
|
|
681
|
+
|
|
666
682
|
/* Camera controls */
|
|
667
683
|
.camera-controls {
|
|
668
684
|
position: absolute;
|
|
@@ -724,10 +740,13 @@ video {
|
|
|
724
740
|
.button-spinner {
|
|
725
741
|
width: 16px;
|
|
726
742
|
height: 16px;
|
|
727
|
-
border: 2px solid rgba(
|
|
728
|
-
border-top: 2px solid #
|
|
743
|
+
border: 2px solid rgba(0, 0, 0, 0.2);
|
|
744
|
+
border-top: 2px solid #333333;
|
|
729
745
|
border-radius: 50%;
|
|
730
746
|
animation: spin 1s linear infinite;
|
|
747
|
+
display: inline-block;
|
|
748
|
+
margin-right: 8px;
|
|
749
|
+
vertical-align: middle;
|
|
731
750
|
}
|
|
732
751
|
|
|
733
752
|
@keyframes spin {
|
|
@@ -1282,10 +1301,10 @@ video {
|
|
|
1282
1301
|
}
|
|
1283
1302
|
|
|
1284
1303
|
.manual-capture-button:disabled {
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1304
|
+
cursor: not-allowed !important;
|
|
1305
|
+
transform: none !important;
|
|
1306
|
+
opacity: 0.7 !important;
|
|
1307
|
+
transition: none !important;
|
|
1289
1308
|
}
|
|
1290
1309
|
|
|
1291
1310
|
/* Responsive para móviles */
|
|
@@ -1300,4 +1319,10 @@ video {
|
|
|
1300
1319
|
padding: 10px 20px;
|
|
1301
1320
|
font-size: 13px;
|
|
1302
1321
|
}
|
|
1322
|
+
|
|
1323
|
+
/* Ensure disabled styles work on mobile too */
|
|
1324
|
+
.manual-capture-button:disabled {
|
|
1325
|
+
opacity: 0.7 !important;
|
|
1326
|
+
cursor: not-allowed !important;
|
|
1327
|
+
}
|
|
1303
1328
|
}
|
|
@@ -52,6 +52,7 @@ export class JaakStamps {
|
|
|
52
52
|
performanceDegradedMode = false; // Auto-switched to manual mode due to performance
|
|
53
53
|
showPerformanceMessage = false; // Show performance message temporarily
|
|
54
54
|
captureStateVersion = 0; // Triggers re-render when StateManager changes
|
|
55
|
+
processingButton = null; // Track which button is processing
|
|
55
56
|
// Services
|
|
56
57
|
serviceContainer;
|
|
57
58
|
eventBus;
|
|
@@ -103,14 +104,19 @@ export class JaakStamps {
|
|
|
103
104
|
canvasPool = [];
|
|
104
105
|
MAX_CANVAS_POOL_SIZE = 3;
|
|
105
106
|
async componentDidLoad() {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
this.
|
|
107
|
+
try {
|
|
108
|
+
this.updateStatus('Preparando capturador...', 'Configurando herramientas de captura', 'initializing');
|
|
109
|
+
await this.initializeServices();
|
|
110
|
+
this.updateStatus('Preparando funciones...', 'Configurando herramientas de trabajo', 'initializing');
|
|
111
|
+
await this.setupEventListeners();
|
|
112
|
+
this.updateStatus('Configurando cámara...', 'Detectando dispositivos disponibles', 'initializing');
|
|
113
|
+
await this.initializeComponent();
|
|
114
|
+
if (this.debug) {
|
|
115
|
+
this.initializePerformanceMonitor();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
this.updateStatus('Error de inicialización', error.message, 'error');
|
|
114
120
|
}
|
|
115
121
|
}
|
|
116
122
|
async initializeServices() {
|
|
@@ -425,8 +431,14 @@ export class JaakStamps {
|
|
|
425
431
|
}
|
|
426
432
|
}
|
|
427
433
|
async skipBackCapture() {
|
|
434
|
+
console.log('🟡 Botón clicked: Saltar reverso');
|
|
435
|
+
// Set processing state immediately
|
|
436
|
+
this.processingButton = 'skip-back';
|
|
437
|
+
// Add small delay to show spinner
|
|
438
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
428
439
|
const readyCheck = this.isComponentReady();
|
|
429
440
|
if (!readyCheck.ready) {
|
|
441
|
+
this.processingButton = null;
|
|
430
442
|
return { success: false, error: readyCheck.message };
|
|
431
443
|
}
|
|
432
444
|
try {
|
|
@@ -443,6 +455,10 @@ export class JaakStamps {
|
|
|
443
455
|
catch (error) {
|
|
444
456
|
return { success: false, error: error.message };
|
|
445
457
|
}
|
|
458
|
+
finally {
|
|
459
|
+
// Always clear processing state when done
|
|
460
|
+
this.processingButton = null;
|
|
461
|
+
}
|
|
446
462
|
}
|
|
447
463
|
async getStatus() {
|
|
448
464
|
const readyCheck = this.isComponentReady();
|
|
@@ -620,9 +636,53 @@ export class JaakStamps {
|
|
|
620
636
|
// Always allow getting capture delay, even during initialization
|
|
621
637
|
return this.captureDelay;
|
|
622
638
|
}
|
|
639
|
+
// Memory and device capability detection
|
|
640
|
+
checkDeviceCapabilities() {
|
|
641
|
+
const deviceMemory = navigator.deviceMemory;
|
|
642
|
+
const hardwareConcurrency = navigator.hardwareConcurrency || 1;
|
|
643
|
+
const isLowEndDevice = hardwareConcurrency <= 2;
|
|
644
|
+
const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
645
|
+
const isSafari = /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
|
|
646
|
+
// Si tenemos info de memoria del dispositivo
|
|
647
|
+
if (deviceMemory && deviceMemory < 4) {
|
|
648
|
+
return {
|
|
649
|
+
canUseML: false,
|
|
650
|
+
reason: `Memoria del dispositivo (${deviceMemory}GB) insuficiente para detección automática. Modo manual activado para mejor rendimiento.`,
|
|
651
|
+
memoryMB: deviceMemory * 1024
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
// Dispositivos móviles de gama baja
|
|
655
|
+
if (isMobile && isLowEndDevice) {
|
|
656
|
+
return {
|
|
657
|
+
canUseML: false,
|
|
658
|
+
reason: 'Dispositivo móvil optimizado detectado. Modo manual activado para mejor rendimiento y duración de batería.',
|
|
659
|
+
memoryMB: null
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
// Safari tiene limitaciones conocidas con WASM
|
|
663
|
+
if (isSafari) {
|
|
664
|
+
return {
|
|
665
|
+
canUseML: false,
|
|
666
|
+
reason: 'Safari detectado. Modo manual activado por compatibilidad optimizada con este navegador.',
|
|
667
|
+
memoryMB: null
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
return {
|
|
671
|
+
canUseML: true,
|
|
672
|
+
reason: 'Dispositivo compatible con detección automática.',
|
|
673
|
+
memoryMB: deviceMemory ? deviceMemory * 1024 : null
|
|
674
|
+
};
|
|
675
|
+
}
|
|
623
676
|
// DETECTION METHODS
|
|
624
677
|
async startDetection() {
|
|
625
678
|
try {
|
|
679
|
+
// Verificar capacidades del dispositivo antes de cargar modelos
|
|
680
|
+
const capabilities = this.checkDeviceCapabilities();
|
|
681
|
+
// Si el dispositivo no puede usar ML o tenemos problemas de memoria, usar modo manual
|
|
682
|
+
if (!capabilities.canUseML && this.useDocumentDetector) {
|
|
683
|
+
this.switchToManualModeWithWarning(capabilities.reason);
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
626
686
|
// Paso 1: Verificar y cargar modelos si es necesario
|
|
627
687
|
if (!this.detectionService.isModelLoaded()) {
|
|
628
688
|
const loadStartTime = performance.now();
|
|
@@ -632,16 +692,32 @@ export class JaakStamps {
|
|
|
632
692
|
await this.detectionService.loadModel();
|
|
633
693
|
}
|
|
634
694
|
catch (modelError) {
|
|
635
|
-
|
|
636
|
-
|
|
695
|
+
// Si es un error de memoria, cambiar a modo manual con mensaje específico
|
|
696
|
+
if (modelError.message.includes('Out of memory') || modelError.message.includes('no available backend')) {
|
|
697
|
+
const memoryInfo = navigator.deviceMemory ? `(${navigator.deviceMemory}GB disponible)` : '';
|
|
698
|
+
this.switchToManualModeWithWarning(`Memoria insuficiente para detección automática ${memoryInfo}. Modo manual activado - funciona igual de bien!`);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
else {
|
|
702
|
+
this.switchToManualModeWithError('Error al cargar modelo de detección');
|
|
703
|
+
throw modelError;
|
|
704
|
+
}
|
|
637
705
|
}
|
|
638
706
|
this.updateStatus('Optimizando detección...', 'Configurando reconocimiento de documentos', 'loading');
|
|
639
707
|
try {
|
|
640
708
|
await this.detectionService.loadClassificationModel();
|
|
641
709
|
}
|
|
642
710
|
catch (classificationError) {
|
|
643
|
-
|
|
644
|
-
|
|
711
|
+
// Si es un error de memoria, cambiar a modo manual con mensaje específico
|
|
712
|
+
if (classificationError.message.includes('Out of memory') || classificationError.message.includes('no available backend')) {
|
|
713
|
+
const memoryInfo = navigator.deviceMemory ? `(${navigator.deviceMemory}GB disponible)` : '';
|
|
714
|
+
this.switchToManualModeWithWarning(`Memoria insuficiente para clasificación automática ${memoryInfo}. Modo manual activado para optimizar rendimiento.`);
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
else {
|
|
718
|
+
this.switchToManualModeWithError('Error al cargar modelo de clasificación');
|
|
719
|
+
throw classificationError;
|
|
720
|
+
}
|
|
645
721
|
}
|
|
646
722
|
const loadEndTime = performance.now();
|
|
647
723
|
const loadTime = loadEndTime - loadStartTime;
|
|
@@ -652,11 +728,27 @@ export class JaakStamps {
|
|
|
652
728
|
}
|
|
653
729
|
// Paso 2: Detectar y configurar dispositivos
|
|
654
730
|
this.updateStatus('Configurando cámara...', 'Buscando dispositivos disponibles', 'loading');
|
|
655
|
-
|
|
656
|
-
|
|
731
|
+
try {
|
|
732
|
+
await this.cameraService.enumerateDevices();
|
|
733
|
+
}
|
|
734
|
+
catch (enumerateError) {
|
|
735
|
+
throw new Error(`Error al enumerar dispositivos: ${enumerateError.message}`);
|
|
736
|
+
}
|
|
737
|
+
try {
|
|
738
|
+
await this.updateCameraInfoWithAutofocus();
|
|
739
|
+
}
|
|
740
|
+
catch (cameraInfoError) {
|
|
741
|
+
throw new Error(`Error al actualizar información de cámara: ${cameraInfoError.message}`);
|
|
742
|
+
}
|
|
657
743
|
// Paso 3: Configurar cámara seleccionada
|
|
658
744
|
this.updateStatus('Ajustando cámara...', 'Configurando calidad de imagen', 'loading');
|
|
659
|
-
|
|
745
|
+
let stream;
|
|
746
|
+
try {
|
|
747
|
+
stream = await this.cameraService.setupCamera();
|
|
748
|
+
}
|
|
749
|
+
catch (setupError) {
|
|
750
|
+
throw new Error(`Error al configurar cámara: ${setupError.message}`);
|
|
751
|
+
}
|
|
660
752
|
// Paso 4: Inicializar video y mostrar estado de análisis inicial
|
|
661
753
|
if (this.useDocumentDetector) {
|
|
662
754
|
this.updateStatus('Analizando estabilidad...', 'Evaluando rendimiento del sistema', 'loading');
|
|
@@ -664,7 +756,12 @@ export class JaakStamps {
|
|
|
664
756
|
else {
|
|
665
757
|
this.updateStatus('Captura activa', 'Posicione su documento y use el botón para capturar', 'active');
|
|
666
758
|
}
|
|
667
|
-
|
|
759
|
+
try {
|
|
760
|
+
await this.initializeVideoStream(stream);
|
|
761
|
+
}
|
|
762
|
+
catch (videoError) {
|
|
763
|
+
throw new Error(`Error al inicializar video: ${videoError.message}`);
|
|
764
|
+
}
|
|
668
765
|
// Paso 5: Calibrar máscara
|
|
669
766
|
if (this.detectionContainer) {
|
|
670
767
|
const container = this.detectionContainer.parentElement;
|
|
@@ -889,7 +986,7 @@ export class JaakStamps {
|
|
|
889
986
|
isCapturing: false
|
|
890
987
|
};
|
|
891
988
|
const cameraInfo = this.cameraInfoWithAutofocus;
|
|
892
|
-
return (h("div", { key: '
|
|
989
|
+
return (h("div", { key: '51cc6d0f873691852f938940b131732252b970c1', class: "detector-container" }, h("div", { key: '009480499c0a2833bf9f6bd28003142ca3dd3750', class: "video-container" }, h("video", { key: '88a99a1a90c8d817e40549a255324b2da342797f', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), h("div", { key: '7ede15ccd6f67b3081d907777de7b0d1a1b4cfd6', 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: {
|
|
893
990
|
position: 'absolute',
|
|
894
991
|
left: `${box.x}px`,
|
|
895
992
|
top: `${box.y}px`,
|
|
@@ -898,9 +995,9 @@ export class JaakStamps {
|
|
|
898
995
|
border: '2px solid #32406C',
|
|
899
996
|
pointerEvents: 'none',
|
|
900
997
|
boxSizing: 'border-box'
|
|
901
|
-
} })))), this.isMaskReady && (h("div", { key: '
|
|
998
|
+
} })))), this.isMaskReady && (h("div", { key: '63beb4330ab171a5e63237b1d83dcace61422018', class: "overlay-mask" }, h("div", { key: '93cfac6898de6ece6c7dd8f02ba2b79ce6591755', class: "card-outline" }, h("div", { key: '3087d3c51f42ea8d720cea4170dcb68e8bb385e1', class: "side side-top" }), h("div", { key: '992e311b895da161d3b5c49dde346ae378139641', class: "side side-right" }), h("div", { key: '5fb3d7b704f08177b2b9c6e4fbaf685f251a3e53', class: "side side-bottom" }), h("div", { key: '76f6e2cb856632c58809ccdabdf3f7d9a588c9da', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '142dfc187e07100278e16b19018e4b5fb96d964a', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'bba078ce4c9585631b6a8154f878464b1f779c8b', class: "back-capture-section" }, h("div", { key: 'ec94c9ba2cb373a539f0e6cc3eb356294cebf3ea', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode) && (h("button", { key: '30561e1fc88090c6bb4d0cd7909a33a9525b0ac2', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-back' && (h("span", { key: '4b3e3356507c7f654705425e201d0303d727db72', class: "button-spinner" })), "Capturar Reverso")), h("button", { key: '1abfada41312658eab4966d8fcdb711a6c4762e6', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'skip-back' && (h("span", { key: '3cab3ce751cb38174b6d061170a66ac654a90a38', class: "button-spinner" })), this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
|
|
902
999
|
? `Saltar reverso (${this.backDocumentTimerRemaining}s)`
|
|
903
|
-
: 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: '
|
|
1000
|
+
: 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: 'b773fe579cc039fd90ff5e61976752bcf631d16e', class: "camera-controls" }, h("button", { key: '8535463b13cc02e0030d14c1d57390e560572b4f', 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: 'c4b159cf28c24ba2ec0a658bf6f1296c6aba47e3', class: "camera-selector-dropdown" }, h("div", { key: '033273241b77cedc414dee00b70926c3a659910a', class: "camera-selector-header" }, h("span", { key: '83fb4c7ae2387b85134a3ca0c5a156beaf73e481' }, "Seleccionar C\u00E1mara"), h("button", { key: 'f65b6e994603e616af8d69df198c3d8471125695', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: 'fd90d4c4db1e910c5d05b9ce19a252967c71ad1f', 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}`, camera.hasAutofocus && (h("span", { class: "autofocus-icon", title: "Autofoco disponible" }, "\u29BF"))), cameraInfo.selectedCameraId === camera.id && (h("span", { class: "selected-indicator" }, "\u2713")))))), h("div", { key: '49faa944b3c0c052e18f48e9dda2758cd2c0ae6b', class: "device-info" }, h("small", { key: '15e95207aef60a78b2912a6c00a1b61ab760b72d' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'a67a3795837adcd307fa3666c338376cecae16d0', class: "manual-capture-section" }, h("button", { key: '7f21ccd9b622d97bfce80962038de8be7cd6e33d', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-front' && (h("span", { key: 'a4b5e865f373cc0e7787098eedd2d4df413d310f', class: "button-spinner" })), "Capturar Frente"))))), captureState.isCapturing && (h("div", { key: '0b02e81963136dfda62a8980bc5a1f5662509fb8', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: '5eb16e12a7ce16720ca7bdd11aefd902ba772e24', class: "flip-animation" }, h("div", { key: '4c6f3ed33c5080e9e18d17c4594cf394250c3517', class: "id-card-icon" }), h("div", { key: 'd848d7a98540988a8f491bcf8f6f6ad9c5dccfd4', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: '94863e6d0c404188d548db428af918274d882652', class: "success-animation" }, h("div", { key: 'a90b777e7b7eb533fabec2c15f79a4bd18778f0b', class: "check-icon" }), h("div", { key: '2152e5a3756f58f996c520b58cb1b6cca1763e94', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: 'ae18e06bf291429a74d1b6c8a0c4d37d473f7b30', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: 'b6b03ed285868d7d3350a2a73e59cb1d65a47401', class: "status-spinner" })), h("div", { key: 'dc85b49dd1cfcddf7300fb3f327d2e1de8ab9bff', class: "status-content" }, h("div", { key: '82461ed0c6d70a0c95ae6b7144ff1d8b8371c6fc', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: '24aa77ec92ca5a48d1bed4cf98ae591bdbff74f0', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: '3b56a0b305ca07407c09a73624a4040cf6625b56', class: "performance-monitor" }, h("div", { key: '52f975da1502f6b08a0b2c828bfd0be8d10e36f8', class: "performance-expanded" }, h("div", { key: 'ea2f444255add0415c7f88cdea2733e1244b17bd', class: "metrics-row" }, h("div", { key: 'e3c2370f1a900594940cb321d5b1661690018025', class: "metric-compact" }, h("span", { key: '25c2f402c9b69f21736c494420e7a396673e9893', class: "metric-label" }, "FPS"), h("span", { key: '505de593f7927544cd874332127e84c72131da72', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: '5cb1ff4bc1ac33988404e59dac3d01d5a55893b9', class: "metric-compact" }, h("span", { key: 'ce701538abbfe797b288520ab4c277bf7a1d6a05', class: "metric-label" }, "MEM"), h("span", { key: 'efc383e993ad72c20cbfc630e20b2bf9a617a02d', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: 'b6b6b832740c44d4f78cddf99ba1d139dc3d4739', class: "metrics-row" }, h("div", { key: '3a8903a05aed8adb1626f93bee6ba258fbea9a7d', class: "metric-compact" }, h("span", { key: 'aabc56057156217b3be771ab3b1e92590fa886c5', class: "metric-label" }, "INF"), h("span", { key: '1080df34860cc891cda94c5aacc754cbde18a138', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: 'ac152093d4c0cc25862aac638fc4693dd0c51a69', class: "metric-compact" }, h("span", { key: 'b23712dbc0b9b8e9cb6e2c659e5af3844ec0ebe7', class: "metric-label" }, "FRAME"), h("span", { key: '461f88519b339fbad6444f009312f72efbc6e450', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: '8f99afe2c94f37fd3a6feb082cc9aa96f54fc5e1', class: "metrics-row" }, h("div", { key: 'da7ac0fd842f38bbdcac01550764f9fe1bd666a2', class: "metric-compact" }, h("span", { key: 'a5dcd9c8753ba42038f869efa50ae9602cdf6256', class: "metric-label" }, "DET"), h("span", { key: 'e98b91ea98a41637baea1fcfda0bb590cf5d24a0', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: '3ac54161a712d305a098eae0a3b5d21a731c6019', class: "metric-compact" }, h("span", { key: '3c8cc465433be3b490887457a6c3967dbbda6a7d', class: "metric-label" }, "RATE"), h("span", { key: 'f2e083118fe107c7dc2a675e3f661466cea6d479', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: '10b6c32b0460e194d680c63b30a078c51a26e9c9', class: "watermark" }, h("img", { key: 'f5954a0ba3f90a642e0d5c6c14d5b549cd193018', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
|
|
904
1001
|
}
|
|
905
1002
|
// Utility methods
|
|
906
1003
|
updateDetectionBoxes(boxes) {
|
|
@@ -1016,9 +1113,24 @@ export class JaakStamps {
|
|
|
1016
1113
|
}
|
|
1017
1114
|
}
|
|
1018
1115
|
async takeManualScreenshot() {
|
|
1019
|
-
|
|
1116
|
+
console.log('🔵 Botón clicked: Capturar (Frente/Reverso)');
|
|
1117
|
+
// Set processing state immediately
|
|
1118
|
+
const captureState = this.stateManager?.getCaptureState();
|
|
1119
|
+
if (captureState?.step === 'front') {
|
|
1120
|
+
this.processingButton = 'capture-front';
|
|
1121
|
+
}
|
|
1122
|
+
else if (captureState?.step === 'back') {
|
|
1123
|
+
this.processingButton = 'capture-back';
|
|
1124
|
+
}
|
|
1125
|
+
console.log('🔵 processingButton set to:', this.processingButton);
|
|
1126
|
+
// Add small delay to show spinner
|
|
1127
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
1128
|
+
if (!this.videoRef) {
|
|
1129
|
+
this.processingButton = null;
|
|
1020
1130
|
return;
|
|
1131
|
+
}
|
|
1021
1132
|
// When using manual capture, use mask coordinates for cropping
|
|
1133
|
+
// Note: processingButton will be cleared inside takeScreenshotWithMaskCoordinates
|
|
1022
1134
|
await this.takeScreenshotWithMaskCoordinates();
|
|
1023
1135
|
}
|
|
1024
1136
|
async takeScreenshotWithMaskCoordinates() {
|
|
@@ -1094,6 +1206,8 @@ export class JaakStamps {
|
|
|
1094
1206
|
this.completeProcess(true);
|
|
1095
1207
|
this.returnCanvasToPool(captureCanvas);
|
|
1096
1208
|
this.returnCanvasToPool(croppedCanvas);
|
|
1209
|
+
// Clear processing button when passport is detected
|
|
1210
|
+
this.processingButton = null;
|
|
1097
1211
|
return;
|
|
1098
1212
|
}
|
|
1099
1213
|
}
|
|
@@ -1114,6 +1228,8 @@ export class JaakStamps {
|
|
|
1114
1228
|
});
|
|
1115
1229
|
this.triggerRerender();
|
|
1116
1230
|
this.startBackDocumentTimer();
|
|
1231
|
+
// Clear processing button after animation completes
|
|
1232
|
+
this.processingButton = null;
|
|
1117
1233
|
}, 3000);
|
|
1118
1234
|
}
|
|
1119
1235
|
else if (captureState.step === 'back') {
|
|
@@ -1124,6 +1240,8 @@ export class JaakStamps {
|
|
|
1124
1240
|
}
|
|
1125
1241
|
});
|
|
1126
1242
|
this.completeProcess(false);
|
|
1243
|
+
// Clear processing button after back capture completes
|
|
1244
|
+
this.processingButton = null;
|
|
1127
1245
|
}
|
|
1128
1246
|
// Return canvases to pool after use
|
|
1129
1247
|
this.returnCanvasToPool(captureCanvas);
|
|
@@ -1217,6 +1335,9 @@ export class JaakStamps {
|
|
|
1217
1335
|
this.stopPerformanceMonitoring();
|
|
1218
1336
|
// Liberar recursos de ONNX
|
|
1219
1337
|
this.releaseOnnxResources();
|
|
1338
|
+
// Resetear máscara a blanco y limpiar detecciones
|
|
1339
|
+
this.resetMaskToWhite();
|
|
1340
|
+
this.detectionBoxes = [];
|
|
1220
1341
|
this.hasAutoSwitchedToManual = true;
|
|
1221
1342
|
this.performanceDegradedMode = true;
|
|
1222
1343
|
this.showManualCaptureButton = true;
|
|
@@ -1227,6 +1348,75 @@ export class JaakStamps {
|
|
|
1227
1348
|
}, 5000);
|
|
1228
1349
|
}
|
|
1229
1350
|
// Método para cambiar a modo manual por errores de ONNX
|
|
1351
|
+
switchToManualModeWithWarning(warningMessage) {
|
|
1352
|
+
// Solo cambiar si el detector está habilitado y no se ha cambiado ya
|
|
1353
|
+
if (!this.useDocumentDetector || this.hasAutoSwitchedToManual) {
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
1356
|
+
// No necesitamos liberar recursos ONNX porque no se han cargado aún
|
|
1357
|
+
// Resetear máscara a blanco y limpiar detecciones
|
|
1358
|
+
this.resetMaskToWhite();
|
|
1359
|
+
this.detectionBoxes = [];
|
|
1360
|
+
// Cambiar a modo manual
|
|
1361
|
+
this.hasAutoSwitchedToManual = true;
|
|
1362
|
+
this.performanceDegradedMode = true;
|
|
1363
|
+
this.showManualCaptureButton = true;
|
|
1364
|
+
this.useDocumentDetector = false; // Desactivar detector automático
|
|
1365
|
+
// Actualizar el estado con mensaje informativo (no error)
|
|
1366
|
+
this.updateStatus('Modo manual activado', warningMessage, 'active');
|
|
1367
|
+
// Continuar con la configuración de cámara
|
|
1368
|
+
this.continueWithCameraSetup();
|
|
1369
|
+
}
|
|
1370
|
+
async continueWithCameraSetup() {
|
|
1371
|
+
try {
|
|
1372
|
+
// Paso 2: Detectar y configurar dispositivos
|
|
1373
|
+
this.updateStatus('Configurando cámara...', 'Buscando dispositivos disponibles', 'loading');
|
|
1374
|
+
try {
|
|
1375
|
+
await this.cameraService.enumerateDevices();
|
|
1376
|
+
}
|
|
1377
|
+
catch (enumerateError) {
|
|
1378
|
+
throw new Error(`Error al enumerar dispositivos: ${enumerateError.message}`);
|
|
1379
|
+
}
|
|
1380
|
+
try {
|
|
1381
|
+
await this.updateCameraInfoWithAutofocus();
|
|
1382
|
+
}
|
|
1383
|
+
catch (cameraInfoError) {
|
|
1384
|
+
throw new Error(`Error al actualizar información de cámara: ${cameraInfoError.message}`);
|
|
1385
|
+
}
|
|
1386
|
+
// Paso 3: Configurar cámara seleccionada
|
|
1387
|
+
this.updateStatus('Ajustando cámara...', 'Configurando calidad de imagen', 'loading');
|
|
1388
|
+
let stream;
|
|
1389
|
+
try {
|
|
1390
|
+
stream = await this.cameraService.setupCamera();
|
|
1391
|
+
}
|
|
1392
|
+
catch (setupError) {
|
|
1393
|
+
throw new Error(`Error al configurar cámara: ${setupError.message}`);
|
|
1394
|
+
}
|
|
1395
|
+
// Paso 4: Inicializar video
|
|
1396
|
+
this.updateStatus('Captura manual', 'Posicione su documento y use el botón para capturar', 'active');
|
|
1397
|
+
try {
|
|
1398
|
+
await this.initializeVideoStream(stream);
|
|
1399
|
+
}
|
|
1400
|
+
catch (videoError) {
|
|
1401
|
+
throw new Error(`Error al inicializar video: ${videoError.message}`);
|
|
1402
|
+
}
|
|
1403
|
+
// Paso 5: Calibrar máscara
|
|
1404
|
+
if (this.detectionContainer) {
|
|
1405
|
+
const container = this.detectionContainer.parentElement;
|
|
1406
|
+
const rect = container.getBoundingClientRect();
|
|
1407
|
+
this.updateMaskDimensions(rect);
|
|
1408
|
+
}
|
|
1409
|
+
// Finalizar
|
|
1410
|
+
this.startTime = Date.now();
|
|
1411
|
+
this.stateManager.updateCaptureState({ isLoading: false });
|
|
1412
|
+
// Mostrar botón manual (ya debe estar habilitado)
|
|
1413
|
+
this.showManualCaptureButton = true;
|
|
1414
|
+
}
|
|
1415
|
+
catch (error) {
|
|
1416
|
+
this.updateStatus('Error de cámara', error.message, 'error');
|
|
1417
|
+
throw error;
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1230
1420
|
switchToManualModeWithError(errorMessage) {
|
|
1231
1421
|
// Solo cambiar si el detector está habilitado y no se ha cambiado ya
|
|
1232
1422
|
if (!this.useDocumentDetector || this.hasAutoSwitchedToManual) {
|
|
@@ -1234,6 +1424,9 @@ export class JaakStamps {
|
|
|
1234
1424
|
}
|
|
1235
1425
|
// Liberar recursos de ONNX inmediatamente
|
|
1236
1426
|
this.releaseOnnxResources();
|
|
1427
|
+
// Resetear máscara a blanco y limpiar detecciones
|
|
1428
|
+
this.resetMaskToWhite();
|
|
1429
|
+
this.detectionBoxes = [];
|
|
1237
1430
|
// Cambiar a modo manual
|
|
1238
1431
|
this.hasAutoSwitchedToManual = true;
|
|
1239
1432
|
this.performanceDegradedMode = true;
|
|
@@ -1484,6 +1677,24 @@ export class JaakStamps {
|
|
|
1484
1677
|
// Performance is good, use base frame skip
|
|
1485
1678
|
return this.BASE_FRAME_SKIP;
|
|
1486
1679
|
}
|
|
1680
|
+
// Método para resetear la máscara a color blanco
|
|
1681
|
+
resetMaskToWhite() {
|
|
1682
|
+
const cardOutline = this.el.shadowRoot?.querySelector('.card-outline');
|
|
1683
|
+
const corners = this.el.shadowRoot?.querySelectorAll('.corner');
|
|
1684
|
+
const topSide = this.el.shadowRoot?.querySelector('.side-top');
|
|
1685
|
+
const rightSide = this.el.shadowRoot?.querySelector('.side-right');
|
|
1686
|
+
const bottomSide = this.el.shadowRoot?.querySelector('.side-bottom');
|
|
1687
|
+
const leftSide = this.el.shadowRoot?.querySelector('.side-left');
|
|
1688
|
+
// Remover todas las clases de alineación y estado perfecto
|
|
1689
|
+
cardOutline?.classList.remove('perfect-match');
|
|
1690
|
+
corners?.forEach(corner => corner.classList.remove('perfect-match'));
|
|
1691
|
+
topSide?.classList.remove('aligned');
|
|
1692
|
+
rightSide?.classList.remove('aligned');
|
|
1693
|
+
bottomSide?.classList.remove('aligned');
|
|
1694
|
+
leftSide?.classList.remove('aligned');
|
|
1695
|
+
// Resetear estado de alineación
|
|
1696
|
+
this.sideAlignment = { top: false, right: false, bottom: false, left: false };
|
|
1697
|
+
}
|
|
1487
1698
|
// Canvas pool management for screenshots
|
|
1488
1699
|
getPooledCanvas(width, height) {
|
|
1489
1700
|
// Try to find a canvas with matching dimensions
|
|
@@ -1746,7 +1957,8 @@ export class JaakStamps {
|
|
|
1746
1957
|
"showManualCaptureButton": {},
|
|
1747
1958
|
"performanceDegradedMode": {},
|
|
1748
1959
|
"showPerformanceMessage": {},
|
|
1749
|
-
"captureStateVersion": {}
|
|
1960
|
+
"captureStateVersion": {},
|
|
1961
|
+
"processingButton": {}
|
|
1750
1962
|
};
|
|
1751
1963
|
}
|
|
1752
1964
|
static get events() {
|