tags:

views:

208

answers:

1

Hi I have an svg file that contains several elements (like path, circles, rectangles, etc..). I'd like to convert that svg file to an svg with embedded base64 data instead of multiple elements. is it possible to do that with batik? The project I'm working on requires I use Java libraries only.

Thanks.

A: 

There's a technique which I've used to embed SVG images in Blogger posts which might work for this. Basically, it's a two-step process:

  1. You serialize the SVG you want to embed, and URL-encode it.
  2. You then use the URL-encoded string as a data URI in the xlink:href attribute of an SVG use element.

Here's a working example that I've tested with Batik. Say that you want to embed the following SVG document, circle.svg:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"&gt;
<svg width="4in" height="4in" id="the_svg"
     viewBox="0 0 4 4" version="1.1"
     xmlns="http://www.w3.org/2000/svg"&gt;
    <circle cx="1" cy="1" r="1" fill="blue" stroke="none" id="the_circle"/>
</svg>

You can URL-encode it by passing its path to the following small Rhino script:

#!/usr/bin/env rhino
print(escape(readFile(arguments[0])))

Of-course, if you want to do this programmatically in Java, then you'll need a Java-specific method of serializing the SVG document and URL-encoding the string.

This gives you the document as a URL-encoded string:

%3C%3Fxml%20version%3D%221.0%22%20standalone%3D%22no%22%3F%3E%0A%3C%21DOCTYPE%20svg%20PUBLIC%20%22-//W3C//DTD%20SVG%201.1//EN%22%20%0A%20%20%22http%3A//www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd%22%3E%0A%3Csvg%20width%3D%224in%22%20height%3D%224in%22%20id%3D%22the_svg%22%0A%20%20%20%20%20viewBox%3D%220%200%204%204%22%20version%3D%221.1%22%0A%20%20%20%20%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%0A%09%3Ccircle%20cx%3D%221%22%20cy%3D%221%22%20r%3D%221%22%20fill%3D%22blue%22%20stroke%3D%22none%22%20id%3D%22the_circle%22/%3E%0A%3C/svg%3E%0A%0A

You can then embed this document by using it in a data URI, which looks like this:

data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20standalone%3D%22no%22%3F%3E%0A%3C%21DOCTYPE%20svg%20PUBLIC%20%22-//W3C//DTD%20SVG%201.1//EN%22%20%0A%20%20%22http%3A//www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd%22%3E%0A%3Csvg%20width%3D%224in%22%20height%3D%224in%22%20id%3D%22the_svg%22%0A%20%20%20%20%20viewBox%3D%220%200%204%204%22%20version%3D%221.1%22%0A%20%20%20%20%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%0A%09%3Ccircle%20cx%3D%221%22%20cy%3D%221%22%20r%3D%221%22%20fill%3D%22blue%22%20stroke%3D%22none%22%20id%3D%22the_circle%22/%3E%0A%3C/svg%3E%0A%0A

For example, the following HTML document uses an object tag and the data URI to embed the SVG document:

<html>
    <head>
    </head>
    <body>
        <object data="data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20standalone%3D%22no%22%3F%3E%0A%3C%21DOCTYPE%20svg%20PUBLIC%20%22-//W3C//DTD%20SVG%201.1//EN%22%20%0A%20%20%22http%3A//www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd%22%3E%0A%3Csvg%20width%3D%224in%22%20height%3D%224in%22%20id%3D%22the_svg%22%0A%20%20%20%20%20viewBox%3D%220%200%204%204%22%20version%3D%221.1%22%0A%20%20%20%20%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%0A%09%3Ccircle%20cx%3D%221%22%20cy%3D%221%22%20r%3D%221%22%20fill%3D%22blue%22%20stroke%3D%22none%22%20id%3D%22the_circle%22/%3E%0A%3C/svg%3E%0A%0A" width="400" height="400"></object>
    </body>
</html>

You can do the same thing with the xlink:href attribute of an SVG 'use' element, with one caveat: it's illegal to reference a full document. Instead, you need to reference an element in the document by its id, and that element will be deep-cloned into the SVG host document. In this example, the SVG document root element is reference by its id "the_svg" (note the hash tag at the end of URI).

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"&gt;
<svg width="4in" height="4in" id="the_svg"
     viewBox="0 0 4 4" version="1.1"
     xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"&gt;
    <use x="0" y="0" width="4" height="4" xlink:href="data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20standalone%3D%22no%22%3F%3E%0A%3C%21DOCTYPE%20svg%20PUBLIC%20%22-//W3C//DTD%20SVG%201.1//EN%22%20%0A%20%20%22http%3A//www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd%22%3E%0A%3Csvg%20width%3D%224in%22%20height%3D%224in%22%20id%3D%22the_svg%22%0A%20%20%20%20%20viewBox%3D%220%200%204%204%22%20version%3D%221.1%22%0A%20%20%20%20%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%0A%09%3Ccircle%20cx%3D%221%22%20cy%3D%221%22%20r%3D%221%22%20fill%3D%22blue%22%20stroke%3D%22none%22%20id%3D%22the_circle%22/%3E%0A%3C/svg%3E%0A%0A#the_svg"/>
</svg>

FYI, this works well in Batik 1.7 (tested in the Squiggle browser), but not Chromium or Firefox.

echo-flow
An svg "image" tag would also work instead of a "use". In that case, you would not need to reference the root element by its id in the URL.
echo-flow
thank you, I tried it and it works well.
Olivier
Great! You should probably mark this answer as correct, then.
echo-flow