浏览器使用Canvas API转SVG为PNG时Safari嵌入式图片随机空白问题
问题原因
- Safari加载包含内嵌资源的SVG时,
load事件触发时机早于内部内嵌base64图片的解码完成时间,此时直接绘制SVG到canvas,就会出现内嵌图片区域空白的问题,随机性来自于不同场景下图片解码速度的差异 - 部分版本Safari对SVG的
xlink:href属性支持不稳定,该属性已被SVG标准废弃,推荐使用标准href属性替代
解决方案
- 预处理SVG字符串,为所有
<image>标签同时补充href属性,值和xlink:href完全一致 - 调整SVG加载逻辑,触发
onload后额外等待一到两个浏览器渲染帧,确保内部资源完全解码后再执行绘制操作 - 绘制完成后及时释放创建的Blob URL避免内存泄漏
修改后可兼容Safari的参考代码如下:
let canvas = document.createElement('canvas') let ctx = canvas.getContext('2d') canvas.width = width canvas.height = height ctx.fillStyle = 'white' ctx.fillRect(0, 0, width, height) // 预处理SVG:给image标签补充标准href属性 const processedSvg = rawSvgString.replace(/<image([^>]+)xlink:href="([^"]+)"([^>]*)>/g, '<image$1xlink:href="$2" href="$2"$3>') let img = new Image() let svgBlob = new Blob([processedSvg], { type: 'image/svg+xml' }) let svgUrl = URL.createObjectURL(svgBlob) img.onload = function () { // 等待2个渲染帧确保Safari完成内部资源解码 requestAnimationFrame(() => { requestAnimationFrame(() => { ctx.drawImage(img, 0, 0, width, height, padding, 0, width, height) canvas.toBlob((blob) => { saveAs(blob, 'image.png') // 释放占用的内存 URL.revokeObjectURL(svgUrl) }) }) }) } img.src = svgUrl
如果仍有偶现空白问题,可将Blob URL替换为base64格式的Data URL进一步提升兼容性:
把img.src = svgUrl替换为img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(processedSvg)即可。
内容的提问来源于stack exchange,提问作者Ivan Bacher
相关产品推荐
相关产品推荐

