Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SVG conversion - efficient way to store Path, Paint and Matrix objects?

Tags:

android

svg

In my Android application I have created an SVG image converter class. It parses through the SVG XML data and converts it into the appropriate Path, Paint and Matrix objects which can then be applied to the Canvas. Using this class I have then implemented a View which uses my SVG converter class to draw images I've produced in Inkscape on the screen. So far, so good. (I appreciate that writing my own SVG converter could be considered reinvention of the wheel considering it's been done before, but for me it's a useful learning exercise in my first Android application, and shall hopefully give me some extra flexibility.)

The purpose of using SVG is so that I can quickly and easily author various designs of graphical gauge. Each gauge typically consists of a section of graphics which only need to be drawn once (e.g. the gauge face and legends), plus graphics which are regularly updated (pointer angle, numeric value text).

At present my gauge View is not very efficient because every time onDraw() is called, my SVG class is called to rattle through the entire SVG file to produce all the vector data for the Canvas.

What I would like to do is to have some intermediate storage of the vector data so that the SVG XML file only need be parsed once. Therefore, I was thinking that the View could lazy-initialize itself from the SVG file on the first onDraw() and then store all of the resulting Paths, Paint and Matrix objects to various Lists. Then, on each subsequent onDraw(), I just pull those out of the List(s) and rattle through those onto the Canvas.

A further advantage of this would be to use separate Lists to store sections of vector graphics that are "moving", e.g. the gauge pointer. I thought of doing this by assigning a certain 'magic' ID to the group of paths in Inkscape that represent the pointer; the SVG parser class would then recognise that this separate group needs to be stored separately to the 'still' graphics. Then, whenever I need to refresh the angle of the pointer in accordance to measurement data, the View will only apply the rotational transform to that bunch of vector data. In fact, I'm thinking of doing it so that the moving pointer graphics are actually drawn in a child View, so that just the child View is redrawn when the pointer has to be refreshed.

The end objective of all of this is this: I (or perhaps even users) could fire up a vector imaging program like Inkscape and quickly produce a new design of gauge widget. I embed a bit of metadata to indicate which bits of the graphics have to be manipulated according to measurement data.

Rather than asking for a solution to a problem as such, I'd like to hear opinions about what I'm doing here, and whether what I'm proposing could be done in a much more optimised way. Could it be very memory inefficient to cache groups of Path and Paint objects?

Furthermore, once it's good enough(!) I'll gladly publish my SVG class somewhere if anyone would find it useful.

like image 215
Trevor Avatar asked Apr 26 '11 18:04

Trevor


1 Answers

Implement and measure! Start with the straightforward approach--store your parsed vector data in lists in memory. If memory usage and rendering speed is acceptable: problem solved. If not, try other things and measure. Some ideas:

  • parse SVG once, render once to Bitmaps, reuse bitmaps
  • render SVG as a part of build process, ship raster bitmaps with app

Except for the simplest cases, we're not very good with assesing how effective a particular technique is going to be. Thus the popular saying that premature optimization is root of all evil.

like image 114
Pēteris Caune Avatar answered Nov 17 '22 15:11

Pēteris Caune