id-scanner-lib 1.3.3 → 1.6.2

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.
Files changed (80) hide show
  1. package/README.md +324 -410
  2. package/dist/id-scanner-lib.esm.js +4826 -0
  3. package/dist/id-scanner-lib.esm.js.map +1 -0
  4. package/dist/id-scanner-lib.js +4858 -0
  5. package/dist/id-scanner-lib.js.map +1 -0
  6. package/dist/types/browser-image-compression.d.ts +19 -0
  7. package/dist/types/tesseract.d.ts +280 -0
  8. package/package.json +89 -78
  9. package/src/core/base-module.ts +78 -0
  10. package/src/core/camera-manager.ts +813 -0
  11. package/src/core/config.ts +305 -0
  12. package/src/core/errors.ts +174 -0
  13. package/src/core/event-emitter.test.ts +42 -0
  14. package/src/core/event-emitter.ts +110 -0
  15. package/src/core/loading-state.test.ts +67 -0
  16. package/src/core/loading-state.ts +156 -0
  17. package/src/core/logger.test.ts +49 -0
  18. package/src/core/logger.ts +549 -0
  19. package/src/core/module-manager.ts +163 -0
  20. package/src/core/plugin-manager.ts +429 -0
  21. package/src/core/resource-manager.ts +762 -0
  22. package/src/core/result.ts +163 -0
  23. package/src/core/scanner-factory.ts +236 -0
  24. package/src/index.ts +117 -939
  25. package/src/interfaces/external-types.ts +200 -0
  26. package/src/interfaces/face-detection.ts +309 -0
  27. package/src/interfaces/scanner-module.ts +384 -0
  28. package/src/modules/face/face-detector.ts +988 -0
  29. package/src/modules/face/index.ts +208 -0
  30. package/src/modules/face/liveness-detector.ts +908 -0
  31. package/src/modules/face/types.ts +133 -0
  32. package/src/{id-recognition → modules/id-card}/anti-fake-detector.ts +274 -240
  33. package/src/modules/id-card/id-card-detector.ts +474 -0
  34. package/src/modules/id-card/index.ts +425 -0
  35. package/src/{id-recognition → modules/id-card}/ocr-processor.ts +149 -92
  36. package/src/modules/id-card/ocr-worker.ts +259 -0
  37. package/src/modules/id-card/types.ts +178 -0
  38. package/src/modules/qrcode/index.ts +175 -0
  39. package/src/modules/qrcode/qr-code-scanner.ts +231 -0
  40. package/src/modules/qrcode/types.ts +169 -0
  41. package/src/types/common.test.ts +99 -0
  42. package/src/types/common.ts +166 -0
  43. package/src/types/tesseract.d.ts +265 -22
  44. package/src/utils/camera.test.ts +30 -0
  45. package/src/utils/camera.ts +4 -1
  46. package/src/utils/error-handler.test.ts +137 -0
  47. package/src/utils/error-handler.ts +110 -0
  48. package/src/utils/image-processing.ts +68 -49
  49. package/src/utils/index.test.ts +186 -0
  50. package/src/utils/index.ts +429 -0
  51. package/src/utils/performance.ts +168 -131
  52. package/src/utils/resource-manager.ts +65 -146
  53. package/src/utils/retry.test.ts +142 -0
  54. package/src/utils/retry.ts +282 -0
  55. package/src/utils/types.ts +90 -2
  56. package/src/utils/utils.test.ts +171 -0
  57. package/src/utils/worker.ts +123 -84
  58. package/src/version.ts +11 -0
  59. package/tools/scaffold.js +543 -0
  60. package/dist/id-scanner-core.esm.js +0 -11349
  61. package/dist/id-scanner-core.js +0 -11361
  62. package/dist/id-scanner-core.min.js +0 -1
  63. package/dist/id-scanner-ocr.esm.js +0 -2319
  64. package/dist/id-scanner-ocr.js +0 -2328
  65. package/dist/id-scanner-ocr.min.js +0 -1
  66. package/dist/id-scanner-qr.esm.js +0 -1296
  67. package/dist/id-scanner-qr.js +0 -1305
  68. package/dist/id-scanner-qr.min.js +0 -1
  69. package/dist/id-scanner.js +0 -4561
  70. package/dist/id-scanner.min.js +0 -1
  71. package/src/core.ts +0 -138
  72. package/src/demo/demo.ts +0 -204
  73. package/src/id-recognition/data-extractor.ts +0 -262
  74. package/src/id-recognition/id-detector.ts +0 -510
  75. package/src/id-recognition/ocr-worker.ts +0 -156
  76. package/src/index-umd.ts +0 -477
  77. package/src/ocr-module.ts +0 -187
  78. package/src/qr-module.ts +0 -179
  79. package/src/scanner/barcode-scanner.ts +0 -251
  80. package/src/scanner/qr-scanner.ts +0 -167
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import imageCompression from "browser-image-compression"
9
+ import { Point, Rect, ImageProcessingOptions } from './types';
9
10
 
