UNPKG

@face-auth/face-id-video

Version:

Utility library for capturing photos from webcam video streams in the browser. Handles camera selection, image formatting, and output for face authentication APIs.

101 lines (100 loc) 4.49 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { DEFAULT_IMAGE_TYPE } from "./common/constants"; export class FacePhotoManager { constructor(video) { this.video = video; } /** * Captura el frame actual, recorta un óvalo +20% de buffer, fondo negro, y devuelve un Blob. */ capture(options) { return __awaiter(this, void 0, void 0, function* () { const imageType = options.imageType || DEFAULT_IMAGE_TYPE; const faceOvalDimensions = options.ovalDimensions || null; const bufferPercent = options.bufferPercent || 0.2; // 20% // Si no hay dimensiones de óvalo, devolvemos la captura completa: if (!faceOvalDimensions) { return this.captureFullFrame(imageType); } const { x = 0, y = 0, radiusX = 0, radiusY = 0, scale = 1 } = faceOvalDimensions; // Radios escalados + buffer const rX = radiusX * scale; const rY = radiusY * scale; const rXb = rX * (1 + bufferPercent); const rYb = rY * (1 + bufferPercent); // Bounding box del óvalo ampliado const boxWidth = 2 * rXb; const boxHeight = 2 * rYb; // Canvas temporal const canvas = document.createElement("canvas"); canvas.width = boxWidth; canvas.height = boxHeight; const ctx = canvas.getContext("2d"); if (!ctx) throw new Error("No se pudo crear el contexto del canvas."); // Fondo negro ctx.fillStyle = "black"; ctx.fillRect(0, 0, boxWidth, boxHeight); // Defino clip oval ctx.beginPath(); ctx.ellipse(boxWidth / 2, // centro x en el nuevo canvas boxHeight / 2, // centro y rXb, // radio X con buffer rYb, // radio Y con buffer 0, // rotación 0, // ángulo inicio Math.PI * 2 // ángulo fin ); ctx.clip(); // Dibujo la porción del video original, desplazando para centrar el box ctx.drawImage(this.video, x - rXb, // origen X en el video y - rYb, // origen Y boxWidth, // ancho a recortar del video boxHeight, // alto a recortar 0, // destino X en el canvas 0, // destino Y boxWidth, // ancho en el canvas boxHeight // alto en el canvas ); // Devuelvo el blob return new Promise((resolve, reject) => { canvas.toBlob(blob => { if (blob) { resolve({ blob, imageType }); } else { reject(new Error("No se pudo crear el blob desde el canvas.")); } }, imageType); }); }); } /** Helper para devolver captura completa sin recorte */ captureFullFrame(imageType) { return __awaiter(this, void 0, void 0, function* () { const canvas = document.createElement("canvas"); canvas.width = this.video.videoWidth; canvas.height = this.video.videoHeight; const ctx = canvas.getContext("2d"); if (!ctx) throw new Error("No se pudo crear el contexto del canvas."); ctx.drawImage(this.video, 0, 0, canvas.width, canvas.height); return new Promise((resolve, reject) => { canvas.toBlob(blob => { if (blob) resolve({ blob, imageType }); else reject(new Error("No se pudo crear el blob del frame completo.")); }, imageType); }); }); } }