id-scanner-lib 1.1.1 → 1.2.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/README.md +80 -0
- package/dist/id-scanner-core.esm.js +160 -0
- package/dist/id-scanner-core.esm.js.map +1 -1
- package/dist/id-scanner-core.js +160 -0
- package/dist/id-scanner-core.js.map +1 -1
- package/dist/id-scanner-core.min.js +2 -2
- package/dist/id-scanner-core.min.js.map +1 -1
- package/dist/id-scanner-ocr.esm.js +791 -78
- package/dist/id-scanner-ocr.esm.js.map +1 -1
- package/dist/id-scanner-ocr.js +790 -77
- package/dist/id-scanner-ocr.js.map +1 -1
- package/dist/id-scanner-ocr.min.js +2 -2
- package/dist/id-scanner-ocr.min.js.map +1 -1
- package/dist/id-scanner-qr.esm.js +160 -0
- package/dist/id-scanner-qr.esm.js.map +1 -1
- package/dist/id-scanner-qr.js +160 -0
- package/dist/id-scanner-qr.js.map +1 -1
- package/dist/id-scanner-qr.min.js +2 -2
- package/dist/id-scanner-qr.min.js.map +1 -1
- package/dist/id-scanner.js +790 -77
- package/dist/id-scanner.js.map +1 -1
- package/dist/id-scanner.min.js +2 -2
- package/dist/id-scanner.min.js.map +1 -1
- package/package.json +1 -1
- package/src/id-recognition/id-detector.ts +210 -65
- package/src/id-recognition/ocr-processor.ts +142 -21
- package/src/id-recognition/ocr-worker.ts +146 -0
- package/src/utils/image-processing.ts +204 -0
- package/src/utils/performance.ts +210 -0
- package/src/utils/resource-manager.ts +198 -0
- package/src/utils/worker.ts +173 -0
package/dist/id-scanner-core.js
CHANGED
|
@@ -10471,6 +10471,166 @@
|
|
|
10471
10471
|
}
|
|
10472
10472
|
return imageData;
|
|
10473
10473
|
}
|
|
10474
|
+
/**
|
|
10475
|
+
* 降低图像分辨率以提高处理速度
|
|
10476
|
+
*
|
|
10477
|
+
* 对于OCR和图像分析,降低分辨率可以在保持识别率的同时大幅提升处理速度
|
|
10478
|
+
*
|
|
10479
|
+
* @param {ImageData} imageData - 原图像数据
|
|
10480
|
+
* @param {number} [maxDimension=1000] - 目标最大尺寸(宽或高)
|
|
10481
|
+
* @returns {ImageData} 处理后的图像数据
|
|
10482
|
+
*/
|
|
10483
|
+
static downsampleForProcessing(imageData, maxDimension = 1000) {
|
|
10484
|
+
const { width, height } = imageData;
|
|
10485
|
+
// 如果图像尺寸已经小于或等于目标尺寸,则无需处理
|
|
10486
|
+
if (width <= maxDimension && height <= maxDimension) {
|
|
10487
|
+
return imageData;
|
|
10488
|
+
}
|
|
10489
|
+
// 计算缩放比例,保持宽高比
|
|
10490
|
+
const scale = maxDimension / Math.max(width, height);
|
|
10491
|
+
const newWidth = Math.round(width * scale);
|
|
10492
|
+
const newHeight = Math.round(height * scale);
|
|
10493
|
+
// 调整图像大小
|
|
10494
|
+
return this.resize(imageData, newWidth, newHeight);
|
|
10495
|
+
}
|
|
10496
|
+
/**
|
|
10497
|
+
* 转换图像为Base64格式,方便在Worker线程中传递
|
|
10498
|
+
*
|
|
10499
|
+
* @param {ImageData} imageData - 原图像数据
|
|
10500
|
+
* @returns {string} base64编码的图像数据
|
|
10501
|
+
*/
|
|
10502
|
+
static imageDataToBase64(imageData) {
|
|
10503
|
+
const canvas = this.imageDataToCanvas(imageData);
|
|
10504
|
+
return canvas.toDataURL('image/jpeg', 0.7); // 使用较低质量的JPEG格式减少数据量
|
|
10505
|
+
}
|
|
10506
|
+
/**
|
|
10507
|
+
* 从Base64字符串还原图像数据
|
|
10508
|
+
*
|
|
10509
|
+
* @param {string} base64 - base64编码的图像数据
|
|
10510
|
+
* @returns {Promise<ImageData>} 还原的图像数据
|
|
10511
|
+
*/
|
|
10512
|
+
static async base64ToImageData(base64) {
|
|
10513
|
+
return new Promise((resolve, reject) => {
|
|
10514
|
+
const img = new Image();
|
|
10515
|
+
img.onload = () => {
|
|
10516
|
+
const canvas = document.createElement('canvas');
|
|
10517
|
+
canvas.width = img.width;
|
|
10518
|
+
canvas.height = img.height;
|
|
10519
|
+
const ctx = canvas.getContext('2d');
|
|
10520
|
+
if (!ctx) {
|
|
10521
|
+
reject(new Error('无法创建Canvas上下文'));
|
|
10522
|
+
return;
|
|
10523
|
+
}
|
|
10524
|
+
ctx.drawImage(img, 0, 0);
|
|
10525
|
+
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
10526
|
+
resolve(imageData);
|
|
10527
|
+
};
|
|
10528
|
+
img.onerror = () => {
|
|
10529
|
+
reject(new Error('图像加载失败'));
|
|
10530
|
+
};
|
|
10531
|
+
img.src = base64;
|
|
10532
|
+
});
|
|
10533
|
+
}
|
|
10534
|
+
/**
|
|
10535
|
+
* 使用Web Worker并行处理图像
|
|
10536
|
+
* 此方法将图像分割为多个部分,并行处理以提高性能
|
|
10537
|
+
*
|
|
10538
|
+
* @param {ImageData} imageData - 原图像数据
|
|
10539
|
+
* @param {Function} processingFunction - 处理函数,接收ImageData返回ImageData
|
|
10540
|
+
* @param {number} [chunks=4] - 分割的块数
|
|
10541
|
+
* @returns {Promise<ImageData>} 处理后的图像数据
|
|
10542
|
+
*/
|
|
10543
|
+
static async processImageInParallel(imageData, processingFunction, chunks = 4) {
|
|
10544
|
+
// 如果不支持Worker或图像太小,直接处理
|
|
10545
|
+
if (typeof Worker === 'undefined' || imageData.width * imageData.height < 100000) {
|
|
10546
|
+
return processingFunction(imageData);
|
|
10547
|
+
}
|
|
10548
|
+
// 创建结果canvas
|
|
10549
|
+
const resultCanvas = document.createElement('canvas');
|
|
10550
|
+
resultCanvas.width = imageData.width;
|
|
10551
|
+
resultCanvas.height = imageData.height;
|
|
10552
|
+
const resultCtx = resultCanvas.getContext('2d');
|
|
10553
|
+
if (!resultCtx) {
|
|
10554
|
+
throw new Error('无法创建Canvas上下文');
|
|
10555
|
+
}
|
|
10556
|
+
// 根据图像特性确定分割方向和每块大小
|
|
10557
|
+
const isWide = imageData.width > imageData.height;
|
|
10558
|
+
const chunkSize = Math.floor((isWide ? imageData.width : imageData.height) / chunks);
|
|
10559
|
+
// 创建Worker处理每个块
|
|
10560
|
+
const promises = [];
|
|
10561
|
+
for (let i = 0; i < chunks; i++) {
|
|
10562
|
+
const chunkCanvas = document.createElement('canvas');
|
|
10563
|
+
const chunkCtx = chunkCanvas.getContext('2d');
|
|
10564
|
+
if (!chunkCtx)
|
|
10565
|
+
continue;
|
|
10566
|
+
let chunkImageData;
|
|
10567
|
+
if (isWide) {
|
|
10568
|
+
// 水平分割
|
|
10569
|
+
const startX = i * chunkSize;
|
|
10570
|
+
const width = (i === chunks - 1) ? imageData.width - startX : chunkSize;
|
|
10571
|
+
chunkCanvas.width = width;
|
|
10572
|
+
chunkCanvas.height = imageData.height;
|
|
10573
|
+
// 复制原图像数据到分块
|
|
10574
|
+
const tempCanvas = this.imageDataToCanvas(imageData);
|
|
10575
|
+
chunkCtx.drawImage(tempCanvas, startX, 0, width, imageData.height, 0, 0, width, imageData.height);
|
|
10576
|
+
chunkImageData = chunkCtx.getImageData(0, 0, width, imageData.height);
|
|
10577
|
+
}
|
|
10578
|
+
else {
|
|
10579
|
+
// 垂直分割
|
|
10580
|
+
const startY = i * chunkSize;
|
|
10581
|
+
const height = (i === chunks - 1) ? imageData.height - startY : chunkSize;
|
|
10582
|
+
chunkCanvas.width = imageData.width;
|
|
10583
|
+
chunkCanvas.height = height;
|
|
10584
|
+
// 复制原图像数据到分块
|
|
10585
|
+
const tempCanvas = this.imageDataToCanvas(imageData);
|
|
10586
|
+
chunkCtx.drawImage(tempCanvas, 0, startY, imageData.width, height, 0, 0, imageData.width, height);
|
|
10587
|
+
chunkImageData = chunkCtx.getImageData(0, 0, imageData.width, height);
|
|
10588
|
+
}
|
|
10589
|
+
// 使用Worker处理
|
|
10590
|
+
const workerCode = `
|
|
10591
|
+
self.onmessage = function(e) {
|
|
10592
|
+
const imageData = e.data.imageData;
|
|
10593
|
+
const processingFunction = ${processingFunction.toString()};
|
|
10594
|
+
const result = processingFunction(imageData);
|
|
10595
|
+
self.postMessage({ result, index: e.data.index }, [result.data.buffer]);
|
|
10596
|
+
}
|
|
10597
|
+
`;
|
|
10598
|
+
const blob = new Blob([workerCode], { type: 'application/javascript' });
|
|
10599
|
+
const workerUrl = URL.createObjectURL(blob);
|
|
10600
|
+
const worker = new Worker(workerUrl);
|
|
10601
|
+
const promise = new Promise((resolve) => {
|
|
10602
|
+
worker.onmessage = function (e) {
|
|
10603
|
+
resolve(e.data);
|
|
10604
|
+
worker.terminate();
|
|
10605
|
+
URL.revokeObjectURL(workerUrl);
|
|
10606
|
+
};
|
|
10607
|
+
// 传输数据
|
|
10608
|
+
worker.postMessage({
|
|
10609
|
+
imageData: chunkImageData,
|
|
10610
|
+
index: i
|
|
10611
|
+
}, [chunkImageData.data.buffer]);
|
|
10612
|
+
});
|
|
10613
|
+
promises.push(promise);
|
|
10614
|
+
}
|
|
10615
|
+
// 等待所有Worker完成并组合结果
|
|
10616
|
+
const results = await Promise.all(promises);
|
|
10617
|
+
// 按索引排序结果
|
|
10618
|
+
results.sort((a, b) => a.index - b.index);
|
|
10619
|
+
// 将处理后的块绘制到结果canvas
|
|
10620
|
+
for (let i = 0; i < results.length; i++) {
|
|
10621
|
+
const { result } = results[i];
|
|
10622
|
+
const tempCanvas = this.imageDataToCanvas(result);
|
|
10623
|
+
if (isWide) {
|
|
10624
|
+
const startX = i * chunkSize;
|
|
10625
|
+
resultCtx.drawImage(tempCanvas, startX, 0);
|
|
10626
|
+
}
|
|
10627
|
+
else {
|
|
10628
|
+
const startY = i * chunkSize;
|
|
10629
|
+
resultCtx.drawImage(tempCanvas, 0, startY);
|
|
10630
|
+
}
|
|
10631
|
+
}
|
|
10632
|
+
return resultCtx.getImageData(0, 0, imageData.width, imageData.height);
|
|
10633
|
+
}
|
|
10474
10634
|
}
|
|
10475
10635
|
|
|
10476
10636
|
/**
|