diff --git a/src/assets/js/qr-code.js b/src/assets/js/qr-code.js index c141e1a..21d2182 100644 --- a/src/assets/js/qr-code.js +++ b/src/assets/js/qr-code.js @@ -4,6 +4,15 @@ import { writeBarcode, } from 'zxing-wasm/full'; +/** 默认背景颜色 */ +const DEFAULT_BGC = 'transparent'; + +/** 默认前景颜色 */ +const DEFAULT_FGC = '#000000'; + +/** 模块名称 */ +const PREFIX = '[qr-code]'; + /** * @desc 二维码读取配置选项 * @type { import('zxing-wasm').ReaderOptions } @@ -25,7 +34,7 @@ const readerOptions = { const writerOptions = { ecLevel: '', format: 'QRCode', - scale: 1, + scale: 0, }; // 配置 wasm 文件路径 @@ -46,7 +55,7 @@ prepareZXingModule({ * @param {Blob} blob * @param {Callback} callback */ -export function blobToDataURL(blob, callback) { +function blobToDataURL(blob, callback) { /** @typedef {(data: { error: boolean, result: string }) => void} Callback */ @@ -70,11 +79,77 @@ export function blobToDataURL(blob, callback) { } +/** + * @description 修改 SVG 内容,获取信息 + * @param {object} options + * @param {string} options.background + * @param {string} options.foreground + * @param {string} options.svgString + */ +function modifySvgContent(options) { + + let { + background = DEFAULT_BGC, + foreground = DEFAULT_FGC, + svgString, + } = options; + + let divElement = document.createElement('div'); + let gElement = null; + let pathElement = null; + let rectElement = null; + let svgElement = null; + + // 添加 DOM 元素,用于获取位置大小信息 + document.body.appendChild(divElement); + + divElement.innerHTML = svgString; + gElement = divElement.getElementsByTagName('g')[0] || null; + pathElement = divElement.getElementsByTagName('path')[0] || null; + rectElement = divElement.getElementsByTagName('rect')[0] || null; + svgElement = divElement.getElementsByTagName('svg')[0] || null; + + if (!(gElement && pathElement && rectElement && svgElement)) { + return null; + } + + // 修改填充颜色 + gElement.setAttribute('fill', foreground); + rectElement.setAttribute('fill', background); + + // 获取位置大小信息 + let rectOfG = gElement.getBoundingClientRect(); + let rectOfPath = pathElement.getBoundingClientRect(); + + let offsetX = Math.round(rectOfPath.left - rectOfG.left); + let offsetY = Math.round(rectOfPath.top - rectOfG.top); + let sizeW = Math.round(rectOfPath.width); + let sizeH = Math.round(rectOfPath.height); + let result = { + offsetX: offsetX, + offsetY: offsetY, + sizeW: sizeW, + sizeH: sizeH, + svgString: divElement.innerHTML, + }; + + // 输出处理结果 + console.debug(PREFIX, '处理 SVG', result); + + // 处理完成,移除 DOM 元素 + document.body.removeChild(divElement); + + return result; + +} + /** * @description 将 SVG 字符串渲染到 Canvas * @param {object} options * @param {HTMLCanvasElement} options.canvas * @param {string} options.svgString + * @param {string} options.background + * @param {string} options.foreground * @param {number} options.drawLeft * @param {number} options.drawTop * @param {number} options.drawWidth @@ -85,27 +160,42 @@ function renderSvgToCanvas(options) { let { canvas, svgString, + background = DEFAULT_BGC, foreground = DEFAULT_FGC, drawLeft = 0, drawTop = 0, drawWidth = 0, drawHeight = 0, } = options; + let svgInfo = modifySvgContent({ + background: background, + foreground: foreground, + svgString: svgString, + }); + + if (!svgInfo) { + return Promise.resolve(false); + } + return new Promise((resolve) => { - let svgBlob = new Blob([svgString], { + let svgBlob = new Blob([svgInfo.svgString], { type: 'image/svg+xml;charset=utf-8', }); let svgUrl = URL.createObjectURL(svgBlob); let image = new Image(); image.onerror = () => { - console.error('加载 SVG 失败'); + console.error(PREFIX, '加载 SVG 失败'); URL.revokeObjectURL(svgUrl); resolve(false); }; image.onload = () => { let ctx = canvas.getContext('2d'); - ctx.drawImage(image, drawLeft, drawTop, drawWidth, drawHeight); + ctx.drawImage( + image, + svgInfo.offsetX, svgInfo.offsetY, svgInfo.sizeW, svgInfo.sizeH, + drawLeft, drawTop, drawWidth, drawHeight, + ); URL.revokeObjectURL(svgUrl); resolve(true); }; @@ -138,7 +228,7 @@ export function readQrCodeImage(image) { // 处理读取异常 fileReader.onerror = function () { - console.error('解析二维码失败:读取图片失败'); + console.error(PREFIX, '解析二维码失败:读取图片失败'); returns.error = '读取图片失败'; resolve(''); }; @@ -163,10 +253,10 @@ export function readQrCodeImage(image) { let textList = returns.textList; if (resultList.length === 0) { - console.warn('解析二维码失败:未识别到内容'); + console.warn(PREFIX, '解析二维码失败:未识别到内容'); return returns; } else { - console.debug('解析二维码成功:', resultList); + console.debug(PREFIX, '解析二维码成功:', resultList); } for (let i = 0; i < resultList.length; i++) { @@ -180,7 +270,7 @@ export function readQrCodeImage(image) { return returns; }).catch((error) => { - console.error('解析二维码失败:'); + console.error(PREFIX, '解析二维码失败:'); console.error(error); returns.error = String(error); return returns; @@ -192,13 +282,19 @@ export function readQrCodeImage(image) { * @description 生成二维码图片 * @param {object} options * @param {string} options.content + * @param {string} options.background + * @param {string} options.foreground * @param {number} options.width * @param {number} options.height * @returns 二维码图片 DataURL */ export function writeQrCodeImage(options = {}) { - let { content = '', width = 256, height = 256 } = options; + let { + content = '', + background = DEFAULT_BGC, foreground = DEFAULT_FGC, + width = 256, height = 256, + } = options; let canvas = document.createElement('canvas'); let ctx = canvas.getContext('2d'); @@ -208,15 +304,15 @@ export function writeQrCodeImage(options = {}) { canvas.height = height; // 设置背景颜色 - ctx.fillStyle = '#FFFFFF'; + ctx.fillStyle = background; ctx.fillRect(0, 0, width, height); return writeBarcode(content, writerOptions).then((result) => { - console.debug('生成二维码', result); + console.debug(PREFIX, '生成二维码', result); if (result.error) { - console.error(`生成二维码失败:${result.error}`); + console.error(PREFIX, `生成二维码失败:${result.error}`); return ''; } else { return result.svg; @@ -227,6 +323,8 @@ export function writeQrCodeImage(options = {}) { return renderSvgToCanvas({ canvas: canvas, svgString: svgString, + background: background, + foreground: foreground, drawLeft: 0, drawTop: 0, drawWidth: width, @@ -244,7 +342,7 @@ export function writeQrCodeImage(options = {}) { } }).catch((error) => { - console.error('生成二维码失败:'); + console.error(PREFIX, '生成二维码失败:'); console.error(error); return ''; }); diff --git a/src/views/ToolboxView/Conversion/QrcodeReaderAndGenerator.vue b/src/views/ToolboxView/Conversion/QrcodeReaderAndGenerator.vue index 87325ce..31cd37a 100644 --- a/src/views/ToolboxView/Conversion/QrcodeReaderAndGenerator.vue +++ b/src/views/ToolboxView/Conversion/QrcodeReaderAndGenerator.vue @@ -3,6 +3,14 @@ + - + + + > + + + + + + + + + px + + + + + + 前景颜色: + + 背景颜色: + + + + + +
+
+ +
+
+
+ +
@@ -72,9 +161,9 @@