id-scanner-lib 1.3.3 → 1.5.0

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 (101) hide show
  1. package/README.md +55 -460
  2. package/dist/id-scanner-lib.esm.js +4641 -0
  3. package/dist/id-scanner-lib.esm.js.map +1 -0
  4. package/dist/id-scanner-lib.js +14755 -0
  5. package/dist/id-scanner-lib.js.map +1 -0
  6. package/dist/types/core/base-module.d.ts +44 -0
  7. package/dist/types/core/camera-manager.d.ts +258 -0
  8. package/dist/types/core/config.d.ts +88 -0
  9. package/dist/types/core/errors.d.ts +111 -0
  10. package/dist/types/core/event-emitter.d.ts +55 -0
  11. package/dist/types/core/logger.d.ts +277 -0
  12. package/dist/types/core/module-manager.d.ts +78 -0
  13. package/dist/types/core/plugin-manager.d.ts +158 -0
  14. package/dist/types/core/resource-manager.d.ts +246 -0
  15. package/dist/types/core/result.d.ts +83 -0
  16. package/dist/types/core/scanner-factory.d.ts +93 -0
  17. package/dist/types/index.bundle.d.ts +1303 -0
  18. package/dist/types/index.d.ts +86 -0
  19. package/dist/types/interfaces/external-types.d.ts +174 -0
  20. package/dist/types/interfaces/face-detection.d.ts +293 -0
  21. package/dist/types/interfaces/scanner-module.d.ts +280 -0
  22. package/dist/types/modules/face/face-detector.d.ts +170 -0
  23. package/dist/types/modules/face/index.d.ts +56 -0
  24. package/dist/types/modules/face/liveness-detector.d.ts +177 -0
  25. package/dist/types/modules/face/types.d.ts +136 -0
  26. package/dist/types/modules/id-card/anti-fake-detector.d.ts +170 -0
  27. package/dist/types/modules/id-card/id-card-detector.d.ts +131 -0
  28. package/dist/types/modules/id-card/index.d.ts +89 -0
  29. package/dist/types/modules/id-card/ocr-processor.d.ts +110 -0
  30. package/dist/types/modules/id-card/ocr-worker.d.ts +31 -0
  31. package/dist/types/modules/id-card/types.d.ts +181 -0
  32. package/dist/types/modules/qrcode/index.d.ts +51 -0
  33. package/dist/types/modules/qrcode/qr-code-scanner.d.ts +64 -0
  34. package/dist/types/modules/qrcode/types.d.ts +67 -0
  35. package/dist/types/utils/camera.d.ts +81 -0
  36. package/dist/types/utils/image-processing.d.ts +176 -0
  37. package/dist/types/utils/index.d.ts +175 -0
  38. package/dist/types/utils/performance.d.ts +81 -0
  39. package/dist/types/utils/resource-manager.d.ts +53 -0
  40. package/dist/types/utils/types.d.ts +166 -0
  41. package/dist/types/utils/worker.d.ts +52 -0
  42. package/dist/types/version.d.ts +7 -0
  43. package/package.json +76 -75
  44. package/src/core/base-module.ts +78 -0
  45. package/src/core/camera-manager.ts +798 -0
  46. package/src/core/config.ts +268 -0
  47. package/src/core/errors.ts +174 -0
  48. package/src/core/event-emitter.ts +110 -0
  49. package/src/core/logger.ts +549 -0
  50. package/src/core/module-manager.ts +165 -0
  51. package/src/core/plugin-manager.ts +429 -0
  52. package/src/core/resource-manager.ts +762 -0
  53. package/src/core/result.ts +163 -0
  54. package/src/core/scanner-factory.ts +237 -0
  55. package/src/index.ts +113 -936
  56. package/src/interfaces/external-types.ts +200 -0
  57. package/src/interfaces/face-detection.ts +309 -0
  58. package/src/interfaces/scanner-module.ts +384 -0
  59. package/src/modules/face/face-detector.ts +931 -0
  60. package/src/modules/face/index.ts +208 -0
  61. package/src/modules/face/liveness-detector.ts +908 -0
  62. package/src/modules/face/types.ts +133 -0
  63. package/src/{id-recognition → modules/id-card}/anti-fake-detector.ts +273 -239
  64. package/src/modules/id-card/id-card-detector.ts +474 -0
  65. package/src/modules/id-card/index.ts +425 -0
  66. package/src/{id-recognition → modules/id-card}/ocr-processor.ts +149 -92
  67. package/src/modules/id-card/ocr-worker.ts +259 -0
  68. package/src/modules/id-card/types.ts +178 -0
  69. package/src/modules/qrcode/index.ts +175 -0
  70. package/src/modules/qrcode/qr-code-scanner.ts +230 -0
  71. package/src/modules/qrcode/types.ts +65 -0
  72. package/src/types/tesseract.d.ts +265 -22
  73. package/src/utils/image-processing.ts +68 -49
  74. package/src/utils/index.ts +426 -0
  75. package/src/utils/performance.ts +168 -131
  76. package/src/utils/resource-manager.ts +65 -146
  77. package/src/utils/types.ts +90 -2
  78. package/src/utils/worker.ts +123 -84
  79. package/src/version.ts +11 -0
  80. package/tools/scaffold.js +543 -0
  81. package/dist/id-scanner-core.esm.js +0 -11349
  82. package/dist/id-scanner-core.js +0 -11361
  83. package/dist/id-scanner-core.min.js +0 -1
  84. package/dist/id-scanner-ocr.esm.js +0 -2319
  85. package/dist/id-scanner-ocr.js +0 -2328
  86. package/dist/id-scanner-ocr.min.js +0 -1
  87. package/dist/id-scanner-qr.esm.js +0 -1296
  88. package/dist/id-scanner-qr.js +0 -1305
  89. package/dist/id-scanner-qr.min.js +0 -1
  90. package/dist/id-scanner.js +0 -4561
  91. package/dist/id-scanner.min.js +0 -1
  92. package/src/core.ts +0 -138
  93. package/src/demo/demo.ts +0 -204
  94. package/src/id-recognition/data-extractor.ts +0 -262
  95. package/src/id-recognition/id-detector.ts +0 -510
  96. package/src/id-recognition/ocr-worker.ts +0 -156
  97. package/src/index-umd.ts +0 -477
  98. package/src/ocr-module.ts +0 -187
  99. package/src/qr-module.ts +0 -179
  100. package/src/scanner/barcode-scanner.ts +0 -251
  101. package/src/scanner/qr-scanner.ts +0 -167
