SVG 到图像返回空白图像 blob

SVG to Image returning blank image blob

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

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

我有两个试验: 由于某种原因,没有触发 onload 函数。 另一个 returns 一个空的 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”触发的两次尝试

问题在于您定义 xmlns:xlink 属性的方式。
当前从您的页面执行 document.querySelector("use").attributes.getNamedItem("xmlns:xlink").namespaceURI 将 return null。这意味着该属性已在文档的命名空间 (HTML) 中定义,因此当您使用 XMLSerializer 对其进行字符串化时,您的元素实际上将具有两个 xmlns:xlink 属性,一个在 HTML 命名空间,以及嵌入在 HTML 文档中的 SVG 中隐含的 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);