UNPKG

@privateid/ultra-web-sdk-alpha

Version:
967 lines 44.8 kB
/* eslint-disable no-loop-func */ /* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable default-param-last */ /* eslint-disable camelcase */ 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()); }); }; /** * @module Face module */ import { proxy } from 'comlink'; import { detect } from 'detect-browser'; import { getCameraList, getVideoConstraints, isFaceTimeCamera, isMobileBackCameraPortrait } from './cameraUtils'; import { facingMode } from './constants'; import { callbackTypeEnum, createCallback } from './createCallback'; import { CameraFaceMode, ImageType } from './types'; import { checkIfModelsLoaded, createImages, getDebugType, getDefaultCameraDeviceId, getIsSIMD, iOS, isMobileFunc, pkiEncrypt, printLogs, setDefaultCameraDeviceId, ultraAgeEstimate, ultraCompareEmbeddings, ultraEnroll, ultraPredict, ultraScanBackDocument, ultraScanFrontDocument, ultraDocumentOcr, freeMemory, } from './utils'; let videoElement = null; let faceMode = CameraFaceMode.front; let mediaDevice = null; let mediaDevices = null; let mediaStream = null; let isSimd = false; const debugType = getDebugType(); const isDebugWithImages = ['900', '901', '902', '903'].includes(debugType); const cameraHeight = 1440; const cameraWidth = 2560; const cameraLowResHeight = 1080; const cameraLowResWidth = 1920; getIsSIMD().then((simd) => (isSimd = simd)); let privid_wasm_result = (operation, id, response_str) => { }; const isVirtualCamera = (deviceLabel) => { const virtualCameraKeywords = ['virtual', 'obs', 'software', 'manycam']; return virtualCameraKeywords.some((keyword) => deviceLabel.toLowerCase().includes(keyword)); }; const callbackWithImageCreation = (callback, imageData, isEnrollFlow) => { return (result) => { if (isDebugWithImages) { createImages([imageData], `${ImageType.original}_${result === null || result === void 0 ? void 0 : result.face_validation_status}_${result === null || result === void 0 ? void 0 : result.antispoof_status}`, isEnrollFlow); } callback(result); }; }; const preparePrivdWasmResult = (callback, callbackType, image, config) => { const callbackForImageCreation = callbackWithImageCreation(callback, image, false); privid_wasm_result = createCallback({ type: callbackType, callbackFunction: callbackForImageCreation, imageData: (config === null || config === void 0 ? void 0 : config.sendImageToJS) ? image : undefined, }); }; const prepareCameraResult = (stream, devices, faceMode, videoElement) => __awaiter(void 0, void 0, void 0, function* () { const track = stream.getVideoTracks()[0]; const capabilities = track.getCapabilities ? track.getCapabilities() : null; const settings = track.getSettings(); printLogs('settings: ', settings); if (capabilities) { printLogs('capabilities: ', capabilities); } yield startVideo(videoElement, stream); mediaStream = stream; mediaDevices = devices; return { status: true, stream, devices, faceMode, settings, capabilities, errorMessage: null, }; }); const openCameraMobile = (domElement, requestFaceMode = null, canvasResolution, requireHD = false, isDocumentScan) => __awaiter(void 0, void 0, void 0, function* () { try { if (mediaStream) { mediaStream.getTracks().forEach((track) => track.stop()); mediaStream = null; } let inCatchBlock = false; videoElement = domElement; printLogs('Opening Camera on Mobile', ''); let devices = yield navigator.mediaDevices.enumerateDevices(); devices = devices.filter((d) => d.kind === 'videoinput'); devices = getDevicesWithCapabilities(devices); let stream; let hasError = true; while (hasError) { try { // @ts-ignore const videoConstraint = getVideoConstraints(yield getCameraList(faceMode === 'back'), // @ts-ignore facingMode[faceMode], requireHD, isDocumentScan, canvasResolution, inCatchBlock); printLogs(`videoConstraint: `, videoConstraint); stream = yield navigator.mediaDevices.getUserMedia( // @ts-ignore videoConstraint); hasError = false; } catch (e) { printLogs(`openCameraMobile:' `, e, 'ERROR'); inCatchBlock = true; // hasError = false; } } return prepareCameraResult(stream, devices, faceMode, domElement); } catch (e) { printLogs(`Error: `, e, 'ERROR'); return null; } }); /** * @ignore */ const openCameraMacSafari = (domElement, deviceId = null, canvasResolution = { width: cameraWidth, height: cameraHeight }, requireHD = false) => __awaiter(void 0, void 0, void 0, function* () { var _a, _b, _c, _d; try { videoElement = domElement; printLogs('Opening Camera on Mac Safari', ''); let devices = yield navigator.mediaDevices.enumerateDevices(); devices = devices.filter((d) => d.kind === 'videoinput' && !isVirtualCamera(d.label)); const defaultDeviceId = getDefaultCameraDeviceId(); const externalDeviceId = devices.length > 1 ? devices.find((device) => !device.label.includes('FaceTime')) : devices[0]; const isDefaultDeviceAvailable = devices.find((device) => defaultDeviceId === device.deviceId); mediaDevice = deviceId || (isDefaultDeviceAvailable ? defaultDeviceId : externalDeviceId.deviceId); setDefaultCameraDeviceId(mediaDevice); const deviceCapabilites = getDefaultDevice(devices, mediaDevice); const resolution = requireHD ? (canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.width) || Math.min(((_b = (_a = deviceCapabilites[0]) === null || _a === void 0 ? void 0 : _a.width) === null || _b === void 0 ? void 0 : _b.max) || cameraWidth, cameraWidth) : (canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.width) || Math.min(((_d = (_c = deviceCapabilites[0]) === null || _c === void 0 ? void 0 : _c.width) === null || _d === void 0 ? void 0 : _d.max) || cameraLowResWidth, cameraLowResWidth); const constraints = { audio: false, video: { deviceId: deviceCapabilites[0].deviceId, width: { ideal: resolution }, height: (canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.height) ? { ideal: canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.height } : undefined, // advance: [{ width: { ideal: 2560 }, height: { ideal: 1440 } }], }, }; const stream = yield navigator.mediaDevices.getUserMedia(constraints); return prepareCameraResult(stream, devices, faceMode, domElement); } catch (e) { printLogs(`Error while getAccessToCamera: `, e, 'ERROR'); return null; } }); const openCameraFirefox = (domElement, canvasResolution = { width: cameraWidth, height: cameraHeight }, requireHD = false) => __awaiter(void 0, void 0, void 0, function* () { printLogs('Open Camera Firefox!', ''); videoElement = domElement; yield navigator.mediaDevices.getUserMedia({ audio: false, video: true }); try { let devices = []; devices = yield navigator.mediaDevices.enumerateDevices(); printLogs(`devices: `, devices); devices = devices.filter((d) => d.kind === 'videoinput' && !isVirtualCamera(d.label)); if (devices.length === 0) { printLogs('NO_CAMERA', '', 'ERROR'); throw new Error('NO_CAMERA'); } const constraints = { audio: false, video: { width: { ideal: (canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.width) || requireHD ? cameraWidth : cameraLowResWidth }, height: (canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.height) || 1080, }, aspectRatio: 1.7777777778, focusMode: 'continuous', facingMode: facingMode[faceMode] || 'user', }; const stream = yield navigator.mediaDevices.getUserMedia(constraints); return prepareCameraResult(stream, devices, faceMode, domElement); } catch (e) { if (parseInt(debugType, 10) >= 2) { printLogs(`Error while getAccessToCamera `, e, 'ERROR'); } return null; } }); export const openCamera = ({ videoElementId, deviceId, requestFaceMode, canvasResolution, isDocumentScan, }) => __awaiter(void 0, void 0, void 0, function* () { var _e; videoElement = videoElementId; faceMode = requestFaceMode; const { name: browserName, os } = detect(); yield navigator.mediaDevices.getUserMedia({ video: true, audio: false }).then((mediaStream) => { const stream = mediaStream; const tracks = stream.getTracks(); tracks.forEach((track) => track.stop()); }); // Firefox if (browserName === 'firefox') { return openCameraFirefox(videoElementId, canvasResolution); } // Mobile if (iOS() || ['iOS', 'android', 'Android OS'].includes(os)) { return openCameraMobile(videoElementId, requestFaceMode, canvasResolution, null, isDocumentScan); } // Mac Safari Browser if (os === 'Mac OS' && browserName === 'safari') { return openCameraMacSafari(videoElementId, deviceId, canvasResolution, null); } try { let devices = []; devices = yield navigator.mediaDevices.enumerateDevices(); devices = devices.filter((d) => d.kind === 'videoinput' && !isVirtualCamera(d.label)); printLogs(`Devices: `, devices); if (devices.length === 0) { printLogs('NO_CAMERA', '', 'ERROR'); throw new Error('NO_CAMERA'); } let defaultDeviceId = getDefaultCameraDeviceId(); if (deviceId) { defaultDeviceId = deviceId; } if (!mediaDevice) { if (deviceId) { mediaDevice = deviceId; } else { if (defaultDeviceId) { const isDefaultDeviceAvailable = devices.find((device) => defaultDeviceId === device.deviceId); mediaDevice = isDefaultDeviceAvailable ? defaultDeviceId : devices[0].deviceId; } else { mediaDevice = devices[0].deviceId; } } } const isWindowsDevice = () => { if (['windows', 'win16', 'win32', 'wince'].includes(navigator.platform.toUpperCase())) { return true; } else { return false; } }; const deviceCapabilites = getDefaultDevice(devices, mediaDevice); const isMacFaceTimeCamera = isFaceTimeCamera((_e = deviceCapabilites[0]) === null || _e === void 0 ? void 0 : _e.label, isDocumentScan); const getBestResolution = () => __awaiter(void 0, void 0, void 0, function* () { var _f, _g; let resolution = (canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.width) || Math.min(((_g = (_f = deviceCapabilites[0]) === null || _f === void 0 ? void 0 : _f.width) === null || _g === void 0 ? void 0 : _g.max) || cameraWidth, cameraWidth); let hasError = true; let constraints = { audio: false, video: { deviceId: deviceCapabilites[0].deviceId, width: { ideal: resolution }, height: (canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.height) ? { ideal: canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.height } : { ideal: cameraHeight }, aspectRatio: isMacFaceTimeCamera ? 1 : 1.777777778, resizeMode: 'none', facingMode: isWindowsDevice() ? 'user' : undefined, }, }; let stream; while (hasError) { try { stream = yield navigator.mediaDevices.getUserMedia(constraints); if (stream) hasError = false; } catch (e) { resolution = getTheNextResolutionAvailable(resolution); constraints = Object.assign(Object.assign({}, constraints), { video: Object.assign(Object.assign({}, constraints.video), { width: { ideal: resolution } }) }); } } return stream; }); let stream; stream = yield getBestResolution(); return prepareCameraResult(stream, devices, faceMode, videoElementId); } catch (e) { printLogs(`Error while getAccessToCamera: `, e, 'ERROR'); return null; } }); function startVideo(videoElement, stream) { return __awaiter(this, void 0, void 0, function* () { const element = document.getElementById(videoElement); element.srcObject = stream; element.play(); yield new Promise((resolve) => (element.onplaying = resolve)); enableMutationObserver(element, stream); }); } let videoMutationObserver = null; function enableMutationObserver(videoElement, stream) { videoMutationObserver = new MutationObserver(() => { if (videoElement.srcObject !== stream) { printLogs('Unauthorized video source change detected! Resetting to correct camera.', '', 'WARN'); videoElement.srcObject = stream; } }); videoMutationObserver.observe(videoElement, { attributes: true, attributeFilter: ['srcObject'] }); } /** * This function close camera, and clear all memories related to the camera. * @category Face * @param domElement id of the video tag */ export const closeCamera = (element) => __awaiter(void 0, void 0, void 0, function* () { try { const video = element || videoElement; const videoEl = document.getElementById(video); // Para o stream associado ao elemento, se ainda existir const streamFromElement = videoEl === null || videoEl === void 0 ? void 0 : videoEl.srcObject; if (streamFromElement) { streamFromElement.getTracks().forEach((track) => track.stop()); videoEl.srcObject = null; } // If mediaStream is still active independent of stop all tracks, i'm forcing the stop again if (mediaStream) { mediaStream.getTracks().forEach((track) => track.stop()); mediaStream = null; } // Clear the video element source and variable memories videoElement = null; mediaDevice = null; mediaDevices = null; // if observer is active, disconnect it if (videoMutationObserver) { videoMutationObserver.disconnect(); videoMutationObserver = null; } } catch (err) { printLogs(`Close Camera: `, err, 'ERROR'); } }); /** * This function open camera, and returns the stream, current faceMode and the list of available media devices * @category Face * @param domElement id of the video tag */ const getTheNextResolutionAvailable = (currentResolution) => { printLogs(`getTheNextResolutionAvailable `, currentResolution); const resolutions = [2560, 1920, 1600, 1552, 1440, 1280, 1024, 960, 800, 720, 704, 640].sort((a, b) => b - a); return resolutions.find((e) => e < currentResolution) || 640; }; /** * This function switch camera from front to back on mobile, and to another device on desktop * @category Face * @param selectedCamera Selected camera either front or back * @param device Selected camera ID * @param canvasResolution */ export const switchCamera = (selectedCamera, device, canvasResolution) => __awaiter(void 0, void 0, void 0, function* () { if (!videoElement) return; let devices = []; if (mediaStream) { mediaStream.getTracks().forEach((track) => track.stop()); } devices = yield navigator.mediaDevices.enumerateDevices(); devices = devices.filter((d) => d.kind === 'videoinput'); devices = getDevicesWithCapabilities(devices); const deviceCapabilites = getDefaultDevice(devices, device); if (selectedCamera) faceMode = selectedCamera; const getBestResolution = () => __awaiter(void 0, void 0, void 0, function* () { var _h, _j, _k, _l; let resolution = (canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.width) || Math.min(((_j = (_h = deviceCapabilites[0]) === null || _h === void 0 ? void 0 : _h.width) === null || _j === void 0 ? void 0 : _j.max) || cameraWidth, cameraWidth); const isPortraitMobileCamera = isMobileBackCameraPortrait(deviceCapabilites[0]); let hasError = true; const videoConstraints = { deviceId: deviceCapabilites[0].deviceId, width: { ideal: calculateWidth() }, height: { ideal: calculateHeight() }, facingMode: ((_l = (_k = deviceCapabilites[0]) === null || _k === void 0 ? void 0 : _k.facingMode) === null || _l === void 0 ? void 0 : _l[0]) || undefined, focusMode: 'continuous', aspectRatio: calculateAspectRatio(), resizeMode: 'none', }; const constraints = { audio: false, video: videoConstraints, // Apply video constraints }; function calculateWidth() { if (canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.width) { return resolution; // Use the specified resolution if canvas width is available } if (isPortraitMobileCamera) { return cameraHeight; // Use camera height for portrait mobile camera } return resolution; // Use the specified resolution for other cases } function calculateHeight() { if (canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.height) { return canvasResolution.height; // Use the specified canvas height } return cameraHeight; // Use camera height if canvas height is not available } function calculateAspectRatio() { if (canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.width) { return 1.7777777778; // 16:9 aspect ratio if canvas width is available } if (isPortraitMobileCamera) { return 1; // 1:1 aspect ratio for portrait mobile camera } return 1.7777777778; // 16:9 aspect ratio for other cases } let stream; while (hasError) { try { stream = yield navigator.mediaDevices.getUserMedia(constraints); hasError = false; } catch (e) { resolution = getTheNextResolutionAvailable(resolution); constraints.video = Object.assign(Object.assign({}, constraints.video), { width: { ideal: resolution } }); } } printLogs(`bestconstraints: `, constraints); return stream; }); if (device) { mediaDevice = device; setDefaultCameraDeviceId(device); } if (selectedCamera && !device) { if (selectedCamera) { const regex = selectedCamera === CameraFaceMode.back ? /back/gi : /front/gi; devices = devices.filter((d) => regex.test(d.label)); } const getBestResolutionWithFacingMode = () => __awaiter(void 0, void 0, void 0, function* () { var _m, _o; const deviceCapabilites = getDefaultDevice(devices, devices[0].deviceId); const { name: browserName, os } = detect(); const resolutionWidth = (canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.width) || (iOS() || ['iOS'].includes(os) ? cameraLowResWidth : cameraWidth); const resolutionHeight = (canvasResolution === null || canvasResolution === void 0 ? void 0 : canvasResolution.height) || (iOS() || ['iOS'].includes(os) ? cameraLowResHeight : cameraHeight); let hasError = true; const constraints = { audio: false, video: { // deviceId: deviceCapabilites[0].deviceId, width: { ideal: resolutionWidth }, facingMode: faceMode ? facingMode[faceMode] : 'user', height: { ideal: resolutionHeight }, resizeMode: 'none', }, advance: [ { focusMode: 'continuous', resizeMode: 'none', // @ts-ignore focusDistance: Math.min(((_o = (_m = deviceCapabilites[0]) === null || _m === void 0 ? void 0 : _m.focusDistance) === null || _o === void 0 ? void 0 : _o.max) || 100, 100), aspectRatio: 1.7777777778, }, ], }; let stream; while (hasError) { try { stream = yield navigator.mediaDevices.getUserMedia(constraints); hasError = false; } catch (e) { // } } printLogs(`bestconstraints: `, constraints); return stream; }); try { // eslint-disable-next-line no-nested-ternary const stream = yield getBestResolutionWithFacingMode(); const element = document.getElementById(videoElement); element.srcObject = stream; mediaStream = stream; const track = stream.getVideoTracks()[0]; const capabilities = (track === null || track === void 0 ? void 0 : track.getCapabilities) ? track.getCapabilities() : null; const settings = track.getSettings(); printLogs(`switch camera capabilities: `, capabilities); printLogs(`switch camera settings: `, settings); // eslint-disable-next-line consistent-return return { capabilities, settings }; } catch (e) { printLogs(`Error while getAccessToCamera : `, e, 'ERROR'); yield switchCamera(null, devices[0].deviceId, canvasResolution); } } else { try { if (videoMutationObserver) { videoMutationObserver.disconnect(); } // eslint-disable-next-line no-nested-ternary const stream = yield getBestResolution(); const element = document.getElementById(videoElement); element.srcObject = stream; mediaStream = stream; const track = stream.getVideoTracks()[0]; const capabilities = (track === null || track === void 0 ? void 0 : track.getCapabilities) ? track.getCapabilities() : null; const settings = track.getSettings(); printLogs(`switch camera capabilities: `, capabilities); printLogs(`switch camera settings: `, settings); enableMutationObserver(element, stream); // eslint-disable-next-line consistent-return return { capabilities, settings }; } catch (e) { printLogs(`Error while getAccessToCamera : `, e, 'ERROR'); yield switchCamera(null, devices[0].deviceId, canvasResolution); } } }); export const getBaseConfigEnroll = () => ({ input_image_format: 'rgba', angle_rotation_left_threshold: 20.0, angle_rotation_right_threshold: 20.0, threshold_high_vertical_enroll: 0.9, threshold_down_vertical_enroll: 2.2, anti_spoofing_threshold: 0.8, threshold_profile_enroll: 0.66, blur_threshold_enroll_pred: 40, threshold_user_too_close: 0.52, threshold_user_too_far: 0.165, allow_only_one_face: true, threshold_user_up: 0.15, threshold_user_down: 0.9, threshold_user_left: 0.8, threshold_user_right: 0.2, }); // eslint-disable-next-line consistent-return export function enroll({ callback, config, element, returnPortrait = false }) { return __awaiter(this, void 0, void 0, function* () { printLogs('ENROLL_ONE_FA', ''); // eslint-disable-next-line consistent-return let configJSON = getBaseConfigEnroll(); 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 (config) { configJSON = Object.assign(Object.assign({}, configJSON), config); } if (element) { videoElement = element; } // eslint-disable-next-line consistent-return const videoEl = document.getElementById(videoElement); const height = (videoEl === null || videoEl === void 0 ? void 0 : videoEl.videoHeight) || 0; const width = (videoEl === null || videoEl === void 0 ? void 0 : videoEl.videoWidth) || 0; // eslint-disable-next-line consistent-return if (width === 0) return { result: 'error' }; printLogs(`isValid: `, { height, width }); const canvas = document.createElement('canvas'); canvas.setAttribute('id', 'test-canvas'); canvas.setAttribute('height', `${height}`); canvas.setAttribute('width', `${width}`); const context = canvas.getContext('2d', { willReadFrequently: true }); if (faceMode === CameraFaceMode.front) { context.translate(width, 0); context.scale(-1, 1); } context.drawImage(videoEl, 0, 0); const imageData = context.getImageData(0, 0, width, height); const callbackForImageCreation = callbackWithImageCreation(callback, imageData, true); privid_wasm_result = createCallback({ type: callbackTypeEnum.enroll, callbackFunction: callbackForImageCreation }); const bestImage = yield ultraEnroll(imageData, isSimd, JSON.stringify(configJSON), proxy(privid_wasm_result)); // eslint-disable-next-line consistent-return if (returnPortrait) { return imageData; } return bestImage; }); } // Base configuration object with common settings const getBaseConfigPredict = () => ({ 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.52, threshold_user_too_far: 0.165, 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: '', disallowed_results: [20], disable_predict_mf: false, mf_count_override: 5, }); const faceLoginCanvas = document.createElement('canvas'); // Helper function to prepare canvas and get image data const 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: 'error' }; printLogs(`isValid:`, { height, width }); let canvas; if (useExistingCanvas) { canvas = faceLoginCanvas; } else { canvas = document.createElement('canvas'); } canvas.setAttribute('id', 'test-canvas'); canvas.setAttribute('height', `${height}`); canvas.setAttribute('width', `${width}`); const context = canvas.getContext('2d', { willReadFrequently: true }); if (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 }; }; const performPredict = (options) => { return runUltraProcess(ultraPredict, Object.assign(Object.assign({}, options), { callbackType: callbackTypeEnum.predict, logMessage: options.logMessage || '---------------------PREDICT_ONE_FA----------------------' })); }; export const estimateAge = (options) => { return runUltraProcess(ultraAgeEstimate, Object.assign(Object.assign({}, options), { callbackType: callbackTypeEnum.ageEstimation, logMessage: options.logMessage || '---------------------AGE_ESTIMATION----------------------', config: Object.assign({ anti_spoofing_threshold: 0.8, mf_count_override: 5, disable_estimate_age_mf: false, threshold_user_too_close: 0.8, threshold_profile_enroll: 0.6, threshold_user_too_far: 0.2, allow_only_one_face: false }, options.config) })); }; const runUltraProcess = (fn, options) => __awaiter(void 0, void 0, void 0, function* () { const { callback, image, config = {}, element, returnPortrait = false, useExistingCanvas = false, logMessage = '---------------------ULTRA_PROCESS----------------------', callbackType, } = options; printLogs(`${logMessage}`, ''); let configJSON = getBaseConfigPredict(); // const { os } = detect(); // if (['iOS', 'android', 'Android OS'].includes(os)) { // configJSON = { // ...configJSON, // threshold_user_too_far: 0.31, // threshold_user_too_close: 0.55, // threshold_user_right: 0.1, // threshold_user_left: 0.9, // }; // } if (config) { configJSON = Object.assign(Object.assign({}, configJSON), config); } if (image) { preparePrivdWasmResult(callback, callbackType, image, config); return yield fn([image], isSimd, JSON.stringify(configJSON), proxy(privid_wasm_result)); } if (element) { videoElement = element; } const result = prepareCanvasAndGetImageData(videoElement, useExistingCanvas); if ('result' in result) return result; const { imageData, canvas } = result; preparePrivdWasmResult(callback, callbackType, imageData, config); printLogs(`Config JSON: `, configJSON); yield fn([imageData], isSimd, JSON.stringify(configJSON), proxy(privid_wasm_result)); if (returnPortrait) { return imageData; } releaseCanvas(canvas); }); /** * Face login function */ export const faceLogin = (props) => __awaiter(void 0, void 0, void 0, function* () { return performPredict(Object.assign(Object.assign({}, props), { useExistingCanvas: true, logMessage: '---------------------FACE_LOGIN----------------------' })); }); /** * This function performs predict, the camera should already be open. the functions performs the identification return the result then restart again. * @category Face * @param callback Callbacks triggered on the predict operation * @param config Configuration recommeded default: { input_image_format: "rgba" } * @param element Element id of video tag. (Optional) By default it uses the element id used when opening the camera using openCamera() * @param image ImageData, If there is an image passed, it will be predicting the image instead of the video feed. */ export const predictVerify = (props) => __awaiter(void 0, void 0, void 0, function* () { return performPredict(Object.assign({}, props)); }); export const predict = (props) => __awaiter(void 0, void 0, void 0, function* () { return performPredict(Object.assign(Object.assign({}, props), { config: Object.assign({ url_name_override: 'predict' }, props.config) })); }); export const predictWithStatus = (props) => __awaiter(void 0, void 0, void 0, function* () { return performPredict(Object.assign(Object.assign({}, props), { config: Object.assign({ url_name_override: 'predict-status' }, props.config) })); }); export const predictConfirmUser = (props) => __awaiter(void 0, void 0, void 0, function* () { return performPredict(Object.assign(Object.assign({}, props), { config: Object.assign({ url_name_override: 'confirm-user' }, props.config) })); }); export const predictDeleteUser = (props) => __awaiter(void 0, void 0, void 0, function* () { return performPredict(Object.assign(Object.assign({}, props), { config: Object.assign({ url_name_override: 'predict/delete' }, props.config) })); }); const getDefaultDevice = (devices, device) => devices.reduce((acc, val) => { if (val.deviceId === device) { // @ts-ignore if (val === null || val === void 0 ? void 0 : val.getCapabilities) { // @ts-ignore acc.push(Object.assign(Object.assign({}, val.getCapabilities()), { label: val.label })); } else { acc.push(val); } } return acc; }, []); const getDevicesWithCapabilities = (devices) => devices.map((device) => { // Check if 'getCapabilities' exists on 'device' // @ts-ignore if (device.getCapabilities) { // Use 'device.getCapabilities()' directly without optional chaining // @ts-ignore const capabilities = device.getCapabilities(); // Return a new object with capabilities and label return Object.assign(Object.assign({}, capabilities), { label: device.label }); } return device; }); function releaseCanvas(canvas) { try { printLogs('STARTING TO RELEASE CANVAS', ''); // eslint-disable-next-line no-param-reassign canvas.width = 1; // eslint-disable-next-line no-param-reassign canvas.height = 1; const ctx = canvas.getContext('2d', { willReadFrequently: true }); // eslint-disable-next-line no-unused-expressions ctx && ctx.clearRect(0, 0, 1, 1); // eslint-disable-next-line no-param-reassign canvas = null; printLogs('CANVAS RELEASED', ''); } catch (e) { printLogs(`CLEARING CANVAS: `, e, 'ERROR'); } } export const pkiEncryptData = (payload) => __awaiter(void 0, void 0, void 0, function* () { const stringPayload = JSON.stringify(payload); const encryptedData = yield pkiEncrypt(stringPayload); return encryptedData; }); export const checkIfModelsAreLoaded = (isEnroll) => __awaiter(void 0, void 0, void 0, function* () { const result = yield checkIfModelsLoaded(isEnroll); return result; }); const frontScanCanvas = document.createElement('canvas'); export const scanFrontDocument = ({ callback, config }) => __awaiter(void 0, void 0, void 0, function* () { printLogs('________________ FRONT DOCUMENT SCAN ______________', ''); const videoEl = document.getElementById(videoElement); let configuration = { input_image_format: 'rgba', fingers_over_document_threshold: 0.2 }; if (config) { configuration = Object.assign(Object.assign({}, configuration), config); } if (!videoElement || !videoEl) { printLogs(`Capture need the video element id`, '', 'ERROR'); return { result: 'error' }; } let height = videoEl.videoHeight; let width = videoEl.videoWidth; if (isMobileFunc()) { height = videoEl.videoHeight; width = videoEl.videoWidth; } frontScanCanvas.setAttribute('id', 'test-canvas'); frontScanCanvas.setAttribute('height', `${height}`); frontScanCanvas.setAttribute('width', `${width}`); const context = frontScanCanvas.getContext('2d', { willReadFrequently: true }); context.drawImage(videoEl, 0, 0); let imageData = context.getImageData(0, 0, width, height); privid_wasm_result = createCallback({ type: callbackTypeEnum.frontScan, callbackFunction: callback, // imageData: doOcr ? imageData : undefined, }); const cb = proxy(privid_wasm_result); if (['900', '901', '902', '903'].includes(debugType)) { yield createImages([imageData], `${ImageType.original}_front_document_scan`, true); } try { configuration = JSON.stringify(configuration); yield ultraScanFrontDocument(imageData, isSimd, configuration, cb); imageData = null; return; } catch (e) { printLogs(`isValidPhotoID error: `, e, 'ERROR'); return { result: -1, }; } }); export const scanPassport = ({ callback, config }) => __awaiter(void 0, void 0, void 0, function* () { printLogs('________________ PASSPORT SCAN ______________', ''); const videoEl = document.getElementById(videoElement); let configuration = { input_image_format: 'rgba', }; if (config) { configuration = Object.assign(Object.assign({}, configuration), config); } privid_wasm_result = createCallback({ type: callbackTypeEnum.passportScan, callbackFunction: callback }); if (!videoElement || !videoEl) { printLogs(`Capture need the video element id`, '', 'ERROR'); return { result: 'error' }; } let height = videoEl.videoHeight; let width = videoEl.videoWidth; if (isMobileFunc()) { height = videoEl.videoHeight; width = videoEl.videoWidth; } frontScanCanvas.setAttribute('id', 'test-canvas'); frontScanCanvas.setAttribute('height', `${height}`); frontScanCanvas.setAttribute('width', `${width}`); const context = frontScanCanvas.getContext('2d', { willReadFrequently: true }); context.drawImage(videoEl, 0, 0); let imageData = context.getImageData(0, 0, width, height); const cb = proxy(privid_wasm_result); if (['900', '901', '902', '903'].includes(debugType)) { yield createImages([imageData], `${ImageType.original}_passport_scan`, true); } try { configuration = JSON.stringify(configuration); yield ultraScanFrontDocument(imageData, isSimd, configuration, cb); imageData = null; return; } catch (e) { printLogs(`isValidPhotoID error: `, e, 'ERROR'); return { result: -1, }; } }); const backScanCanvas = document.createElement('canvas'); export const scanBackDocument = ({ callback, image, config }) => __awaiter(void 0, void 0, void 0, function* () { printLogs('________________ DOCUMENT SCAN ______________', ''); const videoEl = document.getElementById(videoElement); let configuration = { input_image_format: 'rgba', }; if (config) { configuration = Object.assign(Object.assign({}, configuration), config); } const { os } = detect(); if (iOS() || ['iOS', 'android', 'Android OS'].includes(os)) { privid_wasm_result = createCallback({ type: callbackTypeEnum.backScan, callbackFunction: callback, isMobile: true, // barcodeScanEnable }); } else if (configuration === null || configuration === void 0 ? void 0 : configuration.document_scan_barcode_only) { privid_wasm_result = createCallback({ type: callbackTypeEnum.backScan, callbackFunction: callback, isMobile: true, }); } else if (configuration === null || configuration === void 0 ? void 0 : configuration.detect_barcode_without_parsing) { privid_wasm_result = createCallback({ type: callbackTypeEnum.backScan, callbackFunction: callback, }); } else { configuration = Object.assign(Object.assign({}, configuration), { detect_document_only: true }); privid_wasm_result = createCallback({ type: callbackTypeEnum.backScan, callbackFunction: callback }); } configuration = JSON.stringify(configuration); if (!videoElement || !videoEl) { printLogs(`Capture need the video element id`, '', 'ERROR'); return { result: 'error' }; } let height = videoEl.videoHeight; let width = videoEl.videoWidth; // if (isMobileFunc()) { // height = videoEl.videoHeight; // width = videoEl.videoWidth; // } backScanCanvas.setAttribute('id', 'test-canvas'); backScanCanvas.setAttribute('height', `${height}`); backScanCanvas.setAttribute('width', `${width}`); const context = backScanCanvas.getContext('2d', { willReadFrequently: true }); context.drawImage(videoEl, 0, 0); if ((image === null || image === void 0 ? void 0 : image.width) === 0 || width === 0 || height === 0) return { result: 'error' }; let imageData = context.getImageData(0, 0, width, height); let result = null; if (['900', '901', '902', '903'].includes(debugType)) { yield createImages([imageData], ImageType.original, true); } try { printLogs(`Configuration: back scan: `, configuration); // if(isMobileDevice()){ result = yield ultraScanBackDocument(imageData, isSimd, configuration, proxy(privid_wasm_result)); // } // else{ // privid_wasm_result = createCallback({ type: callbackTypeEnum.backScan, callbackFunction: callback }); // result = await scanDocumentNoFace(imageData, isSimd, proxy(privid_wasm_result), configuration, '3'); // } imageData = null; releaseCanvas(backScanCanvas); return Object.assign({}, result); } catch (e) { printLogs(`isValidPhotoID error: `, e, 'ERROR'); return { result: -1, }; } }); export const compareEmbeddings = (embeddingsA, embeddingsB, config = {}, callback, encryptData = false) => __awaiter(void 0, void 0, void 0, function* () { if (encryptData) { config = Object.assign(Object.assign({}, config), { encrypt_compare_result: true }); } printLogs(`ULTRA COMPARE: `, { embeddingsA, embeddingsB, config: JSON.stringify(config), ex: proxy(createCallback({ type: callbackTypeEnum.compareEmbeddings, callbackFunction: callback })), }); const result = yield ultraCompareEmbeddings(embeddingsA, embeddingsB, JSON.stringify(config), proxy(createCallback({ type: callbackTypeEnum.compareEmbeddings, callbackFunction: callback }))); return result; }); export const documentOcr = ({ inputImage, callback, config }) => __awaiter(void 0, void 0, void 0, function* () { printLogs('________________ DOCUMENT OCR ______________', ''); const videoEl = document.getElementById(videoElement); let configuration = { input_image_format: 'rgba', calculate_age_from_ocr_text: true, threshold_doc_x: 0.0, threshold_doc_y: 0.0, threshold_doc_too_close: 0.99, threshold_doc_too_far: 0.1, }; if (config) { configuration = Object.assign(Object.assign({}, configuration), config); } privid_wasm_result = createCallback({ type: callbackTypeEnum.documentOcr, callbackFunction: callback }); const cb = proxy(privid_wasm_result); if (['900', '901', '902', '903'].includes(debugType)) { yield createImages([inputImage], `${ImageType.original}_document_ocr`, true); } try { configuration = JSON.stringify(configuration); yield ultraDocumentOcr(inputImage, configuration, cb); return; } catch (e) { printLogs(`isValidPhotoID error: `, e, 'ERROR'); return { result: -1, }; } }); export const freeFrontScanMemory = () => __awaiter(void 0, void 0, void 0, function* () { const result = yield freeMemory(); return result; }); //# sourceMappingURL=faceModule.js.map