Android Vector Drawable Loader
Overview
The AVD Loader is an Add-On Library that can load vector images from Android Vector Drawable XML files. Unlike the vector images that are loaded using a raw output file format (see Vector Images), the XML parsing and interpreting is done at runtime. This is useful for loading a vector image as an external resource, especially when the resource has to be loaded dynamically (i.e., not known at build-time).
To use the AVD Loader library, add the following dependency to the project build file:
implementation("ej.library.ui:vectorimage-loader:1.1.0")
<dependency org="ej.library.ui" name="vectorimage-loader" rev="1.1.0"/>
Note
The AVD Loader library requires the VG Pack 1.2 and above.
Supported Format
The library supports the vector drawables with the following elements (in that order):
<vector>
:Used to define a vector drawable
android:viewportWidth
:The width of the image (must be a positive value).
android:viewportHeight
:The height of the image (must be a positive value).
<path>
:Defines a path.
android:fillColor
:(optional) The color used to fill the path. Color is specified as a 32-bit ARGB value in hexadecimal format (
#AARRGGBB
). This attribute is optional when a gradient color is specified (see below).android:fillType
:The fillType for the path, can be either
evenOdd
ornonZero
.android:pathData
:The path data, using the commands in {
M
,L
,C
,Q
,Z
} (match upper-case).
A linear gradient can also be used as color fill for a <path>
. This element is optional if a solid color fill has been specified.
<gradient>
:Used to define a linear gradient
android:endX
:The x-coordinate for the end of the gradient vector.
android:endY
:The y-coordinate for the end of the gradient vector.
android:startX
:The x-coordinate for the start of the gradient vector.
android:startY
:The y-coordinate for the start of the gradient vector.
<item>
:Defines an item of the gradient (minimum two items for a gradient).
android:color
:The color of the item. Color is specified as a 32-bit ARGB value in hexadecimal format (
#AARRGGBB
).android:offset
:The position of the item inside the gradient (value in [0..1]).
Here is an example of a Vector Drawable myImage.xml
that complies with that format.
It defines a 100 x 100 image with two paths: the first one with a solid color fill, the second one with a linear gradient.
<vector xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android" android:height="100.0dp" android:viewportHeight="100.0" android:viewportWidth="100.0" android:width="100.0dp">
<path android:fillColor="#FFFFFFAA" android:fillType="nonZero" android:pathData="M0,0L50,0L50,50L0,50Z " />
<path android:fillType="nonZero" android:pathData="M50,50L100,50L100,100L50,100Z ">
<aapt:attr name="android:fillColor">
<gradient android:endX="100.0" android:endY="100.0" android:startX="50.0" android:startY="50.0" android:type="android:linear">
<item android:color="#FF0000FF" android:offset="0.0" />
<item android:color="#FFFF00FF" android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
</vector>
If the input Vector Drawable does not comply with this format, the library will throw an exception.
Note
To make a Vector Drawable compatible with the library, use the image generator tool to convert the AVD into a compatible version. See this section for more information.
Format Limitations
The library only supports a subset of the Vector Drawable specification.
The AVD Loader is designed to load AVDs at runtime on embedded devices. It minimizes Java heap usage and CPU time for XML parsing, Path creation, and adds little code to the final executable. The format is intentionally limited to reduce processing time and complexity while ensuring good performance, knowing that the pre-processing step can convert any AVD into the compatible format.
Note that this limitation on the Android Vector Drawable format does not apply to AVDs loaded as raw vector images.
Loading a Vector Drawable
The following code loads the Vector Drawable myImage.xml
with the AvdImageLoader.loadImage()
method.
This method has one parameter which is the path to the Vector Drawable file, provided as a raw resource of the application.
The resulting vector image can then be drawn on the display:
public static void main(String[] args) {
MicroUI.start();
Display display = Display.getDisplay();
GraphicsContext g = display.getGraphicsContext();
try (ResourceVectorImage image = AvdImageLoader.loadImage("/images/myImage.xml")) {
VectorGraphicsPainter.drawImage(g, image, 100, 100);
display.requestFlush();
}
}
/images/myImage.xml
|
Note
The image must be provided as a raw resource of the application, either internal or external. For external resource loading, the BSP must implement the proper Abstraction Layer API (LLAPI), see External Resources Loader for more information on the implementation.
Warning
The new image is a ResourceVectorImage
. In the current implementation, an image loaded with the AvdImageLoader
is allocated in the Java heap. To release memory, the application must close the image and remove any references to it.
Limitations
The AVD Loader can only load static images (i.e., no animations). The other limitations are the same as for vector images.
Advanced
Make a AVD Compatible with the Library
To ensure that a Vector Drawable can be loaded by the AVD Loader library at runtime, the image generator tool can generate a compatible version of the drawable.
The tool comes with the VG pack installed in the platform, use the following command line to run it:
java -cp [path_to_platform]/source/tools/imagegenerator-vectorimage.jar com.microej.converter.vectorimage.Main --input originalImage.xml --avd myImage.xml
This processes the input Vector Drawable originalImage.xml
and outputs a Vector Drawable myImage.xml
which is compliant with the library and optimized for runtime loading.
The processing does the following:
Normalize the output
Limit the size of the XML file (e.g., minification)
Pre-process the resource-consuming operations (e.g., transformations, stroking)
Make a SVG Compatible with the Library
It is possible to convert a SVG into a compatible Vector Drawable using the platform tooling. Use the following command:
java -cp [path_to_platform]/source/tools/imagegenerator-vectorimage.jar com.microej.converter.vectorimage.Main --input originalImage.svg --avd myImage.xml
This processes the input SVG originalImage.svg
and outputs a Vector Drawable myImage.xml
.
Memory Usage
The loading of a Vector Drawable at runtime uses Java heap:
for the working buffers and intermediate objects used during the loading phase. The XML parser is optimized to stream the data and uses as few heap as possible.
for the image data.
Simplify the Path Data
The loading time and heap usage grow linearly with the number of path commands in the Vector Drawable. To achieve optimal performances, it is recommended to reduce the number of path commands, by “simplifying” the paths. The simplification algorithm will determine the optimal amount of anchor points to use in the artwork. Most of the modern Graphic Design Software have an option to simplify a path (check this article for Adobe Illustrator for example).
Monitor the Number of Path Commands
To print the number of paths and path commands declared in a Vector Drawable, set the constant ej.vectorimage.loader.debug.enabled
to true
.
This will output the numbers in the console when loading a file.
Output example:
avdimageloader INFO: Parsed a path data with a number of 5 commands
avdimageloader INFO: Parsed a path data with a number of 5 commands
avdimageloader INFO: Parsed a path data with a number of 28 commands
avdimageloader INFO: Number of paths in loaded image: 3
Troubleshooting
The Image Cannot Be Parsed
A error can be raised when the parsing fails:
Exception in thread "main" ej.microvg.VectorGraphicsException: MicroVG: The image cannot be parsed. The image must be a valid AVD image, converted with the platform's image generator.
This error indicates that the file is not a compatible Vector Drawable, as specified in this section.