当我只有一段图像的base64字符串时,如何使用<svg>标记?

7
我想展示一个SVG图像。我想使用CSS直接修改SVG,因此需要使用<svg>标签。但是,我没有SVG源代码 - 我只有以base64字符串编码的SVG。在我的HTML页面上,使用图像标签,它看起来像这样:
<img alt="" src="data:image/svg+xml;base64,lotsofunreadablestuff...">

我该如何创建一个svg标签,可以使用相同的base64字符串来显示相同的图像?到目前为止,我找到的每个线程和文档似乎都假定我要在我的SVG中使用<use xlink:href=...></use>标签或在我的<svg>标签中包含原始SVG,但这两种情况都不适用于我的情况。
我想做这样的事情:
<svg>
  <magicalSourceTag>
    data:image/svg+xml;base64,lotsofunreadablestuff...
  </magicalSourceTag>
</svg>

你已经失去了很多信息,因为图像的矢量图形描述已经被转换为位图。反过来转换可能不可行。 - Dale Wilson
1
@DaleWilson data:image/svg+xml <- 这对我来说看起来不像位图 - Siguza
1
你是否尝试过Base64转换器,比如:http://www.askapache.com/online-tools/base64-image-converter/ … 另外,在网络搜索“base64图像转svg”将会提供更多链接。 - Asons
1
经过进一步的审查,这个页面 [https://codepen.io/tigt/post/optimizing-svgs-in-data-uris] 解释了有时SVG ASCII文本被编码成BASE 64,只是为了避免在SVG中HTML转义XML字符。 - Dale Wilson
1
<svg><image width=<value> height=<value> xlink:href=" data:image/svg+xml;base64,lotsofunreadablestuff..."/></svg> 但是,除非您将CSS嵌入到lotsofunreadablestuff本身中,否则您将无法使用CSS对其进行样式设置,因为该图像是一个单独的文档。 - Robert Longson
显示剩余2条评论
1个回答

7

你只能将CSS应用于同一文档中的SVG。这意味着您要么将SVG内联到HTML中,要么将CSS嵌入到SVG代码中。

现在,为了内联SVG,取决于您拥有什么。

对于此答案,我将使用以下数据URL,它转换为(应该是)相机图标:

data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+Cjxzdmcgdmlld0JveD0iMCAtMTAgMTAwIDg1IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogICAgPGRlZnM+CiAgICAgICAgPGNsaXBQYXRoIGlkPSJjbGlwIj4KICAgICAgICAgICAgPHBhdGggZD0iTTAsMCBMMTAwLDAgTDEwMCw3NSBMMCw3NSBMMCwwCiAgICAgICAgICAgICAgICAgICAgIE01MCwxNSBBMjAsMjAgMCAxLDAgNTAsNjAgQTIwLDIwIDAgMSwwIDUwLDE1CiAgICAgICAgICAgICAgICAgICAgIE01MCwyNSBBMTIuNSwxMi41IDAgMSwxIDUwLDUwIEExMi41LDEyLjUgMCAxLDEgNTAsMjUiLz4KICAgICAgICA8L2NsaXBQYXRoPgogICAgPC9kZWZzPgogICAgPHJlY3QgeD0iMzAiIHk9Ii0xMCIgd2lkdGg9IjQwIiBoZWlnaHQ9IjIwIiByeD0iMTAiIHJ5PSIxMCIvPgogICAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCIgaGVpZ2h0PSI3NSIgcng9IjE1IiByeT0iMTUiIGNsaXAtcGF0aD0idXJsKCNjbGlwKSIvPgo8L3N2Zz4K

1. 静态数据

如果您有一个硬编码的数据 URL,想要使用它,您可以使用任何base64解码器进行解码。只需将blob粘贴到base64,后面的解码器中,它应该会返回原始的XML数据,然后您可以将其嵌入到HTML中。

如果您使用上面的data URL,请查找 "\"base64 decode\"的第一个Google结果" 并将base64,后面的部分粘贴在那里,您会得到:

<?xml version="1.0"?>
<svg viewBox="0 -10 100 85" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <clipPath id="clip">
            <path d="M0,0 L100,0 L100,75 L0,75 L0,0
                     M50,15 A20,20 0 1,0 50,60 A20,20 0 1,0 50,15
                     M50,25 A12.5,12.5 0 1,1 50,50 A12.5,12.5 0 1,1 50,25"/>
        </clipPath>
    </defs>
    <rect x="30" y="-10" width="40" height="20" rx="10" ry="10"/>
    <rect x="0" y="0" width="100" height="75" rx="15" ry="15" clip-path="url(#clip)"/>
</svg>

你应该在将XML嵌入到HTML中之前删除<?xml version="1.0"?>标签以达到100%符合标准,但是如果将其粘贴到HTML中,则其余部分应该可以正常工作。

2. 动态数据

如果数据 URL 不是固定的,您需要让应用程序进行解码和内联。

同样有两种方法可以实现:

2.1 服务器端

我认为服务器端内联是处理动态数据最清晰的方法。
理论上任何编程语言都可以做到这一点,只要它有一个 base64 解码器和一个 XML 解析器,就不应该太复杂。
由于您没有说明使用哪种(如果有)服务器端语言,我将以 PHP 为例,并利用默认启用和可用的 DOM 扩展。

首先,您需要从数据 URL 中获取 XML。您可以(滥用)file_get_contents 来实现:

$xml = file_get_contents($dataURL);

接下来,您需要将XML解析为DOM文档:
$dom = new DOMDocument();
$dom->loadXML($xml);

接下来,您需要仅导出根节点(不包括<?xml标签),以便将其内联到HTML中。您可以通过使用根节点作为第一个参数调用$dom->saveXML来实现:

$svg = $dom->saveXML($dom->documentElement);

[在线演示]

这当然有一个缺点,就是需要在服务器端运行应用程序(除了Web服务器)。

2.2 客户端

如果您需要或想要在浏览器中执行此操作,那么实际上只有一种选择:JavaScript。

与PHP的file_get_contents类似,您可以(滥用)JavaScript的XMLHttpRequest从URL“加载”数据:

var xhr = new XMLHttpRequest();
xhr.open('GET', dataURL);
xhr.addEventListener('load', function(ev)
{
    var xml = ev.target.response;
    // All following code here
});
xhr.send(null);

相当于 PHP 的 DOM 库,JavaScript 有 DOMParser,您可以使用它将整个字符串解析为 DOM 文档:
var dom = new DOMParser();
var svg = dom.parseFromString(xml, 'image/svg+xml');

最后,您可以在DOM树中任何位置附加根元素(即svg.rootElement),例如:
document.body.appendChild(svg.rootElement);

演示:

var dataURL = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+Cjxzdmcgdmlld0JveD0iMCAtMTAgMTAwIDg1IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogICAgPGRlZnM+CiAgICAgICAgPGNsaXBQYXRoIGlkPSJjbGlwIj4KICAgICAgICAgICAgPHBhdGggZD0iTTAsMCBMMTAwLDAgTDEwMCw3NSBMMCw3NSBMMCwwCiAgICAgICAgICAgICAgICAgICAgIE01MCwxNSBBMjAsMjAgMCAxLDAgNTAsNjAgQTIwLDIwIDAgMSwwIDUwLDE1CiAgICAgICAgICAgICAgICAgICAgIE01MCwyNSBBMTIuNSwxMi41IDAgMSwxIDUwLDUwIEExMi41LDEyLjUgMCAxLDEgNTAsMjUiLz4KICAgICAgICA8L2NsaXBQYXRoPgogICAgPC9kZWZzPgogICAgPHJlY3QgeD0iMzAiIHk9Ii0xMCIgd2lkdGg9IjQwIiBoZWlnaHQ9IjIwIiByeD0iMTAiIHJ5PSIxMCIvPgogICAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCIgaGVpZ2h0PSI3NSIgcng9IjE1IiByeT0iMTUiIGNsaXAtcGF0aD0idXJsKCNjbGlwKSIvPgo8L3N2Zz4K';
var xhr = new XMLHttpRequest();
xhr.open('GET', dataURL);
xhr.addEventListener('load', function(ev)
{
    var xml = ev.target.response;
    var dom = new DOMParser();
    var svg = dom.parseFromString(xml, 'image/svg+xml');
    document.body.appendChild(svg.rootElement);
});
xhr.send(null);


我从中得到的是,如果不使用JavaScript解码编码字符串,就没有办法将base64编码的字符串用作SVG源。 - Kevin
2
据我所知,这与base64无关,而是与使用img标签有关。只有内联SVG可以使用CSS进行样式设置 - gman
@Kevin,那不是我的意思。我编辑了我的回答,希望现在更清楚了。 - Siguza
如果我的URI编码的SVG包含动态数据,那么我是不是唯一的方法就是应用一些onhover或其他样式?我需要解码它,更改样式,然后重新编码吗? - Dzintars
@Dzintars 技术上有另外两种方法。首先,如果您想到的样式也可以应用于PNG,则可以将其应用于包装的“img”标记。其次,您可以...技术上避免解析/让浏览器执行该操作,方法是创建一个没有CORS约束并访问其“contentDocument”的iframe:请参见此示例。但是,最终结果基本相同。 - Siguza
找了好几个小时才找到这个,谢谢你。 - OJB1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接