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

Posted

技术标签:

【中文标题】如何将内联 svg(在 DOM 中)绘制到画布上?【英文标题】:How to draw an inline svg (in DOM) to a canvas? 【发布时间】:2015-01-29 13:41:42 【问题描述】:

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

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

但问题在于转换。

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

这里是“html idea”模板:

<html>
    <body>
        <svg id="mySvg"  >
            <!-- 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/……感谢阅读/帮助

【问题讨论】:

‘一个 .svg 图像 [...] 被保存 [...] 为一个 .png 文件‘这是如何工作的?! 看看***.com/a/3769883/783219 请查看我在此处提供的this answer。它应该可以解决您的问题 【参考方案1】:

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

@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())
);

【讨论】:

我尝试了上一个答案,如果 SVG 没有 'xmln' 属性,它将失败。 @Kaiido 的答案是一个很好的改进,并且也适用于“格式错误”的 SVG。 @user305883,感谢您的反馈。只是为了让您知道 &lt;svg&gt; 元素在附加到 HTML 文档时不必有 xmlns 声明。所以你的 SVG 不是“格式错误”,只是它是一个 svg 元素,而不是一个 svg 文档。 dataURI 应该代表一个文档,因此失败。 XMLSerializer() 确实为我们处理了转换。 大家好 - 很抱歉将这个问题拖到已经回答的问题上。我正在关注这封信的回答,一切正常,除了当我到达 canvas.toDataURL() 时,我得到的是 SecurityError 。我正在使用这种方法将 Highcharts.js svg 转换为 png,所以我不确定 CORS 的问题出在哪里(从我读过的内容来看,这是一个 CORS 问题??) highcharts svg 全部呈现在浏览器中. @MartinOLeary 这不是 CORS 问题。在画布上绘制一些 svg 元素时,一些 UA 有安全限制。这发生在哪个浏览器上?如果 IE @TanyaGupta,注意根&lt;svg&gt; 节点必须绝对设置widthheight 属性(不是像% 这样的相对属性);请注意,IE 没有在指向 svg 文档的 HTMLImage 上设置 widthheight(也没有设置它们的 naturalXXX 等效项):对于此浏览器,您需要自己获取宽度,或者从svg 标记,来自 in 文档节点的 offsetXXX ;请注意,当通过 drawImage 将 svg 绘制到画布时,所有 IE <foreignObject> 元素时,Safari >= 9 确实会污染画布。【参考方案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 设置。

【讨论】:

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

以上是关于如何将内联 svg(在 DOM 中)绘制到画布上?的主要内容,如果未能解决你的问题,请参考以下文章

Canvas

在画布上绘制一个旋转的 Path2D 对象

重点突破——SVG技术动态随机绘制圆形

如何将多个图像绘制到单个画布上?

.getElementById 的内联 SVG 和 HTML DOM 范围

在SVG中绘制DOM对象时如何在Canvas中使用Google字体?