如何将内联 svg(在 DOM 中)绘制到画布上?

IT技术 javascript html canvas svg png
2021-02-06 14:05:57

好吧,我需要一些关于将 .svg 文件/图像转换为 .png 文件/图像的帮助...

我的页面上显示了 .svg 图像。它保存在我的服务器上(作为 .png 文件)。我需要根据需要将其转换为 .png 文件(单击按钮)并将 .png 文件保存在服务器上(我将使用 .ajax 请求执行此操作)。

但问题是转换。

我阅读了很多关于 html5 Canvas 的内容,这可能有助于做我现在需要做的事情,但我找不到任何明确的问题解决方案,而且,我不明白我发现的一切......所以我需要一些关于我必须做的方式的明确建议/帮助。

这是“html idea”模板:

<html>
    <body>
        <svg id="mySvg" width="300px" height="300px">
            <!-- my svg data -->
        </svg>
        <label id="button">Click to convert</label>
        <canvas id="myCanvas"></canvas>
    </body>
</html>

和一些js:

<script>
    $("body").on("click","#button",function(){
        var svgText = $("#myViewer").outerHTML;
        var myCanvas = document.getElementById("canvas");
        var ctxt = myCanvas.getContext("2d");
    });
</script>

然后,我需要将 svg 绘制到 Canvas 中,取回 base64 数据,并将其保存在我服务器上的 .png 文件中......但是......如何?我读了很多不同的解决方案,我实际上......迷路了......我正在研究一个jsfiddle,但我实际上......无处...... http://jsfiddle.net/xfh7nctk/6 / ...感谢阅读/帮助

2个回答

对于内联 SVG,您需要:

  • 将 SVG 字符串转换为 Blob
  • 获取 Blob 的 URL
  • 创建一个图像元素并将 URL 设置为 src
  • 加载 ( onload) 后,您可以将 SVG 绘制为画布上的图像
  • 用于toDataURL()从画布中获取 PNG 文件。

例如:

function drawInlineSVG(ctx, rawSVG, callback) {

    var svg = new Blob([rawSVG], {type:"image/svg+xml;charset=utf-8"}),
        domURL = self.URL || self.webkitURL || self,
        url = domURL.createObjectURL(svg),
        img = new Image;

    img.onload = function () {
        ctx.drawImage(this, 0, 0);     
        domURL.revokeObjectURL(url);
        callback(this);
    };

    img.src = url;
}

// usage:
drawInlineSVG(ctxt, svgText, function() {
    console.log(canvas.toDataURL());  // -> PNG data-uri
});

当然,这里的console.log 只是举例。在这里存储/传输字符串。(我还建议onerror在方法中添加一个处理程序)。

还要记住使用widthheight属性设置画布大小,或使用属性从 JavaScript 设置。

语法的含义是 self.URL || self.webkitURL || self 什么,你能解释一下表达式的作用吗?
2021-03-16 14:05:57
@ K3N你如何获得canvasconsole.log(canvas.toDataURL());
2021-03-21 14:05:57
这在这里和 JSFiddle 上都很完美....但是当我尝试在我的项目中使用它时,它看起来像绘图功能不起作用......
2021-03-22 14:05:57
这个答案的问题是只有一部分 ger=nerated 图像似乎转换为 png 图像,而不是整个 svg 图像转换
2021-03-27 14:05:57
@Julo0sS 您在控制台中遇到了什么错误?你添加了一个 onerror 处理程序吗?尝试为各个阶段插入 console.log 并查看代码停止的位置。输出变量以查看它们是否实际包含数据或未定义。检查您是否正确抓取了 SVG 外层 HTML。我的 2 美分。
2021-04-09 14:05:57

自从这个问题提出其他一些问题以来,我很久之后才来,因为接受的答案可能会产生不良行为。

@K3N 解决方案几乎是正确的,但我会反对使用svgElement.outerHTML.
相反,人们应该更喜欢new XMLSerializer().serializeToString(svgElement).

此外,blob 和 URL API 的使用不是必需的,简单的 dataURI 具有更多的跨浏览器兼容性。

所以一个完整的版本是:

function drawInlineSVG(svgElement, ctx, callback) {
  var svgURL = new XMLSerializer().serializeToString(svgElement);
  var img = new Image();
  img.onload = function() {
    ctx.drawImage(this, 0, 0);
    callback();
  }
  img.src = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgURL);
}

// usage:
drawInlineSVG(document.querySelector('svg'), ctxt, function() {
  console.log(canvas.toDataURL())
});
@TanyaGupta,请注意,<svg>根节点必须具有绝对设置widthheight属性(而不是像 那样的相对属性%);请注意,IE 没有在指向 svg 文档的 HTMLImages 上设置 anwidth或 an height也没有设置它们的naturalXXX等效项):对于此浏览器,您需要自己获取宽度,无论是从 svg 标记,还是从 in 文档的节点的offsetXXX; 请注意,所有 IE < Edge 在通过 将 svg 绘制到画布时都会污染画布drawImage当在画布<foreignObject>上绘制元素时,Safari >= 9 确实会污染画布
2021-03-17 14:05:57
嘿伙计们 - 抱歉把这个拖到一个已经回答的问题上。我正在关注这封信的这个答案,一切正常,除非我到达canvas.toDataURL()时收到SecurityError. 我正在使用这种方法将 Highcharts.js svg 转换为 png,所以我不确定 CORS 的问题来自哪里(从我读过的内容来看这是一个 CORS 问题??)highcharts svg 全部呈现在浏览器中.
2021-03-20 14:05:57
@ user305883,感谢您的反馈。只是为了让您知道该<svg>元素xmlns在附加到 HTML 文档时不必具有声明。所以你的 SVG 没有“格式错误”,只是它是一个 svg 元素,而不是一个 svg 文档。dataURI 应该代表一个文档,因此失败。XMLSerializer() 确实为我们处理了转换。
2021-03-21 14:05:57
@MartinOLeary 这不是 CORS 问题。在画布上绘制一些 svg 元素时,一些 UA 有安全限制。在哪个浏览器上会发生这种情况?如果 IE < Edge,则所有 svg 都会污染画布。唯一的解决方法:使用画布绘图方法重现 svg(这是像 canvg 这样的库所做的)。对于其他 UA,您的 svg 中可能有一个 foreignObject 元素。Safari 和在某些情况下 chrome 并不真正喜欢它,不幸的是,除了删除此元素或将其替换为 ots 内容上的 html2canvas 的结果之外,没有其他解决方法。
2021-03-31 14:05:57
我尝试了上一个答案,如果 SVG 没有 'xmln' 属性,它就会失败。@Kaiido 的答案是一个很好的改进,并且也适用于“格式错误”的 SVG。
2021-04-08 14:05:57