Anyone ever tested if there is any difference in using a custom font vs multiple SVGs for icons?
If so, any insights into your experiences? Should I prefer a custom font or can I switch to SVGs savely?
Anyone ever tested if there is any difference in using a custom font vs multiple SVGs for icons?
If so, any insights into your experiences? Should I prefer a custom font or can I switch to SVGs savely?
I just wrote a little memory test watch face to see the differences. I tested it with the simulator using the Venu SQ and I used 11 icons:
Type | Memory Usage | Peak Memory |
iconFont, draw all icons using separate dc.drawText() calls | 9.2 | 9.8 |
putting all svg icons in one drawable-list and drawing all at once with one X.draw(dc) call | 10.1 | 10.6 |
using <bitmap> in drawable.xml for each icon and drawing all the icons with separate dc.drawBitmap() calls | 9.7 | 10.2 |
putting each svg icon in a separate drawable-list and drawing all the icons with separate iconX.draw(dc) calls | 14.6 | 15.1 |
So an icon font would be the best memory wise!
I've used an icon font for years. One thing it also has over using bitmaps is that it's simple to change colors based on things like the background color and also if you want the icon's color to indicate a state. For example, the BT icon can change color based on if the phone is connected or not, without having different bitmaps.
That's nice, but usually when developing watch faces the memory isn't the biggest concern, and people tend to optimize for time. Can you modify your test to also measure time? (Though it might not ne that easy as doing the same thing in loop, as some thing will take more time for the 1st time than the 2nd time because of internal cashing I guess)
Thanks for those informations, very interesting. I made a test myself in the meantime.
5 SVG icons and a font containing the same 5 icons, both resized to 36px (either via bmfont or via the resources).
<resources> <strings> <string id="AppName">Test WF</string> </strings> <drawables> <bitmap id="LauncherIcon" filename="launcher_icon.png" /> <!-- SVGs --> <bitmap id="svg_gear" filename="svgs/gear-solid.svg" packingFormat="png" compress="true" scaleX="36" scaleY="36" /> <bitmap id="svg_hammer" filename="svgs/hammer-solid.svg" packingFormat="png" compress="true" scaleX="36" scaleY="36"/> <bitmap id="svg_house" filename="svgs/house-solid.svg" packingFormat="png" compress="true" scaleX="36" scaleY="36" /> <bitmap id="svg_sun" filename="svgs/sun-solid.svg" packingFormat="png" compress="true" scaleX="36" scaleY="36" /> <bitmap id="svg_wind" filename="svgs/wind-solid.svg" packingFormat="png" compress="true" scaleX="36" scaleY="36" /> </drawables> <fonts> <font id="font_icons" filename="fonts2/test2.fnt" antialias="true" filter="ABCDE" /> </fonts> </resources>
Test code:
import Toybox.WatchUi; import Toybox.Graphics; import Toybox.System; import Toybox.Lang; public class WatchView extends WatchUi.WatchFace { var w as Number = 0; var h as Number = 0; var image as BitmapResource? = null; var image2 as BitmapResource? = null; var iconFont as FontResource or FontReference or Null = null; function initialize() { WatchUi.WatchFace.initialize(); image = Application.loadResource(Rez.Drawables.svg_gear) as BitmapResource; image2 = Application.loadResource(Rez.Drawables.svg_hammer) as BitmapResource; iconFont = Application.loadResource(Rez.Fonts.font_icons) as FontResource or FontReference; } function onLayout(dc) { w = dc.getWidth(); h = dc.getHeight(); } function onUpdate(dc) { dc.setColor(Graphics.COLOR_DK_GRAY, Graphics.COLOR_DK_GRAY); dc.clear(); dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT); dc.drawText(w / 2, h / 4, Graphics.FONT_SMALL, "SVG Test", Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER); dc.setColor(Graphics.COLOR_RED, Graphics.COLOR_TRANSPARENT); dc.drawText(w / 2, h / 4 * 3, iconFont as FontResource or FontReference, "ABCDE", Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER); dc.drawBitmap2( (w - (image as BitmapResource).getWidth()) / 2, (h - (image as BitmapResource).getHeight()) / 2, (image as BitmapResource), { :tintColor => Graphics.COLOR_GREEN } ); dc.drawBitmap2( (w - (image2 as BitmapResource).getWidth()) / 2 + 50, (h - (image2 as BitmapResource).getHeight()) / 2, (image2 as BitmapResource), { :tintColor => Graphics.COLOR_BLUE } ); } }
Memory usage:
It seems like the font with all 5 images does use as much runtime memory as a single SVG with the same size - so BMFont is compressing a lot better as the SVG + png format + compress option garmin does provide...
I wanted to enjoy the possibilities of affine transformations with PNGs directly but seems like I should prefer a font + buffered bitmap if I need transformations instead...
In my real world use case I will always show 10-15 icons at once so the cost of the SVG images is relative large for my use cases...