@@ -0,0 +1,426 @@
1
+ /**
2
+ * @file 工具集
3
+ * @description 提供通用工具函数
4
+ * @module utils
5
+ */
6
+
7
+ /**
8
+ * 创建延迟Promise
9
+ * @param ms 延迟毫秒数
10
+ */
11
+ export function delay(ms: number): Promise<void> {
12
+ return new Promise(resolve => setTimeout(resolve, ms));
13
+ }
14
+
15
+ /**
16
+ * 节流函数
17
+ * @param fn 要节流的函数
18
+ * @param wait 等待时间(ms)
19
+ */
20
+ export function throttle<T extends (...args: any[]) => any>(
21
+ fn: T,
22
+ wait: number
23
+ ): (...args: Parameters<T>) => ReturnType<T> | undefined {
24
+ let lastTime = 0;
25
+ let lastResult: ReturnType<T>;
26
+
27
+ return function(this: any, ...args: Parameters<T>): ReturnType<T> | undefined {
28
+ const now = Date.now();
29
+ if (now - lastTime >= wait) {
30
+ lastTime = now;
31
+ lastResult = fn.apply(this, args);
32
+ }
33
+ return lastResult;
34
+ };
35
+ }
36
+
37
+ /**
38
+ * 防抖函数
39
+ * @param fn 要防抖的函数
40
+ * @param wait 等待时间(ms)
41
+ * @param immediate 是否立即执行
42
+ */
43
+ export function debounce<T extends (...args: any[]) => any>(
44
+ fn: T,
45
+ wait: number,
46
+ immediate: boolean = false
47
+ ): (...args: Parameters<T>) => void {
48
+ let timeout: number | null = null;
49
+
50
+ return function(this: any, ...args: Parameters<T>): void {
51
+ const callNow = immediate && !timeout;
52
+
53
+ if (timeout !== null) {
54
+ clearTimeout(timeout);
55
+ }
56
+
57
+ timeout = window.setTimeout(() => {
58
+ timeout = null;
59
+ if (!immediate) {
60
+ fn.apply(this, args);
61
+ }
62
+ }, wait);
63
+
64
+ if (callNow) {
65
+ fn.apply(this, args);
66
+ }
67
+ };
68
+ }
69
+
70
+ /**
71
+ * 格式化字节大小
72
+ * @param bytes 字节数
73
+ * @param decimals 小数位数
74
+ */
75
+ export function formatBytes(bytes: number, decimals: number = 2): string {
76
+ if (bytes === 0) return '0 Bytes';
77
+
78
+ const k = 1024;
79
+ const dm = decimals < 0 ? 0 : decimals;
80
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
81
+
82
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
83
+
84
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
85
+ }
86
+
87
+ /**
88
+ * 生成UUID
89
+ */
90
+ export function generateUUID(): string {
91
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
92
+ const r = Math.random() * 16 | 0;
93
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
94
+ return v.toString(16);
95
+ });
96
+ }
97
+
98
+ /**
99
+ * 检查浏览器支持的功能
100
+ */
101
+ export const browserCapabilities = {
102
+ /**
103
+ * 检查是否支持摄像头
104
+ */
105
+ hasCamera(): boolean {
106
+ return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia);
107
+ },
108
+
109
+ /**
110
+ * 检查是否支持WebAssembly
111
+ */
112
+ hasWasm(): boolean {
113
+ return typeof WebAssembly === 'object' &&
114
+ typeof WebAssembly.compile === 'function' &&
115
+ typeof WebAssembly.instantiate === 'function';
116
+ },
117
+
118
+ /**
119
+ * 检查是否支持WebWorker
120
+ */
121
+ hasWebWorker(): boolean {
122
+ return typeof Worker === 'function';
123
+ },
124
+
125
+ /**
126
+ * 检查是否支持WebGL
127
+ */
128
+ hasWebGL(): boolean {
129
+ try {
130
+ const canvas = document.createElement('canvas');
131
+ return !!(
132
+ window.WebGLRenderingContext &&
133
+ (canvas.getContext('webgl') || canvas.getContext('experimental-webgl'))
134
+ );
135
+ } catch (e) {
136
+ return false;
137
+ }
138
+ },
139
+
140
+ /**
141
+ * 检查是否支持SharedArrayBuffer
142
+ */
143
+ hasSharedArrayBuffer(): boolean {
144
+ return typeof SharedArrayBuffer === 'function';
145
+ },
146
+
147
+ /**
148
+ * 检查是否支持特定的功能
149
+ * @param feature 功能名称
150
+ */
151
+ supports(feature: string): boolean {
152
+ switch (feature.toLowerCase()) {
153
+ case 'camera': return this.hasCamera();
154
+ case 'wasm': return this.hasWasm();
155
+ case 'webworker': case 'worker': return this.hasWebWorker();
156
+ case 'webgl': case 'gl': return this.hasWebGL();
157
+ case 'sharedarraybuffer': case 'sab': return this.hasSharedArrayBuffer();
158
+ default: return false;
159
+ }
160
+ }
161
+ };
162
+
163
+ /**
164
+ * 数组分块
165
+ * @param array 要分块的数组
166
+ * @param chunkSize 每块大小
167
+ */
168
+ export function chunk<T>(array: T[], chunkSize: number): T[][] {
169
+ if (chunkSize < 1) throw new Error('Chunk size must be greater than 0');
170
+
171
+ const result: T[][] = [];
172
+ for (let i = 0; i < array.length; i += chunkSize) {
173
+ result.push(array.slice(i, i + chunkSize));
174
+ }
175
+ return result;
176
+ }
177
+
178
+ /**
179
+ * 安全解析JSON
180
+ * @param text JSON字符串
181
+ * @param fallback 解析失败时的默认值
182
+ */
183
+ export function safeParseJSON<T = any>(text: string, fallback: T): T {
184
+ try {
185
+ return JSON.parse(text) as T;
186
+ } catch (e) {
187
+ return fallback;
188
+ }
189
+ }
190
+
191
+ /**
192
+ * 限制值在指定范围内
193
+ * @param value 要限制的值
194
+ * @param min 最小值
195
+ * @param max 最大值
196
+ */
197
+ export function clamp(value: number, min: number, max: number): number {
198
+ return Math.min(Math.max(value, min), max);
199
+ }
200
+
201
+ /**
202
+ * 等待加载图片
203
+ * @param url 图片URL
204
+ */
205
+ export function loadImage(url: string): Promise<HTMLImageElement> {
206
+ return new Promise((resolve, reject) => {
207
+ const img = new Image();
208
+ img.onload = () => resolve(img);
209
+ img.onerror = () => reject(new Error(`Failed to load image: ${url}`));
210
+ img.src = url;
211
+ });
212
+ }
213
+
214
+ /**
215
+ * 将Blob转换为Base64
216
+ * @param blob Blob对象
217
+ */
218
+ export function blobToBase64(blob: Blob): Promise<string> {
219
+ return new Promise((resolve, reject) => {
220
+ const reader = new FileReader();
221
+ reader.onload = () => resolve(reader.result as string);
222
+ reader.onerror = () => reject(reader.error);
223
+ reader.readAsDataURL(blob);
224
+ });
225
+ }
226
+
227
+ /**
228
+ * 将Base64转换为Blob
229
+ * @param base64 Base64字符串
230
+ * @param contentType 内容类型
231
+ */
232
+ export function base64ToBlob(base64: string, contentType: string = ''): Blob {
233
+ const byteString = atob(base64.split(',')[1]);
234
+ const ab = new ArrayBuffer(byteString.length);
235
+ const ia = new Uint8Array(ab);
236
+
237
+ for (let i = 0; i < byteString.length; i++) {
238
+ ia[i] = byteString.charCodeAt(i);
239
+ }
240
+
241
+ return new Blob([ab], { type: contentType });
242
+ }
243
+
244
+ /**
245
+ * 获取媒体约束
246
+ * @param width 宽度
247
+ * @param height 高度
248
+ * @param facingMode 前后置摄像头
249
+ * @param frameRate 帧率
250
+ */
251
+ export function getMediaConstraints(
252
+ width: number = 1280,
253
+ height: number = 720,
254
+ facingMode: 'user' | 'environment' = 'environment',
255
+ frameRate: number = 30
256
+ ): MediaStreamConstraints {
257
+ return {
258
+ video: {
259
+ width: { ideal: width },
260
+ height: { ideal: height },
261
+ facingMode: { ideal: facingMode },
262
+ frameRate: { ideal: frameRate }
263
+ },
264
+ audio: false
265
+ };
266
+ }
267
+
268
+ /**
269
+ * 检查URL是否有效
270
+ * @param url 要检查的URL
271
+ */
272
+ export function isValidUrl(url: string): boolean {
273
+ try {
274
+ new URL(url);
275
+ return true;
276
+ } catch (e) {
277
+ return false;
278
+ }
279
+ }
280
+
281
+ /**
282
+ * DOM帮助函数
283
+ */
284
+ export const dom = {
285
+ /**
286
+ * 创建元素
287
+ * @param tag 标签名
288
+ * @param attributes 属性
289
+ * @param children 子元素
290
+ */
291
+ createElement<K extends keyof HTMLElementTagNameMap>(
292
+ tag: K,
293
+ attributes: Record<string, any> = {},
294
+ children: (string | Node)[] = []
295
+ ): HTMLElementTagNameMap[K] {
296
+ const element = document.createElement(tag);
297
+
298
+ // 设置属性
299
+ Object.entries(attributes).forEach(([key, value]) => {
300
+ if (key === 'style' && typeof value === 'object') {
301
+ Object.assign(element.style, value);
302
+ } else if (key.startsWith('on') && typeof value === 'function') {
303
+ element.addEventListener(key.substring(2).toLowerCase(), value);
304
+ } else if (key === 'className') {
305
+ element.className = value;
306
+ } else {
307
+ element.setAttribute(key, value);
308
+ }
309
+ });
310
+
311
+ // 添加子元素
312
+ children.forEach(child => {
313
+ if (typeof child === 'string') {
314
+ element.appendChild(document.createTextNode(child));
315
+ } else {
316
+ element.appendChild(child);
317
+ }
318
+ });
319
+
320
+ return element;
321
+ },
322
+
323
+ /**
324
+ * 查找元素
325
+ * @param selector 选择器
326
+ * @param parent 父元素
327
+ */
328
+ find<E extends Element = Element>(
329
+ selector: string,
330
+ parent: Document | Element = document
331
+ ): E | null {
332
+ return parent.querySelector<E>(selector);
333
+ },
334
+
335
+ /**
336
+ * 查找所有元素
337
+ * @param selector 选择器
338
+ * @param parent 父元素
339
+ */
340
+ findAll<E extends Element = Element>(
341
+ selector: string,
342
+ parent: Document | Element = document
343
+ ): E[] {
344
+ return Array.from(parent.querySelectorAll<E>(selector));
345
+ },
346
+
347
+ /**
348
+ * 添加事件监听器
349
+ * @param element 元素
350
+ * @param event 事件名称
351
+ * @param handler 处理函数
352
+ * @param options 选项
353
+ */
354
+ on<K extends keyof HTMLElementEventMap>(
355
+ element: HTMLElement,
356
+ event: K,
357
+ handler: (event: HTMLElementEventMap[K]) => any,
358
+ options?: AddEventListenerOptions
359
+ ): void {
360
+ element.addEventListener(event, handler as EventListener, options);
361
+ },
362
+
363
+ /**
364
+ * 移除事件监听器
365
+ * @param element 元素
366
+ * @param event 事件名称
367
+ * @param handler 处理函数
368
+ * @param options 选项
369
+ */
370
+ off<K extends keyof HTMLElementEventMap>(
371
+ element: HTMLElement,
372
+ event: K,
373
+ handler: (event: HTMLElementEventMap[K]) => any,
374
+ options?: EventListenerOptions
375
+ ): void {
376
+ element.removeEventListener(event, handler as EventListener, options);
377
+ },
378
+
379
+ /**
380
+ * 设置样式
381
+ * @param element 元素
382
+ * @param styles 样式对象
383
+ */
384
+ setStyles(
385
+ element: HTMLElement,
386
+ styles: Partial<CSSStyleDeclaration>
387
+ ): void {
388
+ Object.assign(element.style, styles);
389
+ },
390
+
391
+ /**
392
+ * 添加类名
393
+ * @param element 元素
394
+ * @param classNames 类名
395
+ */
396
+ addClass(
397
+ element: HTMLElement,
398
+ ...classNames: string[]
399
+ ): void {
400
+ element.classList.add(...classNames);
401
+ },
402
+
403
+ /**
404
+ * 移除类名
405
+ * @param element 元素
406
+ * @param classNames 类名
407
+ */
408
+ removeClass(
409
+ element: HTMLElement,
410
+ ...classNames: string[]
411
+ ): void {
412
+ element.classList.remove(...classNames);
413
+ },
414
+
415
+ /**
416
+ * 判断是否包含类名
417
+ * @param element 元素
418
+ * @param className 类名
419
+ */
420
+ hasClass(
421
+ element: HTMLElement,
422
+ className: string
423
+ ): boolean {
424
+ return element.classList.contains(className);
425
+ }
426
+ };