【问题标题】:SVG to Image returning blank image blobSVG 到图像返回空白图像 blob
【发布时间】:2022-01-06 08:23:32
【问题描述】:

我的网站上有一个交互式绘图应用程序,我想创建一个按钮,以便人们可以在 FB 上分享他们的绘图。

我正在尝试将 SVG 元素转换为 blob,然后将其传递给 og:image,但我在转换时遇到了一些问题。

我有两个试验: 由于某种原因,一个不会触发 onload 功能。 另一个返回一个空 blob

然而,这两个试验在 jsfiddle 上都可以正常工作。

第一次尝试

var xmlSerializer = new XMLSerializer();
   
var svgString = xmlSerializer.serializeToString(document.querySelector("#svg"));

var canvas = document.createElement("canvas");

var bounds = {
  width: 1040,
  height: 487
};
canvas.width = bounds.width;
canvas.height = bounds.height;
var ctx = canvas.getContext("2d");
var DOMURL = self.URL || self.webkitURL || self;
var img = new Image();
var svg = new Blob([svgString], {
  type: "image/svg+xml;charset=utf-8"
});
var url = DOMURL.createObjectURL(svg);
img.onload = function() {
  ctx.drawImage(img, 0, 0);
  var png = canvas.toDataURL("image/png");
  var mg = document.createElement("img");
  mg.setAttribute("src", png);
  document.body.appendChild(mg);
  DOMURL.revokeObjectURL(png);
};
img.id = "testimg";
img.setAttribute("src", url);

第二次尝试

var svgString = new XMLSerializer().serializeToString(document.querySelector("svg"));
  var canvas = document.createElement('CANVAS');
  var ctx = canvas.getContext("2d");
  var DOMURL = self.URL || sel.webkitURL || self;
  var img = new Image();
  var svg = new Blob([svgString], {
    type: "image/svg+xml;charset=utf-8"
  });

  var url = DOMURL.createObjectURL(svg);

  img.onload = function() {
    ctx.drawImage(img, 0, 0);
    var png = canvas.toDataURL("image/png");
    var container = document.createElement('DIV');
    container.innerHTML = '<img src="' + png + '"/>';
    DOMURL.revokeObjectURL(png);
  };
  img.src = url;
  document.body.appendChild(img);

Here's the app 由“test1”和“test2”两个按钮触发的两次尝试

【问题讨论】:

    标签: javascript html svg blob


    【解决方案1】:

    问题在于您定义xmlns:xlink 属性的方式。
    目前从您的页面执行document.querySelector("use").attributes.getNamedItem("xmlns:xlink").namespaceURI 将返回null。这意味着该属性已在文档的命名空间 (HTML) 中定义,因此当您使用 XMLSerializer 对其进行字符串化时,您的元素实际上将有两个 xmlns:xlink 属性,一个在 HTML 命名空间中,一个在 SVG嵌入在 HTML 文档中的 SVG 中隐含的内容。
    在 SVG 中的同一个元素上具有两个相同的属性是无效的,因此您的文件无效并且图像不会加载。

    如果您遇到此问题,那肯定是因为您确实通过 JavaScript 设置了此属性:

    const newUse = document.createElementNS("http://www.w3.org/2000/svg", "use");
    newUse.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
    newUse.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", "#foo");
    document.querySelector("svg").append(newUse);
    
    console.log("set from markup:", document.querySelector("use").attributes.getNamedItem("xmlns:xlink").namespaceURI);
    console.log("(badly) set from JS:", document.querySelector("use+use").attributes.getNamedItem("xmlns:xlink").namespaceURI);
    
    // the last <use> has two xmlns:xlink attributes
    console.log("serialization:", new XMLSerializer().serializeToString(document.querySelector("svg")));
    <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30">
      <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#foo"/>
    </svg>

    要正确设置,需要使用setAttributeNS()并使用XMLNS命名空间:

    const newUse = document.createElementNS("http://www.w3.org/2000/svg", "use");
    document.querySelector("svg").append(newUse);
    // beware the last "/"
    newUse.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink");
    
    
    console.log("set from markup", document.querySelector("use").attributes.getNamedItem("xmlns:xlink").namespaceURI);
    console.log("(correctly) set from JS", document.querySelector("use+use").attributes.getNamedItem("xmlns:xlink").namespaceURI);
    <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30">
      <use xmlns:xlink="http://www.w3.org/1999/xlink"/>
    </svg>

    但是最好不要设置所有这些属性。
    正如我上面所说,嵌入在 HTML 中的 SVG 会自动定义正确的 xmlns 和 xlink 命名空间,而无需属性。由于您是通过 JS 创建元素,因此您也已经在正确的命名空间中定义了它们。
    所以不要理会这些属性:

    const SVGNS = "http://www.w3.org/2000/svg";
    const svg = document.createElementNS(SVGNS, "svg");
    // To be able to draw an SVG image on a canvas in Firefox
    // you must set absolute width and height to the root svg node
    svg.setAttribute("width", 50);
    svg.setAttribute("height", 50);
    
    const target = document.createElementNS(SVGNS, "symbol");
    target.id = "target";
    const rect = document.createElementNS(SVGNS, "rect");
    rect.setAttribute("width", 50);
    rect.setAttribute("height", 50);
    rect.setAttribute("fill", "green");
    
    const use = document.createElementNS(SVGNS, "use");
    // since SVG2 we don't even need to set href in the xlink NS
    use.setAttribute("href", "#target");
    
    target.append(rect);
    svg.append(target, use);
    
    const svgString = new XMLSerializer().serializeToString(svg);
    console.log(svgString); // contains all the NS attributes
    
    const blob = new Blob([svgString], { type: "image/svg+xml" });
    const img = new Image();
    img.src = URL.createObjectURL(blob);
    document.body.append(img);

    【讨论】:

      猜你喜欢
      • 2015-10-28
      • 2014-03-27
      • 2012-06-03
      • 1970-01-01
      • 2015-02-23
      • 2022-11-12
      • 2015-01-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多