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,474 @@
1
+ /**
2
+ * @file 身份证检测器
3
+ * @description 提供身份证检测和解析功能
4
+ * @module modules/id-card/id-card-detector
5
+ */
6
+
7
+ import { EventEmitter } from '../../core/event-emitter';
8
+ import { Logger } from '../../core/logger';
9
+ import { Result } from '../../core/result';
10
+ import { IDCardType, IDCardEdge, IDCardInfo } from './types';
11
+
12
+ /**
13
+ * 身份证检测器配置选项
14
+ */
15
+ export interface IDCardDetectorOptions {
16
+ /** 是否启用 */
17
+ enabled?: boolean;
18
+ /** 最小置信度 */
19
+ minConfidence?: number;
20
+ /** 是否检测身份证类型 */
21
+ detectType?: boolean;
22
+ /** 是否检测边缘 */
23
+ detectEdge?: boolean;
24
+ /** 是否启用边缘检测(用于更精确的边缘检测) */
25
+ enableEdgeDetection?: boolean;
26
+ /** 是否启用OCR识别 */
27
+ enableOCR?: boolean;
28
+ /** 是否裁剪并校正图像 */
29
+ cropAndAlign?: boolean;
30
+ /** 是否启用防伪检测 */
31
+ enableAntiFake?: boolean;
32
+ /** 是否返回原始图像 */
33
+ returnImage?: boolean;
34
+ /** 模型路径 */
35
+ modelPath?: string;
36
+ }
37
+
38
+ /**
39
+ * 图像处理配置选项
40
+ */
41
+ export interface ImageProcessOptions {
42
+ /** 是否进行预处理 */
43
+ preprocess?: boolean;
44
+ /** 是否校正图像 */
45
+ correctPerspective?: boolean;
46
+ /** 是否增强图像 */
47
+ enhance?: boolean;
48
+ /** 是否去噪 */
49
+ denoise?: boolean;
50
+ /** 是否二值化 */
51
+ binarize?: boolean;
52
+ }
53
+
54
+ /**
55
+ * 身份证检测器类
56
+ */
57
+ export class IDCardDetector extends EventEmitter {
58
+ private options: IDCardDetectorOptions;
59
+ private logger: Logger;
60
+ private initialized: boolean = false;
61
+ private models: {
62
+ detection?: any;
63
+ ocr?: any;
64
+ antiFake?: any;
65
+ } = {};
66
+
67
+ /**
68
+ * 构造函数
69
+ * @param options 配置选项
70
+ */
71
+ constructor(options: IDCardDetectorOptions = {}) {
72
+ super();
73
+ this.options = {
74
+ enabled: true,
75
+ minConfidence: 0.7,
76
+ detectType: true,
77
+ detectEdge: true,
78
+ enableEdgeDetection: false,
79
+ enableOCR: true,
80
+ cropAndAlign: true,
81
+ enableAntiFake: false,
82
+ returnImage: false,
83
+ modelPath: '/models/id-card',
84
+ ...options
85
+ };
86
+ this.logger = Logger.getInstance();
87
+ }
88
+
89
+ /**
90
+ * 初始化检测器
91
+ */
92
+ public async initialize(): Promise<void> {
93
+ if (this.initialized || !this.options.enabled) {
94
+ return;
95
+ }
96
+
97
+ this.logger.debug('IDCardDetector', '初始化身份证检测器');
98
+
99
+ try {
100
+ // 加载检测模型
101
+ await this.loadDetectionModel();
102
+
103
+ // 如果启用OCR,加载OCR模型
104
+ if (this.options.enableOCR) {
105
+ await this.loadOCRModel();
106
+ }
107
+
108
+ // 如果启用防伪检测,加载防伪模型
109
+ if (this.options.enableAntiFake) {
110
+ await this.loadAntiFakeModel();
111
+ }
112
+
113
+ this.initialized = true;
114
+ this.emit('detector:initialized', {});
115
+ this.logger.debug('IDCardDetector', '身份证检测器初始化完成');
116
+ } catch (error) {
117
+ this.logger.error('IDCardDetector', '身份证检测器初始化失败', error as Error);
118
+ throw error;
119
+ }
120
+ }
121
+
122
+ /**
123
+ * 加载检测模型
124
+ * @private
125
+ */
126
+ private async loadDetectionModel(): Promise<void> {
127
+ // 实际项目中,这里应该加载检测模型
128
+ this.logger.debug('IDCardDetector', '加载身份证检测模型');
129
+
130
+ // 模拟加载模型的延迟
131
+ await new Promise(resolve => setTimeout(resolve, 100));
132
+
133
+ // 设置模型
134
+ this.models.detection = {
135
+ loaded: true,
136
+ name: 'id-card-detection'
137
+ };
138
+ }
139
+
140
+ /**
141
+ * 加载OCR模型
142
+ * @private
143
+ */
144
+ private async loadOCRModel(): Promise<void> {
145
+ // 实际项目中,这里应该加载OCR模型
146
+ this.logger.debug('IDCardDetector', '加载身份证OCR模型');
147
+
148
+ // 模拟加载模型的延迟
149
+ await new Promise(resolve => setTimeout(resolve, 100));
150
+
151
+ // 设置模型
152
+ this.models.ocr = {
153
+ loaded: true,
154
+ name: 'id-card-ocr'
155
+ };
156
+ }
157
+
158
+ /**
159
+ * 加载防伪模型
160
+ * @private
161
+ */
162
+ private async loadAntiFakeModel(): Promise<void> {
163
+ // 实际项目中,这里应该加载防伪模型
164
+ this.logger.debug('IDCardDetector', '加载身份证防伪模型');
165
+
166
+ // 模拟加载模型的延迟
167
+ await new Promise(resolve => setTimeout(resolve, 100));
168
+
169
+ // 设置模型
170
+ this.models.antiFake = {
171
+ loaded: true,
172
+ name: 'id-card-anti-fake'
173
+ };
174
+ }
175
+
176
+ /**
177
+ * 处理图像
178
+ * @param image 图像源(可以是ImageData、HTMLImageElement、HTMLCanvasElement等)
179
+ * @param processOptions 图像处理选项
180
+ * @returns 处理结果
181
+ */
182
+ public async processImage(
183
+ image: ImageData | HTMLImageElement | HTMLCanvasElement,
184
+ processOptions: ImageProcessOptions = {}
185
+ ): Promise<Result<IDCardInfo>> {
186
+ if (!this.initialized) {
187
+ return Result.failure(new Error('身份证检测器未初始化'));
188
+ }
189
+
190
+ try {
191
+ this.logger.debug('IDCardDetector', '开始处理图像');
192
+
193
+ // 预处理图像
194
+ const processedImage = await this.preprocessImage(image, processOptions);
195
+
196
+ // 检测身份证
197
+ const detectionResult = await this.detectIDCard(processedImage);
198
+
199
+ if (!detectionResult || detectionResult.confidence < (this.options.minConfidence || 0.7)) {
200
+ return Result.failure(new Error('未检测到身份证或置信度过低'));
201
+ }
202
+
203
+ let idCardInfo: IDCardInfo = {
204
+ type: detectionResult.type,
205
+ edge: detectionResult.edge,
206
+ confidence: detectionResult.confidence
207
+ };
208
+
209
+ // 如果启用OCR识别,提取文字信息
210
+ if (this.options.enableOCR && this.models.ocr) {
211
+ // 裁剪并校正图像
212
+ const alignedImage = this.options.cropAndAlign ?
213
+ await this.cropAndAlign(processedImage, detectionResult.edge) :
214
+ processedImage;
215
+
216
+ // 识别文字
217
+ const ocrResult = await this.recognizeText(alignedImage, detectionResult.type);
218
+
219
+ // 合并结果
220
+ idCardInfo = {
221
+ ...idCardInfo,
222
+ ...ocrResult
223
+ };
224
+ }
225
+
226
+ // 如果启用防伪检测,进行防伪检测
227
+ if (this.options.enableAntiFake && this.models.antiFake) {
228
+ const antiFakeResult = await this.detectAntiFake(processedImage, detectionResult);
229
+ idCardInfo.antiFake = antiFakeResult;
230
+ }
231
+
232
+ // 如果需要返回原始图像
233
+ if (this.options.returnImage) {
234
+ // 根据图像类型获取ImageData
235
+ if (image instanceof ImageData) {
236
+ idCardInfo.image = image;
237
+ } else if (image instanceof HTMLCanvasElement) {
238
+ const context = image.getContext('2d');
239
+ if (context) {
240
+ idCardInfo.image = context.getImageData(0, 0, image.width, image.height);
241
+ }
242
+ } else if (image instanceof HTMLImageElement && image.complete) {
243
+ const canvas = document.createElement('canvas');
244
+ canvas.width = image.naturalWidth;
245
+ canvas.height = image.naturalHeight;
246
+ const context = canvas.getContext('2d');
247
+ if (context) {
248
+ context.drawImage(image, 0, 0);
249
+ idCardInfo.image = context.getImageData(0, 0, canvas.width, canvas.height);
250
+ }
251
+ }
252
+ }
253
+
254
+ this.logger.debug('IDCardDetector', '图像处理完成');
255
+ this.emit('detector:result', { result: idCardInfo });
256
+
257
+ return Result.success(idCardInfo);
258
+ } catch (error) {
259
+ this.logger.error('IDCardDetector', '图像处理失败', error as Error);
260
+ return Result.failure(error as Error);
261
+ }
262
+ }
263
+
264
+ /**
265
+ * 预处理图像
266
+ * @param image 图像源
267
+ * @param options 处理选项
268
+ * @returns 处理后的图像
269
+ * @private
270
+ */
271
+ private async preprocessImage(
272
+ image: ImageData | HTMLImageElement | HTMLCanvasElement,
273
+ options: ImageProcessOptions
274
+ ): Promise<ImageData> {
275
+ // 实际项目中,这里应该对图像进行预处理
276
+ this.logger.debug('IDCardDetector', '预处理图像');
277
+
278
+ // 创建ImageData对象
279
+ let imageData: ImageData;
280
+
281
+ if (image instanceof ImageData) {
282
+ imageData = image;
283
+ } else {
284
+ const canvas = document.createElement('canvas');
285
+ const width = image instanceof HTMLImageElement ? image.naturalWidth : image.width;
286
+ const height = image instanceof HTMLImageElement ? image.naturalHeight : image.height;
287
+
288
+ canvas.width = width;
289
+ canvas.height = height;
290
+
291
+ const context = canvas.getContext('2d');
292
+ if (!context) {
293
+ throw new Error('无法获取Canvas上下文');
294
+ }
295
+
296
+ if (image instanceof HTMLImageElement) {
297
+ context.drawImage(image, 0, 0);
298
+ } else {
299
+ context.drawImage(image, 0, 0);
300
+ }
301
+
302
+ imageData = context.getImageData(0, 0, width, height);
303
+ }
304
+
305
+ // 应用图像处理选项
306
+ // 实际项目中,这里应该根据options进行相应的图像处理
307
+
308
+ return imageData;
309
+ }
310
+
311
+ /**
312
+ * 检测身份证
313
+ * @param image 图像数据
314
+ * @returns 检测结果
315
+ * @private
316
+ */
317
+ private async detectIDCard(image: ImageData): Promise<{
318
+ type: IDCardType;
319
+ edge: IDCardEdge;
320
+ confidence: number;
321
+ } | null> {
322
+ // 实际项目中,这里应该调用模型进行身份证检测
323
+ this.logger.debug('IDCardDetector', '检测身份证');
324
+
325
+ // 模拟检测结果
326
+ // 在实际应用中,这里应该使用机器学习模型进行推理
327
+ return {
328
+ type: IDCardType.FRONT,
329
+ edge: {
330
+ topLeft: { x: 10, y: 10 },
331
+ topRight: { x: image.width - 10, y: 10 },
332
+ bottomRight: { x: image.width - 10, y: image.height - 10 },
333
+ bottomLeft: { x: 10, y: image.height - 10 }
334
+ },
335
+ confidence: 0.95
336
+ };
337
+ }
338
+
339
+ /**
340
+ * 裁剪并校正图像
341
+ * @param image 图像数据
342
+ * @param edge 边缘信息
343
+ * @returns 校正后的图像
344
+ * @private
345
+ */
346
+ private async cropAndAlign(image: ImageData, edge: IDCardEdge): Promise<ImageData> {
347
+ // 实际项目中,这里应该进行透视变换以校正图像
348
+ this.logger.debug('IDCardDetector', '裁剪并校正图像');
349
+
350
+ // 创建Canvas
351
+ const canvas = document.createElement('canvas');
352
+ // 设置标准身份证尺寸比例
353
+ canvas.width = 428;
354
+ canvas.height = 270;
355
+
356
+ const context = canvas.getContext('2d');
357
+ if (!context) {
358
+ throw new Error('无法获取Canvas上下文');
359
+ }
360
+
361
+ // 创建临时Canvas
362
+ const tempCanvas = document.createElement('canvas');
363
+ tempCanvas.width = image.width;
364
+ tempCanvas.height = image.height;
365
+
366
+ const tempContext = tempCanvas.getContext('2d');
367
+ if (!tempContext) {
368
+ throw new Error('无法获取临时Canvas上下文');
369
+ }
370
+
371
+ // 将ImageData绘制到临时Canvas
372
+ tempContext.putImageData(image, 0, 0);
373
+
374
+ // 在实际应用中,这里应该使用透视变换算法
375
+ // 例如使用Canvas的transform或WebGL进行变换
376
+
377
+ // 简化处理:直接裁剪
378
+ context.drawImage(
379
+ tempCanvas,
380
+ edge.topLeft.x,
381
+ edge.topLeft.y,
382
+ edge.topRight.x - edge.topLeft.x,
383
+ edge.bottomLeft.y - edge.topLeft.y,
384
+ 0,
385
+ 0,
386
+ canvas.width,
387
+ canvas.height
388
+ );
389
+
390
+ return context.getImageData(0, 0, canvas.width, canvas.height);
391
+ }
392
+
393
+ /**
394
+ * 识别文字
395
+ * @param image 图像数据
396
+ * @param type 身份证类型
397
+ * @returns 识别结果
398
+ * @private
399
+ */
400
+ private async recognizeText(image: ImageData, type: IDCardType): Promise<Partial<IDCardInfo>> {
401
+ // 实际项目中,这里应该调用OCR模型进行文字识别
402
+ this.logger.debug('IDCardDetector', '识别文字');
403
+
404
+ // 模拟OCR结果
405
+ // 在实际应用中,这里应该使用OCR模型进行文字识别
406
+ if (type === IDCardType.FRONT) {
407
+ return {
408
+ name: '张三',
409
+ gender: '男',
410
+ ethnicity: '汉',
411
+ birthDate: '1990-01-01',
412
+ address: '北京市朝阳区某某街道某某社区1号楼1单元101',
413
+ idNumber: '110101199001010001',
414
+ photoRegion: {
415
+ x: 300,
416
+ y: 40,
417
+ width: 100,
418
+ height: 130
419
+ }
420
+ };
421
+ } else if (type === IDCardType.BACK) {
422
+ return {
423
+ issueAuthority: '北京市公安局朝阳分局',
424
+ validFrom: '2015-01-01',
425
+ validTo: '2035-01-01'
426
+ };
427
+ }
428
+
429
+ return {};
430
+ }
431
+
432
+ /**
433
+ * 检测防伪特征
434
+ * @param image 图像数据
435
+ * @param detectionResult 检测结果
436
+ * @returns 防伪检测结果
437
+ * @private
438
+ */
439
+ private async detectAntiFake(
440
+ image: ImageData,
441
+ detectionResult: { type: IDCardType; edge: IDCardEdge; confidence: number }
442
+ ): Promise<IDCardInfo['antiFake']> {
443
+ // 实际项目中,这里应该调用防伪模型进行特征检测
444
+ this.logger.debug('IDCardDetector', '检测防伪特征');
445
+
446
+ // 模拟防伪检测结果
447
+ // 在实际应用中,这里应该使用机器学习模型检测防伪特征
448
+ return {
449
+ passed: true,
450
+ score: 0.92,
451
+ features: {
452
+ fluorescent: true,
453
+ microtext: true,
454
+ opticalVariable: true,
455
+ texture: true,
456
+ watermark: true
457
+ }
458
+ };
459
+ }
460
+
461
+ /**
462
+ * 释放资源
463
+ */
464
+ public dispose(): void {
465
+ this.logger.debug('IDCardDetector', '释放资源');
466
+
467
+ // 清理模型
468
+ this.models = {};
469
+ this.initialized = false;
470
+
471
+ // 清理事件监听
472
+ this.removeAllListeners();
473
+ }
474
+ }