10
11
  /**
11
12
  * 图像处理器配置选项
@@ -481,68 +482,86 @@ export class ImageProcessor {
481
482
  }
482
483
 
483
484
  /**
484
- * 调整图像大小
485
- *
486
- * @param imageData 原始图像数据
485
+ * 将图像调整到指定大小
486
+ * @param image 输入图像
487
487
  * @param maxWidth 最大宽度
488
488
  * @param maxHeight 最大高度
489
- * @param maintainAspectRatio 是否保持宽高比
490
- * @returns ImageData 调整大小后的图像数据
489
+ * @param keepAspectRatio 是否保持宽高比
490
+ * @returns 调整后的图像
491
491
  */
492
- static resizeImage(
493
- imageData: ImageData,
492
+ public static resizeImage(
493
+ image: ImageData | HTMLImageElement | HTMLCanvasElement,
494
494
  maxWidth: number,
495
495
  maxHeight: number,
496
- maintainAspectRatio: boolean = true
496
+ keepAspectRatio: boolean = true
497
497
  ): ImageData {
498
- const { width, height } = imageData
499
-
500
- // 如果图像已经小于指定大小,则不需要调整
501
- if (width <= maxWidth && height <= maxHeight) {
502
- return imageData
498
+ // 创建canvas元素
499
+ const canvas = document.createElement('canvas');
500
+ const ctx = canvas.getContext('2d');
501
+
502
+ if (!ctx) {
503
+ throw new Error('无法创建Canvas上下文');
503
504
  }
504
-
505
- let newWidth = maxWidth
506
- let newHeight = maxHeight
507
-
508
- // 计算新的尺寸,保持宽高比
509
- if (maintainAspectRatio) {
510
- const ratio = Math.min(maxWidth / width, maxHeight / height)
511
- newWidth = Math.floor(width * ratio)
512
- newHeight = Math.floor(height * ratio)
505
+
506
+ // 获取图像尺寸
507
+ let width: number;
508
+ let height: number;
509
+
510
+ if (image instanceof ImageData) {
511
+ width = image.width;
512
+ height = image.height;
513
+ } else {
514
+ width = image.width;
515
+ height = image.height;
513
516
  }
514
-
515
- // 创建用于调整大小的Canvas
516
- const canvas = document.createElement("canvas")
517
- canvas.width = newWidth
518
- canvas.height = newHeight
519
-
520
- const ctx = canvas.getContext("2d")
521
- if (!ctx) {
522
- throw new Error("无法创建2D上下文")
517
+
518
+ // 计算调整后的尺寸
519
+ let newWidth = width;
520
+ let newHeight = height;
521
+
522
+ if (keepAspectRatio) {
523
+ if (width > height) {
524
+ if (width > maxWidth) {
525
+ newHeight = Math.round(height * (maxWidth / width));
526
+ newWidth = maxWidth;
527
+ }
528
+ } else {
529
+ if (height > maxHeight) {
530
+ newWidth = Math.round(width * (maxHeight / height));
531
+ newHeight = maxHeight;
532
+ }
533
+ }
534
+ } else {
535
+ newWidth = Math.min(width, maxWidth);
536
+ newHeight = Math.min(height, maxHeight);
523
537
  }
524
-
525
- // 创建临时Canvas绘制原始ImageData
526
- const tempCanvas = document.createElement("canvas")
527
- tempCanvas.width = width
528
- tempCanvas.height = height
529
-
530
- const tempCtx = tempCanvas.getContext("2d")
538
+
539
+ // 设置canvas尺寸
540
+ canvas.width = newWidth;
541
+ canvas.height = newHeight;
542
+
543
+ // 绘制调整后的图像
544
+ if (image instanceof ImageData) {
545
+ // 创建临时canvas存储ImageData
546
+ const tempCanvas = document.createElement('canvas');
547
+ const tempCtx = tempCanvas.getContext('2d');
548
+
531
549
  if (!tempCtx) {
532
- throw new Error("无法创建临时2D上下文")
550
+ throw new Error('无法创建临时Canvas上下文');
533
551
  }
534
552
 
535
- tempCtx.putImageData(imageData, 0, 0)
536
-
537
- // 使用缩放平滑算法
538
- ctx.imageSmoothingEnabled = true
539
- ctx.imageSmoothingQuality = "high"
540
-
541
- // 绘制调整大小的图像
542
- ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, newWidth, newHeight)
553
+ tempCanvas.width = image.width;
554
+ tempCanvas.height = image.height;
555
+ tempCtx.putImageData(image, 0, 0);
556
+
557
+ // 绘制调整后的图像
558
+ ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, newWidth, newHeight);
559
+ } else {
560
+ ctx.drawImage(image, 0, 0, width, height, 0, 0, newWidth, newHeight);
561
+ }
543
562
 
544
- // 获取新的ImageData
545
- return ctx.getImageData(0, 0, newWidth, newHeight)
563
+ // 返回调整后的ImageData
564
+ return ctx.getImageData(0, 0, newWidth, newHeight);
546
565
  }
547
566
 
548
567
  /**
@@ -0,0 +1,186 @@
1
+ /**
2
+ * @file 通用工具测试
3
+ * @description 测试通用工具函数
4
+ */
5
+
6
+ import {
7
+ delay,
8
+ throttle,
9
+ debounce,
10
+ formatBytes,
11
+ generateUUID,
12
+ chunk,
13
+ safeParseJSON,
14
+ clamp,
15
+ isValidUrl,
16
+ browserCapabilities
17
+ } from './index';
18
+
19
+ describe('delay', () => {
20
+ it('should delay for specified milliseconds', async () => {
21
+ const start = Date.now();
22
+ await delay(50);
23
+ const elapsed = Date.now() - start;
24
+
25
+ expect(elapsed).toBeGreaterThanOrEqual(45);
26
+ });
27
+ });
28
+
29
+ describe('throttle', () => {
30
+ beforeEach(() => {
31
+ jest.useFakeTimers();
32
+ });
33
+
34
+ afterEach(() => {
35
+ jest.useRealTimers();
36
+ });
37
+
38
+ it('should throttle function calls', () => {
39
+ let count = 0;
40
+ const fn = throttle(() => count++, 100);
41
+
42
+ fn();
43
+ fn();
44
+ fn();
45
+
46
+ expect(count).toBe(1);
47
+
48
+ jest.advanceTimersByTime(100);
49
+
50
+ fn();
51
+ expect(count).toBe(2);
52
+ });
53
+ });
54
+
55
+ describe('debounce', () => {
56
+ beforeEach(() => {
57
+ jest.useFakeTimers();
58
+ });
59
+
60
+ afterEach(() => {
61
+ jest.useRealTimers();
62
+ });
63
+
64
+ it('should debounce function calls', () => {
65
+ let count = 0;
66
+ const fn = debounce(() => count++, 100);
67
+
68
+ fn();
69
+ fn();
70
+ fn();
71
+
72
+ expect(count).toBe(0);
73
+
74
+ jest.advanceTimersByTime(100);
75
+
76
+ expect(count).toBe(1);
77
+ });
78
+
79
+ it('should execute immediately when immediate is true', () => {
80
+ let count = 0;
81
+ const fn = debounce(() => count++, 100, true);
82
+
83
+ fn();
84
+ // Immediate should execute once
85
+ expect(count).toBe(1);
86
+
87
+ // Advance time and check if it runs again
88
+ jest.advanceTimersByTime(100);
89
+ // Depending on implementation, this may vary
90
+ expect(count).toBeGreaterThanOrEqual(1);
91
+ });
92
+ });
93
+
94
+ describe('formatBytes', () => {
95
+ it('should format bytes correctly', () => {
96
+ expect(formatBytes(0)).toBe('0 Bytes');
97
+ expect(formatBytes(1024)).toBe('1 KB');
98
+ expect(formatBytes(1024 * 1024)).toBe('1 MB');
99
+ expect(formatBytes(1024 * 1024 * 1024)).toBe('1 GB');
100
+ });
101
+
102
+ it('should handle decimals', () => {
103
+ expect(formatBytes(1536, 2)).toBe('1.5 KB');
104
+ });
105
+ });
106
+
107
+ describe('generateUUID', () => {
108
+ it('should generate valid UUID', () => {
109
+ const uuid = generateUUID();
110
+
111
+ expect(uuid).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/);
112
+ });
113
+
114
+ it('should generate unique UUIDs', () => {
115
+ const uuids = new Set<string>();
116
+ for (let i = 0; i < 100; i++) {
117
+ uuids.add(generateUUID());
118
+ }
119
+
120
+ expect(uuids.size).toBe(100);
121
+ });
122
+ });
123
+
124
+ describe('chunk', () => {
125
+ it('should split array into chunks', () => {
126
+ const arr = [1, 2, 3, 4, 5, 6, 7];
127
+ const chunks = chunk(arr, 3);
128
+
129
+ expect(chunks).toEqual([[1, 2, 3], [4, 5, 6], [7]]);
130
+ });
131
+
132
+ it('should throw error for invalid chunk size', () => {
133
+ expect(() => chunk([1, 2, 3], 0)).toThrow();
134
+ });
135
+ });
136
+
137
+ describe('safeParseJSON', () => {
138
+ it('should parse valid JSON', () => {
139
+ const result = safeParseJSON('{"a": 1}', { default: true });
140
+ expect(result).toEqual({ a: 1 });
141
+ });
142
+
143
+ it('should return fallback for invalid JSON', () => {
144
+ const result = safeParseJSON<boolean>('invalid', true);
145
+ expect(result).toBe(true);
146
+ });
147
+ });
148
+
149
+ describe('clamp', () => {
150
+ it('should clamp value within range', () => {
151
+ expect(clamp(5, 0, 10)).toBe(5);
152
+ expect(clamp(-5, 0, 10)).toBe(0);
153
+ expect(clamp(15, 0, 10)).toBe(10);
154
+ });
155
+ });
156
+
157
+ describe('isValidUrl', () => {
158
+ it('should validate URLs', () => {
159
+ expect(isValidUrl('https://example.com')).toBe(true);
160
+ expect(isValidUrl('http://test.com/path')).toBe(true);
161
+ expect(isValidUrl('invalid')).toBe(false);
162
+ expect(isValidUrl('not a url')).toBe(false);
163
+ });
164
+ });
165
+
166
+ describe('browserCapabilities', () => {
167
+ it('should check camera support', () => {
168
+ expect(typeof browserCapabilities.hasCamera).toBe('function');
169
+ });
170
+
171
+ it('should check WebAssembly support', () => {
172
+ expect(typeof browserCapabilities.hasWasm).toBe('function');
173
+ });
174
+
175
+ it('should check WebWorker support', () => {
176
+ expect(typeof browserCapabilities.hasWebWorker).toBe('function');
177
+ });
178
+
179
+ it('should check WebGL support', () => {
180
+ expect(typeof browserCapabilities.hasWebGL).toBe('function');
181
+ });
182
+
183
+ it('should use supports method', () => {
184
+ expect(typeof browserCapabilities.supports).toBe('function');
185
+ });
186
+ });