Vector Graphics in Android: Converting SVG to VectorDrawable

Vector graphics native support has long been on the wishlist of Android developers who have to export their vector graphics as a rasterized PNG file for each different device resolution.

Introducing VectorDrawable

The good news is that the Android SDK now has native support for basic vector graphic definitions. With the release of API 21 (Android 5.0) came VectorDrawable.

android.graphics.drawable.VectorDrawable

The most important things to understand if you want to implement drawables in your app using VectorDrawable are:

  • VectorDrawable is not implemented in the support library, therefore it will only work in Android 5.0+ (VectorDrawable support for older APIs may be coming soon to the support library)
  • VectorDrawable supports paths using the same definition as the ‘d’ attribute in the SVG format
  • VectorDrawable does not read or support the SVG format
  • VectorDrawable does not support gradients and patterns
  • VectorDrawable does not support numbers using scientific E notation (as commonly used in SVG)

While it is important to understand that the SVG format is not supported, it doesn’t necessarily mean you can’t convert your existing simple SVG files. A VectorDrawable is specified through XML, with the format of the path data in the VectorDrawable using the same format as the specification for SVG paths. This allows us to reformat the XML in some SVG files to convert it into a VectorDrawable XML file.

If you are looking to use SVG files directly in your Android app take a look at this comparison of 3rd party solutions:

https://androidbycode.wordpress.com/2015/02/27/vector-graphics-in-android-part-1-svg/

Case Study: Converting SVG to VectorDrawable

The penguin in the image below (Attribution: Larry Ewing) has been rendered from a SVG image.  SVG images such as this can not be converted into a VectorDrawable as it uses LinearGradient in the original source.NewTux

Below is a rendered image of the flag of Ghana, it is also rendered from an SVG however as this image doesn’t have a gradient and only includes simple shapes, it is most suitable for conversion to a VectorDrawable. We will use this image as to illustrate how to convert an SVG into a VectorDrawable.

Flag of Ghana

SVG Images are described using the XML format. The above image contains 4 elements; three stripes and a star. The SVG XML source may appear as follows:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:svg="http://www.w3.org/2000/svg"
  width="450"
  height="300"
  id="svg2"
  version="1.1">
<rect
  width="450"
  height="300"
  fill="#006b3f"
  id="rect4" />
<rect
  width="450"
  height="200"
  fill="#fcd116"
  id="rect6" />
<rect
  width="450"
  height="100"
  fill="#ce1126"
  id="rect8" />
<path
  d="M225,100 L257.492,200 172.427,138.197H277.573L192.508,200z"
  fill="#000"
  id="path10" />
</svg>

If we want to create this same image as an Android VectorDrawable the first thing we need to do is ensure all items are described using paths. Remember only paths are supported in VectorDrawable.  To do this we convert each rect definition in the SVG image to use a path definition. The following XML shows the new path objects:


<path
  style="fill:#006b3f"
  d="m 0,0 450,0 0,300 -450,0 z" />
<path
  style="fill:#fcd116"
  d="m 0,0 450,0 0,200 -450,0 z" />
<path
  style="fill:#ce1126"
  d="m 0,0 450,0 0,100 -450,0 z" />

The next step is to convert the XML into Android’s new VectorDrawable format.  To do this we need to keep the path and color definitions but replace the formatting.  The XML should now look like this:


<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="450dp"
android:height="300dp"
android:viewportWidth="450"
android:viewportHeight="300">

<group>
  <path
    android:fillColor="#006b3f"
    android:pathData="M 0,0 l 450,0 0,300 -450,0 z" />
  <path
    android:fillColor="#fcd116"
    android:pathData="M 0,0 l 450,0 0,200 -450,0 z" />
  <path
    android:fillColor="#ce1126"
    android:pathData="M 0,0 l 450,0 0,100 -450,0 z" />
  <path
    android:fillColor="#000"
    android:pathData="M225,100 L257.492,200 172.427,138.197H277.573L192.508,200z" />
</group>
</vector>

This VectorDrawable file should be named with an .xml extension and placed in your drawables folder so it can be accessed in your Java source code or layout definition as you would with any other drawable.

The good news is you don’t need to step through this process by hand each time, there are tools to help you out. I have documented this process as it is important to know what and how to hand code the xml format as the conversion tools will not work all of the time so you may need to tweak the code from time to time.

To convert your SVG file to use only paths you can use Inkscape (The awesome open source SVG tool).  Open the SVG file in Inkscape and select all items you want to convert to a path.  Then from the Path menu select Object to path. If you use Adobe Illustrator then you need to convert the shapes into compound paths before saving the SVG.

To automate the conversion of an SVG file to the VectorDrawable format you can use the on-line open source svg2android tool.

VectorDrawable support pre Android 5.0

While the VectorDrawable class is only available on 5.0+ at this stage, an unofficial project has released support for older versions of Android.

Visit Mr. Vector on GitHub for the source code and usage instructions. You should note that the Vector XML used in this project is slightly different to the standard VectorDrawable specification. You can convert your simple SVG files to the Mr. Vector format using Svg2MrVector.

UPDATE MAY 2015: VectorDrawableCompat is in the process of being developed and may be added to the official support library. Once released there is no need to use the Mr. Vector project anymore, so keep an eye on the official Android Developers Blog for updates to the support library.

References:

Scalable Vector Graphics http://en.wikipedia.org/wiki/Scalable_Vector_Graphics

SVG Path Format http://www.w3.org/TR/SVG11/paths.html#PathData

VectorDrawable https://developer.android.com/reference/android/graphics/drawable/VectorDrawable.html

MrVector https://github.com/telly/MrVector

Inkscape https://inkscape.org/

“NewTux” by Larry Ewing. Licensed under Attribution via Wikimedia Commons – http://commons.wikimedia.org/wiki/File:NewTux.svg#/media/File:NewTux.svg

“Flag of Ghana”. Licensed under Public Domain via Wikimedia Commons – http://commons.wikimedia.org/wiki/File:Flag_of_Ghana.svg

2 Comments

Filed under Android SDK, Image

2 responses to “Vector Graphics in Android: Converting SVG to VectorDrawable

  1. phil

    What a bad idea from Google to introduce one more new format instead of supporting SVG ( standard ) which is directly supported by visual editors.
    Some thing as Microsoft introducing Direct X instead of relying on OpenGL.
    More messy code and incomptibilities will arise from this.
    This one supports gradients but this one doesn’t so there will be versions also. What a mess😦

    Like

  2. Bernard

    @phil: “Yet another format” I also thought that too at first. At the same time, SVG format is full of issues to start with. I think Android started with a clean slate so they can have a robust solution without introducing tons of code and complications. They at least tried to borrow the element (the most important one).
    Have you ever worked with SVG? To this day SVG files never renders the same across all browsers or players. I mean, after 15 years… Gradients, references system, nested documents. There are always problems.

    SVG is the mess.

    Liked by 1 person

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s