SVG是否有类似于canvas中toDataURL方法的等效方法?

16

我正在尝试将SVG图像加载到画布中进行像素操作,我需要一个类似于toDataURLgetImageData的方法来处理SVG。

在Chrome / Safari上,我可以通过使用图片和画布来尝试实现它。

var img = new Image()
img.onload = function(){
  ctx.drawImage(img,0,0) //this correctly draws the svg image to the canvas! however...
  var dataURL = canvas.toDataURL(); //SECURITY_ERR: DOM Exception 18
  var data = ctx.getImageData(0,0,img.width, img.height).data //also SECURITY_ERR: DOM Exception 18
  }
  img.src = "image.svg" //that is an svg file. (same domain as html file :))

但是我会收到安全错误。还有其他方法吗?

这里有一个问题的实时演示 http://clstff.appspot.com/gist/462846(您可以查看源代码)


SVG图片来自不同的域吗?如果是,你就不能调用toDataURL或者getImageData,因为画布不再是“origin-clean”的。 - Matthew Crumley
它来自同一域。我甚至尝试过img.src = "data:image/svg+xml;base64,...",但也没有起作用。 - Drew LeSueur
这似乎是Webkit中的一个错误:https://bugs.webkit.org/show_bug.cgi?id=39059 - stefanw
1
我看了一下那个 bug。它说问题出在 drawImage 上。对我来说,drawImage 是可以工作的。问题是在我绘制完图像后 toDataURLgetImageData 无法工作。 - Drew LeSueur
2
你尝试过使用fabric.js将SVG加载到画布上,然后获取dataurl图像吗? - kangax
5个回答

13
var dataUrl = 'data:image/svg+xml,'+encodeURIComponent(svgString);

3
svgString的意思是什么? - Sandeep sandy
1
var svgString = document.getElementById("svg_element_id").outerHTML - Eugenio
@Eugenio:如果那样不起作用,可以使用我回答中的outerXHTML函数执行var svgString = outerXHTML(document.getElementById("svg_element_id"))。如果您是通过编程方式创建节点,则“标准”的.outerHTML缺少命名空间属性。 - mathheadinclouds

7

来源:http://www.svgopen.org/2009/papers/12-Using_Canvas_in_SVG/#d4e105

为什么你不能使用SVG图像元素作为drawImage方法的源呢?原因很简单,但也很痛苦:当前的Canvas规范还不允许(尚未)引用SVGImageElement作为drawImage的源,只能处理HTMLImageElement、HTMLCanvasElement和HTMLVideoelement。这个缺陷在定义“HTML5中的SVG”行为的过程中有望得到解决,并且可以扩展以允许SVGSVGElement。列表3中的xhtml:img元素使用visibility:hidden,因为我们不希望它干扰Canvas上可见的副本。


0

是的,你不能直接这样做,但你可以使用canvg来实现,也就是将SVG绘制到画布上,并从画布中获取数据URL。它并不完美,特别是对于复杂渐变处理,但我有一些积极的经验。


0

通过代码说明Hubert OG的答案; 首先有两点需要注意。

首先(感谢Robert Longson),它可能在没有encodeURIComponent的情况下工作,但最好包括它(例如,如果您有像fill="url(#pattern)"这样的东西,由于#字符,需要encodeURIComponent)

其次,SVG命名空间是不可选的,但它可能不包含在svgElt.outerHTML中。特别是,如果您通过createElementNS创建了您的svg节点,就像这样

svgElt = document.createElementNS("http://www.w3.org/2000/svg", 'svg')

然后对svgElt.outerHTML的后续调用将不会包含命名空间属性,这将导致代码无法正常工作,除非您稍后以某种方式包含命名空间属性。

var imgEnc    = new Image();
var imgEncNS  = new Image();
var prefix    = 'data:image/svg+xml,';
var svgOpen   = '<svg width="200" height="30">';
var svgClose  = '</svg>';
var svgOpenNS = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="30">';
var rect      = '<rect width="200" height="30" fill="black"/>';
var html      = svgOpen + rect + svgClose;
var htmlNS    = svgOpenNS + rect + svgClose;
var htmlEnc   = window.encodeURIComponent(html);
var htmlEncNS = window.encodeURIComponent(htmlNS);
imgEnc.src   = prefix + htmlEnc;
imgEncNS.src = prefix + htmlEncNS;
function T(txt){
  document.body.appendChild(document.createTextNode(txt));
}
function HR(){ document.body.appendChild(document.createElement('hr')); }
function BR(){ document.body.appendChild(document.createElement('br')); }
function A(arg){ document.body.appendChild(arg); }
T('without namespace'); BR(); A(imgEnc); HR();
T('with namespace'); BR(); A(imgEncNS);

你可以通过使用我在这个问题中回答的outerXHTML函数来解决缺少命名空间的问题。

或者像这样

function imgFromSVGnode(node){
    function setNS(elt, parentNS){
        var namespace = elt.namespaceURI;
        if (namespace!==parentNS){
            elt.setAttribute('xmlns', namespace);
        }
        for (var i=0; i<elt.childNodes.length; i++){
            setNS(elt.childNodes[i], namespace);
        }
    }
    setNS(node, null);
    var html = node.outerHTML;
    var dataURL = 'data:image/svg+xml,' + window.encodeURIComponent(html);
    var img = new Image();
    img.src = dataURL;
    return img;
};

https://stackoverflow.com/questions/62109331/namespace-attributes-not-present-in-outerhtml - mathheadinclouds
https://dev59.com/bmsy5IYBdhLWcg3w6yUN - mathheadinclouds
你回答的问题是由于canvas API的早期实现引起的,当时尚未接受svg图像作为源图像。今天没有任何真正的理由会让任何人面临这个问题。你可能是在寻找https://dev59.com/tl4d5IYBdhLWcg3wDu-0。 - Kaiido

-1

首先下载一个名为svg_todataurl.js的js库并将其包含进来

然后只需粘贴以下代码

var SVGtopngDataURL = document.getElementById("svg_element_id").toDataURL("image/png");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接