将svg转换为base64

时间:2016-01-11 15:09:59

标签: javascript svg base64

以编程方式创建的SVG无法正确转换为base64。

在我的应用程序中,我有一个服务,它使用g-element获取响应然后放入创建的svg-element并将其转换为base64,但如果我尝试打开一个链接,我发现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);
    }

https://jsfiddle.net/6sra5c5L/

4 个答案:

答案 0 :(得分:4)

尝试在<svg></svg>元素周围添加<g>,在}函数处关闭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/

答案 1 :(得分:2)

  

@ guest271314和我的回答之间的区别:

     

@ guest271314他的回答:

     

将g元素包装在svg元素中,以确保浏览器呈现g元素onload。

     

我的回答:

     

强制#test内的svg元素呈现g元素,因为g元素没有被渲染为onload。

     

在这种情况下的最佳答案:@ guest271314

     

原因:g元素应位于有效html中的svg元素内。

我应该何时使用我的答案?
在g元素不是html文档中的元素的情况下。

你没有用}}关闭test()。 下面的代码返回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;

答案 2 :(得分:1)

HTML元素和SVG元素具有不同的命名空间。通过在HTML中添加<g>元素,您已创建了<html:g>元素。当它移到<svg>内时,它仍然是<html:g>,并且不会被SVG渲染器识别。

您必须将其放入soem <svg>标签内,如@ guest271314所述。或者,在附加到SVG之后,遍历<g>中的所有元素并将其所有名称空间更改为SVG。

答案 3 :(得分:0)

我看不到完整的解释,这里什么地方实际发生了什么,所以就去了。

浏览器将HTML解析为HTML

虽然这看起来很明显,但当您将非HTML(SVG,XML等)元素放入其中时,情况并非如此。

浏览器太好了,当您提供有效的SGML(XML,HTML的父级...)时,浏览器会根据查找不属于该元素的元素(<g>) >您说会在那儿(HTML)-他们不会抱怨,只会将未知的元素视为未知的HTML元素,从而产生类HTMLUnknownElement

浏览器通常不会更改元素对象类

因此,您基本上是将HTMLUnknownElement放入SVGSVGElement,这会将标签内容放入svg,但是由于基础对象不是SVG的有效子元素( SVGGElement)不会执行任何操作。
这就是为什么必须使用命名空间==创建动态创建的<svg>的原因,与<svg>元素结合使用时,命名空间告诉浏览器-嘿!这个标签来自SVG规范=>将其视为SVG!

解决方案

您当前的示例代码有一个语法错误,我不会解决,因为这不是真正的问题。

静态定义的<g>模板

如果模板已经在原始文档中-强制浏览器通过用SVGSVGElement进行包装来将其视为<svg xmlns="http://www.w3.org/2000/svg"></svg>(浏览器可以不使用xmlns属性来使用它,但这是更安全的方法)办法)。
担心会显示吗?只需使用CSS display: none;隐藏它-它不会影响渲染

动态定义的<g>模板

如果要动态创建<g>元素,则应在使用createElementNS()指定名称空间的同时创建它,例如:

document.createElementNS('http://www.w3.org/2000/svg', 'g');

静态但不可更改的<g>模板

如果您陷于中间而无法更改静态模板,则仍然可以基于动态方法:

  1. 使用正确的命名空间创建新的<g>

    var newGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');

  2. 让“原始”旧<g>-将会是HTMLUnknownElement,但是没关系,因为它是基于HTMLElement构建的,这使我们可以调用API我们所需要的

    var oldGroup = document.querySelector('oldGroupSelector');

  3. 可能将旧的组属性转移到新的组-方便的是element.attributes

    for (var i = 0; i < oldGroup.attributes.length; ++i) { newGroup.setAttribute( oldGroup.attributes.item(i).name, oldGroup.attributes.item(i).value ); }

  4. 现在浏览器已经知道newGroup <g>的内容实际上是svg-newGroup是SVGGElement-现在我们可以重新填充内容

    newGroup.innerHTML = oldGroup.innerHTML;