Svelte构建后Canvas绘制SVG导出图片出现破损问题
问题解决:Svelte Build后SVG转图片出现中心破损伪影
可能原因
- Build工具优化后,SVG丢失了
xmlns命名空间,导致XMLSerializer生成的SVG在非Safari浏览器中无法正确解析渲染 - Blob URL的编码处理在部分浏览器中存在兼容性问题
- SVG加载和Canvas绘制的时机未完全同步,导致渲染不完整
解决方案
方案1:手动添加SVG命名空间
Build过程中部分工具会自动移除SVG的xmlns属性,这会导致非Safari浏览器无法正确识别SVG结构。在序列化SVG时手动补充该属性:
const downloadAsJpeg = () => { if (!qrSvg) return; const canvas = document.createElement('canvas'); canvas.width = 1000; canvas.height = 1000; const ctx = canvas.getContext('2d'); if (ctx) { ctx.fillStyle = 'white'; ctx.fillRect(0, 0, canvas.width, canvas.height); let svgString = new XMLSerializer().serializeToString(qrSvg); // 检查并添加xmlns命名空间 if (!qrSvg.hasAttribute('xmlns')) { svgString = svgString.replace('<svg', '<svg xmlns="http://www.w3.org/2000/svg"'); } const svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' }); const svgUrl = URL.createObjectURL(svgBlob); const img = new Image(); img.onload = () => { ctx.drawImage(img, 0, 0, canvas.width, canvas.height); const logo = new Image(); logo.onload = () => { const logoSize = 250; const logoX = (canvas.width - logoSize) / 2; const logoY = (canvas.height - logoSize) / 2; ctx.drawImage(logo, logoX, logoY, logoSize, logoSize); const jpegDataUrl = canvas.toDataURL('image/jpeg', 0.9); const link = document.createElement('a'); link.href = jpegDataUrl; link.download = `just-type-${scanToChatPhoneNumber}.jpeg`; link.click(); URL.revokeObjectURL(svgUrl); }; logo.src = logoLight; }; img.src = svgUrl; } else { console.error('Failed to get 2d context from canvas.'); } };
方案2:改用SVG Data URL替代Blob URL
部分浏览器对Blob URL加载SVG的兼容性较差,直接使用base64编码的Data URL可以避免该问题:
const downloadAsJpeg = () => { if (!qrSvg) return; const canvas = document.createElement('canvas'); canvas.width = 1000; canvas.height = 1000; const ctx = canvas.getContext('2d'); if (ctx) { ctx.fillStyle = 'white'; ctx.fillRect(0, 0, canvas.width, canvas.height); let svgString = new XMLSerializer().serializeToString(qrSvg); if (!qrSvg.hasAttribute('xmlns')) { svgString = svgString.replace('<svg', '<svg xmlns="http://www.w3.org/2000/svg"'); } // 转为Data URL const svgDataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`; const img = new Image(); img.onload = () => { ctx.drawImage(img, 0, 0, canvas.width, canvas.height); const logo = new Image(); logo.onload = () => { const logoSize = 250; const logoX = (canvas.width - logoSize) / 2; const logoY = (canvas.height - logoSize) / 2; ctx.drawImage(logo, logoX, logoY, logoSize, logoSize); const jpegDataUrl = canvas.toDataURL('image/jpeg', 0.9); const link = document.createElement('a'); link.href = jpegDataUrl; link.download = `just-type-${scanToChatPhoneNumber}.jpeg`; link.click(); }; logo.src = logoLight; }; img.src = svgDataUrl; } else { console.error('Failed to get 2d context from canvas.'); } };
方案3:调整Build工具的SVG优化配置
如果使用Vite/Rollup等构建工具,检查SVG插件的优化设置,禁止移除xmlns属性或过度压缩SVG:
以Vite为例,修改vite.config.js:
import { sveltekit } from '@sveltejs/kit/vite'; import svg from '@poppanator/sveltekit-svg'; export default { plugins: [ sveltekit(), svg({ // 保留xmlns属性 preserveAttributes: ['xmlns'], // 禁用不必要的压缩优化 optimize: false }) ] };
内容的提问来源于stack exchange,提问作者Zulfiqar Laili
相关产品推荐
相关产品推荐

