Document-Detector V2 SDK
Stamps(@jaak.ai/stamps) es la versión 2 de document-detector, un componente web que permite la captura de identificaciones.
Introducción
JAAK Stamps es un componente web diseñado para facilitar la detección y captura automática de documentos de identificación en aplicaciones web modernas. Este componente forma parte de un ecosistema de componentes web interoperables, compatibles con los principales estándares de la Web. Su arquitectura basada en shadow DOM, slots (ranuras) y encapsulamiento de estilos permite una integración limpia, segura y mantenible en cualquier entorno con soporte para Web Components.
Funcionalidades Clave
- Detección automática en tiempo real: Identifica documentos de identificación a través de la cámara del dispositivo.
- Guía visual para posicionamiento: Ayuda al usuario a alinear el documento para una captura óptima.
- Captura adaptativa: Se ajusta automáticamente si el documento tiene o no reverso.
- Clasificación inteligente de documentos: Determina automáticamente si se requiere captura del reverso.
- Salida de imágenes base64: Proporciona tanto la imagen completa del cuadro de video como un recorte preciso del documento para cada lado capturado.
- Control de cámara avanzado: Selección de cámara, enfoque automático y control de linterna.
- Responsivo: Compatible con dispositivos móviles y de escritorio.
- Optimización automática: Mejora del rendimiento y gestión inteligente de recursos.
Instalación
-
Pre-requisitos:
- Node.js y npm instalados.
- Descargar desde: https://nodejs.org
- Verifica la instalación:
node -v npm -v
-
Inicializa tu proyecto (si aplica):
npm init
-
Instala el paquete:
npm install @jaak.ai/stamps
o con Yarn:
yarn add @jaak.ai/stamps
-
Confirma la instalación: Verifica que el paquete
@jaak.ai/stamps
esté listado en tu archivopackage.json
.
Versión EstableRecomendamos utilizar la version 2.0.0 la cuál es considerada como estable
Opción alternativa de instalación
También puedes instalar el componente directamente mediante una etiqueta <script>
en la cabecera head
HTML, ideal para implementaciones rápidas o en entornos que no utilizan npm.
<script type="module" src="https://unpkg.com/@jaak.ai/[email protected]"></script>
Configuración del Componente
Las propiedades de configuración se pueden establecer como atributos directamente en la etiqueta HTML del componente.
Propiedad | Descripción | Requerido | Tipo | Valor por defecto |
---|---|---|---|---|
debug | Activa el modo debug para mostrar información de depuración. | No | boolean | false |
alignmentTolerance | Tolerancia en píxeles para considerar un lado del documento como alineado. | No | number | 15 |
maskSize | Porcentaje del video que ocupará la máscara de detección (rango: 50-100). | No | number | 80 |
cropMargin | Margen en píxeles que se agrega al recorte del documento (rango: 0-100). | No | number | 20 |
captureDelay | Tiempo en milisegundos que el documento debe permanecer en posición antes de capturar automáticamente (rango: 0-10000). | No | number | 1500 |
useDocumentClassification | Habilita la clasificación automática para determinar si se debe solicitar el reverso. | No | boolean | false |
preferredCamera | Define qué cámara usar: 'auto' (automática), 'front' (frontal), 'back' (trasera). | No | string | 'auto' |
Notificación de UsoEl modelo implementado en la clasificación de documentos(
useDocumentClassification
) aún se encuentra en fase Beta por lo que podría presentar fallas en la exactitud de la detección.
Ejemplo de Implementación Básica
Este ejemplo, basado en el archivo index.html
proporcionado, muestra cómo integrar y controlar el componente JAAK Stamps en una página web con HTML y JavaScript puros.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script type="module" src="https://unpkg.com/@jaak.ai/[email protected]"></script>
</head>
<body>
<div>
<div class="content">
<div class="card">
<div class="card-title">
<h1>Document Detector</h1>
</div>
<div class="frame">
<div class="component-container">
<jaak-stamps
id="detector"
debug="false"
mask-size="80"
crop-margin="20"
capture-delay="1500"
use-document-classification="false"
preferred-camera="auto"></jaak-stamps>
</div>
</div>
</div>
</div>
<div class="button-group">
<div class="button-with-desc">
<button class="card-btn" onclick="preloadModel()">Precargar Modelo</button>
</div>
<div class="button-with-desc">
<button class="card-btn" onclick="startCapture()">Iniciar Captura</button>
</div>
<div class="button-with-desc">
<button class="card-btn" onclick="stopCapture()">Detener</button>
</div>
<div class="button-with-desc">
<button class="card-btn" onclick="resetCapture()">Reiniciar</button>
</div>
<div class="button-with-desc">
<button class="card-btn" onclick="getImages()">Ver Imágenes</button>
</div>
<div class="button-with-desc">
<button class="card-btn" onclick="skipBackCapture()">Omitir Reverso</button>
</div>
<div class="button-with-desc">
<button class="card-btn" onclick="toggleTorch()">Activar/Desactivar Linterna</button>
</div>
</div>
<div id="captured-images-container" class="images-container">
<div class="images-section front-section">
<h2>Frente del Documento</h2>
<div class="image-row">
<div class="image-card">
<h3>Imagen Completa</h3>
<img id="front-full" src="" alt="Imagen completa del frente" />
</div>
<div class="image-card">
<h3>Documento Recortado</h3>
<img id="front-cropped" src="" alt="Documento recortado del frente" />
</div>
</div>
</div>
<div class="images-section back-section">
<h2>Reverso del Documento</h2>
<div class="image-row">
<div class="image-card">
<h3>Imagen Completa</h3>
<img id="back-full" src="" alt="Imagen completa del reverso" />
</div>
<div class="image-card">
<h3>Documento Recortado</h3>
<img id="back-cropped" src="" alt="Documento recortado del reverso" />
</div>
</div>
</div>
</div>
</div>
<script>
const detector = document.getElementById('detector');
let torchEnabled = false;
// 1. Escuchar eventos del componente
detector.addEventListener('captureCompleted', (event) => {
console.log('Captura completada:', event.detail);
displayCapturedImages(event.detail);
});
detector.addEventListener('isReady', (event) => {
console.log('Componente listo:', event.detail);
});
// 2. Funciones para los botones
async function preloadModel() {
try {
const result = await detector.preloadModel();
console.log('Modelo precargado:', result);
} catch (error) {
console.error('Error al precargar:', error);
}
}
function startCapture() {
detector.startCapture();
}
function stopCapture() {
detector.stopCapture();
}
function resetCapture() {
detector.resetCapture();
document.getElementById('captured-images-container').style.display = 'none';
}
async function getImages() {
try {
const images = await detector.getCapturedImages();
displayCapturedImages(images);
} catch (error) {
console.error('Error:', error.message);
}
}
async function skipBackCapture() {
try {
await detector.skipBackCapture();
} catch (error) {
console.error('Error al omitir reverso:', error);
}
}
async function toggleTorch() {
try {
torchEnabled = !torchEnabled;
const result = await detector.setTorchEnabled(torchEnabled);
console.log('Linterna:', result);
} catch (error) {
console.error('Error con linterna:', error);
}
}
// 3. Función para mostrar imágenes en la UI
function displayCapturedImages(images) {
const container = document.getElementById('captured-images-container');
container.style.display = 'flex';
// Asignar imágenes del frente
const frontFullImg = document.getElementById('front-full');
const frontCroppedImg = document.getElementById('front-cropped');
if (images.front && images.front.fullFrame) {
frontFullImg.src = images.front.fullFrame;
}
if (images.front && images.front.cropped) {
frontCroppedImg.src = images.front.cropped;
}
// Asignar imágenes del reverso
const backFullImg = document.getElementById('back-full');
const backCroppedImg = document.getElementById('back-cropped');
if (images.back && images.back.fullFrame) {
backFullImg.src = images.back.fullFrame;
}
if (images.back && images.back.cropped) {
backCroppedImg.src = images.back.cropped;
}
}
</script>
</body>
</html>
Deberías obtener un HTML muy similar a este:

Eventos Emitidos
Evento | Payload | Descripción |
---|---|---|
captureCompleted | CapturedImages | Se emite cuando el proceso de captura (frente y reverso, si aplica) se ha completado exitosamente. |
isReady | boolean | Se emite cuando el componente ha cargado sus modelos y está listo para iniciar la detección. |
Métodos Públicos
Método | Retorna | Descripción |
---|---|---|
startCapture() | Promise<void> | Inicia el proceso de detección y captura de imágenes. |
stopCapture() | Promise<void> | Detiene el proceso de captura y libera el uso de la cámara. |
resetCapture() | Promise<void> | Reinicia el estado del componente para una nueva captura. |
preloadModel() | Promise<{success: boolean, ...}> | Precarga el modelo de detección para mejorar el rendimiento al iniciar la captura. |
getCapturedImages() | Promise<CapturedImages> | Obtiene las imágenes capturadas después de que el proceso ha finalizado. |
isProcessCompleted() | Promise<boolean> | Verifica si el proceso de captura ha sido completado. |
getStatus() | Promise<Status> | Obtiene un objeto con el estado actual del detector. |
skipBackCapture() | Promise<void> | Permite omitir la captura del reverso cuando el componente lo está solicitando. |
getCameraInfo() | Promise<CameraInfo> | Obtiene información detallada sobre las cámaras disponibles. |
setPreferredCamera(camera) | Promise<{success: boolean, ...}> | Establece la cámara preferida ('auto', 'front', 'back'). |
setCaptureDelay(delay) | Promise<{success: boolean, ...}> | Establece el tiempo de espera antes de capturar automáticamente (0-10000ms). |
getCaptureDelay() | Promise<number> | Obtiene el tiempo de espera actual configurado para captura automática. |
setTorchEnabled(enabled) | Promise<{success: boolean, ...}> | Habilita o deshabilita la linterna/flash de la cámara. |
focusAtPoint(x, y) | Promise<{success: boolean, ...}> | Enfoca la cámara en coordenadas específicas. |
Tipos de Datos
A continuación se describen las interfaces para los datos que maneja el componente.
CapturedImages
: Objeto devuelto por getCapturedImages()
y en el evento captureCompleted
.
interface CapturedImages {
front: {
fullFrame: string | null; // Imagen completa del frente en Base64
cropped: string | null; // Recorte del documento del frente en Base64
};
back: {
fullFrame: string | null; // Imagen completa del reverso en Base64
cropped: string | null; // Recorte del documento del reverso en Base64
};
timestamp: string; // Timestamp de la captura en formato ISO
metadata: {
totalImages: number; // Número total de imágenes capturadas
processCompleted: boolean; // Indica si el proceso fue completado
backCaptureSkipped?: boolean; // Indica si se omitió la captura del reverso
};
}
Status
: Objeto devuelto por el método getStatus()
.
interface Status {
isVideoActive: boolean; // Indica si la cámara está activa
captureStep: 'front' | 'back' | 'completed'; // Paso actual del proceso
hasImages: boolean; // Indica si ya hay imágenes capturadas
isProcessCompleted: boolean; // Indica si el proceso está completado
isModelPreloaded: boolean; // Indica si el modelo fue precargado
}
CameraInfo
: Objeto devuelto por el método getCameraInfo()
.
interface CameraInfo {
availableCameras: number; // Número de cámaras disponibles
selectedCamera: string; // Cámara actualmente seleccionada
supportedConstraints: object; // Restricciones soportadas por la cámara
}
Flujo de Trabajo
Flujo Estándar (useDocumentClassification = false)
- Inicialización: El componente se prepara para la detección
- Iniciar captura: El modelo de detección se carga automáticamente
- Captura frontal: El usuario posiciona el documento y se captura automáticamente
- Solicitud de reverso: Siempre solicita voltear el documento para captura del reverso
- Botón omitir reverso: Disponible para omitir manualmente la captura del reverso
- Completado: Emite evento
captureCompleted
con las imágenes correspondientes
Flujo de Clasificación Inteligente (useDocumentClassification = true)
- Inicialización: El componente se prepara para la detección
- Iniciar captura: Los modelos de detección y clasificación se cargan automáticamente
- Captura frontal: El usuario posiciona el documento y se captura automáticamente
- Clasificación automática: El sistema determina si el documento requiere captura del reverso
- Flujo adaptativo:
- Si es pasaporte: El proceso se completa automáticamente (sin reverso)
- Si es otro documento: Solicita voltear el documento para captura del reverso
- Completado: Emite evento
captureCompleted
con las imágenes correspondientes
Flujo de Precarga (Recomendado)
- Precarga de modelo: Llamar a
preloadModel()
para cargar modelos en memoria - Inicio optimizado: Al iniciar captura, utiliza modelos ya cargados
- Captura frontal: Detección y clasificación más rápida con modelos precargados
- Flujo inteligente:
- Documento sin reverso: Proceso completado inmediatamente
- Documento con reverso: Solicita captura del reverso
- Completado: Emite evento
captureCompleted
con todas las imágenes
Consideraciones de Rendimiento y Privacidad
Privacidad
- Las imágenes se procesan localmente en el navegador
- No se envían datos a servidores externos
- Todo el procesamiento se ejecuta completamente en el lado del cliente
- La clasificación de documentos se realiza de manera privada y local
- Las imágenes capturadas solo están disponibles dentro del contexto de tu aplicación
Optimización de Recursos
- Carga condicional: Solo descarga los modelos necesarios según la configuración
- Carga perezosa: Los modelos se cargan cuando realmente se necesitan
- Caché del navegador: Los modelos se almacenan localmente después de la primera descarga
Requerimientos del Sistema
- Navegadores: Chrome/Edge 88+, Firefox 85+, Safari 14+
- Cámara: Acceso a cámara trasera (móvil) o webcam (escritorio)
- Conexión: Conexión a internet para cargar modelos de detección
Recursos Complementarios
📦 Repositorio de ejemplo
Puedes apoyarte con un ejemplo funcional en el siguiente repositorio:
https://github.com/jaak-ai/stamps-js-example
📦 Live-Demo
En este link encontrarás una demo en vivo para hacer pruebas:
https://stamps.jaak.solutions/
Updated 12 days ago