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
@@ -0,0 +1,543 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @file ID Scanner 快速脚手架工具
5
+ * @description 帮助开发者快速生成基本的扫描器配置和初始化代码
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const readline = require('readline');
11
+
12
+ // 创建交互式命令行界面
13
+ const rl = readline.createInterface({
14
+ input: process.stdin,
15
+ output: process.stdout
16
+ });
17
+
18
+ // 模板配置
19
+ const templates = {
20
+ face: {
21
+ filename: 'face-recognition.js',
22
+ content: `import { IDScannerLib, FaceModule } from 'id-scanner-lib';
23
+
24
+ /**
25
+ * 人脸识别初始化函数
26
+ * @param {Object} options - 配置选项
27
+ * @returns {Promise<FaceModule>} 人脸模块实例
28
+ */
29
+ async function initializeFaceRecognition(options = {}) {
30
+ // 初始化库
31
+ await IDScannerLib.initialize({
32
+ debug: options.debug || false
33
+ });
34
+
35
+ // 创建人脸模块
36
+ const faceModule = new FaceModule({
37
+ cameraOptions: options.cameraOptions || {
38
+ facingMode: 'user',
39
+ idealResolution: { width: 1280, height: 720 }
40
+ },
41
+ onFaceDetected: options.onFaceDetected || ((faces) => {
42
+ console.log(\`检测到 \${faces.length} 个人脸\`);
43
+ }),
44
+ onError: options.onError || ((error) => {
45
+ console.error('人脸识别错误:', error);
46
+ })
47
+ });
48
+
49
+ // 初始化人脸模块
50
+ await faceModule.initialize();
51
+ console.log('人脸识别模块初始化成功');
52
+
53
+ return faceModule;
54
+ }
55
+
56
+ /**
57
+ * 启动人脸识别
58
+ * @param {FaceModule} faceModule - 人脸模块实例
59
+ * @param {HTMLVideoElement} videoElement - 视频元素
60
+ */
61
+ async function startFaceRecognition(faceModule, videoElement) {
62
+ try {
63
+ await faceModule.startFaceRecognition(videoElement);
64
+ console.log('人脸识别已启动');
65
+ } catch (error) {
66
+ console.error('启动人脸识别失败:', error);
67
+ }
68
+ }
69
+
70
+ export { initializeFaceRecognition, startFaceRecognition };
71
+ `
72
+ },
73
+ qr: {
74
+ filename: 'qr-scanner.js',
75
+ content: `import { IDScannerLib } from 'id-scanner-lib';
76
+
77
+ /**
78
+ * 二维码扫描初始化函数
79
+ * @param {Object} options - 配置选项
80
+ * @returns {Promise<Object>} 二维码扫描器实例
81
+ */
82
+ async function initializeQRScanner(options = {}) {
83
+ // 初始化库
84
+ await IDScannerLib.initialize({
85
+ debug: options.debug || false
86
+ });
87
+
88
+ // 创建二维码扫描器
89
+ const qrScanner = IDScannerLib.createQRScanner({
90
+ scanFrequency: options.scanFrequency || 200,
91
+ formats: options.formats || ['qrcode', 'code_128', 'code_39', 'ean_13'],
92
+ minConfidence: options.minConfidence || 0.6
93
+ });
94
+
95
+ // 初始化扫描器
96
+ await qrScanner.init();
97
+ console.log('二维码扫描器初始化成功');
98
+
99
+ return qrScanner;
100
+ }
101
+
102
+ /**
103
+ * 启动实时扫描
104
+ * @param {Object} qrScanner - 二维码扫描器实例
105
+ * @param {HTMLVideoElement} videoElement - 视频元素
106
+ * @param {Function} onResult - 结果回调函数
107
+ */
108
+ async function startQRScanning(qrScanner, videoElement, onResult) {
109
+ try {
110
+ // 注册结果处理回调
111
+ if (onResult) {
112
+ qrScanner.on('module:realtime:result', onResult);
113
+ }
114
+
115
+ // 启动实时扫描
116
+ await qrScanner.startRealtime(videoElement);
117
+ console.log('二维码实时扫描已启动');
118
+ } catch (error) {
119
+ console.error('启动二维码扫描失败:', error);
120
+ }
121
+ }
122
+
123
+ export { initializeQRScanner, startQRScanning };
124
+ `
125
+ },
126
+ combined: {
127
+ filename: 'combined-scanner.js',
128
+ content: `import { IDScannerLib, FaceModule, CameraManager } from 'id-scanner-lib';
129
+
130
+ /**
131
+ * 组合扫描器初始化函数
132
+ * @param {Object} options - 配置选项
133
+ * @returns {Promise<Object>} 组合扫描器实例
134
+ */
135
+ async function initializeCombinedScanner(options = {}) {
136
+ // 初始化库
137
+ await IDScannerLib.initialize({
138
+ debug: options.debug || false
139
+ });
140
+
141
+ // 获取摄像头管理器
142
+ const cameraManager = CameraManager.getInstance();
143
+
144
+ // 创建人脸模块
145
+ const faceModule = new FaceModule({
146
+ onFaceDetected: options.onFaceDetected || ((faces) => {
147
+ console.log(\`检测到 \${faces.length} 个人脸\`);
148
+ }),
149
+ onError: options.onFaceError || ((error) => {
150
+ console.error('人脸识别错误:', error);
151
+ })
152
+ });
153
+
154
+ // 初始化人脸模块
155
+ await faceModule.initialize();
156
+
157
+ // 创建二维码扫描器
158
+ const qrScanner = IDScannerLib.createQRScanner({
159
+ scanFrequency: options.scanFrequency || 200,
160
+ formats: options.formats || ['qrcode']
161
+ });
162
+
163
+ // 初始化扫描器
164
+ await qrScanner.init();
165
+
166
+ // 返回组合对象
167
+ return {
168
+ cameraManager,
169
+ faceModule,
170
+ qrScanner,
171
+
172
+ // 注册二维码结果处理回调
173
+ onQRCodeResult(callback) {
174
+ qrScanner.on('module:realtime:result', callback);
175
+ return this;
176
+ },
177
+
178
+ // 启动摄像头
179
+ async startCamera(videoElement, options = {}) {
180
+ try {
181
+ await cameraManager.init({
182
+ facingMode: options.facingMode || 'user',
183
+ idealResolution: options.idealResolution || { width: 1280, height: 720 }
184
+ });
185
+
186
+ cameraManager.setVideoElement(videoElement);
187
+ await cameraManager.start();
188
+ return this;
189
+ } catch (error) {
190
+ console.error('启动摄像头失败:', error);
191
+ throw error;
192
+ }
193
+ },
194
+
195
+ // 启动人脸检测
196
+ async startFaceDetection(videoElement) {
197
+ try {
198
+ await faceModule.startFaceRecognition(videoElement);
199
+ return this;
200
+ } catch (error) {
201
+ console.error('启动人脸检测失败:', error);
202
+ throw error;
203
+ }
204
+ },
205
+
206
+ // 启动二维码扫描
207
+ async startQRScanning(videoElement) {
208
+ try {
209
+ await qrScanner.startRealtime(videoElement);
210
+ return this;
211
+ } catch (error) {
212
+ console.error('启动二维码扫描失败:', error);
213
+ throw error;
214
+ }
215
+ },
216
+
217
+ // 启动所有功能
218
+ async startAll(videoElement, cameraOptions = {}) {
219
+ await this.startCamera(videoElement, cameraOptions);
220
+ await this.startFaceDetection(videoElement);
221
+ await this.startQRScanning(videoElement);
222
+ return this;
223
+ },
224
+
225
+ // 停止所有功能
226
+ stop() {
227
+ faceModule.stop();
228
+ qrScanner.stopRealtime();
229
+ cameraManager.stop();
230
+ return this;
231
+ },
232
+
233
+ // 释放资源
234
+ async dispose() {
235
+ await faceModule.terminate();
236
+ await qrScanner.dispose();
237
+ }
238
+ };
239
+ }
240
+
241
+ export { initializeCombinedScanner };
242
+ `
243
+ },
244
+ html: {
245
+ filename: 'scanner.html',
246
+ content: `<!DOCTYPE html>
247
+ <html lang="zh-CN">
248
+ <head>
249
+ <meta charset="UTF-8">
250
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
251
+ <title>ID Scanner 示例</title>
252
+ <style>
253
+ body {
254
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
255
+ max-width: 800px;
256
+ margin: 0 auto;
257
+ padding: 20px;
258
+ }
259
+
260
+ .video-container {
261
+ position: relative;
262
+ margin-bottom: 20px;
263
+ }
264
+
265
+ video {
266
+ width: 100%;
267
+ border: 1px solid #ddd;
268
+ border-radius: 8px;
269
+ }
270
+
271
+ canvas {
272
+ position: absolute;
273
+ top: 0;
274
+ left: 0;
275
+ width: 100%;
276
+ height: 100%;
277
+ pointer-events: none;
278
+ }
279
+
280
+ .controls {
281
+ margin-bottom: 20px;
282
+ }
283
+
284
+ button {
285
+ background-color: #3498db;
286
+ color: white;
287
+ border: none;
288
+ padding: 10px 15px;
289
+ border-radius: 4px;
290
+ cursor: pointer;
291
+ margin-right: 10px;
292
+ }
293
+
294
+ button:hover {
295
+ background-color: #2980b9;
296
+ }
297
+
298
+ #result {
299
+ padding: 15px;
300
+ background-color: #f8f9fa;
301
+ border-radius: 8px;
302
+ border: 1px solid #ddd;
303
+ min-height: 50px;
304
+ }
305
+ </style>
306
+ </head>
307
+ <body>
308
+ <h1>ID Scanner 示例</h1>
309
+
310
+ <div class="video-container">
311
+ <video id="video" autoplay playsinline muted></video>
312
+ <canvas id="canvas-overlay"></canvas>
313
+ </div>
314
+
315
+ <div class="controls">
316
+ <button id="start-button">开始扫描</button>
317
+ <button id="stop-button" disabled>停止扫描</button>
318
+ </div>
319
+
320
+ <div>
321
+ <h3>扫描结果</h3>
322
+ <pre id="result">等待扫描...</pre>
323
+ </div>
324
+
325
+ <!-- 加载库 -->
326
+ <script src="../dist/id-scanner-lib.js"></script>
327
+
328
+ <script>
329
+ document.addEventListener('DOMContentLoaded', async () => {
330
+ const videoEl = document.getElementById('video');
331
+ const canvasEl = document.getElementById('canvas-overlay');
332
+ const resultEl = document.getElementById('result');
333
+ const startButton = document.getElementById('start-button');
334
+ const stopButton = document.getElementById('stop-button');
335
+
336
+ let scanner = null;
337
+
338
+ // 开始扫描
339
+ startButton.addEventListener('click', async () => {
340
+ try {
341
+ resultEl.textContent = '正在初始化...';
342
+
343
+ // 初始化扫描器
344
+ scanner = await IDScannerLib.IDScannerLib.initialize({
345
+ debug: true
346
+ });
347
+
348
+ // 这里根据需要选择不同的扫描模块
349
+ // 例如,使用FaceModule或createQRScanner等
350
+
351
+ // 请替换为您的实现
352
+ resultEl.textContent = '初始化成功,请替换此代码为您的实现';
353
+
354
+ // 更新按钮状态
355
+ startButton.disabled = true;
356
+ stopButton.disabled = false;
357
+ } catch (error) {
358
+ resultEl.textContent = '初始化失败: ' + error.message;
359
+ console.error('初始化错误:', error);
360
+ }
361
+ });
362
+
363
+ // 停止扫描
364
+ stopButton.addEventListener('click', () => {
365
+ if (scanner) {
366
+ // 清理资源
367
+ // 例如: scanner.stop();
368
+
369
+ resultEl.textContent = '扫描已停止';
370
+
371
+ // 更新按钮状态
372
+ startButton.disabled = false;
373
+ stopButton.disabled = true;
374
+ }
375
+ });
376
+ });
377
+ </script>
378
+ </body>
379
+ </html>
380
+ `
381
+ }
382
+ };
383
+
384
+ // 工具标识
385
+ console.log('\n=== ID Scanner 脚手架工具 ===\n');
386
+ console.log('这个工具将帮助您生成基本的扫描器代码模板。\n');
387
+
388
+ // 询问要生成的模板类型
389
+ function askTemplateType() {
390
+ rl.question('请选择要生成的模板类型 (1: 人脸识别, 2: 二维码扫描, 3: 组合扫描器, 4: HTML示例): ', (answer) => {
391
+ const type = parseInt(answer);
392
+
393
+ if (isNaN(type) || type < 1 || type > 4) {
394
+ console.log('无效的选择,请输入1-4之间的数字。');
395
+ return askTemplateType();
396
+ }
397
+
398
+ let templateKey;
399
+ switch (type) {
400
+ case 1: templateKey = 'face'; break;
401
+ case 2: templateKey = 'qr'; break;
402
+ case 3: templateKey = 'combined'; break;
403
+ case 4: templateKey = 'html'; break;
404
+ }
405
+
406
+ askOutputDir(templateKey);
407
+ });
408
+ }
409
+
410
+ // 询问输出目录
411
+ function askOutputDir(templateKey) {
412
+ rl.question('请输入要保存文件的目录路径 (默认为当前目录): ', (dirPath) => {
413
+ const outputDir = dirPath.trim() || '.';
414
+
415
+ // 检查目录是否存在
416
+ if (!fs.existsSync(outputDir)) {
417
+ console.log(`目录 "${outputDir}" 不存在,是否创建? (y/n): `);
418
+ rl.question('', (answer) => {
419
+ if (answer.toLowerCase() === 'y') {
420
+ try {
421
+ fs.mkdirSync(outputDir, { recursive: true });
422
+ generateTemplate(templateKey, outputDir);
423
+ } catch (error) {
424
+ console.error(`创建目录失败: ${error.message}`);
425
+ askOutputDir(templateKey);
426
+ }
427
+ } else {
428
+ askOutputDir(templateKey);
429
+ }
430
+ });
431
+ } else {
432
+ generateTemplate(templateKey, outputDir);
433
+ }
434
+ });
435
+ }
436
+
437
+ // 生成模板文件
438
+ function generateTemplate(templateKey, outputDir) {
439
+ const template = templates[templateKey];
440
+ const outputPath = path.join(outputDir, template.filename);
441
+
442
+ // 检查文件是否已存在
443
+ if (fs.existsSync(outputPath)) {
444
+ rl.question(`文件 "${outputPath}" 已存在,是否覆盖? (y/n): `, (answer) => {
445
+ if (answer.toLowerCase() === 'y') {
446
+ writeTemplateFile(template, outputPath);
447
+ } else {
448
+ console.log('操作已取消。');
449
+ rl.close();
450
+ }
451
+ });
452
+ } else {
453
+ writeTemplateFile(template, outputPath);
454
+ }
455
+ }
456
+
457
+ // 写入模板文件
458
+ function writeTemplateFile(template, outputPath) {
459
+ try {
460
+ fs.writeFileSync(outputPath, template.content);
461
+ console.log(`\n✅ 文件已成功生成: ${outputPath}`);
462
+
463
+ if (path.extname(outputPath) === '.js') {
464
+ console.log('\n示例用法:');
465
+ if (template.filename === 'face-recognition.js') {
466
+ console.log(`
467
+ import { initializeFaceRecognition, startFaceRecognition } from './${template.filename}';
468
+
469
+ // 初始化
470
+ const faceModule = await initializeFaceRecognition({
471
+ debug: true,
472
+ onFaceDetected: (faces) => {
473
+ console.log(\`检测到 \${faces.length} 个人脸\`);
474
+ }
475
+ });
476
+
477
+ // 启动识别
478
+ const videoElement = document.getElementById('video');
479
+ await startFaceRecognition(faceModule, videoElement);
480
+ `);
481
+ } else if (template.filename === 'qr-scanner.js') {
482
+ console.log(`
483
+ import { initializeQRScanner, startQRScanning } from './${template.filename}';
484
+
485
+ // 初始化
486
+ const qrScanner = await initializeQRScanner({
487
+ scanFrequency: 200,
488
+ formats: ['qrcode']
489
+ });
490
+
491
+ // 启动扫描
492
+ const videoElement = document.getElementById('video');
493
+ await startQRScanning(qrScanner, videoElement, (event) => {
494
+ console.log('扫描结果:', event.result.content);
495
+ });
496
+ `);
497
+ } else if (template.filename === 'combined-scanner.js') {
498
+ console.log(`
499
+ import { initializeCombinedScanner } from './${template.filename}';
500
+
501
+ // 初始化组合扫描器
502
+ const scanner = await initializeCombinedScanner({
503
+ debug: true,
504
+ onFaceDetected: (faces) => {
505
+ console.log(\`检测到 \${faces.length} 个人脸\`);
506
+ }
507
+ });
508
+
509
+ // 注册二维码结果处理
510
+ scanner.onQRCodeResult((event) => {
511
+ console.log('扫描结果:', event.result.content);
512
+ });
513
+
514
+ // 启动所有功能
515
+ const videoElement = document.getElementById('video');
516
+ await scanner.startAll(videoElement, { facingMode: 'user' });
517
+
518
+ // 使用完后停止并释放资源
519
+ // scanner.stop();
520
+ // await scanner.dispose();
521
+ `);
522
+ }
523
+ } else {
524
+ console.log('\n请在浏览器中打开生成的HTML文件来测试功能。');
525
+ }
526
+
527
+ // 询问是否生成更多模板
528
+ rl.question('\n是否需要生成更多模板? (y/n): ', (answer) => {
529
+ if (answer.toLowerCase() === 'y') {
530
+ askTemplateType();
531
+ } else {
532
+ console.log('\n感谢使用 ID Scanner 脚手架工具!');
533
+ rl.close();
534
+ }
535
+ });
536
+ } catch (error) {
537
+ console.error(`生成文件失败: ${error.message}`);
538
+ rl.close();
539
+ }
540
+ }
541
+
542
+ // 开始询问
543
+ askTemplateType();