7

I would like to show an SVG image. I want to use CSS to modify the SVG directly, so I need to use an <svg> tag. However, I don't have the SVG source - all I have is the SVG encoded as a base64 string. In my HTML page, with an image tag, it looks something like this:

<img alt="" src="data:image/svg+xml;base64,lotsofunreadablestuff...">

How can I create an svg tag those shows the same image using the same base64 string? Every thread and piece of documentation I've found so far seems to assume that I'm either using the <use xlink:href=...></use> tag in my SVG or including my raw SVG inside my <svg> tags, neither of which apply in my situation.

I want to do something like this:

<svg>
  <magicalSourceTag>
    data:image/svg+xml;base64,lotsofunreadablestuff...
  </magicalSourceTag>
</svg>
Kevin
  • 14,655
  • 24
  • 74
  • 124
  • You've lost a lot of information because the vector graphics description of the image has been converted to a bitmap already. Converting the other way is not likely to be feasible. – Dale Wilson Sep 19 '16 at 22:09
  • 1
    @DaleWilson `data:image/svg+xml` <- doesn't look like bitmap to me – Siguza Sep 19 '16 at 22:11
  • @DaleWilson I'm surprised to here that. My understanding was that encoding information into a base64 string kept the exact same information, but in a binary format instead of a human-readable format. Isn't that the case? If so, isn't the original svg vector graphics description still available? – Kevin Sep 19 '16 at 22:12
  • You're probably right. Normally I've seen BASE64 use to represent a binary image. If it's just a conversion of the ASCII SVG into binary (I don't see the point) then the original might be recoverable. – Dale Wilson Sep 19 '16 at 22:15
  • 1
    Have you tried a Base64 converter, ie: http://www.askapache.com/online-tools/base64-image-converter/ ... and a web search on "base64 image to svg" will give more links – Asons Sep 19 '16 at 22:15
  • 1
    Upon further review, this page [ https://codepen.io/tigt/post/optimizing-svgs-in-data-uris ] explains that sometimes SVG ascii text is encoded into BASE 64 just to avoid having to HTML escape the XML characters in the SVG. – Dale Wilson Sep 19 '16 at 22:17
  • 1
    height= xlink:href=" data:image/svg+xml;base64,lotsofunreadablestuff..."/> but you won't be able to style it with CSS unless you embed the CSS into lotsofunreadablestuff itself as the image is a separate document. – Robert Longson Sep 20 '16 at 07:14

1 Answers1

7

You can only apply CSS to SVGs within the same document. That means you'll either have to inline the SVG into your HTML, or embed your CSS into the SVG code itself.

Now, in order to inline an SVG, it depends on what you have.

For this answer I'm going to use the following data URL, which translates into (what is supposed to be) a camera icon:

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

1. Static data

If you have a hardcoded data URL that you want to use, you can simply decode it using any base64 decoder out there. Just paste the blob after base64, into the decoder and it should give your the raw XML back, which you can then embed into your HTML.

If you use the data URL from above, look up the first Google result for "base64 decode" and paste the part after base64, in there, you get:

<?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>

You should strip the <?xml version="1.0"?> tag before inlining it into HTML to be 100% standard-compliant, but that's all you have to do, the rest should work just fine if pasted into your HTML.


2. Dynamic data

If the data URL is not fixed however, you need your application to do the decoding and inlining.

Again there are two ways to do this:

2.1 Server-side

I would consider server-side inlining the cleanest way to deal with dynamic data.
In theory any programming language can do this, and as long as it's got a base64 decoder and an XML parser, it shouldn't be too complicated.
Since you didn't say what (if any) server-side language you're using, I'm going to use PHP as an example, and I'm making use of the DOM extension, which is enabled and available by default.

First you'll want to get the XML from your data URL. You can (ab)use file_get_contents for that:

$xml = file_get_contents($dataURL);

Next you'll want to parse that XML into a DOM document:

$dom = new DOMDocument();
$dom->loadXML($xml);

And then you'll want to export just the root node (without the <?xml tag), so that it can be inlined into HTML. You can do this by calling $dom->saveXML with the root node as first argument, i.e.:

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

[ Online demo ]

This of course has the disadvantage of needing to have a server-side application run in the first place (other than the web server).

2.2 Client-side

If you need or want to do this in the browser, there is really only one option: JavaScript.

Similar to PHP's file_get_contents, you can (ab)use JavaScript's XMLHttpRequest to "load" the data from the 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);

Equivalent to PHP's DOM library, JavaScript has DOMParser, which you can use to parse the entire string into a DOM document:

var dom = new DOMParser();
var svg = dom.parseFromString(xml, 'image/svg+xml');

And finally you can append the root element (i.e. svg.rootElement) anywhere you like in your DOM tree, e.g.

document.body.appendChild(svg.rootElement);

Demo:

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);
Siguza
  • 21,155
  • 6
  • 52
  • 89
  • What I'm getting from this is that there isn't a way to use the base64-encoded string as an SVG source without at least using JavaScript to unpack the encoded string? – Kevin Sep 19 '16 at 23:31
  • 2
    AFAIK It has nothing to do with base64, it has to do using an img tag. [Only inline SVG can styled using CSS](https://css-tricks.com/using-svg/) – gman Sep 19 '16 at 23:54
  • @Kevin That was not the meaning. I edited my answer, hopefully it's clearer now. – Siguza Sep 20 '16 at 21:24
  • Am i right that if my URI encoded SVG contains dynamic data, then this is pretty much the only way to apply some `onhover` or whatever styling? I need to decode it, change the style and encode it back? – Dzintars Dec 14 '18 at 00:07
  • @Dzintars There are technically two other ways. First, if the style you have in mind could also be applied to a PNG, you can just apply it to the wrapping `img` tag. And secondly, you can... technically avoid the parsing/let the browser do that, by creating an iframe with no CORS constraints and accessing its `contentDocument`: [see this example](https://jsfiddle.net/Siguza/u3qyj58m/). But yes, the end result remains pretty much the same. – Siguza Dec 14 '18 at 01:10
  • Spent hours looking for this, thank you – OJB1 Jul 29 '23 at 18:35