You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Safari 15环境下Canvas toDataURL将SVG转图片时输出异常

Safari 15 SVG转PNG异常解决方案

问题根因

你遇到的兼容性问题核心来自两个Safari的布局特性差异:

  • 未显式设置width/height属性、仅靠viewBox和百分比样式定义尺寸的SVG,加载到<img>标签后,Safari计算的clientWidth/clientHeight和Chrome逻辑不一致,大概率会拿到0或者不符合预期的数值,直接用于设置canvas宽高就会导致绘制内容截断/空白。
  • 临时创建的SVG加载用<img>插入到DOM后,会受页面全局样式影响,进一步放大不同浏览器的尺寸计算差异。

修复方案

直接解析SVG的viewBox属性获取原始宽高,完全不依赖DOM布局计算的尺寸值,同时避免将临时元素插入DOM,从根源消除兼容性差异。
修复后的代码如下:

const base64Image = 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjkyLjk3NzUyODA4OTg4NzY0IDEyOSAzNzQuMDQ0OTQzODIwMjI0NyAxMTAiIGNsYXNzPSJQU1BERktpdC04czFzYmM1MTN0MzRxMzg4OTViNGJoM2p2biIgZm9jdXNhYmxlPSJmYWxzZSIgZGF0YS10ZXN0aWQ9Imluay1zdmciIHN0eWxlPSJsZWZ0OiAwcHg7IHRvcDogMHB4OyB3aWR0aDogMTAwJTsgaGVpZ2h0OiAxMDAlOyBvcGFjaXR5OiAxOyBvdmVyZmxvdzogaGlkZGVuOyI+PHJlY3QgeD0iOTcuOTc3NTI4MDg5ODg3NjQiIHk9IjEzNCIgd2lkdGg9IjM2NC4wNDQ5NDM4MjAyMjQ3IiBoZWlnaHQ9IjEwMCIgY2xhc3M9IlBTUERGS2l0LTc4NzFyZmh5eGI3cGRta3MxbjN4N2F2dnRhIiBzdHlsZT0iZmlsbDogdHJhbnNwYXJlbnQ7Ii8+PGcgc3R5bGU9ImZpbGw6IHRyYW5zcGFyZW50OyI+PGc+PHBhdGggY2xhc3M9IlBTUERGS2l0LTQ3cjV6eHB0eWtoanFwenFkdWU5YWNwaHR6IFBTUERGS2l0LTQ0OG5jcjVtdWhycGM4cDh5dmFkeTUxZW1jIFBTUERGS2l0LVNtb290aC1MaW5lcyIgZD0iTSAyMTIuNzYzODUwODAyMDQ4MiwxNjYuMDQwNTk0NDE4MjY3NDYgQyAxODMuNiwxNjAuNyAxNTQuNSwxNTUuNCAxMzUuNiwxNTIuMyBDIDExNi43LDE0OS4xIDEwNy45LDE0OC4yIDEwNC4wLDE0OS45IEMgMTAwLjIsMTUxLjUgMTAxLjEsMTU1LjkgMTAzLjMsMTYwLjcgQyAxMDUuNSwxNjUuNiAxMDguOSwxNzAuOSAxMTYuNCwxNzYuMiBDIDEyMy45LDE4MS41IDEzNS42LDE4Ni44IDE0Mi45LDE4Ny4xIEMgMTUwLjIsMTg3LjMgMTUzLjEsMTgyLjUgMTU1LjUsMTc3LjYgQyAxNTcuOSwxNzIuOCAxNTkuOSwxNjguMCAxNjEuMSwxNjUuMyBDIDE2Mi4zLDE2Mi43IDE2Mi44LDE2Mi4yIDE2NS43LDE2NS44IEMgMTY4LjYsMTY5LjQgMTczLjksMTc3LjIgMTgwLjcsMTg1LjQgQyAxODcuNSwxOTMuNiAxOTUuOCwyMDIuMyAyMDIuMSwyMDcuNiBDIDIwOC40LDIxMi45IDIxMi44LDIxNC45IDIxOC4zLDIxNS42IEMgMjIzLjksMjE2LjMgMjMwLjcsMjE1LjggMjM1LjYsMjEyLjkgQyAyNDAuNCwyMTAuMCAyNDMuMywyMDQuNyAyNDYuMywxOTcuMiBDIDI0OS4yLDE4OS43IDI1Mi4xLDE4MC4xIDI1My41LDE3NS4wIEMgMjU1LjAsMTY5LjkgMjU1LjAsMTY5LjQgMjU1LjIsMTY5LjIgQyAyNTUuNSwxNjguOSAyNTYuMCwxNjguOSAyNTYuOSwxNjkuNCBDIDI1Ny45LDE2OS45IDI1OS40LDE3MC45IDI2MS41LDE7MS44IEMgMjYzLjcsMTcyLjggMjY2LjYsMTczLjggMjY5LjgsMTc0LjMgQyAyNzIuOSwxNzQuNyAyNzYuMywxNzQuNyAyNzkuMywxNzQuMCBDIDI4Mi4yLDE3My4zIDI4NC42LDE3MS44IDI4Ni41LDE2OS45IEMgMjg4LjUsMTY4LjAgMjg5LjksMTY1LjYgMjkwLjksMTYxLjIgQyAyOTEuOSwxNTYuOSAyOTIuNCwxNTAuNiAyOTAuMiwxNDYuMCBDIDI4OC4wLDE0MS40IDI4My4xLDEzOC41IDI3Ny44LDEzNy4wIEMgMjcyLjUsMTM1LjYgMjY2LjYsMTM1LjYgMjYzLjUsMTM1LjYgQyAyNjAuMywxMzUuNiAyNTkuOCwxMzUuNiAyNTkuNCwxMzYuMSBDIDI1OC45LDEzNi42IDI1OC40LDEzNy41IDI2MS4zLDE0MC45IEMgMjY0LjIsMTQ0LjMgMjcwLjUsMTUwLjEgMjgzLjksMTU2LjEgQyAyOTcuMiwxNjIuMiAzMTcuNiwxNjguNSAzMjkuNSwxNzEuNiBDIDM0MS40LDE3NC43IDM0NC44LDE3NC43IDM1MC44LDE3NC4zIEMgMzU2LjksMTczLjggMzY1LjcsMTcyLjggMzcwLjMsMTcyLjEgQyAzNzQuOSwxNzEuNCAzNzUuNCwxNzAuOSAzNzUuNiwxNzIuMyBDIDM3NS44LDE3My44IDM3NS44LDE3Ny4yIDM3NS44LDE4Mi43IEMgMzc1LjgsMTg4LjMgMzc1LjgsMTk2LjAgMzc1LjYsMjAzLjUgQyAzNzUuNCwyMTEuMCAzNzQuOSwyMTguMiAzNzQuOSwyMjMuMSBDIDM3NC45LDIyNy45IDM3NS40LDIzMC4zIDM3OS43LDIzMS41IEMgMzg0LjEsMjMyLjcgMzkyLjMsMjMyLjcgNDAwLjYsMjMyLjIgQyA0MDguOCwyMzEuOCA0MTcuMSwyMzAuOCA0MjUuNiwyMjkuNiBDIDQzNC4xLDIyOC40IDQ0Mi44LDIyNi45IDQ0OC42LDIyNi4wIEMgNDU0LjUsMjI1LjAgNDU3LjQsMjI0LjUgNDYwLjMsMjI0LjAiIGRhdGEtdGVzdGlkPSJpbmstcGF0aCIgc3R5bGU9InN0cm9rZTogcmdiKDAsIDAsIDApOyBzdHJva2Utd2lkdGg6IDRweDsgcG9pbnRlci1ldmVudHM6IG5vbmU7Ii8+PHBhdGggY2xhc3M9IlBTUERGS2l0LTQ3cjV6eHB0eWtoanFwenFkdWU5YWNwaHR6IFBTUERGS2l0LTQ0OG5jcjVtdWhycGM4cDh5dmFkeTUxZW1jIFBTUERGS2l0LVNtb290aC1MaW5lcyIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZD0iTSAyMTIuNzYzODUwODAyMDQ4MiwxNjYuMDQwNTk0NDE4MjY3NDYgQyAxODMuNiwxNjAuNyAxNTQuNSwxNTUuNCAxMzUuNiwxNTIuMyBDIDExNi43LDE0OS4xIDEwNy45LDE0OC4yIDEwNC4wLDE0OS45IEMgMTAwLjIsMTUxLjUgMTAxLjEsMTU1LjkgMTAzLjMsMTYwLjcgQyAxMDUuNSwxNjUuNiAxMDguOSwxNzAuOSAxMTYuNCwxNzYuMiBDIDEyMy45LDE4MS41IDEzNS42LDE4Ni44IDE0Mi45LDE4Ny4xIEMgMTUwLjIsMTg3LjMgMTUzLjEsMTgyLjUgMTU1LjUsMTc3LjYgQyAxNTcuOSwxNzIuOCAxNTkuOSwxNjguMCAxNjEuMSwxNjUuMyBDIDE2Mi4zLDE2Mi43IDE2Mi44LDE2Mi4yIDE2NS43LDE2NS44IEMgMTY4LjYsMTY5LjQgMTczLjksMTc3LjIgMTgwLjcsMTg1LjQgQyAxODcuNSwxOTMuNiAxOTUuOCwyMDIuMyAyMDIuMSwyMDcuNiBDIDIwOC40LDIxMi45IDIxMi44LDIxNC45IDIxOC4zLDIxNS42IEMgMjIzLjksMjE2LjMgMjMwLjcsMjE1LjggMjM1LjYsMjEyLjkgQyAyNDAuNCwyMTAuMCAyNDMuMywyMDQuNyAyNDYuMywxOTcuMiBDIDI0OS4yLDE4OS43IDI1Mi4xLDE4MC4xIDI1My41LDE3NS4wIEMgMjU1LjAsMTY5LjkgMjU1LjAsMTY5LjQgMjU1LjIsMTY5LjIgQyAyNTUuNSwxNjguOSAyNTYuMCwxNjguOSAyNTYuOSwxNjkuNCBDIDI1Ny45LDE2OS45IDI1OS40LDE3MC45IDI2MS41LDE3MS44IEMgMjYzLjcsMTcyLjggMjY2LjYsMTczLjggMjY5LjgsMTc0LjMgQyAyNzIuOSwxNzQuNyAyNzYuMywxNzQuNyAyNzkuMywxNzQuMCBDIDI4Mi4yLDE3My4zIDI4NC42LDE7MS44IDI4Ni41LDE2OS45IEMgMjg4LjUsMTY4LjAgMjg5LjksMTY1LjYgMjkwLjksMTYxLjIgQyAyOTEuOSwxNTYuOSAyOTIuNCwxNTAuNiAyOTAuMiwxNDYuMCBDIDI4OC4wLDE0MS40IDI4My4xLDEzOC41IDI3Ny44LDEzNy4wIEMgMjcyLjUsMTM1LjYgMjY2LjYsMTM1LjYgMjYzLjUsMTM1LjYgQyAyNjAuMywxMzUuNiAyNTkuOCwxMzUuNiAyNTkuNCwxMzYuMSBDIDI1OC45LDEzNi42IDI1OC40LDEzNy41IDI2MS4zLDE0MC45IEMgMjY0LjIsMTQ0LjMgMjcwLjUsMTUwLjEgMjgzLjksMTU2LjEgQyAyOTcuMiwxNjIuMiAzMTcuNiwxNjguNSAzMjkuNSwxNzEuNiBDIDM0MS40LDE3NC43IDM0NC44LDE3NC43IDM1MC44LDE3NC4zIEMgMzU2LjksMTczLjggMzY1LjcsMTcyLjggMzcwLjMsMTcyLjEgQyAzNzQuOSwxNzEuNCAzNzUuNCwxNzAuOSAzNzUuNiwxNzIuMyBDIDM3NS44LDE3My44IDM3NS44LDE3Ny4yIDM3NS44LDE4Mi43IEMgMzc1LjgsMTg4LjMgMzc1LjgsMTk2LjAgMzc1LjYsMjAzLjUgQyAzNzUuNCwyMTEuMCAzNzQuOSwyMTguMiAzNzQuOSwyMjMuMSBDIDM3NC45LDIyNy45IDM3NS40LDIzMC4zIDM3OS43LDIzMS41IEMgMzg0LjEsMjMyLjcgMzkyLjMsMjMyLjcgNDAwLjYsMjMyLjIgQyA0MDguOCwyMzEuOCA0MTcuMSwyMzAuOCA0MjUuNiwyMjkuNiBDIDQzNC4xLDIyOC40IDQ0Mi44LDIyNi45IDQ0OC42LDIyNi4wIEMgNDU0LjUsMjI1LjAgNDU3LjQsMjI0LjUgNDYwLjMsMjI0LjAiIGRhdGEtdGVzdGlkPSJjbGlja2FibGUtcGF0aCIgc3R5bGU9InN0cm9rZS13aWR0aDogNXB4OyIvPjwvZz48L2c+PC9zdmc+';

