@jaak.ai/stamps 2.0.0-dev.21 → 2.0.0-dev.23
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 +11 -4
- package/dist/cjs/jaak-stamps-webcomponent.cjs.js +1 -1
- package/dist/cjs/jaak-stamps.cjs.entry.js +27 -9
- 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.js +67 -9
- package/dist/collection/components/my-component/my-component.js.map +1 -1
- package/dist/components/jaak-stamps.js +29 -9
- 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 +27 -9
- 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-380b1ebe.entry.js +2 -0
- package/dist/jaak-stamps-webcomponent/p-380b1ebe.entry.js.map +1 -0
- package/dist/types/components/my-component/my-component.d.ts +4 -0
- package/dist/types/components.d.ts +16 -0
- package/package.json +1 -1
- package/dist/jaak-stamps-webcomponent/p-dd6cc14e.entry.js +0 -2
- package/dist/jaak-stamps-webcomponent/p-dd6cc14e.entry.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Jaak Stamps - Document Detector Web Component
|
|
2
2
|
|
|
3
|
-
[](https://stenciljs.com)
|
|
4
|
-
|
|
5
3
|
Un componente web para la detección y captura automática de documentos de identificación usando visión artificial y redes neuronales.
|
|
6
4
|
|
|
7
5
|
## Características
|
|
@@ -10,6 +8,7 @@ Un componente web para la detección y captura automática de documentos de iden
|
|
|
10
8
|
- 🎯 **Guía visual** para posicionamiento óptimo del documento
|
|
11
9
|
- 📋 **Captura doble cara** (frente y reverso) con opción de omitir reverso
|
|
12
10
|
- 🖼 **Doble salida** para cada lado: imagen completa y recorte del documento
|
|
11
|
+
- ✂️ **Recorte configurable** con margen personalizable alrededor del documento
|
|
13
12
|
- 🔧 **API programática** para control total del proceso
|
|
14
13
|
- 📱 **Responsive** y compatible con dispositivos móviles
|
|
15
14
|
- ⚡ **Optimización automática** usando ONNX Runtime Web
|
|
@@ -43,7 +42,7 @@ yarn add @jaak.ai/stamps
|
|
|
43
42
|
<script type="module" src="https://unpkg.com/@jaak.ai/stamps/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js"></script>
|
|
44
43
|
</head>
|
|
45
44
|
<body>
|
|
46
|
-
<jaak-stamps id="detector" debug="false"></jaak-stamps>
|
|
45
|
+
<jaak-stamps id="detector" debug="false" mask-size="90" crop-margin="10"></jaak-stamps>
|
|
47
46
|
|
|
48
47
|
<button onclick="startCapture()">Iniciar Captura</button>
|
|
49
48
|
<button onclick="stopCapture()">Detener</button>
|
|
@@ -140,6 +139,8 @@ import { Component, ElementRef, ViewChild, OnInit } from '@angular/core';
|
|
|
140
139
|
<jaak-stamps
|
|
141
140
|
#detector
|
|
142
141
|
[debug]="false"
|
|
142
|
+
[maskSize]="90"
|
|
143
|
+
[cropMargin]="10"
|
|
143
144
|
(captureCompleted)="onCaptureCompleted($event)"
|
|
144
145
|
(isReady)="onComponentReady($event)">
|
|
145
146
|
</jaak-stamps>
|
|
@@ -241,7 +242,7 @@ import React, { useRef, useEffect, useImperativeHandle, forwardRef } from 'react
|
|
|
241
242
|
// Importar el web component
|
|
242
243
|
import '@jaak.ai/stamps/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js';
|
|
243
244
|
|
|
244
|
-
const JaakStampsWrapper = forwardRef(({ debug = false, onCaptureCompleted, onIsReady }, ref) => {
|
|
245
|
+
const JaakStampsWrapper = forwardRef(({ debug = false, maskSize = 90, cropMargin = 0, onCaptureCompleted, onIsReady }, ref) => {
|
|
245
246
|
const elementRef = useRef(null);
|
|
246
247
|
|
|
247
248
|
useImperativeHandle(ref, () => ({
|
|
@@ -285,6 +286,8 @@ const JaakStampsWrapper = forwardRef(({ debug = false, onCaptureCompleted, onIsR
|
|
|
285
286
|
<jaak-stamps
|
|
286
287
|
ref={elementRef}
|
|
287
288
|
debug={debug}
|
|
289
|
+
mask-size={maskSize}
|
|
290
|
+
crop-margin={cropMargin}
|
|
288
291
|
/>
|
|
289
292
|
);
|
|
290
293
|
});
|
|
@@ -364,6 +367,8 @@ function App() {
|
|
|
364
367
|
<JaakStampsWrapper
|
|
365
368
|
ref={detectorRef}
|
|
366
369
|
debug={false}
|
|
370
|
+
maskSize={90}
|
|
371
|
+
cropMargin={10}
|
|
367
372
|
onCaptureCompleted={handleCaptureCompleted}
|
|
368
373
|
onIsReady={handleIsReady}
|
|
369
374
|
/>
|
|
@@ -435,6 +440,8 @@ export default App;
|
|
|
435
440
|
|-----------|------|---------------|-------------|
|
|
436
441
|
| `debug` | `boolean` | `false` | Activa el modo debug para mostrar información de depuración |
|
|
437
442
|
| `alignmentTolerance` | `number` | `10` | Tolerancia en píxeles para considerar un lado alineado |
|
|
443
|
+
| `maskSize` | `number` | `90` | Porcentaje del video que ocupará la máscara de detección (50-100) |
|
|
444
|
+
| `cropMargin` | `number` | `0` | Margen en píxeles agregado al recorte del documento (0-100) |
|
|
438
445
|
|
|
439
446
|
### Métodos Públicos
|
|
440
447
|
|
|
@@ -18,7 +18,7 @@ var patchBrowser = () => {
|
|
|
18
18
|
|
|
19
19
|
patchBrowser().then(async (options) => {
|
|
20
20
|
await index.globalScripts();
|
|
21
|
-
return index.bootstrapLazy([["jaak-stamps.cjs",[[1,"jaak-stamps",{"debug":[4],"alignmentTolerance":[2,"alignment-tolerance"],"isVideoActive":[32],"statusMessage":[32],"statusColor":[32],"bestScore":[32],"capturedFullFrame":[32],"capturedCroppedId":[32],"capturedBackFullFrame":[32],"capturedBackCroppedId":[32],"captureStep":[32],"isCapturing":[32],"showFlipAnimation":[32],"showSuccessAnimation":[32],"shouldMirrorVideo":[32],"sideAlignment":[32],"isDetectionPaused":[32],"isLoading":[32],"isModelPreloaded":[32],"isMaskReady":[32],"getCapturedImages":[64],"isProcessCompleted":[64],"startCapture":[64],"stopCapture":[64],"resetCapture":[64],"getStatus":[64],"preloadModel":[64],"skipBackCapture":[64]}]]]], options);
|
|
21
|
+
return index.bootstrapLazy([["jaak-stamps.cjs",[[1,"jaak-stamps",{"debug":[4],"alignmentTolerance":[2,"alignment-tolerance"],"maskSize":[2,"mask-size"],"cropMargin":[2,"crop-margin"],"isVideoActive":[32],"statusMessage":[32],"statusColor":[32],"bestScore":[32],"capturedFullFrame":[32],"capturedCroppedId":[32],"capturedBackFullFrame":[32],"capturedBackCroppedId":[32],"captureStep":[32],"isCapturing":[32],"showFlipAnimation":[32],"showSuccessAnimation":[32],"shouldMirrorVideo":[32],"sideAlignment":[32],"isDetectionPaused":[32],"isLoading":[32],"isModelPreloaded":[32],"isMaskReady":[32],"getCapturedImages":[64],"isProcessCompleted":[64],"startCapture":[64],"stopCapture":[64],"resetCapture":[64],"getStatus":[64],"preloadModel":[64],"skipBackCapture":[64]}]]]], options);
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
exports.setNonce = index.setNonce;
|
|
@@ -13,6 +13,8 @@ const JaakStamps = class {
|
|
|
13
13
|
get el() { return index.getElement(this); }
|
|
14
14
|
debug = false;
|
|
15
15
|
alignmentTolerance = 10; // Tolerancia en píxeles para considerar un lado alineado (escalado para 320x320)
|
|
16
|
+
maskSize = 90; // Porcentaje del video que ocupará la máscara (default 90%)
|
|
17
|
+
cropMargin = 0; // Margen en píxeles para el recorte del documento (default 0)
|
|
16
18
|
captureCompleted;
|
|
17
19
|
isReady;
|
|
18
20
|
isVideoActive = false;
|
|
@@ -68,6 +70,18 @@ const JaakStamps = class {
|
|
|
68
70
|
console.log(...args);
|
|
69
71
|
}
|
|
70
72
|
}
|
|
73
|
+
validateMaskSize() {
|
|
74
|
+
if (this.maskSize < 50 || this.maskSize > 100) {
|
|
75
|
+
console.warn(`maskSize debe estar entre 50 y 100. Valor actual: ${this.maskSize}. Usando valor por defecto: 90`);
|
|
76
|
+
this.maskSize = 90;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
validateCropMargin() {
|
|
80
|
+
if (this.cropMargin < 0 || this.cropMargin > 100) {
|
|
81
|
+
console.warn(`cropMargin debe estar entre 0 y 100. Valor actual: ${this.cropMargin}. Usando valor por defecto: 0`);
|
|
82
|
+
this.cropMargin = 0;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
71
85
|
emitReadyEvent() {
|
|
72
86
|
const isDocumentReady = !!window.ort && this.isModelPreloaded;
|
|
73
87
|
this.isReady.emit(isDocumentReady);
|
|
@@ -81,6 +95,8 @@ const JaakStamps = class {
|
|
|
81
95
|
return settings.facingMode === 'environment';
|
|
82
96
|
}
|
|
83
97
|
async componentDidLoad() {
|
|
98
|
+
this.validateMaskSize();
|
|
99
|
+
this.validateCropMargin();
|
|
84
100
|
if (!window.ort) {
|
|
85
101
|
const script = document.createElement('script');
|
|
86
102
|
script.src = 'https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js';
|
|
@@ -148,14 +164,15 @@ const JaakStamps = class {
|
|
|
148
164
|
// Calculate what would be the max width if limited by video height
|
|
149
165
|
const maxWidthByHeight = displayedVideoHeight * this.ID1_ASPECT_RATIO;
|
|
150
166
|
let maskWidthInVideo, maskHeightInVideo;
|
|
167
|
+
const sizeRatio = this.maskSize / 100;
|
|
151
168
|
if (maxWidthByHeight <= displayedVideoWidth) {
|
|
152
169
|
// Video height is the limiting factor
|
|
153
|
-
maskHeightInVideo = displayedVideoHeight *
|
|
170
|
+
maskHeightInVideo = displayedVideoHeight * sizeRatio;
|
|
154
171
|
maskWidthInVideo = maskHeightInVideo * this.ID1_ASPECT_RATIO;
|
|
155
172
|
}
|
|
156
173
|
else {
|
|
157
174
|
// Video width is the limiting factor
|
|
158
|
-
maskWidthInVideo = displayedVideoWidth *
|
|
175
|
+
maskWidthInVideo = displayedVideoWidth * sizeRatio;
|
|
159
176
|
maskHeightInVideo = maskWidthInVideo / this.ID1_ASPECT_RATIO;
|
|
160
177
|
}
|
|
161
178
|
// Convert to percentages of the container
|
|
@@ -593,14 +610,15 @@ const JaakStamps = class {
|
|
|
593
610
|
// Calculate mask dimensions using the same logic as updateMaskDimensions
|
|
594
611
|
const maxWidthByHeight = displayedVideoHeight * this.ID1_ASPECT_RATIO;
|
|
595
612
|
let visualMaskWidth, visualMaskHeight;
|
|
613
|
+
const sizeRatio = this.maskSize / 100;
|
|
596
614
|
if (maxWidthByHeight <= displayedVideoWidth) {
|
|
597
615
|
// Video height is the limiting factor
|
|
598
|
-
visualMaskHeight = displayedVideoHeight *
|
|
616
|
+
visualMaskHeight = displayedVideoHeight * sizeRatio;
|
|
599
617
|
visualMaskWidth = visualMaskHeight * this.ID1_ASPECT_RATIO;
|
|
600
618
|
}
|
|
601
619
|
else {
|
|
602
620
|
// Video width is the limiting factor
|
|
603
|
-
visualMaskWidth = displayedVideoWidth *
|
|
621
|
+
visualMaskWidth = displayedVideoWidth * sizeRatio;
|
|
604
622
|
visualMaskHeight = visualMaskWidth / this.ID1_ASPECT_RATIO;
|
|
605
623
|
}
|
|
606
624
|
// Now map these visual mask dimensions to the distorted model space
|
|
@@ -767,10 +785,10 @@ const JaakStamps = class {
|
|
|
767
785
|
// Calcular las coordenadas de recorte basadas en la detección
|
|
768
786
|
const scaleX = this.videoRef.videoWidth / this.INPUT_SIZE;
|
|
769
787
|
const scaleY = this.videoRef.videoHeight / this.INPUT_SIZE;
|
|
770
|
-
const cropX = Math.max(0, this.lastDetectedBox.x * scaleX);
|
|
771
|
-
const cropY = Math.max(0, this.lastDetectedBox.y * scaleY);
|
|
772
|
-
const cropWidth = Math.min(this.lastDetectedBox.w * scaleX, this.videoRef.videoWidth - cropX);
|
|
773
|
-
const cropHeight = Math.min(this.lastDetectedBox.h * scaleY, this.videoRef.videoHeight - cropY);
|
|
788
|
+
const cropX = Math.max(0, (this.lastDetectedBox.x * scaleX) - this.cropMargin);
|
|
789
|
+
const cropY = Math.max(0, (this.lastDetectedBox.y * scaleY) - this.cropMargin);
|
|
790
|
+
const cropWidth = Math.min((this.lastDetectedBox.w * scaleX) + (2 * this.cropMargin), this.videoRef.videoWidth - cropX);
|
|
791
|
+
const cropHeight = Math.min((this.lastDetectedBox.h * scaleY) + (2 * this.cropMargin), this.videoRef.videoHeight - cropY);
|
|
774
792
|
// OPTIMIZATION: Create temporary canvas only for cropped version
|
|
775
793
|
// (We reuse main capture canvas for full frame)
|
|
776
794
|
const croppedCanvas = document.createElement('canvas');
|
|
@@ -914,7 +932,7 @@ const JaakStamps = class {
|
|
|
914
932
|
this.cleanup();
|
|
915
933
|
}
|
|
916
934
|
render() {
|
|
917
|
-
return (index.h("div", { key: '
|
|
935
|
+
return (index.h("div", { key: '7cd80970b12ba60949ff34b5a9405b9782267918', class: "detector-container" }, index.h("div", { key: '0e66e46a524bd37f60f30504a270f72b64a97fc1', class: "video-container" }, index.h("video", { key: '0c1b0719c626659e54bec8ce3383f50d990c32c1', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: this.isVideoActive ? 'block' : 'none' } }), index.h("canvas", { key: '09fc3a2d511e48186099a0ff5d3d6378f15fe1c4', ref: el => this.canvasRef = el, class: this.shouldMirrorVideo ? 'mirror' : '' }), this.isMaskReady && (index.h("div", { key: '70a31b04c9543fc0834a848013daf06c654e4194', class: "overlay-mask" }, index.h("div", { key: '050dcdaa59b028b5c379de310a80ca7191bf8af8', class: "card-outline" }, index.h("div", { key: 'adef93f2e6b16b308dc5d67469f35c2025ca160f', class: "side side-top" }), index.h("div", { key: '4900bed8cc2607f92163a25bbf3c0d3a272b9840', class: "side side-right" }), index.h("div", { key: '11fc9da6cfe04b993bf4a72413da2344122b21e4', class: "side side-bottom" }), index.h("div", { key: 'ed95ac2578ba045e003d61144aecd09ef4f01561', class: "side side-left" }), index.h("div", { key: '37eec8aad0a0d449174d52caab7aec5a25d11731', class: "corner corner-tl" }), index.h("div", { key: 'c7247e71d8936d0a30f415f73377713a8c457420', class: "corner corner-tr" }), index.h("div", { key: 'e131e0c3bd66068ae1d33cd7211edafd92dfbe62', class: "corner corner-bl" }), index.h("div", { key: '89234ddcde735501907276e10287af983033ec85', class: "corner corner-br" }), !this.showFlipAnimation && !this.showSuccessAnimation && (index.h("div", { key: '4b2543dd05f173b3ee4e3053ed7b62d4e7b75e63', class: "guide-text" }, this.statusMessage))), this.captureStep === 'back' && !this.showFlipAnimation && !this.showSuccessAnimation && (index.h("button", { key: 'e7e2b2b1486f7024fc2d42073313833bca88e315', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button" }, "Saltar reverso")))), this.isCapturing && (index.h("div", { key: '6ca8283fe3eb1c5b2700c0d313afb51c2db3ea7f', class: "capture-animation" })), this.showFlipAnimation && (index.h("div", { key: 'eaed1200385a98a8750cdaef2dad9f8ff63914f3', class: "flip-animation" }, index.h("div", { key: 'dbe9bfc929fa8b13cadc60cdece603c48dbcbd4c', class: "id-card-icon" }), index.h("div", { key: '82b9de0910a993b6cf3af7ecdf43de41d495c181', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), this.showSuccessAnimation && (index.h("div", { key: '92ef47686b0fbf91f6a3f8c3c3f23a78a6fc76f8', class: "success-animation" }, index.h("div", { key: '35aeb41dce144fc844d7447a958473834f6b0843', class: "check-icon" }), index.h("div", { key: '2ba06161a8d665394803ce8cc90320b154048c0b', class: "success-text" }, "\u00A1Proceso completado!"))), this.isLoading && (index.h("div", { key: '8abc4f5724ca6543698f7ca9116ccfc9c042edbd', class: "loading-overlay" }, index.h("div", { key: '5c8f73bb7c30c6a4c304e96e4db2bf75dc89b89e', class: "loading-spinner" }), index.h("div", { key: '8f5665f21be98ddccb9d9d2c6412e4edf4571a51', class: "loading-text" }, this.statusMessage))), index.h("div", { key: '00316bee3c56f07b9771c400f5b84b7e14dca4af', class: "watermark" }, index.h("img", { key: 'd7f58ffa993405912f8aa26386f39caa72e7a000', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
|
|
918
936
|
}
|
|
919
937
|
};
|
|
920
938
|
JaakStamps.style = myComponentCss;
|