id-scanner-lib 1.6.5 → 1.6.7
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/dist/id-scanner-lib.esm.js +107 -67
- package/dist/id-scanner-lib.esm.js.map +1 -1
- package/dist/id-scanner-lib.js +107 -66
- package/dist/id-scanner-lib.js.map +1 -1
- package/package.json +1 -1
- package/src/core/event-emitter.ts +9 -0
- package/src/core/logger.ts +52 -34
- package/src/core/resource-manager.ts +23 -9
- package/src/core/result.ts +3 -3
- package/src/index.ts +5 -5
- package/src/modules/face/face-detector.ts +8 -6
- package/src/modules/face/liveness-detector.ts +3 -2
- package/src/modules/id-card/index.ts +10 -8
- package/src/utils/image-processing.ts +22 -31
- package/src/core/plugin-manager.ts +0 -429
- package/src/core/scanner-factory.ts +0 -236
package/dist/id-scanner-lib.js
CHANGED
|
@@ -261,13 +261,17 @@
|
|
|
261
261
|
/**
|
|
262
262
|
* 日志级别枚举
|
|
263
263
|
*/
|
|
264
|
-
exports.
|
|
265
|
-
(function (
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
})(exports.
|
|
264
|
+
exports.LoggerLevel = void 0;
|
|
265
|
+
(function (LoggerLevel) {
|
|
266
|
+
LoggerLevel["DEBUG"] = "debug";
|
|
267
|
+
LoggerLevel["INFO"] = "info";
|
|
268
|
+
LoggerLevel["WARN"] = "warn";
|
|
269
|
+
LoggerLevel["ERROR"] = "error";
|
|
270
|
+
})(exports.LoggerLevel || (exports.LoggerLevel = {}));
|
|
271
|
+
/**
|
|
272
|
+
* @deprecated 使用 LoggerLevel 代替
|
|
273
|
+
*/
|
|
274
|
+
const LogLevel = exports.LoggerLevel;
|
|
271
275
|
/**
|
|
272
276
|
* 控制台日志处理器
|
|
273
277
|
* 将日志输出到浏览器控制台
|
|
@@ -281,16 +285,16 @@
|
|
|
281
285
|
const timestamp = new Date(entry.timestamp).toISOString();
|
|
282
286
|
const prefix = `[${timestamp}] [${entry.level.toUpperCase()}] [${entry.tag}]`;
|
|
283
287
|
switch (entry.level) {
|
|
284
|
-
case exports.
|
|
288
|
+
case exports.LoggerLevel.DEBUG:
|
|
285
289
|
console.debug(prefix, entry.message, entry.error || '');
|
|
286
290
|
break;
|
|
287
|
-
case exports.
|
|
291
|
+
case exports.LoggerLevel.INFO:
|
|
288
292
|
console.info(prefix, entry.message, entry.error || '');
|
|
289
293
|
break;
|
|
290
|
-
case exports.
|
|
294
|
+
case exports.LoggerLevel.WARN:
|
|
291
295
|
console.warn(prefix, entry.message, entry.error || '');
|
|
292
296
|
break;
|
|
293
|
-
case exports.
|
|
297
|
+
case exports.LoggerLevel.ERROR:
|
|
294
298
|
console.error(prefix, entry.message, entry.error || '');
|
|
295
299
|
break;
|
|
296
300
|
// 输出什么也不做
|
|
@@ -368,12 +372,15 @@
|
|
|
368
372
|
this.endpoint = endpoint;
|
|
369
373
|
this.maxQueueSize = maxQueueSize;
|
|
370
374
|
this.flushInterval = flushInterval;
|
|
375
|
+
this.isBrowser = typeof window !== 'undefined' && typeof window.addEventListener === 'function';
|
|
371
376
|
// 设置定时发送
|
|
372
377
|
this.startTimer();
|
|
373
378
|
// 页面卸载前尝试发送剩余日志
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
379
|
+
if (this.isBrowser) {
|
|
380
|
+
window.addEventListener('beforeunload', () => {
|
|
381
|
+
this.flush();
|
|
382
|
+
});
|
|
383
|
+
}
|
|
377
384
|
}
|
|
378
385
|
/**
|
|
379
386
|
* 处理日志条目
|
|
@@ -381,7 +388,7 @@
|
|
|
381
388
|
*/
|
|
382
389
|
handle(entry) {
|
|
383
390
|
// 只处理INFO以上级别的日志
|
|
384
|
-
if (entry.level >= exports.
|
|
391
|
+
if (entry.level >= exports.LoggerLevel.INFO) {
|
|
385
392
|
this.queue.push(entry);
|
|
386
393
|
// 如果队列满了,立即发送
|
|
387
394
|
if (this.queue.length >= this.maxQueueSize) {
|
|
@@ -441,6 +448,8 @@
|
|
|
441
448
|
* 开始定时发送
|
|
442
449
|
*/
|
|
443
450
|
startTimer() {
|
|
451
|
+
if (!this.isBrowser)
|
|
452
|
+
return;
|
|
444
453
|
if (this.timerId !== null)
|
|
445
454
|
return;
|
|
446
455
|
this.timerId = window.setInterval(() => {
|
|
@@ -471,7 +480,7 @@
|
|
|
471
480
|
/** 默认标签 */
|
|
472
481
|
this.defaultTag = 'IDScanner';
|
|
473
482
|
/** 日志级别 */
|
|
474
|
-
this.logLevel = exports.
|
|
483
|
+
this.logLevel = exports.LoggerLevel.INFO;
|
|
475
484
|
this.config = ConfigManager.getInstance();
|
|
476
485
|
// 默认添加控制台处理器
|
|
477
486
|
this.addHandler(new ConsoleLogHandler());
|
|
@@ -489,6 +498,12 @@
|
|
|
489
498
|
}
|
|
490
499
|
return Logger.instance;
|
|
491
500
|
}
|
|
501
|
+
/**
|
|
502
|
+
* 重置单例实例(主要用于测试)
|
|
503
|
+
*/
|
|
504
|
+
static resetInstance() {
|
|
505
|
+
Logger.instance = undefined;
|
|
506
|
+
}
|
|
492
507
|
/**
|
|
493
508
|
* 添加日志处理器
|
|
494
509
|
* @param handler 日志处理器
|
|
@@ -526,7 +541,7 @@
|
|
|
526
541
|
* @param error 错误
|
|
527
542
|
*/
|
|
528
543
|
debug(tag, message, error) {
|
|
529
|
-
this.log(exports.
|
|
544
|
+
this.log(exports.LoggerLevel.DEBUG, tag, message, error);
|
|
530
545
|
}
|
|
531
546
|
/**
|
|
532
547
|
* 记录信息级别日志
|
|
@@ -535,7 +550,7 @@
|
|
|
535
550
|
* @param error 错误
|
|
536
551
|
*/
|
|
537
552
|
info(tag, message, error) {
|
|
538
|
-
this.log(exports.
|
|
553
|
+
this.log(exports.LoggerLevel.INFO, tag, message, error);
|
|
539
554
|
}
|
|
540
555
|
/**
|
|
541
556
|
* 记录警告级别日志
|
|
@@ -544,7 +559,7 @@
|
|
|
544
559
|
* @param error 错误
|
|
545
560
|
*/
|
|
546
561
|
warn(tag, message, error) {
|
|
547
|
-
this.log(exports.
|
|
562
|
+
this.log(exports.LoggerLevel.WARN, tag, message, error);
|
|
548
563
|
}
|
|
549
564
|
/**
|
|
550
565
|
* 记录错误级别日志
|
|
@@ -553,7 +568,7 @@
|
|
|
553
568
|
* @param error 错误
|
|
554
569
|
*/
|
|
555
570
|
error(tag, message, error) {
|
|
556
|
-
this.log(exports.
|
|
571
|
+
this.log(exports.LoggerLevel.ERROR, tag, message, error);
|
|
557
572
|
}
|
|
558
573
|
/**
|
|
559
574
|
* 创建标记了特定标签的日志记录器
|
|
@@ -606,16 +621,16 @@
|
|
|
606
621
|
const timestamp = new Date(entry.timestamp).toISOString();
|
|
607
622
|
const prefix = `[${timestamp}] [${entry.level.toUpperCase()}] [${entry.tag}]`;
|
|
608
623
|
switch (entry.level) {
|
|
609
|
-
case exports.
|
|
624
|
+
case exports.LoggerLevel.DEBUG:
|
|
610
625
|
console.debug(`${prefix} ${entry.message}`, entry.error || '');
|
|
611
626
|
break;
|
|
612
|
-
case exports.
|
|
627
|
+
case exports.LoggerLevel.INFO:
|
|
613
628
|
console.info(`${prefix} ${entry.message}`, entry.error || '');
|
|
614
629
|
break;
|
|
615
|
-
case exports.
|
|
630
|
+
case exports.LoggerLevel.WARN:
|
|
616
631
|
console.warn(`${prefix} ${entry.message}`, entry.error || '');
|
|
617
632
|
break;
|
|
618
|
-
case exports.
|
|
633
|
+
case exports.LoggerLevel.ERROR:
|
|
619
634
|
console.error(`${prefix} ${entry.message}`, entry.error || '');
|
|
620
635
|
break;
|
|
621
636
|
}
|
|
@@ -626,13 +641,13 @@
|
|
|
626
641
|
*/
|
|
627
642
|
getLevelValue(level) {
|
|
628
643
|
switch (level) {
|
|
629
|
-
case exports.
|
|
644
|
+
case exports.LoggerLevel.DEBUG:
|
|
630
645
|
return 0;
|
|
631
|
-
case exports.
|
|
646
|
+
case exports.LoggerLevel.INFO:
|
|
632
647
|
return 1;
|
|
633
|
-
case exports.
|
|
648
|
+
case exports.LoggerLevel.WARN:
|
|
634
649
|
return 2;
|
|
635
|
-
case exports.
|
|
650
|
+
case exports.LoggerLevel.ERROR:
|
|
636
651
|
return 3;
|
|
637
652
|
default:
|
|
638
653
|
return 1; // 默认INFO级别
|
|
@@ -646,19 +661,19 @@
|
|
|
646
661
|
if (typeof level === 'string') {
|
|
647
662
|
switch (level) {
|
|
648
663
|
case 'debug':
|
|
649
|
-
this.logLevel = exports.
|
|
664
|
+
this.logLevel = exports.LoggerLevel.DEBUG;
|
|
650
665
|
break;
|
|
651
666
|
case 'info':
|
|
652
|
-
this.logLevel = exports.
|
|
667
|
+
this.logLevel = exports.LoggerLevel.INFO;
|
|
653
668
|
break;
|
|
654
669
|
case 'warn':
|
|
655
|
-
this.logLevel = exports.
|
|
670
|
+
this.logLevel = exports.LoggerLevel.WARN;
|
|
656
671
|
break;
|
|
657
672
|
case 'error':
|
|
658
|
-
this.logLevel = exports.
|
|
673
|
+
this.logLevel = exports.LoggerLevel.ERROR;
|
|
659
674
|
break;
|
|
660
675
|
default:
|
|
661
|
-
this.logLevel = exports.
|
|
676
|
+
this.logLevel = exports.LoggerLevel.INFO;
|
|
662
677
|
}
|
|
663
678
|
}
|
|
664
679
|
else {
|
|
@@ -771,6 +786,14 @@
|
|
|
771
786
|
this.eventHandlers.delete(eventName);
|
|
772
787
|
}
|
|
773
788
|
}
|
|
789
|
+
/**
|
|
790
|
+
* 取消订阅事件 (off的别名)
|
|
791
|
+
* @param eventName 事件名称
|
|
792
|
+
* @param handler 事件处理器
|
|
793
|
+
*/
|
|
794
|
+
removeListener(eventName, handler) {
|
|
795
|
+
this.off(eventName, handler);
|
|
796
|
+
}
|
|
774
797
|
/**
|
|
775
798
|
* 订阅事件,但只触发一次
|
|
776
799
|
* @param eventName 事件名称
|
|
@@ -1058,19 +1081,19 @@
|
|
|
1058
1081
|
/**
|
|
1059
1082
|
* 获取结果数据
|
|
1060
1083
|
*/
|
|
1061
|
-
|
|
1084
|
+
getData() {
|
|
1062
1085
|
return this._data;
|
|
1063
1086
|
}
|
|
1064
1087
|
/**
|
|
1065
1088
|
* 获取错误对象
|
|
1066
1089
|
*/
|
|
1067
|
-
|
|
1090
|
+
getError() {
|
|
1068
1091
|
return this._error;
|
|
1069
1092
|
}
|
|
1070
1093
|
/**
|
|
1071
1094
|
* 获取元数据
|
|
1072
1095
|
*/
|
|
1073
|
-
|
|
1096
|
+
getMeta() {
|
|
1074
1097
|
return this._meta;
|
|
1075
1098
|
}
|
|
1076
1099
|
/**
|
|
@@ -1701,17 +1724,32 @@
|
|
|
1701
1724
|
outputData[pos + 3] = data[pos + 3]; // 保持透明度不变
|
|
1702
1725
|
}
|
|
1703
1726
|
}
|
|
1704
|
-
//
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1727
|
+
// 处理边缘像素(仅遍历四条边,而非全图 O(width×height) → O(width+height))
|
|
1728
|
+
// 上边 + 下边
|
|
1729
|
+
for (let x = 0; x < width; x++) {
|
|
1730
|
+
const topPos = x * 4;
|
|
1731
|
+
const bottomPos = ((height - 1) * width + x) * 4;
|
|
1732
|
+
outputData[topPos] = data[topPos];
|
|
1733
|
+
outputData[topPos + 1] = data[topPos + 1];
|
|
1734
|
+
outputData[topPos + 2] = data[topPos + 2];
|
|
1735
|
+
outputData[topPos + 3] = data[topPos + 3];
|
|
1736
|
+
outputData[bottomPos] = data[bottomPos];
|
|
1737
|
+
outputData[bottomPos + 1] = data[bottomPos + 1];
|
|
1738
|
+
outputData[bottomPos + 2] = data[bottomPos + 2];
|
|
1739
|
+
outputData[bottomPos + 3] = data[bottomPos + 3];
|
|
1740
|
+
}
|
|
1741
|
+
// 左边 + 右边(排除四角,它们已在上下一行处理)
|
|
1742
|
+
for (let y = 1; y < height - 1; y++) {
|
|
1743
|
+
const leftPos = y * width * 4;
|
|
1744
|
+
const rightPos = (y * width + width - 1) * 4;
|
|
1745
|
+
outputData[leftPos] = data[leftPos];
|
|
1746
|
+
outputData[leftPos + 1] = data[leftPos + 1];
|
|
1747
|
+
outputData[leftPos + 2] = data[leftPos + 2];
|
|
1748
|
+
outputData[leftPos + 3] = data[leftPos + 3];
|
|
1749
|
+
outputData[rightPos] = data[rightPos];
|
|
1750
|
+
outputData[rightPos + 1] = data[rightPos + 1];
|
|
1751
|
+
outputData[rightPos + 2] = data[rightPos + 2];
|
|
1752
|
+
outputData[rightPos + 3] = data[rightPos + 3];
|
|
1715
1753
|
}
|
|
1716
1754
|
// 创建新的ImageData对象
|
|
1717
1755
|
return new ImageData(outputData, width, height);
|
|
@@ -1724,11 +1762,10 @@
|
|
|
1724
1762
|
* @returns 处理后的图像数据
|
|
1725
1763
|
*/
|
|
1726
1764
|
static threshold(imageData, threshold = 128) {
|
|
1727
|
-
//
|
|
1728
|
-
const grayscaleImage = this.toGrayscale(
|
|
1765
|
+
// 先转换为灰度图(toGrayscale 内部已创建新 ImageData,无需外部拷贝)
|
|
1766
|
+
const grayscaleImage = this.toGrayscale(imageData);
|
|
1729
1767
|
const data = grayscaleImage.data;
|
|
1730
|
-
|
|
1731
|
-
for (let i = 0; i < length; i += 4) {
|
|
1768
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
1732
1769
|
// 二值化处理
|
|
1733
1770
|
const value = data[i] < threshold ? 0 : 255;
|
|
1734
1771
|
data[i] = data[i + 1] = data[i + 2] = value;
|
|
@@ -1742,8 +1779,8 @@
|
|
|
1742
1779
|
* @returns 二值化后的图像数据
|
|
1743
1780
|
*/
|
|
1744
1781
|
static toBinaryImage(imageData) {
|
|
1745
|
-
//
|
|
1746
|
-
const grayscaleImage = this.toGrayscale(
|
|
1782
|
+
// 先转换为灰度图(toGrayscale 内部已创建新 ImageData,无需外部拷贝)
|
|
1783
|
+
const grayscaleImage = this.toGrayscale(imageData);
|
|
1747
1784
|
// 使用OTSU算法自动确定阈值
|
|
1748
1785
|
const threshold = this.getOtsuThreshold(grayscaleImage);
|
|
1749
1786
|
return this.threshold(grayscaleImage, threshold);
|
|
@@ -1756,8 +1793,9 @@
|
|
|
1756
1793
|
*/
|
|
1757
1794
|
static getOtsuThreshold(imageData) {
|
|
1758
1795
|
const data = imageData.data;
|
|
1759
|
-
|
|
1760
|
-
|
|
1796
|
+
// 使用 Uint8Array 替代 Array<number>,避免 boxing 开销,提升直方图统计性能
|
|
1797
|
+
const histogram = new Uint32Array(256);
|
|
1798
|
+
// 统计灰度直方图(每4字节取R通道,即灰度值)
|
|
1761
1799
|
for (let i = 0; i < data.length; i += 4) {
|
|
1762
1800
|
histogram[data[i]]++;
|
|
1763
1801
|
}
|
|
@@ -3776,18 +3814,19 @@
|
|
|
3776
3814
|
try {
|
|
3777
3815
|
// 检测身份证
|
|
3778
3816
|
const detectionResult = await this.detector.processImage(image);
|
|
3779
|
-
|
|
3817
|
+
const detectionData = detectionResult.getData();
|
|
3818
|
+
if (!detectionResult.isSuccess() || !detectionData) {
|
|
3780
3819
|
throw new Error('未检测到身份证');
|
|
3781
3820
|
}
|
|
3782
3821
|
// 创建结果对象
|
|
3783
3822
|
const idCardInfo = {
|
|
3784
|
-
type:
|
|
3785
|
-
confidence:
|
|
3823
|
+
type: detectionData.type || exports.IDCardType.FRONT,
|
|
3824
|
+
confidence: detectionData.confidence
|
|
3786
3825
|
};
|
|
3787
3826
|
// 如果启用OCR且OCR处理器已初始化
|
|
3788
3827
|
if (this.options.detector?.enableOCR && this.ocrProcessor) {
|
|
3789
3828
|
// 裁剪并处理图像
|
|
3790
|
-
const processedImage =
|
|
3829
|
+
const processedImage = detectionData.image || this.convertToImageData(image);
|
|
3791
3830
|
// 识别文本信息
|
|
3792
3831
|
const ocrResult = await this.ocrProcessor.processIDCard(processedImage);
|
|
3793
3832
|
// 合并OCR结果
|
|
@@ -3969,14 +4008,15 @@
|
|
|
3969
4008
|
try {
|
|
3970
4009
|
// 调用检测器处理图像
|
|
3971
4010
|
const result = await this.detector.processImage(image);
|
|
3972
|
-
if (!result.isSuccess() || !result.
|
|
4011
|
+
if (!result.isSuccess() || !result.getData()) {
|
|
3973
4012
|
return { success: false, confidence: 0 };
|
|
3974
4013
|
}
|
|
4014
|
+
const data = result.getData();
|
|
3975
4015
|
return {
|
|
3976
4016
|
success: true,
|
|
3977
|
-
type:
|
|
3978
|
-
confidence:
|
|
3979
|
-
croppedImage:
|
|
4017
|
+
type: data.type,
|
|
4018
|
+
confidence: data.confidence || 0,
|
|
4019
|
+
croppedImage: data.image
|
|
3980
4020
|
};
|
|
3981
4021
|
}
|
|
3982
4022
|
catch (error) {
|
|
@@ -4851,13 +4891,13 @@
|
|
|
4851
4891
|
}
|
|
4852
4892
|
this.moduleManager = ModuleManager.getInstance();
|
|
4853
4893
|
// 注册模块
|
|
4854
|
-
if (options.enableIDCard
|
|
4894
|
+
if (options.enableIDCard === true) {
|
|
4855
4895
|
this.moduleManager.register(new IDCardModule(options.idCard));
|
|
4856
4896
|
}
|
|
4857
|
-
if (options.enableQRCode
|
|
4897
|
+
if (options.enableQRCode === true) {
|
|
4858
4898
|
this.moduleManager.register(new QRCodeModule(options.qrCode));
|
|
4859
4899
|
}
|
|
4860
|
-
if (options.enableFace
|
|
4900
|
+
if (options.enableFace === true) {
|
|
4861
4901
|
this.moduleManager.register(new FaceModule(options.face));
|
|
4862
4902
|
}
|
|
4863
4903
|
}
|
|
@@ -4940,6 +4980,7 @@
|
|
|
4940
4980
|
exports.InvalidArgumentError = InvalidArgumentError;
|
|
4941
4981
|
exports.LivenessDetectionError = LivenessDetectionError;
|
|
4942
4982
|
exports.LoadingStateManager = LoadingStateManager;
|
|
4983
|
+
exports.LogLevel = LogLevel;
|
|
4943
4984
|
exports.Logger = Logger;
|
|
4944
4985
|
exports.MemoryLogHandler = MemoryLogHandler;
|
|
4945
4986
|
exports.ModuleManager = ModuleManager;
|