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);
我的网站上有一个交互式绘图应用程序,我想创建一个按钮,让人们可以在 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);