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.
@@ -261,13 +261,17 @@
261
261
  /**
262
262
  * 日志级别枚举
263
263
  */
264
- exports.LogLevel = void 0;
265
- (function (LogLevel) {
266
- LogLevel["DEBUG"] = "debug";
267
- LogLevel["INFO"] = "info";
268
- LogLevel["WARN"] = "warn";
269
- LogLevel["ERROR"] = "error";
270
- })(exports.LogLevel || (exports.LogLevel = {}));
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.LogLevel.DEBUG:
288
+ case exports.LoggerLevel.DEBUG:
285
289
  console.debug(prefix, entry.message, entry.error || '');
286
290
  break;
287
- case exports.LogLevel.INFO:
291
+ case exports.LoggerLevel.INFO:
288
292
  console.info(prefix, entry.message, entry.error || '');
289
293
  break;
290
- case exports.LogLevel.WARN:
294
+ case exports.LoggerLevel.WARN:
291
295
  console.warn(prefix, entry.message, entry.error || '');
292
296
  break;
293
- case exports.LogLevel.ERROR:
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
- window.addEventListener('beforeunload', () => {
375
- this.flush();
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.LogLevel.INFO) {
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.LogLevel.INFO;
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.LogLevel.DEBUG, tag, message, error);
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.LogLevel.INFO, tag, message, error);
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.LogLevel.WARN, tag, message, error);
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.LogLevel.ERROR, tag, message, error);
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.LogLevel.DEBUG:
624
+ case exports.LoggerLevel.DEBUG:
610
625
  console.debug(`${prefix} ${entry.message}`, entry.error || '');
611
626
  break;
612
- case exports.LogLevel.INFO:
627
+ case exports.LoggerLevel.INFO:
613
628
  console.info(`${prefix} ${entry.message}`, entry.error || '');
614
629
  break;
615
- case exports.LogLevel.WARN:
630
+ case exports.LoggerLevel.WARN:
616
631
  console.warn(`${prefix} ${entry.message}`, entry.error || '');
617
632
  break;
618
- case exports.LogLevel.ERROR:
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.LogLevel.DEBUG:
644
+ case exports.LoggerLevel.DEBUG:
630
645
  return 0;
631
- case exports.LogLevel.INFO:
646
+ case exports.LoggerLevel.INFO:
632
647
  return 1;
633
- case exports.LogLevel.WARN:
648
+ case exports.LoggerLevel.WARN:
634
649
  return 2;
635
- case exports.LogLevel.ERROR:
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.LogLevel.DEBUG;
664
+ this.logLevel = exports.LoggerLevel.DEBUG;
650
665
  break;
651
666
  case 'info':
652
- this.logLevel = exports.LogLevel.INFO;
667
+ this.logLevel = exports.LoggerLevel.INFO;
653
668
  break;
654
669
  case 'warn':
655
- this.logLevel = exports.LogLevel.WARN;
670
+ this.logLevel = exports.LoggerLevel.WARN;
656
671
  break;
657
672
  case 'error':
658
- this.logLevel = exports.LogLevel.ERROR;
673
+ this.logLevel = exports.LoggerLevel.ERROR;
659
674
  break;
660
675
  default:
661
- this.logLevel = exports.LogLevel.INFO;
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
- get data() {
1084
+ getData() {
1062
1085
  return this._data;
1063
1086
  }
1064
1087
  /**
1065
1088
  * 获取错误对象
1066
1089
  */
1067
- get error() {
1090
+ getError() {
1068
1091
  return this._error;
1069
1092
  }
1070
1093
  /**
1071
1094
  * 获取元数据
1072
1095
  */
1073
- get meta() {
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
- for (let y = 0; y < height; y++) {
1706
- for (let x = 0; x < width; x++) {
1707
- if (y === 0 || y === height - 1 || x === 0 || x === width - 1) {
1708
- const pos = (y * width + x) * 4;
1709
- outputData[pos] = data[pos];
1710
- outputData[pos + 1] = data[pos + 1];
1711
- outputData[pos + 2] = data[pos + 2];
1712
- outputData[pos + 3] = data[pos + 3];
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(new ImageData(new Uint8ClampedArray(imageData.data), imageData.width, imageData.height));
1765
+ // 先转换为灰度图(toGrayscale 内部已创建新 ImageData,无需外部拷贝)
1766
+ const grayscaleImage = this.toGrayscale(imageData);
1729
1767
  const data = grayscaleImage.data;
1730
- const length = data.length;
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(new ImageData(new Uint8ClampedArray(imageData.data), imageData.width, imageData.height));
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
- const histogram = new Array(256).fill(0);
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
- if (!detectionResult.isSuccess() || !detectionResult.data) {
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: detectionResult.data.type || exports.IDCardType.FRONT,
3785
- confidence: detectionResult.data.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 = detectionResult.data.image || this.convertToImageData(image);
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.data) {
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: result.data.type,
3978
- confidence: result.data.confidence || 0,
3979
- croppedImage: result.data.image
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 !== false) {
4894
+ if (options.enableIDCard === true) {
4855
4895
  this.moduleManager.register(new IDCardModule(options.idCard));
4856
4896
  }
4857
- if (options.enableQRCode !== false) {
4897
+ if (options.enableQRCode === true) {
4858
4898
  this.moduleManager.register(new QRCodeModule(options.qrCode));
4859
4899
  }
4860
- if (options.enableFace !== false) {
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;