id-scanner-lib 1.2.2 → 1.3.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.
- package/LICENSE +1 -1
- package/README.md +375 -363
- package/dist/id-scanner-core.esm.js +427 -221
- package/dist/id-scanner-core.esm.js.map +1 -1
- package/dist/id-scanner-core.js +427 -221
- package/dist/id-scanner-core.js.map +1 -1
- package/dist/id-scanner-core.min.js +1 -9
- package/dist/id-scanner-core.min.js.map +1 -1
- package/dist/id-scanner-ocr.esm.js +451 -276
- package/dist/id-scanner-ocr.esm.js.map +1 -1
- package/dist/id-scanner-ocr.js +451 -276
- package/dist/id-scanner-ocr.js.map +1 -1
- package/dist/id-scanner-ocr.min.js +1 -9
- package/dist/id-scanner-ocr.min.js.map +1 -1
- package/dist/id-scanner-qr.esm.js +483 -233
- package/dist/id-scanner-qr.esm.js.map +1 -1
- package/dist/id-scanner-qr.js +482 -232
- package/dist/id-scanner-qr.js.map +1 -1
- package/dist/id-scanner-qr.min.js +1 -9
- package/dist/id-scanner-qr.min.js.map +1 -1
- package/dist/id-scanner.js +2138 -358
- package/dist/id-scanner.js.map +1 -1
- package/dist/id-scanner.min.js +1 -9
- package/dist/id-scanner.min.js.map +1 -1
- package/package.json +27 -7
- package/src/demo/demo.ts +178 -62
- package/src/id-recognition/anti-fake-detector.ts +317 -0
- package/src/id-recognition/id-detector.ts +184 -155
- package/src/id-recognition/ocr-processor.ts +193 -146
- package/src/id-recognition/ocr-worker.ts +82 -72
- package/src/index-umd.ts +347 -110
- package/src/index.ts +866 -91
- package/src/ocr-module.ts +108 -60
- package/src/qr-module.ts +104 -54
- package/src/scanner/barcode-scanner.ts +145 -58
- package/src/scanner/qr-scanner.ts +86 -47
- package/src/utils/image-processing.ts +479 -294
- package/dist/core.d.ts +0 -77
- package/dist/demo/demo.d.ts +0 -14
- package/dist/id-recognition/data-extractor.d.ts +0 -105
- package/dist/id-recognition/id-detector.d.ts +0 -100
- package/dist/id-recognition/ocr-processor.d.ts +0 -64
- package/dist/id-scanner.esm.js +0 -94656
- package/dist/id-scanner.esm.js.map +0 -1
- package/dist/index-umd.d.ts +0 -96
- package/dist/index.d.ts +0 -78
- package/dist/ocr-module.d.ts +0 -67
- package/dist/qr-module.d.ts +0 -68
- package/dist/scanner/barcode-scanner.d.ts +0 -90
- package/dist/scanner/qr-scanner.d.ts +0 -80
- package/dist/types/core.d.ts +0 -77
- package/dist/types/demo/demo.d.ts +0 -14
- package/dist/types/id-recognition/data-extractor.d.ts +0 -105
- package/dist/types/id-recognition/id-detector.d.ts +0 -100
- package/dist/types/id-recognition/ocr-processor.d.ts +0 -64
- package/dist/types/index-umd.d.ts +0 -96
- package/dist/types/index.d.ts +0 -78
- package/dist/types/ocr-module.d.ts +0 -67
- package/dist/types/qr-module.d.ts +0 -68
- package/dist/types/scanner/barcode-scanner.d.ts +0 -90
- package/dist/types/scanner/qr-scanner.d.ts +0 -80
- package/dist/types/utils/camera.d.ts +0 -81
- package/dist/types/utils/image-processing.d.ts +0 -75
- package/dist/types/utils/types.d.ts +0 -65
- package/dist/utils/camera.d.ts +0 -81
- package/dist/utils/image-processing.d.ts +0 -75
- package/dist/utils/types.d.ts +0 -65
package/src/index-umd.ts
CHANGED
|
@@ -6,30 +6,35 @@
|
|
|
6
6
|
* @license MIT
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { Camera, CameraOptions } from
|
|
10
|
-
import { IDCardInfo, DetectionResult } from
|
|
11
|
-
import type { QRScannerOptions } from
|
|
12
|
-
import type { BarcodeScannerOptions } from
|
|
9
|
+
import { Camera, CameraOptions } from "./utils/camera"
|
|
10
|
+
import { IDCardInfo, DetectionResult } from "./utils/types"
|
|
11
|
+
import type { QRScannerOptions } from "./scanner/qr-scanner"
|
|
12
|
+
import type { BarcodeScannerOptions } from "./scanner/barcode-scanner"
|
|
13
13
|
|
|
14
14
|
// 静态导入所有依赖
|
|
15
|
-
import { QRScanner } from
|
|
16
|
-
import { BarcodeScanner } from
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
import { QRScanner } from "./scanner/qr-scanner"
|
|
16
|
+
import { BarcodeScanner } from "./scanner/barcode-scanner"
|
|
17
|
+
import {
|
|
18
|
+
IDCardDetector,
|
|
19
|
+
IDCardDetectorOptions,
|
|
20
|
+
} from "./id-recognition/id-detector"
|
|
21
|
+
import { OCRProcessor } from "./id-recognition/ocr-processor"
|
|
22
|
+
import { DataExtractor } from "./id-recognition/data-extractor"
|
|
23
|
+
import { ImageProcessor } from "./utils/image-processing"
|
|
24
|
+
// 导入IDScannerDemo
|
|
25
|
+
import { IDScannerDemo } from "./demo/demo"
|
|
21
26
|
|
|
22
27
|
/**
|
|
23
28
|
* IDScanner配置选项接口
|
|
24
29
|
*/
|
|
25
30
|
export interface IDScannerOptions {
|
|
26
|
-
cameraOptions?: CameraOptions
|
|
27
|
-
qrScannerOptions?: QRScannerOptions
|
|
28
|
-
barcodeScannerOptions?: BarcodeScannerOptions
|
|
29
|
-
onQRCodeScanned?: (result: string) => void
|
|
30
|
-
onBarcodeScanned?: (result: string) => void
|
|
31
|
-
onIDCardScanned?: (info: IDCardInfo) => void
|
|
32
|
-
onError?: (error: Error) => void
|
|
31
|
+
cameraOptions?: CameraOptions
|
|
32
|
+
qrScannerOptions?: QRScannerOptions
|
|
33
|
+
barcodeScannerOptions?: BarcodeScannerOptions
|
|
34
|
+
onQRCodeScanned?: (result: string) => void
|
|
35
|
+
onBarcodeScanned?: (result: string) => void
|
|
36
|
+
onIDCardScanned?: (info: IDCardInfo) => void
|
|
37
|
+
onError?: (error: Error) => void
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
/**
|
|
@@ -37,23 +42,26 @@ export interface IDScannerOptions {
|
|
|
37
42
|
* UMD版本使用静态导入实现
|
|
38
43
|
*/
|
|
39
44
|
export class IDScanner {
|
|
40
|
-
private camera: Camera
|
|
41
|
-
private qrScanner: QRScanner | null = null
|
|
42
|
-
private barcodeScanner: BarcodeScanner | null = null
|
|
43
|
-
private idDetector: IDCardDetector | null = null
|
|
44
|
-
private ocrProcessor: OCRProcessor | null = null
|
|
45
|
-
private dataExtractor: DataExtractor | null = null
|
|
46
|
-
private scanMode:
|
|
47
|
-
private videoElement: HTMLVideoElement | null = null
|
|
48
|
-
|
|
45
|
+
private camera: Camera
|
|
46
|
+
private qrScanner: QRScanner | null = null
|
|
47
|
+
private barcodeScanner: BarcodeScanner | null = null
|
|
48
|
+
private idDetector: IDCardDetector | null = null
|
|
49
|
+
private ocrProcessor: OCRProcessor | null = null
|
|
50
|
+
private dataExtractor: DataExtractor | null = null
|
|
51
|
+
private scanMode: "qr" | "barcode" | "idcard" = "qr"
|
|
52
|
+
private videoElement: HTMLVideoElement | null = null
|
|
53
|
+
|
|
54
|
+
// 添加静态属性IDScannerDemo,使其能被通过IDScanner.IDScannerDemo访问
|
|
55
|
+
static IDScannerDemo = IDScannerDemo
|
|
56
|
+
|
|
49
57
|
/**
|
|
50
58
|
* 构造函数
|
|
51
59
|
* @param options 配置选项
|
|
52
60
|
*/
|
|
53
61
|
constructor(private options: IDScannerOptions = {}) {
|
|
54
|
-
this.camera = new Camera(options.cameraOptions)
|
|
62
|
+
this.camera = new Camera(options.cameraOptions)
|
|
55
63
|
}
|
|
56
|
-
|
|
64
|
+
|
|
57
65
|
/**
|
|
58
66
|
* 初始化模块
|
|
59
67
|
* 根据需要初始化OCR引擎
|
|
@@ -61,180 +69,409 @@ export class IDScanner {
|
|
|
61
69
|
async initialize(): Promise<void> {
|
|
62
70
|
try {
|
|
63
71
|
// 初始化OCR模块
|
|
64
|
-
this.ocrProcessor = new OCRProcessor()
|
|
65
|
-
this.dataExtractor = new DataExtractor()
|
|
66
|
-
await this.ocrProcessor.initialize()
|
|
67
|
-
|
|
68
|
-
console.log(
|
|
72
|
+
this.ocrProcessor = new OCRProcessor()
|
|
73
|
+
this.dataExtractor = new DataExtractor()
|
|
74
|
+
await this.ocrProcessor.initialize()
|
|
75
|
+
|
|
76
|
+
console.log("IDScanner initialized")
|
|
69
77
|
} catch (error) {
|
|
70
|
-
this.handleError(error as Error)
|
|
71
|
-
throw error
|
|
78
|
+
this.handleError(error as Error)
|
|
79
|
+
throw error
|
|
72
80
|
}
|
|
73
81
|
}
|
|
74
|
-
|
|
82
|
+
|
|
75
83
|
/**
|
|
76
84
|
* 启动二维码扫描
|
|
77
85
|
* @param videoElement HTML视频元素
|
|
78
86
|
*/
|
|
79
87
|
async startQRScanner(videoElement: HTMLVideoElement): Promise<void> {
|
|
80
|
-
this.stop()
|
|
81
|
-
this.videoElement = videoElement
|
|
82
|
-
this.scanMode =
|
|
83
|
-
|
|
88
|
+
this.stop()
|
|
89
|
+
this.videoElement = videoElement
|
|
90
|
+
this.scanMode = "qr"
|
|
91
|
+
|
|
84
92
|
try {
|
|
85
93
|
if (!this.qrScanner) {
|
|
86
94
|
this.qrScanner = new QRScanner({
|
|
87
95
|
...this.options.qrScannerOptions,
|
|
88
|
-
onScan: this.handleQRScan.bind(this)
|
|
89
|
-
})
|
|
96
|
+
onScan: this.handleQRScan.bind(this),
|
|
97
|
+
})
|
|
90
98
|
}
|
|
91
|
-
|
|
92
|
-
await this.camera.start(videoElement)
|
|
93
|
-
this.qrScanner.start(videoElement)
|
|
99
|
+
|
|
100
|
+
await this.camera.start(videoElement)
|
|
101
|
+
this.qrScanner.start(videoElement)
|
|
94
102
|
} catch (error) {
|
|
95
|
-
this.handleError(error as Error)
|
|
103
|
+
this.handleError(error as Error)
|
|
96
104
|
}
|
|
97
105
|
}
|
|
98
|
-
|
|
106
|
+
|
|
99
107
|
/**
|
|
100
108
|
* 启动条形码扫描
|
|
101
109
|
* @param videoElement HTML视频元素
|
|
102
110
|
*/
|
|
103
111
|
async startBarcodeScanner(videoElement: HTMLVideoElement): Promise<void> {
|
|
104
|
-
this.stop()
|
|
105
|
-
this.videoElement = videoElement
|
|
106
|
-
this.scanMode =
|
|
107
|
-
|
|
112
|
+
this.stop()
|
|
113
|
+
this.videoElement = videoElement
|
|
114
|
+
this.scanMode = "barcode"
|
|
115
|
+
|
|
108
116
|
try {
|
|
109
117
|
if (!this.barcodeScanner) {
|
|
110
118
|
this.barcodeScanner = new BarcodeScanner({
|
|
111
119
|
...this.options.barcodeScannerOptions,
|
|
112
|
-
onScan: this.handleBarcodeScan.bind(this)
|
|
113
|
-
})
|
|
120
|
+
onScan: this.handleBarcodeScan.bind(this),
|
|
121
|
+
})
|
|
114
122
|
}
|
|
115
|
-
|
|
116
|
-
await this.camera.start(videoElement)
|
|
117
|
-
this.barcodeScanner.start(videoElement)
|
|
123
|
+
|
|
124
|
+
await this.camera.start(videoElement)
|
|
125
|
+
this.barcodeScanner.start(videoElement)
|
|
118
126
|
} catch (error) {
|
|
119
|
-
this.handleError(error as Error)
|
|
127
|
+
this.handleError(error as Error)
|
|
120
128
|
}
|
|
121
129
|
}
|
|
122
|
-
|
|
130
|
+
|
|
123
131
|
/**
|
|
124
132
|
* 启动身份证扫描
|
|
125
133
|
* @param videoElement HTML视频元素
|
|
126
134
|
*/
|
|
127
135
|
async startIDCardScanner(videoElement: HTMLVideoElement): Promise<void> {
|
|
128
|
-
this.stop()
|
|
129
|
-
this.videoElement = videoElement
|
|
130
|
-
this.scanMode =
|
|
131
|
-
|
|
136
|
+
this.stop()
|
|
137
|
+
this.videoElement = videoElement
|
|
138
|
+
this.scanMode = "idcard"
|
|
139
|
+
|
|
132
140
|
try {
|
|
133
141
|
if (!this.ocrProcessor) {
|
|
134
|
-
await this.initialize()
|
|
142
|
+
await this.initialize()
|
|
135
143
|
}
|
|
136
|
-
|
|
144
|
+
|
|
137
145
|
if (!this.idDetector) {
|
|
138
146
|
this.idDetector = new IDCardDetector({
|
|
139
147
|
onDetection: this.handleIDDetection.bind(this),
|
|
140
|
-
onError: this.handleError.bind(this)
|
|
141
|
-
} as IDCardDetectorOptions)
|
|
148
|
+
onError: this.handleError.bind(this),
|
|
149
|
+
} as IDCardDetectorOptions)
|
|
142
150
|
}
|
|
143
|
-
|
|
144
|
-
await this.camera.start(videoElement)
|
|
145
|
-
this.idDetector.start(videoElement)
|
|
151
|
+
|
|
152
|
+
await this.camera.start(videoElement)
|
|
153
|
+
this.idDetector.start(videoElement)
|
|
146
154
|
} catch (error) {
|
|
147
|
-
this.handleError(error as Error)
|
|
155
|
+
this.handleError(error as Error)
|
|
148
156
|
}
|
|
149
157
|
}
|
|
150
|
-
|
|
158
|
+
|
|
151
159
|
/**
|
|
152
160
|
* 停止扫描
|
|
153
161
|
*/
|
|
154
162
|
stop(): void {
|
|
155
|
-
if (this.scanMode ===
|
|
156
|
-
this.qrScanner.stop()
|
|
157
|
-
} else if (this.scanMode ===
|
|
158
|
-
this.barcodeScanner.stop()
|
|
159
|
-
} else if (this.scanMode ===
|
|
160
|
-
this.idDetector.stop()
|
|
163
|
+
if (this.scanMode === "qr" && this.qrScanner) {
|
|
164
|
+
this.qrScanner.stop()
|
|
165
|
+
} else if (this.scanMode === "barcode" && this.barcodeScanner) {
|
|
166
|
+
this.barcodeScanner.stop()
|
|
167
|
+
} else if (this.scanMode === "idcard" && this.idDetector) {
|
|
168
|
+
this.idDetector.stop()
|
|
161
169
|
}
|
|
162
|
-
|
|
163
|
-
this.camera.stop()
|
|
170
|
+
|
|
171
|
+
this.camera.stop()
|
|
164
172
|
}
|
|
165
|
-
|
|
173
|
+
|
|
166
174
|
/**
|
|
167
175
|
* 处理二维码扫描结果
|
|
168
176
|
*/
|
|
169
177
|
private handleQRScan(result: string): void {
|
|
170
178
|
if (this.options.onQRCodeScanned) {
|
|
171
|
-
this.options.onQRCodeScanned(result)
|
|
179
|
+
this.options.onQRCodeScanned(result)
|
|
172
180
|
}
|
|
173
181
|
}
|
|
174
|
-
|
|
182
|
+
|
|
175
183
|
/**
|
|
176
184
|
* 处理条形码扫描结果
|
|
177
185
|
*/
|
|
178
186
|
private handleBarcodeScan(result: string): void {
|
|
179
187
|
if (this.options.onBarcodeScanned) {
|
|
180
|
-
this.options.onBarcodeScanned(result)
|
|
188
|
+
this.options.onBarcodeScanned(result)
|
|
181
189
|
}
|
|
182
190
|
}
|
|
183
|
-
|
|
191
|
+
|
|
184
192
|
/**
|
|
185
193
|
* 处理身份证检测结果
|
|
186
194
|
*/
|
|
187
195
|
private async handleIDDetection(result: DetectionResult): Promise<void> {
|
|
188
|
-
if (!this.ocrProcessor || !this.dataExtractor) return
|
|
189
|
-
|
|
196
|
+
if (!this.ocrProcessor || !this.dataExtractor) return
|
|
197
|
+
|
|
190
198
|
try {
|
|
191
199
|
// 检查 imageData 是否存在
|
|
192
200
|
if (!result.imageData) {
|
|
193
|
-
this.handleError(new Error(
|
|
194
|
-
return
|
|
201
|
+
this.handleError(new Error("无效的图像数据"))
|
|
202
|
+
return
|
|
195
203
|
}
|
|
196
|
-
|
|
197
|
-
const idCardInfo = await this.ocrProcessor.processIDCard(result.imageData)
|
|
198
|
-
const extractedInfo = this.dataExtractor.extractAndValidate(idCardInfo)
|
|
199
|
-
|
|
204
|
+
|
|
205
|
+
const idCardInfo = await this.ocrProcessor.processIDCard(result.imageData)
|
|
206
|
+
const extractedInfo = this.dataExtractor.extractAndValidate(idCardInfo)
|
|
207
|
+
|
|
200
208
|
if (this.options.onIDCardScanned) {
|
|
201
|
-
this.options.onIDCardScanned(extractedInfo)
|
|
209
|
+
this.options.onIDCardScanned(extractedInfo)
|
|
202
210
|
}
|
|
203
211
|
} catch (error) {
|
|
204
|
-
this.handleError(error as Error)
|
|
212
|
+
this.handleError(error as Error)
|
|
205
213
|
}
|
|
206
214
|
}
|
|
207
|
-
|
|
215
|
+
|
|
208
216
|
/**
|
|
209
217
|
* 处理错误
|
|
210
218
|
*/
|
|
211
219
|
private handleError(error: Error): void {
|
|
212
220
|
if (this.options.onError) {
|
|
213
|
-
this.options.onError(error)
|
|
221
|
+
this.options.onError(error)
|
|
214
222
|
} else {
|
|
215
|
-
console.error(
|
|
223
|
+
console.error("IDScanner error:", error)
|
|
216
224
|
}
|
|
217
225
|
}
|
|
218
|
-
|
|
226
|
+
|
|
219
227
|
/**
|
|
220
228
|
* 释放资源
|
|
221
229
|
*/
|
|
222
230
|
async terminate(): Promise<void> {
|
|
223
|
-
this.stop()
|
|
224
|
-
|
|
231
|
+
this.stop()
|
|
232
|
+
|
|
225
233
|
if (this.ocrProcessor) {
|
|
226
|
-
await this.ocrProcessor.terminate()
|
|
227
|
-
this.ocrProcessor = null
|
|
234
|
+
await this.ocrProcessor.terminate()
|
|
235
|
+
this.ocrProcessor = null
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
this.qrScanner = null
|
|
239
|
+
this.barcodeScanner = null
|
|
240
|
+
this.idDetector = null
|
|
241
|
+
this.dataExtractor = null
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* 处理图片中的二维码
|
|
246
|
+
* @param imageSource 图片源,可以是Image元素、Canvas元素或URL字符串
|
|
247
|
+
* @returns 返回Promise,解析为扫描结果
|
|
248
|
+
*/
|
|
249
|
+
async processQRCodeImage(
|
|
250
|
+
imageSource: HTMLImageElement | HTMLCanvasElement | string
|
|
251
|
+
): Promise<string> {
|
|
252
|
+
try {
|
|
253
|
+
if (!this.qrScanner) {
|
|
254
|
+
this.qrScanner = new QRScanner({
|
|
255
|
+
...this.options.qrScannerOptions,
|
|
256
|
+
onScan: this.handleQRScan.bind(this),
|
|
257
|
+
})
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 处理不同类型的图片源
|
|
261
|
+
let imageElement: HTMLImageElement
|
|
262
|
+
if (typeof imageSource === "string") {
|
|
263
|
+
// 如果是URL字符串,创建新的Image元素并加载图片
|
|
264
|
+
imageElement = new Image()
|
|
265
|
+
imageElement.crossOrigin = "anonymous" // 处理跨域图片
|
|
266
|
+
await new Promise((resolve, reject) => {
|
|
267
|
+
imageElement.onload = resolve
|
|
268
|
+
imageElement.onerror = reject
|
|
269
|
+
imageElement.src = imageSource
|
|
270
|
+
})
|
|
271
|
+
} else if (imageSource instanceof HTMLImageElement) {
|
|
272
|
+
// 如果已经是Image元素,直接使用
|
|
273
|
+
imageElement = imageSource
|
|
274
|
+
} else if (imageSource instanceof HTMLCanvasElement) {
|
|
275
|
+
// 如果是Canvas元素,创建新的Image元素并从Canvas获取数据
|
|
276
|
+
const dataURL = imageSource.toDataURL()
|
|
277
|
+
imageElement = new Image()
|
|
278
|
+
await new Promise((resolve, reject) => {
|
|
279
|
+
imageElement.onload = resolve
|
|
280
|
+
imageElement.onerror = reject
|
|
281
|
+
imageElement.src = dataURL
|
|
282
|
+
})
|
|
283
|
+
} else {
|
|
284
|
+
throw new Error("不支持的图片源类型")
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// 创建Canvas处理图片
|
|
288
|
+
const canvas = document.createElement("canvas")
|
|
289
|
+
const ctx = canvas.getContext("2d")
|
|
290
|
+
if (!ctx) {
|
|
291
|
+
throw new Error("无法创建Canvas上下文")
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// 设置Canvas尺寸与图片相同
|
|
295
|
+
canvas.width = imageElement.naturalWidth
|
|
296
|
+
canvas.height = imageElement.naturalHeight
|
|
297
|
+
ctx.drawImage(imageElement, 0, 0)
|
|
298
|
+
|
|
299
|
+
// 获取图像数据并处理
|
|
300
|
+
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
|
|
301
|
+
return new Promise((resolve, reject) => {
|
|
302
|
+
try {
|
|
303
|
+
const result = this.qrScanner?.processImageData(imageData)
|
|
304
|
+
if (result) {
|
|
305
|
+
resolve(result)
|
|
306
|
+
} else {
|
|
307
|
+
reject(new Error("未检测到二维码"))
|
|
308
|
+
}
|
|
309
|
+
} catch (error) {
|
|
310
|
+
reject(error)
|
|
311
|
+
}
|
|
312
|
+
})
|
|
313
|
+
} catch (error) {
|
|
314
|
+
this.handleError(error as Error)
|
|
315
|
+
throw error
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* 处理图片中的条形码
|
|
321
|
+
* @param imageSource 图片源,可以是Image元素、Canvas元素或URL字符串
|
|
322
|
+
* @returns 返回Promise,解析为扫描结果
|
|
323
|
+
*/
|
|
324
|
+
async processBarcodeImage(
|
|
325
|
+
imageSource: HTMLImageElement | HTMLCanvasElement | string
|
|
326
|
+
): Promise<string> {
|
|
327
|
+
try {
|
|
328
|
+
if (!this.barcodeScanner) {
|
|
329
|
+
this.barcodeScanner = new BarcodeScanner({
|
|
330
|
+
...this.options.barcodeScannerOptions,
|
|
331
|
+
onScan: this.handleBarcodeScan.bind(this),
|
|
332
|
+
})
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// 处理不同类型的图片源
|
|
336
|
+
let imageElement: HTMLImageElement
|
|
337
|
+
if (typeof imageSource === "string") {
|
|
338
|
+
// 如果是URL字符串,创建新的Image元素并加载图片
|
|
339
|
+
imageElement = new Image()
|
|
340
|
+
imageElement.crossOrigin = "anonymous" // 处理跨域图片
|
|
341
|
+
await new Promise((resolve, reject) => {
|
|
342
|
+
imageElement.onload = resolve
|
|
343
|
+
imageElement.onerror = reject
|
|
344
|
+
imageElement.src = imageSource
|
|
345
|
+
})
|
|
346
|
+
} else if (imageSource instanceof HTMLImageElement) {
|
|
347
|
+
// 如果已经是Image元素,直接使用
|
|
348
|
+
imageElement = imageSource
|
|
349
|
+
} else if (imageSource instanceof HTMLCanvasElement) {
|
|
350
|
+
// 如果是Canvas元素,创建新的Image元素并从Canvas获取数据
|
|
351
|
+
const dataURL = imageSource.toDataURL()
|
|
352
|
+
imageElement = new Image()
|
|
353
|
+
await new Promise((resolve, reject) => {
|
|
354
|
+
imageElement.onload = resolve
|
|
355
|
+
imageElement.onerror = reject
|
|
356
|
+
imageElement.src = dataURL
|
|
357
|
+
})
|
|
358
|
+
} else {
|
|
359
|
+
throw new Error("不支持的图片源类型")
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// 创建Canvas处理图片
|
|
363
|
+
const canvas = document.createElement("canvas")
|
|
364
|
+
const ctx = canvas.getContext("2d")
|
|
365
|
+
if (!ctx) {
|
|
366
|
+
throw new Error("无法创建Canvas上下文")
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// 设置Canvas尺寸与图片相同
|
|
370
|
+
canvas.width = imageElement.naturalWidth
|
|
371
|
+
canvas.height = imageElement.naturalHeight
|
|
372
|
+
ctx.drawImage(imageElement, 0, 0)
|
|
373
|
+
|
|
374
|
+
// 获取图像数据并处理
|
|
375
|
+
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
|
|
376
|
+
return new Promise((resolve, reject) => {
|
|
377
|
+
try {
|
|
378
|
+
const result = this.barcodeScanner?.processImageData(imageData)
|
|
379
|
+
if (result) {
|
|
380
|
+
resolve(result)
|
|
381
|
+
} else {
|
|
382
|
+
reject(new Error("未检测到条形码"))
|
|
383
|
+
}
|
|
384
|
+
} catch (error) {
|
|
385
|
+
reject(error)
|
|
386
|
+
}
|
|
387
|
+
})
|
|
388
|
+
} catch (error) {
|
|
389
|
+
this.handleError(error as Error)
|
|
390
|
+
throw error
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* 处理图片中的身份证
|
|
396
|
+
* @param imageSource 图片源,可以是Image元素、Canvas元素或URL字符串
|
|
397
|
+
* @returns 返回Promise,解析为身份证信息
|
|
398
|
+
*/
|
|
399
|
+
async processIDCardImage(
|
|
400
|
+
imageSource: HTMLImageElement | HTMLCanvasElement | string
|
|
401
|
+
): Promise<IDCardInfo> {
|
|
402
|
+
try {
|
|
403
|
+
if (!this.ocrProcessor || !this.dataExtractor) {
|
|
404
|
+
await this.initialize()
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// 处理不同类型的图片源
|
|
408
|
+
let imageElement: HTMLImageElement
|
|
409
|
+
if (typeof imageSource === "string") {
|
|
410
|
+
// 如果是URL字符串,创建新的Image元素并加载图片
|
|
411
|
+
imageElement = new Image()
|
|
412
|
+
imageElement.crossOrigin = "anonymous" // 处理跨域图片
|
|
413
|
+
await new Promise((resolve, reject) => {
|
|
414
|
+
imageElement.onload = resolve
|
|
415
|
+
imageElement.onerror = reject
|
|
416
|
+
imageElement.src = imageSource
|
|
417
|
+
})
|
|
418
|
+
} else if (imageSource instanceof HTMLImageElement) {
|
|
419
|
+
// 如果已经是Image元素,直接使用
|
|
420
|
+
imageElement = imageSource
|
|
421
|
+
} else if (imageSource instanceof HTMLCanvasElement) {
|
|
422
|
+
// 如果是Canvas元素,创建新的Image元素并从Canvas获取数据
|
|
423
|
+
const dataURL = imageSource.toDataURL()
|
|
424
|
+
imageElement = new Image()
|
|
425
|
+
await new Promise((resolve, reject) => {
|
|
426
|
+
imageElement.onload = resolve
|
|
427
|
+
imageElement.onerror = reject
|
|
428
|
+
imageElement.src = dataURL
|
|
429
|
+
})
|
|
430
|
+
} else {
|
|
431
|
+
throw new Error("不支持的图片源类型")
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// 创建Canvas处理图片
|
|
435
|
+
const canvas = document.createElement("canvas")
|
|
436
|
+
const ctx = canvas.getContext("2d")
|
|
437
|
+
if (!ctx) {
|
|
438
|
+
throw new Error("无法创建Canvas上下文")
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// 设置Canvas尺寸与图片相同
|
|
442
|
+
canvas.width = imageElement.naturalWidth
|
|
443
|
+
canvas.height = imageElement.naturalHeight
|
|
444
|
+
ctx.drawImage(imageElement, 0, 0)
|
|
445
|
+
|
|
446
|
+
// 获取图像数据并处理
|
|
447
|
+
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
|
|
448
|
+
|
|
449
|
+
// 调用OCR处理器处理身份证图像
|
|
450
|
+
const ocrResult = await this.ocrProcessor!.processIDCard(imageData)
|
|
451
|
+
const extractedInfo = this.dataExtractor!.extractAndValidate(ocrResult)
|
|
452
|
+
|
|
453
|
+
if (this.options.onIDCardScanned) {
|
|
454
|
+
this.options.onIDCardScanned(extractedInfo)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return extractedInfo
|
|
458
|
+
} catch (error) {
|
|
459
|
+
this.handleError(error as Error)
|
|
460
|
+
throw error
|
|
228
461
|
}
|
|
229
|
-
|
|
230
|
-
this.qrScanner = null;
|
|
231
|
-
this.barcodeScanner = null;
|
|
232
|
-
this.idDetector = null;
|
|
233
|
-
this.dataExtractor = null;
|
|
234
462
|
}
|
|
235
463
|
}
|
|
236
464
|
|
|
237
465
|
// 导出核心类型
|
|
238
|
-
export { IDCardInfo } from
|
|
239
|
-
export { CameraOptions } from
|
|
240
|
-
export {
|
|
466
|
+
export { IDCardInfo } from "./utils/types"
|
|
467
|
+
export { CameraOptions } from "./utils/camera"
|
|
468
|
+
export {
|
|
469
|
+
QRScanner,
|
|
470
|
+
BarcodeScanner,
|
|
471
|
+
IDCardDetector,
|
|
472
|
+
OCRProcessor,
|
|
473
|
+
DataExtractor,
|
|
474
|
+
ImageProcessor,
|
|
475
|
+
}
|
|
476
|
+
// 导出IDScannerDemo类
|
|
477
|
+
export { IDScannerDemo }
|