id-scanner-lib 1.6.3 → 1.6.5
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/LICENSE +1 -1
- package/dist/id-scanner-lib.esm.js +153 -52
- package/dist/id-scanner-lib.esm.js.map +1 -1
- package/dist/id-scanner-lib.js +153 -52
- package/dist/id-scanner-lib.js.map +1 -1
- package/package.json +1 -1
- package/src/core/config.ts +29 -11
- package/src/core/logger.ts +27 -3
- package/src/core/module-manager.ts +9 -0
- package/src/index.ts +1 -0
- package/src/modules/face/face-detector.ts +1 -0
- package/src/modules/face/index.ts +1 -0
- package/src/modules/face/liveness-detector.ts +1 -0
- package/src/modules/id-card/id-card-detector.ts +98 -35
- package/src/modules/id-card/index.ts +1 -0
- package/src/modules/id-card/ocr-processor.ts +3 -3
- package/src/modules/qrcode/index.ts +1 -0
- package/src/utils/camera.ts +16 -2
- package/src/utils/resource-manager.ts +2 -2
- package/src/utils/worker.ts +4 -4
package/dist/id-scanner-lib.js
CHANGED
|
@@ -22,7 +22,30 @@
|
|
|
22
22
|
this.config = {};
|
|
23
23
|
/** 配置变更回调 */
|
|
24
24
|
this.changeCallbacks = new Map();
|
|
25
|
+
/** 初始化状态 */
|
|
26
|
+
this.initialized = false;
|
|
25
27
|
// 设置默认配置
|
|
28
|
+
this._resetDefaults();
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 获取单例实例
|
|
32
|
+
*/
|
|
33
|
+
static getInstance() {
|
|
34
|
+
if (!ConfigManager.instance) {
|
|
35
|
+
ConfigManager.instance = new ConfigManager();
|
|
36
|
+
}
|
|
37
|
+
return ConfigManager.instance;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 重置单例实例(主要用于测试)
|
|
41
|
+
*/
|
|
42
|
+
static resetInstance() {
|
|
43
|
+
ConfigManager.instance = undefined;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 重置为默认配置
|
|
47
|
+
*/
|
|
48
|
+
_resetDefaults() {
|
|
26
49
|
this.config = {
|
|
27
50
|
debug: false,
|
|
28
51
|
logLevel: 'info',
|
|
@@ -38,15 +61,7 @@
|
|
|
38
61
|
useCache: true
|
|
39
62
|
}
|
|
40
63
|
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* 获取单例实例
|
|
44
|
-
*/
|
|
45
|
-
static getInstance() {
|
|
46
|
-
if (!ConfigManager.instance) {
|
|
47
|
-
ConfigManager.instance = new ConfigManager();
|
|
48
|
-
}
|
|
49
|
-
return ConfigManager.instance;
|
|
64
|
+
this.initialized = true;
|
|
50
65
|
}
|
|
51
66
|
/**
|
|
52
67
|
* 获取配置值
|
|
@@ -86,7 +101,7 @@
|
|
|
86
101
|
*/
|
|
87
102
|
reset() {
|
|
88
103
|
const oldConfig = { ...this.config };
|
|
89
|
-
//
|
|
104
|
+
// 使用私有 reset 方法重建默认配置
|
|
90
105
|
this.config = {
|
|
91
106
|
debug: false,
|
|
92
107
|
logLevel: 'info',
|
|
@@ -382,6 +397,16 @@
|
|
|
382
397
|
return;
|
|
383
398
|
const entriesToSend = [...this.queue];
|
|
384
399
|
this.queue = [];
|
|
400
|
+
// 防止在 fetch 失败时无限重试
|
|
401
|
+
const sendCount = this._sendCount || 0;
|
|
402
|
+
this._sendCount = sendCount + 1;
|
|
403
|
+
// 如果发送次数过多,停止发送以防止无限循环
|
|
404
|
+
if (sendCount > 10) {
|
|
405
|
+
console.warn('RemoteLogHandler: Too many failed sends, stopping. Clear queue.');
|
|
406
|
+
this.queue = [];
|
|
407
|
+
this._sendCount = 0;
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
385
410
|
try {
|
|
386
411
|
fetch(this.endpoint, {
|
|
387
412
|
method: 'POST',
|
|
@@ -389,14 +414,23 @@
|
|
|
389
414
|
'Content-Type': 'application/json'
|
|
390
415
|
},
|
|
391
416
|
body: JSON.stringify(entriesToSend),
|
|
392
|
-
// 不等待响应,避免阻塞
|
|
393
417
|
keepalive: true
|
|
394
|
-
}).catch(err => {
|
|
418
|
+
}).catch((err) => {
|
|
395
419
|
console.error('Failed to send logs to remote server:', err);
|
|
420
|
+
// 防止无限重试 - 如果失败次数过多,丢弃日志
|
|
421
|
+
if (this._sendCount > 10) {
|
|
422
|
+
console.warn('RemoteLogHandler: Max retry exceeded, discarding logs');
|
|
423
|
+
this.queue = []; // 清空队列,避免内存泄漏
|
|
424
|
+
this._sendCount = 0;
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
396
427
|
// 失败时把日志放回队列,但防止无限增长
|
|
397
428
|
if (this.queue.length < this.maxQueueSize) {
|
|
398
|
-
|
|
429
|
+
const maxReturn = Math.min(entriesToSend.length, this.maxQueueSize - this.queue.length);
|
|
430
|
+
const returnedEntries = entriesToSend.slice(0, maxReturn);
|
|
431
|
+
this.queue = [...returnedEntries, ...this.queue];
|
|
399
432
|
}
|
|
433
|
+
this._sendCount = 0;
|
|
400
434
|
});
|
|
401
435
|
}
|
|
402
436
|
catch (error) {
|
|
@@ -798,6 +832,7 @@
|
|
|
798
832
|
// 构建日期
|
|
799
833
|
const BUILD_DATE = new Date().toISOString();
|
|
800
834
|
|
|
835
|
+
/* eslint-disable */
|
|
801
836
|
/**
|
|
802
837
|
* @file 模块管理器
|
|
803
838
|
* @description 统一管理库的各功能模块,提供模块的注册、初始化和卸载功能
|
|
@@ -817,6 +852,12 @@
|
|
|
817
852
|
}
|
|
818
853
|
return ModuleManager.instance;
|
|
819
854
|
}
|
|
855
|
+
/**
|
|
856
|
+
* 重置单例实例(主要用于测试)
|
|
857
|
+
*/
|
|
858
|
+
static resetInstance() {
|
|
859
|
+
ModuleManager.instance = undefined;
|
|
860
|
+
}
|
|
820
861
|
/**
|
|
821
862
|
* 私有构造函数,确保单例模式
|
|
822
863
|
*/
|
|
@@ -824,6 +865,7 @@
|
|
|
824
865
|
super();
|
|
825
866
|
this.modules = new Map();
|
|
826
867
|
this.initialized = false;
|
|
868
|
+
this.initPromise = null;
|
|
827
869
|
this.logger = Logger.getInstance();
|
|
828
870
|
this.logger.debug('ModuleManager', `初始化模块管理器 v${VERSION}`);
|
|
829
871
|
}
|
|
@@ -1146,6 +1188,9 @@
|
|
|
1146
1188
|
super();
|
|
1147
1189
|
this.initialized = false;
|
|
1148
1190
|
this.models = {};
|
|
1191
|
+
/** 重用的 Canvas 元素,用于减少内存分配 */
|
|
1192
|
+
this.reusableCanvas = null;
|
|
1193
|
+
this.reusableContext = null;
|
|
1149
1194
|
this.options = {
|
|
1150
1195
|
enabled: true,
|
|
1151
1196
|
minConfidence: 0.7,
|
|
@@ -1244,6 +1289,26 @@
|
|
|
1244
1289
|
if (!this.initialized) {
|
|
1245
1290
|
return Result.failure(new Error('身份证检测器未初始化'));
|
|
1246
1291
|
}
|
|
1292
|
+
// 输入验证
|
|
1293
|
+
if (!image) {
|
|
1294
|
+
return Result.failure(new Error('图像源不能为空'));
|
|
1295
|
+
}
|
|
1296
|
+
// 验证 HTMLImageElement 是否已加载
|
|
1297
|
+
if (image instanceof HTMLImageElement && !image.complete) {
|
|
1298
|
+
return Result.failure(new Error('图像尚未加载完成'));
|
|
1299
|
+
}
|
|
1300
|
+
// 验证 ImageData 尺寸
|
|
1301
|
+
if (image instanceof ImageData) {
|
|
1302
|
+
if (image.width === 0 || image.height === 0) {
|
|
1303
|
+
return Result.failure(new Error('图像尺寸无效'));
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
// 验证 Canvas 尺寸
|
|
1307
|
+
if (image instanceof HTMLCanvasElement) {
|
|
1308
|
+
if (image.width === 0 || image.height === 0) {
|
|
1309
|
+
return Result.failure(new Error('Canvas尺寸无效'));
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1247
1312
|
try {
|
|
1248
1313
|
this.logger.debug('IDCardDetector', '开始处理图像');
|
|
1249
1314
|
// 预处理图像
|
|
@@ -1290,9 +1355,7 @@
|
|
|
1290
1355
|
}
|
|
1291
1356
|
}
|
|
1292
1357
|
else if (image instanceof HTMLImageElement && image.complete) {
|
|
1293
|
-
const canvas =
|
|
1294
|
-
canvas.width = image.naturalWidth;
|
|
1295
|
-
canvas.height = image.naturalHeight;
|
|
1358
|
+
const canvas = this.getReusableCanvas(image.naturalWidth, image.naturalHeight);
|
|
1296
1359
|
const context = canvas.getContext('2d');
|
|
1297
1360
|
if (context) {
|
|
1298
1361
|
context.drawImage(image, 0, 0);
|
|
@@ -1309,6 +1372,26 @@
|
|
|
1309
1372
|
return Result.failure(error);
|
|
1310
1373
|
}
|
|
1311
1374
|
}
|
|
1375
|
+
/**
|
|
1376
|
+
* 获取可重用的 Canvas 元素
|
|
1377
|
+
* @param width 宽度
|
|
1378
|
+
* @param height 高度
|
|
1379
|
+
* @returns CanvasRenderingContext2D
|
|
1380
|
+
*/
|
|
1381
|
+
getReusableCanvas(width, height) {
|
|
1382
|
+
// 如果存在可重用的 canvas 且尺寸匹配,直接返回
|
|
1383
|
+
if (this.reusableCanvas &&
|
|
1384
|
+
this.reusableCanvas.width === width &&
|
|
1385
|
+
this.reusableCanvas.height === height) {
|
|
1386
|
+
return this.reusableCanvas;
|
|
1387
|
+
}
|
|
1388
|
+
// 创建新的 canvas
|
|
1389
|
+
this.reusableCanvas = document.createElement('canvas');
|
|
1390
|
+
this.reusableCanvas.width = width;
|
|
1391
|
+
this.reusableCanvas.height = height;
|
|
1392
|
+
this.reusableContext = this.reusableCanvas.getContext('2d');
|
|
1393
|
+
return this.reusableCanvas;
|
|
1394
|
+
}
|
|
1312
1395
|
/**
|
|
1313
1396
|
* 预处理图像
|
|
1314
1397
|
* @param image 图像源
|
|
@@ -1317,7 +1400,6 @@
|
|
|
1317
1400
|
* @private
|
|
1318
1401
|
*/
|
|
1319
1402
|
async preprocessImage(image, options) {
|
|
1320
|
-
// 实际项目中,这里应该对图像进行预处理
|
|
1321
1403
|
this.logger.debug('IDCardDetector', '预处理图像');
|
|
1322
1404
|
// 创建ImageData对象
|
|
1323
1405
|
let imageData;
|
|
@@ -1325,11 +1407,9 @@
|
|
|
1325
1407
|
imageData = image;
|
|
1326
1408
|
}
|
|
1327
1409
|
else {
|
|
1328
|
-
const canvas = document.createElement('canvas');
|
|
1329
1410
|
const width = image instanceof HTMLImageElement ? image.naturalWidth : image.width;
|
|
1330
1411
|
const height = image instanceof HTMLImageElement ? image.naturalHeight : image.height;
|
|
1331
|
-
canvas
|
|
1332
|
-
canvas.height = height;
|
|
1412
|
+
const canvas = this.getReusableCanvas(width, height);
|
|
1333
1413
|
const context = canvas.getContext('2d');
|
|
1334
1414
|
if (!context) {
|
|
1335
1415
|
throw new Error('无法获取Canvas上下文');
|
|
@@ -1376,18 +1456,16 @@
|
|
|
1376
1456
|
* @private
|
|
1377
1457
|
*/
|
|
1378
1458
|
async cropAndAlign(image, edge) {
|
|
1379
|
-
// 实际项目中,这里应该进行透视变换以校正图像
|
|
1380
1459
|
this.logger.debug('IDCardDetector', '裁剪并校正图像');
|
|
1381
|
-
// 创建Canvas
|
|
1382
|
-
const canvas = document.createElement('canvas');
|
|
1383
1460
|
// 设置标准身份证尺寸比例
|
|
1384
|
-
|
|
1385
|
-
|
|
1461
|
+
const standardWidth = 428;
|
|
1462
|
+
const standardHeight = 270;
|
|
1463
|
+
const canvas = this.getReusableCanvas(standardWidth, standardHeight);
|
|
1386
1464
|
const context = canvas.getContext('2d');
|
|
1387
1465
|
if (!context) {
|
|
1388
1466
|
throw new Error('无法获取Canvas上下文');
|
|
1389
1467
|
}
|
|
1390
|
-
// 创建临时Canvas
|
|
1468
|
+
// 创建临时Canvas用于源图像
|
|
1391
1469
|
const tempCanvas = document.createElement('canvas');
|
|
1392
1470
|
tempCanvas.width = image.width;
|
|
1393
1471
|
tempCanvas.height = image.height;
|
|
@@ -1400,29 +1478,37 @@
|
|
|
1400
1478
|
// 在实际应用中,这里应该使用透视变换算法
|
|
1401
1479
|
// 例如使用Canvas的transform或WebGL进行变换
|
|
1402
1480
|
// 简化处理:直接裁剪
|
|
1403
|
-
context.drawImage(tempCanvas, edge.topLeft.x, edge.topLeft.y, edge.topRight.x - edge.topLeft.x, edge.bottomLeft.y - edge.topLeft.y, 0, 0,
|
|
1404
|
-
return context.getImageData(0, 0,
|
|
1481
|
+
context.drawImage(tempCanvas, edge.topLeft.x, edge.topLeft.y, edge.topRight.x - edge.topLeft.x, edge.bottomLeft.y - edge.topLeft.y, 0, 0, standardWidth, standardHeight);
|
|
1482
|
+
return context.getImageData(0, 0, standardWidth, standardHeight);
|
|
1405
1483
|
}
|
|
1406
1484
|
/**
|
|
1407
1485
|
* 识别文字
|
|
1486
|
+
*
|
|
1487
|
+
* @note 此方法返回模拟数据,用于框架开发和测试
|
|
1488
|
+
* 实际使用时需要替换为真实的 OCR 模型集成
|
|
1489
|
+
*
|
|
1408
1490
|
* @param image 图像数据
|
|
1409
1491
|
* @param type 身份证类型
|
|
1410
1492
|
* @returns 识别结果
|
|
1411
1493
|
* @private
|
|
1412
1494
|
*/
|
|
1413
1495
|
async recognizeText(image, type) {
|
|
1414
|
-
// 实际项目中,这里应该调用OCR模型进行文字识别
|
|
1415
1496
|
this.logger.debug('IDCardDetector', '识别文字');
|
|
1416
1497
|
// 模拟OCR结果
|
|
1417
|
-
//
|
|
1498
|
+
// 注意:这是框架的占位实现,真实场景需要接入实际的 OCR 服务
|
|
1499
|
+
// 可选的方案包括:
|
|
1500
|
+
// - TensorFlow.js + 自定义 OCR 模型
|
|
1501
|
+
// - 第三方 OCR API (如百度OCR、腾讯OCR)
|
|
1502
|
+
// - Tesseract.js WASM 版本
|
|
1503
|
+
//
|
|
1418
1504
|
if (type === exports.IDCardType.FRONT) {
|
|
1419
1505
|
return {
|
|
1420
|
-
name: '张三',
|
|
1421
|
-
gender: '男',
|
|
1422
|
-
ethnicity: '汉',
|
|
1423
|
-
birthDate: '1990-01-01',
|
|
1424
|
-
address: '北京市朝阳区某某街道某某社区1号楼1单元101',
|
|
1425
|
-
idNumber: '110101199001010001',
|
|
1506
|
+
name: '张三', // TODO: 替换为真实OCR结果
|
|
1507
|
+
gender: '男', // TODO: 替换为真实OCR结果
|
|
1508
|
+
ethnicity: '汉', // TODO: 替换为真实OCR结果
|
|
1509
|
+
birthDate: '1990-01-01', // TODO: 替换为真实OCR结果
|
|
1510
|
+
address: '北京市朝阳区某某街道某某社区1号楼1单元101', // TODO: 替换为真实OCR结果
|
|
1511
|
+
idNumber: '110101199001010001', // TODO: 替换为真实OCR结果
|
|
1426
1512
|
photoRegion: {
|
|
1427
1513
|
x: 300,
|
|
1428
1514
|
y: 40,
|
|
@@ -1433,34 +1519,42 @@
|
|
|
1433
1519
|
}
|
|
1434
1520
|
else if (type === exports.IDCardType.BACK) {
|
|
1435
1521
|
return {
|
|
1436
|
-
issueAuthority: '北京市公安局朝阳分局',
|
|
1437
|
-
validFrom: '2015-01-01',
|
|
1438
|
-
validTo: '2035-01-01'
|
|
1522
|
+
issueAuthority: '北京市公安局朝阳分局', // TODO: 替换为真实OCR结果
|
|
1523
|
+
validFrom: '2015-01-01', // TODO: 替换为真实OCR结果
|
|
1524
|
+
validTo: '2035-01-01' // TODO: 替换为真实OCR结果
|
|
1439
1525
|
};
|
|
1440
1526
|
}
|
|
1441
1527
|
return {};
|
|
1442
1528
|
}
|
|
1443
1529
|
/**
|
|
1444
1530
|
* 检测防伪特征
|
|
1531
|
+
*
|
|
1532
|
+
* @note 此方法返回模拟数据,用于框架开发和测试
|
|
1533
|
+
* 实际使用时需要替换为真实的防伪检测模型
|
|
1534
|
+
*
|
|
1445
1535
|
* @param image 图像数据
|
|
1446
1536
|
* @param detectionResult 检测结果
|
|
1447
1537
|
* @returns 防伪检测结果
|
|
1448
1538
|
* @private
|
|
1449
1539
|
*/
|
|
1450
1540
|
async detectAntiFake(image, detectionResult) {
|
|
1451
|
-
// 实际项目中,这里应该调用防伪模型进行特征检测
|
|
1452
1541
|
this.logger.debug('IDCardDetector', '检测防伪特征');
|
|
1453
1542
|
// 模拟防伪检测结果
|
|
1454
|
-
//
|
|
1543
|
+
// 注意:这是框架的占位实现,真实场景需要接入实际的防伪检测模型
|
|
1544
|
+
// 可选的方案包括:
|
|
1545
|
+
// - 紫外光特征检测
|
|
1546
|
+
// - 红外光特征检测
|
|
1547
|
+
// - 微缩文字检测
|
|
1548
|
+
// - 光学变色特征检测
|
|
1455
1549
|
return {
|
|
1456
1550
|
passed: true,
|
|
1457
1551
|
score: 0.92,
|
|
1458
1552
|
features: {
|
|
1459
|
-
fluorescent: true,
|
|
1460
|
-
microtext: true,
|
|
1461
|
-
opticalVariable: true,
|
|
1462
|
-
texture: true,
|
|
1463
|
-
watermark: true
|
|
1553
|
+
fluorescent: true, // TODO: 替换为真实检测结果
|
|
1554
|
+
microtext: true, // TODO: 替换为真实检测结果
|
|
1555
|
+
opticalVariable: true, // TODO: 替换为真实检测结果
|
|
1556
|
+
texture: true, // TODO: 替换为真实检测结果
|
|
1557
|
+
watermark: true // TODO: 替换为真实检测结果
|
|
1464
1558
|
}
|
|
1465
1559
|
};
|
|
1466
1560
|
}
|
|
@@ -1472,6 +1566,9 @@
|
|
|
1472
1566
|
// 清理模型
|
|
1473
1567
|
this.models = {};
|
|
1474
1568
|
this.initialized = false;
|
|
1569
|
+
// 清理可重用的 Canvas
|
|
1570
|
+
this.reusableCanvas = null;
|
|
1571
|
+
this.reusableContext = null;
|
|
1475
1572
|
// 清理事件监听
|
|
1476
1573
|
this.removeAllListeners();
|
|
1477
1574
|
}
|
|
@@ -2390,7 +2487,7 @@
|
|
|
2390
2487
|
let messageCounter = 0;
|
|
2391
2488
|
// 监听Worker消息
|
|
2392
2489
|
worker.addEventListener('message', (event) => {
|
|
2393
|
-
const { messageId, success, result, error } = event.data;
|
|
2490
|
+
const { messageId, success, result, error: _error } = event.data;
|
|
2394
2491
|
// 查找对应的Promise
|
|
2395
2492
|
const promiseHandlers = promiseMap.get(messageId);
|
|
2396
2493
|
if (promiseHandlers) {
|
|
@@ -2398,7 +2495,7 @@
|
|
|
2398
2495
|
promiseHandlers.resolve(result);
|
|
2399
2496
|
}
|
|
2400
2497
|
else {
|
|
2401
|
-
promiseHandlers.reject(new Error(
|
|
2498
|
+
promiseHandlers.reject(new Error(_error));
|
|
2402
2499
|
}
|
|
2403
2500
|
// 删除Promise映射
|
|
2404
2501
|
promiseMap.delete(messageId);
|
|
@@ -2422,8 +2519,8 @@
|
|
|
2422
2519
|
// 释放Blob URL
|
|
2423
2520
|
URL.revokeObjectURL(url);
|
|
2424
2521
|
// 拒绝所有未完成的Promise
|
|
2425
|
-
for (const [, { reject }] of promiseMap) {
|
|
2426
|
-
|
|
2522
|
+
for (const [, { reject: _reject }] of promiseMap) {
|
|
2523
|
+
_reject(new Error('Worker已终止'));
|
|
2427
2524
|
}
|
|
2428
2525
|
// 清空Promise映射
|
|
2429
2526
|
promiseMap.clear();
|
|
@@ -2799,8 +2896,8 @@
|
|
|
2799
2896
|
? JSON.stringify(error)
|
|
2800
2897
|
: String(error);
|
|
2801
2898
|
this.options.logger?.(`OCR识别错误: ${errorMessage}`);
|
|
2802
|
-
//
|
|
2803
|
-
return
|
|
2899
|
+
// 返回 null,让调用方知道识别失败
|
|
2900
|
+
return null;
|
|
2804
2901
|
}
|
|
2805
2902
|
}
|
|
2806
2903
|
/**
|
|
@@ -3584,6 +3681,7 @@
|
|
|
3584
3681
|
}
|
|
3585
3682
|
}
|
|
3586
3683
|
|
|
3684
|
+
/* eslint-disable */
|
|
3587
3685
|
/**
|
|
3588
3686
|
* @file 身份证模块入口
|
|
3589
3687
|
* @description 提供身份证识别和验证功能的模块入口
|
|
@@ -4137,6 +4235,7 @@
|
|
|
4137
4235
|
}
|
|
4138
4236
|
}
|
|
4139
4237
|
|
|
4238
|
+
/* eslint-disable */
|
|
4140
4239
|
/**
|
|
4141
4240
|
* @file 二维码模块入口
|
|
4142
4241
|
* @description 提供二维码识别和解析功能的模块入口
|
|
@@ -4278,6 +4377,7 @@
|
|
|
4278
4377
|
}
|
|
4279
4378
|
}
|
|
4280
4379
|
|
|
4380
|
+
/* eslint-disable */
|
|
4281
4381
|
/**
|
|
4282
4382
|
* @file 人脸模块入口
|
|
4283
4383
|
* @description 提供人脸检测、活体检测和人脸比对功能的模块入口
|
|
@@ -4726,6 +4826,7 @@
|
|
|
4726
4826
|
}
|
|
4727
4827
|
}
|
|
4728
4828
|
|
|
4829
|
+
/* eslint-disable */
|
|
4729
4830
|
/**
|
|
4730
4831
|
* @file 主入口文件
|
|
4731
4832
|
* @description ID Scanner库的主入口点,提供统一的API和模块导出
|