将 svg 转换为 base64
Convert svg into base64
以编程方式创建的 SVG 无法正确转换为 base64。
在我的应用程序中,我有一个服务,它通过 g-element 获得响应,然后放入创建的 svg-element 并将其转换为 base64,但是如果我尝试打开 link 我发现该 svg 不会在页面上呈现。
var xmlns = 'http://www.w3.org/2000/svg',
IMAGE_TEMPLATE = document.createElementNS(xmlns, 'svg');
IMAGE_TEMPLATE.appendChild(document.body.querySelector('#ico-appliance-thermostat-128'));
IMAGE_TEMPLATE.setAttribute('id', 'svg');
IMAGE_TEMPLATE.setAttributeNS(null, 'width', 128);
IMAGE_TEMPLATE.setAttributeNS(null, 'height', 128);
IMAGE_TEMPLATE.setAttributeNS(null, 'viewBox', '0 0 128 128');
document.body.querySelector('#test').appendChild(IMAGE_TEMPLATE);
test = function(){
var s = new XMLSerializer().serializeToString(document.getElementById("svg"))
var encodedData = window.btoa(s);
console.log('data:image/svg+xml;base64,' + encodedData);
}
Difference between @guest271314 and my answer:
@guest271314 his answer:
Wrap the g element inside a svg element to make sure that the browser renders the g element onload.
My answer:
Forces the svg element inside #test to render the g element since the g element wasn't rendered onload.
Best answer in this case: @guest271314
Reason: A g element should be inside a svg element in valid html.
When should my answer be used?
In the case that the g element is not an element in the html document.
您没有使用 } 关闭 test()。
下面的代码 returns 一个 base64 编码的 svg:
https://jsfiddle.net/seahorsepip/6sra5c5L/1/
编辑:
svg 渲染问题是我之前 运行 自己遇到的问题,这里是 jquery 行的修复:
https://jsfiddle.net/seahorsepip/6sra5c5L/3/
//Force refresh svg
$("#test").html($("#test").html());
这是关于该问题的原始 SO 线程:jquery's append not working with svg element?
我不知道我添加的 jQuery 代码的 javascript 等效项,我尝试编写它但没有成功:/
编辑 2:
这是纯 js 等效项:
https://jsfiddle.net/seahorsepip/6sra5c5L/4/
//Force refresh svg
var svg = document.body.querySelector('#test').innerHTML;
document.body.querySelector('#test').innerHTML = "";
document.body.querySelector('#test').innerHTML = svg;
尝试在 <g>
元素周围添加 <svg></svg>
,在 test
函数处关闭 }
;将 test
定义为命名函数
var xmlns = 'http://www.w3.org/2000/svg',
IMAGE_TEMPLATE = document.createElementNS(xmlns, 'svg');
IMAGE_TEMPLATE.appendChild(document.body.querySelector('#ico-appliance-thermostat-128'));
IMAGE_TEMPLATE.setAttribute('id', 'svg');
IMAGE_TEMPLATE.setAttributeNS(null, 'width', 128);
IMAGE_TEMPLATE.setAttributeNS(null, 'height', 128);
IMAGE_TEMPLATE.setAttributeNS(null, 'viewBox', '0 0 128 128');
document.body.querySelector('#test').appendChild(IMAGE_TEMPLATE);
function test() {
var s = new XMLSerializer().serializeToString(document.getElementById("svg"))
console.log(document.getElementById("svg"))
console.log(s)
var encodedData = window.btoa(s);
console.log('data:image/svg+xml;base64,' + encodedData);
}
<svg>
<g id="ico-appliance-thermostat-128" transform="scale(2)">
<path d="M106.949,128.009 L105.294,124.692 C115.967,119.333 123.298,108.278 123.298,95.500 C123.298,82.722 115.967,71.666 105.294,66.308 L106.949,62.990 C118.835,68.958 126.999,81.270 126.999,95.500 C126.999,109.730 118.835,122.042 106.949,128.009 ZM117.376,95.500 C117.376,105.954 111.378,115.000 102.645,119.384 L100.990,116.067 C108.510,112.292 113.676,104.502 113.676,95.500 C113.676,86.497 108.510,78.708 100.990,74.933 L102.645,71.615 C111.378,76.000 117.376,85.045 117.376,95.500 ZM106.999,95.213 C106.999,98.063 104.756,100.373 101.988,100.373 C100.251,100.373 98.720,99.462 97.822,98.080 L91.490,98.080 L85.840,116.427 L85.662,116.427 L85.840,117.000 L80.829,117.000 L70.082,82.422 L65.795,97.506 L65.795,98.080 L54.999,98.080 L54.999,92.920 L62.087,92.920 L67.465,74.000 L72.477,74.000 L83.234,108.615 L88.067,92.920 L89.738,92.920 L93.079,92.920 L97.504,92.920 C98.324,91.222 100.021,90.053 101.988,90.053 C104.756,90.053 106.999,92.363 106.999,95.213 ZM24.999,128.000 C11.787,128.000 0.999,117.189 0.999,103.993 C0.999,96.779 4.177,90.380 8.986,85.988 C8.986,85.173 8.986,84.776 8.986,83.981 L8.986,15.997 C8.986,7.193 16.177,-0.000 24.979,-0.000 C33.780,-0.000 40.972,7.193 40.972,15.997 L40.972,83.981 C40.972,84.796 40.972,85.194 40.972,85.988 C45.780,90.380 48.979,96.779 48.999,103.993 C48.999,117.210 38.212,128.000 24.999,128.000 ZM33.999,90.000 L33.999,17.000 C33.999,12.373 29.662,8.009 24.988,8.009 C20.314,8.009 16.000,12.373 16.000,17.000 L16.000,90.000 C10.903,92.952 7.985,97.813 7.985,104.136 C7.985,113.411 15.641,120.990 25.011,120.990 C34.380,120.990 42.037,113.389 41.992,104.114 C41.992,97.791 39.118,92.952 33.999,90.000 ZM24.999,112.990 C19.904,112.990 15.999,109.082 15.999,103.983 C15.999,100.092 18.383,96.796 21.989,95.588 C21.989,95.290 21.989,95.290 21.989,94.992 L21.989,38.991 C21.989,37.500 23.181,35.994 24.984,35.994 C26.787,35.994 27.979,37.187 27.979,38.991 L27.979,95.008 C27.979,95.306 27.979,95.306 27.979,95.604 C31.585,96.812 33.984,100.107 33.999,103.983 C33.999,109.082 30.095,112.990 24.999,112.990 Z"
style="fill: #5aac21;fill-rule: evenodd;"></path>
</g>
</svg>
<div id="test"></div>
<button onclick="test()">Test</button>
jsfiddle https://jsfiddle.net/6sra5c5L/5/
HTML 元素和 SVG 元素具有不同的命名空间。通过将 <g>
元素放入 HTML 中,您创建了一个 <html:g>
元素。当它在 <svg>
内移动时,它仍然是一个 <html:g>
,并且不会被 SVG 渲染器识别。
您要么必须将其放入 soem <svg>
标签中,如 @guest271314 所述。或者,在附加到 SVG 之后,遍历 <g>
中的所有元素并将它们的所有名称空间更改为 SVG 名称空间。
我没有看到完整的解释这里实际发生了什么,所以就这样吧。
浏览器将 HTML 解析为 HTML
虽然这看起来很明显,但当您将非 HTML(SVG、XML、...)元素放入其中时,情况并非如此。
浏览器太好了,当你提供有效的 SGML (parent of XML, HTML, ...) and they find element that doesn't belong there(<g>
) according to what you said will be there (HTML) - they don't complain and only treat the unknown elmenents as unknown HTML elements, resulting in class HTMLUnknownElement
。
浏览器一般不会改变元素对象class
所以您基本上是将 HTMLUnknownElement
放入 SVGSVGElement
, which will put the tag content into the svg, but since the underlying object is not a valid subelement of SVG (SVGGElement) 它不会执行任何操作。
这与动态创建的 <svg>
必须使用名称空间创建的原因相同 => 名称空间与 <svg>
元素结合使用时,告诉浏览器 - 嘿!这个标签来自SVG 规范 => 将其视为 SVG!
解决方案
您当前的示例代码存在语法错误,我不会解决这个问题,因为那不是真正的问题。
静态定义<g>
模板
如果模板已经在原始文档中 - 通过用 <svg xmlns="http://www.w3.org/2000/svg"></svg>
包装强制浏览器将其视为 SVGSVGElement
(浏览器可能会在没有 xmlns
属性的情况下使用它,但它是更安全的方式)。
担心会显示?只需使用 CSS display: none;
隐藏它 - 它 将 不会 影响渲染 .
动态定义<g>
模板
如果您正在动态创建 <g>
元素,您应该在使用 createElementNS()
指定命名空间的同时创建它,例如:
document.createElementNS('http://www.w3.org/2000/svg', 'g');
静态但不可更改的<g>
模板
如果您卡在中间无法更改静态模板,您仍然可以基于动态方法进行构建:
使用正确的命名空间创建新的 <g>
var newGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
得到 "raw" 旧的 <g>
- 它将是 HTMLUnknownElement
,但没关系,因为它建立在 HTMLElement
之上让我们能够 API 转移我们需要的一切
var oldGroup = document.querySelector('oldGroupSelector');
可能会将旧组属性转移到新组 - 方便的是 element.attributes
for (var i = 0; i < oldGroup.attributes.length; ++i) {
newGroup.setAttribute(
oldGroup.attributes.item(i).name,
oldGroup.attributes.item(i).value
);
}
现在浏览器已经知道 newGroup <g>
的内容实际上是 svg - newGroup 是 SVGGElement
- 现在我们可以重新填充内容
newGroup.innerHTML = oldGroup.innerHTML;
以编程方式创建的 SVG 无法正确转换为 base64。
在我的应用程序中,我有一个服务,它通过 g-element 获得响应,然后放入创建的 svg-element 并将其转换为 base64,但是如果我尝试打开 link 我发现该 svg 不会在页面上呈现。
var xmlns = 'http://www.w3.org/2000/svg',
IMAGE_TEMPLATE = document.createElementNS(xmlns, 'svg');
IMAGE_TEMPLATE.appendChild(document.body.querySelector('#ico-appliance-thermostat-128'));
IMAGE_TEMPLATE.setAttribute('id', 'svg');
IMAGE_TEMPLATE.setAttributeNS(null, 'width', 128);
IMAGE_TEMPLATE.setAttributeNS(null, 'height', 128);
IMAGE_TEMPLATE.setAttributeNS(null, 'viewBox', '0 0 128 128');
document.body.querySelector('#test').appendChild(IMAGE_TEMPLATE);
test = function(){
var s = new XMLSerializer().serializeToString(document.getElementById("svg"))
var encodedData = window.btoa(s);
console.log('data:image/svg+xml;base64,' + encodedData);
}
Difference between @guest271314 and my answer:
@guest271314 his answer:
Wrap the g element inside a svg element to make sure that the browser renders the g element onload.
My answer:
Forces the svg element inside #test to render the g element since the g element wasn't rendered onload.
Best answer in this case: @guest271314
Reason: A g element should be inside a svg element in valid html.
When should my answer be used?
In the case that the g element is not an element in the html document.
您没有使用 } 关闭 test()。 下面的代码 returns 一个 base64 编码的 svg: https://jsfiddle.net/seahorsepip/6sra5c5L/1/
编辑:
svg 渲染问题是我之前 运行 自己遇到的问题,这里是 jquery 行的修复: https://jsfiddle.net/seahorsepip/6sra5c5L/3/
//Force refresh svg
$("#test").html($("#test").html());
这是关于该问题的原始 SO 线程:jquery's append not working with svg element?
我不知道我添加的 jQuery 代码的 javascript 等效项,我尝试编写它但没有成功:/
编辑 2:
这是纯 js 等效项:
https://jsfiddle.net/seahorsepip/6sra5c5L/4/
//Force refresh svg
var svg = document.body.querySelector('#test').innerHTML;
document.body.querySelector('#test').innerHTML = "";
document.body.querySelector('#test').innerHTML = svg;
尝试在 <g>
元素周围添加 <svg></svg>
,在 test
函数处关闭 }
;将 test
定义为命名函数
var xmlns = 'http://www.w3.org/2000/svg',
IMAGE_TEMPLATE = document.createElementNS(xmlns, 'svg');
IMAGE_TEMPLATE.appendChild(document.body.querySelector('#ico-appliance-thermostat-128'));
IMAGE_TEMPLATE.setAttribute('id', 'svg');
IMAGE_TEMPLATE.setAttributeNS(null, 'width', 128);
IMAGE_TEMPLATE.setAttributeNS(null, 'height', 128);
IMAGE_TEMPLATE.setAttributeNS(null, 'viewBox', '0 0 128 128');
document.body.querySelector('#test').appendChild(IMAGE_TEMPLATE);
function test() {
var s = new XMLSerializer().serializeToString(document.getElementById("svg"))
console.log(document.getElementById("svg"))
console.log(s)
var encodedData = window.btoa(s);
console.log('data:image/svg+xml;base64,' + encodedData);
}
<svg>
<g id="ico-appliance-thermostat-128" transform="scale(2)">
<path d="M106.949,128.009 L105.294,124.692 C115.967,119.333 123.298,108.278 123.298,95.500 C123.298,82.722 115.967,71.666 105.294,66.308 L106.949,62.990 C118.835,68.958 126.999,81.270 126.999,95.500 C126.999,109.730 118.835,122.042 106.949,128.009 ZM117.376,95.500 C117.376,105.954 111.378,115.000 102.645,119.384 L100.990,116.067 C108.510,112.292 113.676,104.502 113.676,95.500 C113.676,86.497 108.510,78.708 100.990,74.933 L102.645,71.615 C111.378,76.000 117.376,85.045 117.376,95.500 ZM106.999,95.213 C106.999,98.063 104.756,100.373 101.988,100.373 C100.251,100.373 98.720,99.462 97.822,98.080 L91.490,98.080 L85.840,116.427 L85.662,116.427 L85.840,117.000 L80.829,117.000 L70.082,82.422 L65.795,97.506 L65.795,98.080 L54.999,98.080 L54.999,92.920 L62.087,92.920 L67.465,74.000 L72.477,74.000 L83.234,108.615 L88.067,92.920 L89.738,92.920 L93.079,92.920 L97.504,92.920 C98.324,91.222 100.021,90.053 101.988,90.053 C104.756,90.053 106.999,92.363 106.999,95.213 ZM24.999,128.000 C11.787,128.000 0.999,117.189 0.999,103.993 C0.999,96.779 4.177,90.380 8.986,85.988 C8.986,85.173 8.986,84.776 8.986,83.981 L8.986,15.997 C8.986,7.193 16.177,-0.000 24.979,-0.000 C33.780,-0.000 40.972,7.193 40.972,15.997 L40.972,83.981 C40.972,84.796 40.972,85.194 40.972,85.988 C45.780,90.380 48.979,96.779 48.999,103.993 C48.999,117.210 38.212,128.000 24.999,128.000 ZM33.999,90.000 L33.999,17.000 C33.999,12.373 29.662,8.009 24.988,8.009 C20.314,8.009 16.000,12.373 16.000,17.000 L16.000,90.000 C10.903,92.952 7.985,97.813 7.985,104.136 C7.985,113.411 15.641,120.990 25.011,120.990 C34.380,120.990 42.037,113.389 41.992,104.114 C41.992,97.791 39.118,92.952 33.999,90.000 ZM24.999,112.990 C19.904,112.990 15.999,109.082 15.999,103.983 C15.999,100.092 18.383,96.796 21.989,95.588 C21.989,95.290 21.989,95.290 21.989,94.992 L21.989,38.991 C21.989,37.500 23.181,35.994 24.984,35.994 C26.787,35.994 27.979,37.187 27.979,38.991 L27.979,95.008 C27.979,95.306 27.979,95.306 27.979,95.604 C31.585,96.812 33.984,100.107 33.999,103.983 C33.999,109.082 30.095,112.990 24.999,112.990 Z"
style="fill: #5aac21;fill-rule: evenodd;"></path>
</g>
</svg>
<div id="test"></div>
<button onclick="test()">Test</button>
jsfiddle https://jsfiddle.net/6sra5c5L/5/
HTML 元素和 SVG 元素具有不同的命名空间。通过将 <g>
元素放入 HTML 中,您创建了一个 <html:g>
元素。当它在 <svg>
内移动时,它仍然是一个 <html:g>
,并且不会被 SVG 渲染器识别。
您要么必须将其放入 soem <svg>
标签中,如 @guest271314 所述。或者,在附加到 SVG 之后,遍历 <g>
中的所有元素并将它们的所有名称空间更改为 SVG 名称空间。
我没有看到完整的解释这里实际发生了什么,所以就这样吧。
浏览器将 HTML 解析为 HTML
虽然这看起来很明显,但当您将非 HTML(SVG、XML、...)元素放入其中时,情况并非如此。
浏览器太好了,当你提供有效的 SGML (parent of XML, HTML, ...) and they find element that doesn't belong there(<g>
) according to what you said will be there (HTML) - they don't complain and only treat the unknown elmenents as unknown HTML elements, resulting in class HTMLUnknownElement
。
浏览器一般不会改变元素对象class
所以您基本上是将 HTMLUnknownElement
放入 SVGSVGElement
, which will put the tag content into the svg, but since the underlying object is not a valid subelement of SVG (SVGGElement) 它不会执行任何操作。
这与动态创建的 <svg>
必须使用名称空间创建的原因相同 => 名称空间与 <svg>
元素结合使用时,告诉浏览器 - 嘿!这个标签来自SVG 规范 => 将其视为 SVG!
解决方案
您当前的示例代码存在语法错误,我不会解决这个问题,因为那不是真正的问题。
静态定义<g>
模板
如果模板已经在原始文档中 - 通过用 <svg xmlns="http://www.w3.org/2000/svg"></svg>
包装强制浏览器将其视为 SVGSVGElement
(浏览器可能会在没有 xmlns
属性的情况下使用它,但它是更安全的方式)。
担心会显示?只需使用 CSS display: none;
隐藏它 - 它 将 不会 影响渲染 .
动态定义<g>
模板
如果您正在动态创建 <g>
元素,您应该在使用 createElementNS()
指定命名空间的同时创建它,例如:
document.createElementNS('http://www.w3.org/2000/svg', 'g');
静态但不可更改的<g>
模板
如果您卡在中间无法更改静态模板,您仍然可以基于动态方法进行构建:
使用正确的命名空间创建新的
<g>
var newGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
得到 "raw" 旧的
<g>
- 它将是HTMLUnknownElement
,但没关系,因为它建立在HTMLElement
之上让我们能够 API 转移我们需要的一切var oldGroup = document.querySelector('oldGroupSelector');
可能会将旧组属性转移到新组 - 方便的是
element.attributes
for (var i = 0; i < oldGroup.attributes.length; ++i) { newGroup.setAttribute( oldGroup.attributes.item(i).name, oldGroup.attributes.item(i).value ); }
现在浏览器已经知道 newGroup
<g>
的内容实际上是 svg - newGroup 是SVGGElement
- 现在我们可以重新填充内容newGroup.innerHTML = oldGroup.innerHTML;