将 svg 转换为 base64.以编程方式创建的

Convert svg into base64

本文关键字:编程 方式 创建 base64 svg 转换      更新时间:2023-09-26

SVG无法正确转换为base64。

在我的应用程序中,我有一个服务,它使用 g 元素获取响应,然后放入创建的 svg 元素并将其转换为 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/

尝试在

元素周围添加<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/

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

@guest271314他的回答:

将 g 元素

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

我的回答:

强制 #test 中的 svg 元素呈现 g 元素,因为 g 元素未在加载时呈现。

在这种情况下的最佳答案: @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 的追加不适用于 svg 元素?

我不知道我添加的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;

HTML元素和SVG元素具有不同的命名空间。 通过将<g>元素放入 HTML 中,您已经创建了一个 <html:g> 元素。 当它在<svg>内移动时,它仍然是一个<html:g>,不会被SVG渲染器识别。

您必须按照@guest271314所述将其放入一些<svg>标签中。 或者,在追加到 SVG 后,遍历<g>中的所有元素,并将其所有命名空间更改为 SVG 命名空间。

我没有看到这里任何地方实际发生的完整解释,所以就在这里。

浏览器将 HTML 解析为 HTML

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

浏览器太好了,当你提供有效的SGML(XML,HTML的父级,...(并且他们根据所说的找到不属于那里的元素(<g>(时(HTML( - 他们不抱怨,只将未知的elmenents视为未知的HTML元素,导致类HTMLUnknownElement

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

所以你基本上是把HTMLUnknownElement放到SVGSVGElement,这会把标签内容放到 svg 中,但由于底层对象不是 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>模板

如果您被困在中间并且无法更改静态模板,您仍然可以基于动态方法进行构建:

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

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

  2. 获取"原始"旧<g> - 它会HTMLUnknownElement,但没关系,因为它建立在HTMLElement之上,这给了我们 enaugh 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;