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.
@@ -259,13 +259,17 @@ class ConfigManager {
259
259
  /**
260
260
  * 日志级别枚举
261
261
  */
262
- var LogLevel;
263
- (function (LogLevel) {
264
- LogLevel["DEBUG"] = "debug";
265
- LogLevel["INFO"] = "info";
266
- LogLevel["WARN"] = "warn";
267
- LogLevel["ERROR"] = "error";
268
- })(LogLevel || (LogLevel = {}));
262
+ var LoggerLevel;
263
+ (function (LoggerLevel) {
264
+ LoggerLevel["DEBUG"] = "debug";
265
+ LoggerLevel["INFO"] = "info";
266
+ LoggerLevel["WARN"] = "warn";
267
+ LoggerLevel["ERROR"] = "error";
268
+ })(LoggerLevel || (LoggerLevel = {}));
269
+ /**
270
+ * @deprecated 使用 LoggerLevel 代替
271
+ */
272
+ const LogLevel = LoggerLevel;
269
273
  /**
270
274
  * 控制台日志处理器
271
275
  * 将日志输出到浏览器控制台
@@ -279,16 +283,16 @@ class ConsoleLogHandler {
279
283
  const timestamp = new Date(entry.timestamp).toISOString();
280
284
  const prefix = `[${timestamp}] [${entry.level.toUpperCase()}] [${entry.tag}]`;
281
285
  switch (entry.level) {
282
- case LogLevel.DEBUG:
286
+ case LoggerLevel.DEBUG:
283
287
  console.debug(prefix, entry.message, entry.error || '');
284
288
  break;
285
- case LogLevel.INFO:
289
+ case LoggerLevel.INFO:
286
290
  console.info(prefix, entry.message, entry.error || '');
287
291
  break;
288
- case LogLevel.WARN:
292
+ case LoggerLevel.WARN:
289
293
  console.warn(prefix, entry.message, entry.error || '');
290
294
  break;
291
- case LogLevel.ERROR:
295
+ case LoggerLevel.ERROR:
292
296
  console.error(prefix, entry.message, entry.error || '');
293
297
  break;
294
298
  // 输出什么也不做
@@ -366,12 +370,15 @@ class RemoteLogHandler {
366
370
  this.endpoint = endpoint;
367
371
  this.maxQueueSize = maxQueueSize;
368
372
  this.flushInterval = flushInterval;
373
+ this.isBrowser = typeof window !== 'undefined' && typeof window.addEventListener === 'function';
369
374
  // 设置定时发送
370
375
  this.startTimer();
371
376
  // 页面卸载前尝试发送剩余日志
372
- window.addEventListener('beforeunload', () => {
373
- this.flush();
374
- });
377
+ if (this.isBrowser) {
378
+ window.addEventListener('beforeunload', () => {
379
+ this.flush();
380
+ });
381
+ }
375
382
  }
376
383
  /**
377
384
  * 处理日志条目
@@ -379,7 +386,7 @@ class RemoteLogHandler {
379
386
  */
380
387
  handle(entry) {
381
388
  // 只处理INFO以上级别的日志
382
- if (entry.level >= LogLevel.INFO) {
389
+ if (entry.level >= LoggerLevel.INFO) {
383
390
  this.queue.push(entry);
384
391
  // 如果队列满了,立即发送
385
392
  if (this.queue.length >= this.maxQueueSize) {
@@ -439,6 +446,8 @@ class RemoteLogHandler {
439
446
  * 开始定时发送
440
447
  */
441
448
  startTimer() {
449
+ if (!this.isBrowser)
450
+ return;
442
451
  if (this.timerId !== null)
443
452
  return;
444
453
  this.timerId = window.setInterval(() => {
@@ -469,7 +478,7 @@ class Logger {
469
478
  /** 默认标签 */
470
479
  this.defaultTag = 'IDScanner';
471
480
  /** 日志级别 */
472
- this.logLevel = LogLevel.INFO;
481
+ this.logLevel = LoggerLevel.INFO;
473
482
  this.config = ConfigManager.getInstance();
474
483
  // 默认添加控制台处理器
475
484
  this.addHandler(new ConsoleLogHandler());
@@ -487,6 +496,12 @@ class Logger {
487
496
  }
488
497
  return Logger.instance;
489
498
  }
499
+ /**
500
+ * 重置单例实例(主要用于测试)
501
+ */
502
+ static resetInstance() {
503
+ Logger.instance = undefined;
504
+ }
490
505
  /**
491
506
  * 添加日志处理器
492
507
  * @param handler 日志处理器
@@ -524,7 +539,7 @@ class Logger {
524
539
  * @param error 错误
525
540
  */
526
541
  debug(tag, message, error) {
527
- this.log(LogLevel.DEBUG, tag, message, error);
542
+ this.log(LoggerLevel.DEBUG, tag, message, error);
528
543
  }
529
544
  /**
530
545
  * 记录信息级别日志
@@ -533,7 +548,7 @@ class Logger {
533
548
  * @param error 错误
534
549
  */
535
550
  info(tag, message, error) {
536
- this.log(LogLevel.INFO, tag, message, error);
551
+ this.log(LoggerLevel.INFO, tag, message, error);
537
552
  }
538
553
  /**
539
554
  * 记录警告级别日志
@@ -542,7 +557,7 @@ class Logger {
542
557
  * @param error 错误
543
558
  */
544
559
  warn(tag, message, error) {
545
- this.log(LogLevel.WARN, tag, message, error);
560
+ this.log(LoggerLevel.WARN, tag, message, error);
546
561
  }
547
562
  /**
548
563
  * 记录错误级别日志
@@ -551,7 +566,7 @@ class Logger {
551
566
  * @param error 错误
552
567
  */
553
568
  error(tag, message, error) {
554
- this.log(LogLevel.ERROR, tag, message, error);
569
+ this.log(LoggerLevel.ERROR, tag, message, error);
555
570
  }
556
571
  /**
557
572
  * 创建标记了特定标签的日志记录器
@@ -604,16 +619,16 @@ class Logger {
604
619
  const timestamp = new Date(entry.timestamp).toISOString();
605
620
  const prefix = `[${timestamp}] [${entry.level.toUpperCase()}] [${entry.tag}]`;
606
621
  switch (entry.level) {
607
- case LogLevel.DEBUG:
622
+ case LoggerLevel.DEBUG:
608
623
  console.debug(`${prefix} ${entry.message}`, entry.error || '');
609
624
  break;
610
- case LogLevel.INFO:
625
+ case LoggerLevel.INFO:
611
626
  console.info(`${prefix} ${entry.message}`, entry.error || '');
612
627
  break;
613
- case LogLevel.WARN:
628
+ case LoggerLevel.WARN:
614
629
  console.warn(`${prefix} ${entry.message}`, entry.error || '');
615
630
  break;
616
- case LogLevel.ERROR:
631
+ case LoggerLevel.ERROR:
617
632
  console.error(`${prefix} ${entry.message}`, entry.error || '');
618
633
  break;
619
634
  }
@@ -624,13 +639,13 @@ class Logger {
624
639
  */
625
640
  getLevelValue(level) {
626
641
  switch (level) {
627
- case LogLevel.DEBUG:
642
+ case LoggerLevel.DEBUG:
628
643
  return 0;
629
- case LogLevel.INFO:
644
+ case LoggerLevel.INFO:
630
645
  return 1;
631
- case LogLevel.WARN:
646
+ case LoggerLevel.WARN:
632
647
  return 2;
633
- case LogLevel.ERROR:
648
+ case LoggerLevel.ERROR:
634
649
  return 3;
635
650
  default:
636
651
  return 1; // 默认INFO级别
@@ -644,19 +659,19 @@ class Logger {
644
659
  if (typeof level === 'string') {
645
660
  switch (level) {
646
661
  case 'debug':
647
- this.logLevel = LogLevel.DEBUG;
662
+ this.logLevel = LoggerLevel.DEBUG;
648
663
  break;
649
664
  case 'info':
650
- this.logLevel = LogLevel.INFO;
665
+ this.logLevel = LoggerLevel.INFO;
651
666
  break;
652
667
  case 'warn':
653
- this.logLevel = LogLevel.WARN;
668
+ this.logLevel = LoggerLevel.WARN;
654
669
  break;
655
670
  case 'error':
656
- this.logLevel = LogLevel.ERROR;
671
+ this.logLevel = LoggerLevel.ERROR;
657
672
  break;
658
673
  default:
659
- this.logLevel = LogLevel.INFO;
674
+ this.logLevel = LoggerLevel.INFO;
660
675
  }
661
676
  }
662
677
  else {
@@ -769,6 +784,14 @@ class EventEmitter {
769
784
  this.eventHandlers.delete(eventName);
770
785
  }
771
786
  }
787
+ /**
788
+ * 取消订阅事件 (off的别名)
789
+ * @param eventName 事件名称
790
+ * @param handler 事件处理器
791
+ */
792
+ removeListener(eventName, handler) {
793
+ this.off(eventName, handler);
794
+ }
772
795
  /**
773
796
  * 订阅事件,但只触发一次
774
797
  * @param eventName 事件名称
@@ -1056,19 +1079,19 @@ class Result {
1056
1079
  /**
1057
1080
  * 获取结果数据
1058
1081
  */
1059
- get data() {
1082
+ getData() {
1060
1083
  return this._data;
1061
1084
  }
1062
1085
  /**
1063
1086
  * 获取错误对象
1064
1087
  */
1065
- get error() {
1088
+ getError() {
1066
1089
  return this._error;
1067
1090
  }
1068
1091
  /**
1069
1092
  * 获取元数据
1070
1093
  */
1071
- get meta() {
1094
+ getMeta() {
1072
1095
  return this._meta;
1073
1096
  }
1074
1097
  /**
@@ -1699,17 +1722,32 @@ class ImageProcessor {
1699
1722
  outputData[pos + 3] = data[pos + 3]; // 保持透明度不变
1700
1723
  }
1701
1724
  }
1702
- // 处理边缘像素
1703
- for (let y = 0; y < height; y++) {
1704
- for (let x = 0; x < width; x++) {
1705
- if (y === 0 || y === height - 1 || x === 0 || x === width - 1) {
1706
- const pos = (y * width + x) * 4;
1707
- outputData[pos] = data[pos];
1708
- outputData[pos + 1] = data[pos + 1];
1709
- outputData[pos + 2] = data[pos + 2];
1710
- outputData[pos + 3] = data[pos + 3];
1711
- }
1712
- }
1725
+ // 处理边缘像素(仅遍历四条边,而非全图 O(width×height) → O(width+height))
1726
+ // 上边 + 下边
1727
+ for (let x = 0; x < width; x++) {
1728
+ const topPos = x * 4;
1729
+ const bottomPos = ((height - 1) * width + x) * 4;
1730
+ outputData[topPos] = data[topPos];
1731
+ outputData[topPos + 1] = data[topPos + 1];
1732
+ outputData[topPos + 2] = data[topPos + 2];
1733
+ outputData[topPos + 3] = data[topPos + 3];
1734
+ outputData[bottomPos] = data[bottomPos];
1735
+ outputData[bottomPos + 1] = data[bottomPos + 1];
1736
+ outputData[bottomPos + 2] = data[bottomPos + 2];
1737
+ outputData[bottomPos + 3] = data[bottomPos + 3];
1738
+ }
1739
+ // 左边 + 右边(排除四角,它们已在上下一行处理)
1740
+ for (let y = 1; y < height - 1; y++) {
1741
+ const leftPos = y * width * 4;
1742
+ const rightPos = (y * width + width - 1) * 4;
1743
+ outputData[leftPos] = data[leftPos];
1744
+ outputData[leftPos + 1] = data[leftPos + 1];
1745
+ outputData[leftPos + 2] = data[leftPos + 2];
1746
+ outputData[leftPos + 3] = data[leftPos + 3];
1747
+ outputData[rightPos] = data[rightPos];
1748
+ outputData[rightPos + 1] = data[rightPos + 1];
1749
+ outputData[rightPos + 2] = data[rightPos + 2];
1750
+ outputData[rightPos + 3] = data[rightPos + 3];
1713
1751
  }
1714
1752
  // 创建新的ImageData对象
1715
1753
  return new ImageData(outputData, width, height);
@@ -1722,11 +1760,10 @@ class ImageProcessor {
1722
1760
  * @returns 处理后的图像数据
1723
1761
  */
1724
1762
  static threshold(imageData, threshold = 128) {
1725
- // 先转换为灰度图
1726
- const grayscaleImage = this.toGrayscale(new ImageData(new Uint8ClampedArray(imageData.data), imageData.width, imageData.height));
1763
+ // 先转换为灰度图(toGrayscale 内部已创建新 ImageData,无需外部拷贝)
1764
+ const grayscaleImage = this.toGrayscale(imageData);
1727
1765
  const data = grayscaleImage.data;
1728
- const length = data.length;
1729
- for (let i = 0; i < length; i += 4) {
1766
+ for (let i = 0; i < data.length; i += 4) {
1730
1767
  // 二值化处理
1731
1768
  const value = data[i] < threshold ? 0 : 255;
1732
1769
  data[i] = data[i + 1] = data[i + 2] = value;
@@ -1740,8 +1777,8 @@ class ImageProcessor {
1740
1777
  * @returns 二值化后的图像数据
1741
1778
  */
1742
1779
  static toBinaryImage(imageData) {
1743
- // 先转换为灰度图
1744
- const grayscaleImage = this.toGrayscale(new ImageData(new Uint8ClampedArray(imageData.data), imageData.width, imageData.height));
1780
+ // 先转换为灰度图(toGrayscale 内部已创建新 ImageData,无需外部拷贝)
1781
+ const grayscaleImage = this.toGrayscale(imageData);
1745
1782
  // 使用OTSU算法自动确定阈值
1746
1783
  const threshold = this.getOtsuThreshold(grayscaleImage);
1747
1784
  return this.threshold(grayscaleImage, threshold);
@@ -1754,8 +1791,9 @@ class ImageProcessor {
1754
1791
  */
1755
1792
  static getOtsuThreshold(imageData) {
1756
1793
  const data = imageData.data;
1757
- const histogram = new Array(256).fill(0);
1758
- // 统计灰度直方图
1794
+ // 使用 Uint8Array 替代 Array<number>,避免 boxing 开销,提升直方图统计性能
1795
+ const histogram = new Uint32Array(256);
1796
+ // 统计灰度直方图(每4字节取R通道,即灰度值)
1759
1797
  for (let i = 0; i < data.length; i += 4) {
1760
1798
  histogram[data[i]]++;
1761
1799
  }
@@ -3774,18 +3812,19 @@ class IDCardModule extends BaseModule {
3774
3812
  try {
3775
3813
  // 检测身份证
3776
3814
  const detectionResult = await this.detector.processImage(image);
3777
- if (!detectionResult.isSuccess() || !detectionResult.data) {
3815
+ const detectionData = detectionResult.getData();
3816
+ if (!detectionResult.isSuccess() || !detectionData) {
3778
3817
  throw new Error('未检测到身份证');
3779
3818
  }
3780
3819
  // 创建结果对象
3781
3820
  const idCardInfo = {
3782
- type: detectionResult.data.type || IDCardType.FRONT,
3783
- confidence: detectionResult.data.confidence
3821
+ type: detectionData.type || IDCardType.FRONT,
3822
+ confidence: detectionData.confidence
3784
3823
  };
3785
3824
  // 如果启用OCR且OCR处理器已初始化
3786
3825
  if (this.options.detector?.enableOCR && this.ocrProcessor) {
3787
3826
  // 裁剪并处理图像
3788
- const processedImage = detectionResult.data.image || this.convertToImageData(image);
3827
+ const processedImage = detectionData.image || this.convertToImageData(image);
3789
3828
  // 识别文本信息
3790
3829
  const ocrResult = await this.ocrProcessor.processIDCard(processedImage);
3791
3830
  // 合并OCR结果
@@ -3967,14 +4006,15 @@ class IDCardModule extends BaseModule {
3967
4006
  try {
3968
4007
  // 调用检测器处理图像
3969
4008
  const result = await this.detector.processImage(image);
3970
- if (!result.isSuccess() || !result.data) {
4009
+ if (!result.isSuccess() || !result.getData()) {
3971
4010
  return { success: false, confidence: 0 };
3972
4011
  }
4012
+ const data = result.getData();
3973
4013
  return {
3974
4014
  success: true,
3975
- type: result.data.type,
3976
- confidence: result.data.confidence || 0,
3977
- croppedImage: result.data.image
4015
+ type: data.type,
4016
+ confidence: data.confidence || 0,
4017
+ croppedImage: data.image
3978
4018
  };
3979
4019
  }
3980
4020
  catch (error) {
@@ -4849,13 +4889,13 @@ class IDScanner {
4849
4889
  }
4850
4890
  this.moduleManager = ModuleManager.getInstance();
4851
4891
  // 注册模块
4852
- if (options.enableIDCard !== false) {
4892
+ if (options.enableIDCard === true) {
4853
4893
  this.moduleManager.register(new IDCardModule(options.idCard));
4854
4894
  }
4855
- if (options.enableQRCode !== false) {
4895
+ if (options.enableQRCode === true) {
4856
4896
  this.moduleManager.register(new QRCodeModule(options.qrCode));
4857
4897
  }
4858
- if (options.enableFace !== false) {
4898
+ if (options.enableFace === true) {
4859
4899
  this.moduleManager.register(new FaceModule(options.face));
4860
4900
  }
4861
4901
  }
@@ -4923,5 +4963,5 @@ IDScanner.VERSION = VERSION;
4923
4963
  /** 构建日期 */
4924
4964
  IDScanner.BUILD_DATE = BUILD_DATE;
4925
4965
 
4926
- export { BarcodeFormat, CameraAccessError, ConsoleLogHandler, DEFAULT_FORMATS, DeviceError, FaceComparisonError, FaceDetectionError, FaceModule, IDCardDetectionError, IDCardModule, IDCardType, IDScanner, IDScannerError, InitializationError, InvalidArgumentError, LivenessDetectionError, LoadingState, LoadingStateManager, LogLevel, Logger, MemoryLogHandler, ModuleManager, NotSupportedError, OCRProcessingError, QRCodeModule, QRScanError, RemoteLogHandler, ResourceLoadError, TaggedLogger, createLoadingStateManager, IDScanner as default };
4966
+ export { BarcodeFormat, CameraAccessError, ConsoleLogHandler, DEFAULT_FORMATS, DeviceError, FaceComparisonError, FaceDetectionError, FaceModule, IDCardDetectionError, IDCardModule, IDCardType, IDScanner, IDScannerError, InitializationError, InvalidArgumentError, LivenessDetectionError, LoadingState, LoadingStateManager, LogLevel, Logger, LoggerLevel, MemoryLogHandler, ModuleManager, NotSupportedError, OCRProcessingError, QRCodeModule, QRScanError, RemoteLogHandler, ResourceLoadError, TaggedLogger, createLoadingStateManager, IDScanner as default };
4927
4967
  //# sourceMappingURL=id-scanner-lib.esm.js.map