Dev diary: SVG markup optimizations
2 Over-optimizing SVGs
Previous optimizations were useful only for optimizing consecutive line segments with the same color and thickness. It would be useful to group lines with same thickness and color to groups. Unfortunately in order to do that it is necessary to reorder lines. Reordering might cause different rendering result if lines are overlapping but in many cases order does not matter. Examples of such L-systems are shows in Figure 1. Because of possibility of unpredictable results of this optimization, it is disabled by default and it can be explicitly enabled with overoptimizeSvg
settable property of SvgRenderer2D
.
The L-systems with no overlapping lines or when order does not matter too much greatly benefit from reordering and file size savings are large. To save even more, there is two-level hierarchy of groups - by color and by line width. It is dynamically resolved whether it is better to have width groups with color sub-groups or vice versa. Implementation uses SVG g tag to group lines.
Lastly, thanks to path element which enables not only to draw ploy-line but also jump to different location, line segments with same width and color are grouped to the same path tag even if they are not continuous line. This gives us even larger savings in L-systems which have many branches.
2.1 Results
Nice example to demonstrate benefit of described "over-optimization" are L-systems H-tree and rainbow-colored Hexa Gosper curve. SVG code in Code listing 1 shows how H-tree was "over-optimized" without "damaging" the image (code is truncated). The SVG has as many path
tags as many different thicknesses there is. The same is true for the color.
1 2 3 4 5 6 7 8 9 10 | <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC ...> <svg xmlns="http://www.w3.org/2000/svg" viewBox="-319.8 -451 639.6 454" ...> <g stroke="#000"> <path stroke-width="6" d="M 0 0 L 0 -256 " /> <path stroke-width="5" d="M 0 -256 L -181 -256 M 0 -256 L 181 -256 " /> <path stroke-width="4" d="M -181 -256 L -181 -128 M -181 -256 L -181 -384 ..." /> <path stroke-width="3" d="M -181 -128 L -90.51 -128 M -181 -128 L -271.5 ..." /> </g> </svg> |
Figure 2 shows results of optimization and over-optimization on several examples. The reduction on non-gzipped SVGs is around 60-80%, gzipped SVGs are around 30-50% smaller.
(a) Raw SVG sizes comparison
(b) GZippled SVG sizes comparison
Figure 2: Results of over-optimization
Notice how over-optimization "messed" up order in Plant L-system in Figure 4. However, in this case it is barely noticable and acceptable. Look at the bottom of the plant, the small branches were in the back and now they are in the front.
2.2 Future work
As an update to SVG optimization topic on July 2014, I realized that there are several tools that do the SVG optimization, for example:
Optimizations described in this article are specific to L-systems but I believe that those tools would do even better job. Those tools would be quite simple to plug to existing pipeline but I don't like to use non-native tools in 100% managed application like Malsys. However, if there ever be a good reason to use them, I can consider it.