UNPKG

@privateid/ultra-web-sdk-alpha

Version:
230 lines 11.7 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()); }); }; /* eslint-disable import/prefer-default-export */ /* eslint-disable lines-between-class-members */ import { proxy } from 'comlink'; import { detect } from 'detect-browser'; import { callbackTypeEnum, createCallback } from '../../../../createCallback'; import { CameraFaceMode } from '../../../../types'; import { callbackWithImageCreation, defineDimensionsForCanvas, getBaseEnrollConfig, releaseCanvas } from './face.utils'; import { DEFAULT_PREDICT_CONFIG } from '../../support/wasm'; import { getIsSIMD, printLogs } from '../../global/shared.utils'; import { CANVAS_TEST_ID, INVALID_VIDEO_ERROR, LOG_MESSAGES, URL_OVERRIDES } from './face.constants'; export class FaceService { constructor(wasmService, cameraService) { this.isSimd = false; // eslint-disable-next-line class-methods-use-this this.privid_wasm_result = () => { }; this.faceMode = CameraFaceMode.front; getIsSIMD().then((simd) => { this.isSimd = simd; }); const canvas = document.createElement('canvas'); canvas.setAttribute('id', CANVAS_TEST_ID); this.canvas = canvas; this.wasmService = wasmService; this.cameraService = cameraService; printLogs('[FaceService] initialized', ''); } preparePrivdWasmResult(callback, callbackType, image, config) { const callbackForImageCreation = callbackWithImageCreation(callback, image, false); this.privid_wasm_result = createCallback({ type: callbackType, callbackFunction: callbackForImageCreation, imageData: (config === null || config === void 0 ? void 0 : config.sendImageToJS) ? image : undefined, }); } // TODO: Refactor this method to use the canvas from camera service prepareCanvasAndGetImageData(elementId, useExistingCanvas = false) { const videoEl = document.getElementById(elementId); const height = (videoEl === null || videoEl === void 0 ? void 0 : videoEl.videoHeight) || 0; const width = (videoEl === null || videoEl === void 0 ? void 0 : videoEl.videoWidth) || 0; if (width === 0) return { result: INVALID_VIDEO_ERROR }; printLogs(`isValid:`, { height, width }); let canvas; if (useExistingCanvas) { canvas = this.canvas; } else { canvas = document.createElement('canvas'); } canvas.setAttribute('id', CANVAS_TEST_ID); canvas.setAttribute('height', `${height}`); canvas.setAttribute('width', `${width}`); const context = canvas.getContext('2d', { willReadFrequently: true }); if (this.faceMode === CameraFaceMode.front) { context.translate(width, 0); context.scale(-1, 1); } context.drawImage(videoEl, 0, 0); const imageData = context.getImageData(0, 0, width, height); return { imageData, canvas, width, height }; } runUltraProcess(fn, options) { return __awaiter(this, void 0, void 0, function* () { const { callback, image, config = {}, element, returnPortrait = false, useExistingCanvas = false, logMessage = LOG_MESSAGES.ULTRA_PROCESS, callbackType, } = options; printLogs(`${logMessage}`, ''); const configJSON = Object.keys(config).length > 0 ? Object.assign({}, config) : Object.assign({}, DEFAULT_PREDICT_CONFIG); if (image) { this.preparePrivdWasmResult(callback, callbackType, image, config); return fn([image], this.isSimd, JSON.stringify(configJSON), proxy(this.privid_wasm_result)); } if (element) { this.cameraService.setVideoElementId(element); } const result = this.prepareCanvasAndGetImageData(this.cameraService.getVideoElementId(), useExistingCanvas); if ('result' in result) return result; const { imageData, canvas } = result; this.preparePrivdWasmResult(callback, callbackType, imageData, config); yield fn([imageData], this.isSimd, JSON.stringify(configJSON), proxy(this.privid_wasm_result)); if (returnPortrait) { return imageData; } releaseCanvas(canvas); return undefined; }); } performPredict(options) { return this.runUltraProcess(this.wasmService.predict, Object.assign(Object.assign({}, options), { callbackType: callbackTypeEnum.predict, logMessage: options.logMessage || LOG_MESSAGES.PREDICT_ONE_FA })); } faceLogin(props) { return __awaiter(this, void 0, void 0, function* () { return this.performPredict(Object.assign(Object.assign({}, props), { useExistingCanvas: true, logMessage: LOG_MESSAGES.FACE_LOGIN })); }); } predict(props) { return __awaiter(this, void 0, void 0, function* () { return this.performPredict(Object.assign(Object.assign({}, props), { config: Object.assign({ url_name_override: URL_OVERRIDES.PREDICT }, props.config) })); }); } predictWithStatus(props) { return __awaiter(this, void 0, void 0, function* () { return this.performPredict(Object.assign(Object.assign({}, props), { config: Object.assign({ url_name_override: URL_OVERRIDES.PREDICT_STATUS }, props.config) })); }); } predictConfirmUser(props) { return __awaiter(this, void 0, void 0, function* () { return this.performPredict(Object.assign(Object.assign({}, props), { config: Object.assign({ url_name_override: URL_OVERRIDES.CONFIRM_USER }, props.config) })); }); } predictDeleteUser(props) { return __awaiter(this, void 0, void 0, function* () { return this.performPredict(Object.assign(Object.assign({}, props), { config: Object.assign({ url_name_override: URL_OVERRIDES.DELETE_USER }, props.config) })); }); } estimateAge(props) { return __awaiter(this, void 0, void 0, function* () { const baseConfig = { input_image_format: 'rgba', angle_rotation_left_threshold: 20.0, angle_rotation_right_threshold: 20.0, anti_spoofing_threshold: 0.8, threshold_profile_predict: 0.66, blur_threshold_enroll_pred: 40, threshold_user_too_close: 0.8, threshold_user_too_far: 0.2, threshold_user_up: 0.15, threshold_user_down: 0.9, threshold_user_left: 0.8, threshold_user_right: 0.2, threshold_high_vertical_predict: 0.9, threshold_down_vertical_predict: 2.2, url_name_override: '', disable_predict_mf: false, mf_count_override: 5, disable_estimate_age_mf: false, threshold_profile_enroll: 0.6, allow_only_one_face: false, }; printLogs('[FaceService] estimateAge', true); return this.runUltraProcess(this.wasmService.estimateAge, Object.assign(Object.assign({}, props), { callbackType: callbackTypeEnum.ageEstimation, logMessage: props.logMessage || LOG_MESSAGES.AGE_ESTIMATION, config: Object.assign(Object.assign({}, baseConfig), props.config) })); }); } enroll(props) { return __awaiter(this, void 0, void 0, function* () { printLogs('ENROLL_ONE_FA', ''); let configJSON = getBaseEnrollConfig(); const { os } = detect(); if (['iOS', 'android', 'Android OS'].includes(os)) { configJSON = Object.assign(Object.assign({}, configJSON), { threshold_user_too_far: 0.31, threshold_user_too_close: 0.55, threshold_user_right: 0.2, threshold_user_left: 0.8, threshold_profile_enroll: 0.66 }); } if (props.config) { configJSON = Object.assign(Object.assign({}, configJSON), props.config); } if (props.element) { this.cameraService.setVideoElementId(props.element); } const imageData = this.generateImageData(this.cameraService.getVideoElementDOM(), true); const callbackForImageCreation = callbackWithImageCreation(props.callback, imageData, true); this.privid_wasm_result = createCallback({ type: callbackTypeEnum.enroll, callbackFunction: callbackForImageCreation, }); const bestImage = yield this.wasmService.enroll(imageData, JSON.stringify(configJSON), proxy(this.privid_wasm_result)); if (props.returnPortrait) { return imageData; } return bestImage; }); } generateImageData(videoElement, shouldDownscale = false) { var _a; const canvas = this.prepareCanvas(videoElement, shouldDownscale); const context = canvas.getContext('2d', { willReadFrequently: true }); (_a = context.resetTransform) === null || _a === void 0 ? void 0 : _a.call(context); if (this.faceMode === CameraFaceMode.front) { context.translate(canvas.width, 0); context.scale(-1, 1); } context.clearRect(0, 0, canvas.width, canvas.height); context.drawImage(videoElement, 0, 0, canvas.width, canvas.height); return context.getImageData(0, 0, canvas.width, canvas.height); } prepareCanvas(videoElement, shouldDownscale = false) { const height = (videoElement === null || videoElement === void 0 ? void 0 : videoElement.videoHeight) || 0; const width = (videoElement === null || videoElement === void 0 ? void 0 : videoElement.videoWidth) || 0; if (width === 0) { throw new Error(INVALID_VIDEO_ERROR); } if (!shouldDownscale) { this.canvas.setAttribute('height', `${height}`); this.canvas.setAttribute('width', `${width}`); printLogs(`[FaceService] Valid Canvas:`, { width: this.canvas.width, height: this.canvas.height }); return this.canvas; } const canvasDimensions = defineDimensionsForCanvas({ width, height }); this.canvas.setAttribute('height', `${canvasDimensions.height}`); this.canvas.setAttribute('width', `${canvasDimensions.width}`); printLogs(`[FaceService] Valid Canvas Downscaled:`, { width: this.canvas.width, height: this.canvas.height }); return this.canvas; } // Getters and Setters getIsSimd() { return this.isSimd; } setIsSimd(value) { this.isSimd = value; } getPrivid_wasm_result() { return this.privid_wasm_result; } setPrivid_wasm_result(value) { this.privid_wasm_result = value; } getFaceMode() { return this.faceMode; } setFaceMode(value) { this.faceMode = value; } } //# sourceMappingURL=FaceService.js.map