feat(工具箱/二维码解析和生成): 优化解析功能,在二维码所在位置添加矩形标记
This commit is contained in:
@@ -51,31 +51,49 @@ prepareZXingModule({
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 转换 Blob 为 DataURL
|
* @description 在图片上绘制矩形,返回 DataURL
|
||||||
* @param {Blob} blob
|
* @param {Blob} blob 图片二进制
|
||||||
* @param {Callback} callback
|
* @param {Rect[]} rects 矩形位置信息列表
|
||||||
*/
|
*/
|
||||||
function blobToDataURL(blob, callback) {
|
function drawRectsOnImage(blob, rects) {
|
||||||
|
|
||||||
/** @typedef {(data: { error: boolean, result: string }) => void} Callback */
|
/** @typedef {{ x: number; y: number; w: number; h: number }} Rect */
|
||||||
|
|
||||||
let reader = new FileReader();
|
let canvas = document.createElement('canvas');
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
return renderImageToCanvas(blob, canvas).then((success) => {
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
rects.forEach((rect, index) => {
|
||||||
|
|
||||||
|
let { x, y, w, h } = rect;
|
||||||
|
|
||||||
|
let text = String(index + 1);
|
||||||
|
|
||||||
|
// 绘制矩形
|
||||||
|
ctx.fillStyle = 'rgba(0, 255, 0, 0.25)';
|
||||||
|
ctx.lineWidth = 4;
|
||||||
|
ctx.strokeStyle = 'rgba(0, 255, 0, 1)';
|
||||||
|
ctx.fillRect(x, y, w, h);
|
||||||
|
ctx.strokeRect(x, y, w, h);
|
||||||
|
|
||||||
|
// 绘制文本
|
||||||
|
ctx.font = `bold ${Math.round(w / 2)}px sans-serif`;
|
||||||
|
ctx.fillStyle = 'rgba(255, 255, 255, 1)';
|
||||||
|
ctx.lineWidth = Number((w / 100).toFixed(4));
|
||||||
|
ctx.strokeStyle = 'rgba(0, 0, 0, 1)';
|
||||||
|
ctx.fillText(text, x, y + h);
|
||||||
|
ctx.strokeText(text, x, y + h);
|
||||||
|
|
||||||
reader.onerror = function () {
|
|
||||||
callback({
|
|
||||||
error: true,
|
|
||||||
result: reader.result,
|
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
reader.onload = function () {
|
return canvas.toDataURL('image/png');
|
||||||
callback({
|
|
||||||
error: false,
|
|
||||||
result: reader.result,
|
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
reader.readAsDataURL(blob);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +161,54 @@ function modifySvgContent(options) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将图片 Blob 渲染到 Canvas
|
||||||
|
* @param {Blob} blob
|
||||||
|
* @param {HTMLCanvasElement} canvas
|
||||||
|
* @returns {Promise<boolean>}
|
||||||
|
*/
|
||||||
|
function renderImageToCanvas(blob, canvas) {
|
||||||
|
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
if (window.createImageBitmap) {
|
||||||
|
return createImageBitmap(blob).then((bitmap) => {
|
||||||
|
canvas.width = bitmap.width;
|
||||||
|
canvas.height = bitmap.height;
|
||||||
|
ctx.drawImage(bitmap, 0, 0);
|
||||||
|
return true;
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error('渲染图片失败:');
|
||||||
|
console.error(error);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
|
||||||
|
let image = new Image();
|
||||||
|
let url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
image.onload = () => {
|
||||||
|
canvas.width = image.naturalWidth;
|
||||||
|
canvas.height = image.naturalHeight;
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
ctx.drawImage(image, 0, 0);
|
||||||
|
resolve(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
image.onerror = () => {
|
||||||
|
console.error(PREFIX, '渲染图片失败:加载图片失败');
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
resolve(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
image.src = url;
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 将 SVG 字符串渲染到 Canvas
|
* @description 将 SVG 字符串渲染到 Canvas
|
||||||
* @param {object} options
|
* @param {object} options
|
||||||
@@ -177,11 +243,12 @@ function renderSvgToCanvas(options) {
|
|||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
|
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
let image = new Image();
|
||||||
let svgBlob = new Blob([svgInfo.svgString], {
|
let svgBlob = new Blob([svgInfo.svgString], {
|
||||||
type: 'image/svg+xml;charset=utf-8',
|
type: 'image/svg+xml;charset=utf-8',
|
||||||
});
|
});
|
||||||
let svgUrl = URL.createObjectURL(svgBlob);
|
let svgUrl = URL.createObjectURL(svgBlob);
|
||||||
let image = new Image();
|
|
||||||
|
|
||||||
image.onerror = () => {
|
image.onerror = () => {
|
||||||
console.error(PREFIX, '加载 SVG 失败');
|
console.error(PREFIX, '加载 SVG 失败');
|
||||||
@@ -190,7 +257,6 @@ function renderSvgToCanvas(options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
image.onload = () => {
|
image.onload = () => {
|
||||||
let ctx = canvas.getContext('2d');
|
|
||||||
ctx.drawImage(
|
ctx.drawImage(
|
||||||
image,
|
image,
|
||||||
svgInfo.offsetX, svgInfo.offsetY, svgInfo.sizeW, svgInfo.sizeH,
|
svgInfo.offsetX, svgInfo.offsetY, svgInfo.sizeW, svgInfo.sizeH,
|
||||||
@@ -207,74 +273,70 @@ function renderSvgToCanvas(options) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 解析二维码图片
|
* @description 解析二维码图片
|
||||||
* @param {Blob} image 图片二进制
|
* @param {Blob} blob 图片二进制
|
||||||
*/
|
*/
|
||||||
export function readQrCodeImage(image) {
|
export function readQrCodeImage(blob) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc 返回结果
|
* @desc 返回结果
|
||||||
* @type {{ error: string; image: string; textList: string[]; }}
|
* @type {{ error: string; image: string; textList: string[]; }}
|
||||||
*/
|
*/
|
||||||
let returns = {
|
let result = {
|
||||||
error: '',
|
error: '',
|
||||||
image: '',
|
image: '',
|
||||||
textList: [],
|
textList: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 读取图片,转换为 DataURL */
|
return readBarcodes(blob, readerOptions).then((codeList) => {
|
||||||
let fileReader = new FileReader();
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
let rectList = [];
|
||||||
|
let textList = result.textList;
|
||||||
|
|
||||||
// 处理读取异常
|
if (codeList.length === 0) {
|
||||||
fileReader.onerror = function () {
|
|
||||||
console.error(PREFIX, '解析二维码失败:读取图片失败');
|
|
||||||
returns.error = '读取图片失败';
|
|
||||||
resolve('');
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理读取完成
|
|
||||||
fileReader.onload = function () {
|
|
||||||
resolve(fileReader.result);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 开始读取
|
|
||||||
fileReader.readAsDataURL(image);
|
|
||||||
|
|
||||||
}).then((dataURL) => {
|
|
||||||
if (dataURL) {
|
|
||||||
returns.image = dataURL;
|
|
||||||
return readBarcodes(image, readerOptions);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).then((resultList) => {
|
|
||||||
|
|
||||||
let textList = returns.textList;
|
|
||||||
|
|
||||||
if (resultList.length === 0) {
|
|
||||||
console.warn(PREFIX, '解析二维码失败:未识别到内容');
|
console.warn(PREFIX, '解析二维码失败:未识别到内容');
|
||||||
return returns;
|
|
||||||
} else {
|
} else {
|
||||||
console.debug(PREFIX, '解析二维码成功:', resultList);
|
console.debug(PREFIX, '解析二维码成功:', codeList);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < resultList.length; i++) {
|
for (let i = 0; i < codeList.length; i++) {
|
||||||
|
|
||||||
let item = resultList[i];
|
let item = codeList[i];
|
||||||
|
let position = item.position;
|
||||||
|
let posX0 = position.topLeft.x;
|
||||||
|
let posX1 = position.bottomRight.x;
|
||||||
|
let posY0 = position.topLeft.y;
|
||||||
|
let posY1 = position.bottomRight.y;
|
||||||
|
|
||||||
|
// 记录二维码坐标
|
||||||
|
rectList.push({
|
||||||
|
x: posX0,
|
||||||
|
y: posY0,
|
||||||
|
w: posX1 - posX0,
|
||||||
|
h: posY1 - posY0,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 记录二维码文本
|
||||||
textList.push(item.text);
|
textList.push(item.text);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return returns;
|
// 框选二维码区域
|
||||||
|
return drawRectsOnImage(blob, rectList);
|
||||||
|
|
||||||
|
}).then((dataURL) => {
|
||||||
|
|
||||||
|
if (dataURL) {
|
||||||
|
result.image = dataURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.error(PREFIX, '解析二维码失败:');
|
console.error(PREFIX, '解析二维码失败:');
|
||||||
console.error(error);
|
console.error(error);
|
||||||
returns.error = String(error);
|
result.error = String(error);
|
||||||
return returns;
|
return result;
|
||||||
});;
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -50,7 +50,7 @@
|
|||||||
object-fit="contain"
|
object-fit="contain"
|
||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
:preview-disabled="true"
|
:preview-disabled="false"
|
||||||
:src="readerData.dataURL"
|
:src="readerData.dataURL"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user