// 解析SVG的viewBox获取原始宽高
function getSvgViewBoxSize(svgStr) {
  const parser = new DOMParser();
  const svgDoc = parser.parseFromString(svgStr, 'image/svg+xml');
  const svgEl = svgDoc.documentElement;
  const viewBox = svgEl.viewBox.baseVal;
  return {
    width: viewBox.width,
    height: viewBox.height
  };
}

const svg = window.atob(base64Image);
const svgSize = getSvgViewBoxSize(svg);

svgToPng(svg, svgSize, (imgData) => {
  const pngImage = document.createElement('img');
  document.body.appendChild(pngImage);
  pngImage.src = imgData;
});

function svgToPng(svg, size, callback) {
  const url = getSvgUrl(svg);
  svgUrlToPng(url, size, (imgData) => {
    callback(imgData);
    URL.revokeObjectURL(url);
  });
}

function getSvgUrl(svg) {
  return URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' }));
}

function svgUrlToPng(svgUrl, size, callback) {
  const svgImage = new Image();
  // 不要插入到DOM,避免样式干扰
  svgImage.onload = function () {
    const canvas = document.createElement('canvas');
    // 直接用viewBox的宽高,不依赖clientWidth/clientHeight
    canvas.width = size.width;
    canvas.height = size.height;
    const canvasCtx = canvas.getContext('2d');
    canvasCtx.drawImage(svgImage, 0, 0, size.width, size.height);
    const imgData = canvas.toDataURL('image/png');
    callback(imgData);
    // 清理临时img对象
    svgImage.src = '';
  };
  svgImage.src = svgUrl;
}

额外注意点

你提供的SVG代码中第二个path的d属性存在语法错误,包含无效字符,建议先修正SVG源文件的语法问题,避免不同浏览器的容错逻辑差异导致渲染结果不一致。


内容的提问来源于stack exchange,提问作者pritesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 15:00:00