Sunday, 15 May 2011

Groovy, Apache Batik and a little syntactical sugar speeds up Android development

As I read more and more of Android in Actionand further delve into the world of mobile development, one of the newer concepts I have come across is how to scale android applications to various different sizes of screen, hardware and resolutions.Google have good documentation in this subject area and have an entire section of the developer portal dedicated to this but this doesn't mean that trying to ad hear to them isn't a time consuming activity.

The problem I have been having is as I further try to improve the usability and functionality of my current Android applications in development, and try to follow the guidelines laid out by Google for simple things such as various different icon sizes depending on different screen resolutions, this process is eating all my time!

Table 1. Summary of finished icon dimensions for each of the three generalized screen densities, by icon type.
Icon TypeStandard Asset Sizes (in Pixels), for Generalized Screen Densities

Low density screen (ldpi) Medium density screen (mdpi) High density screen (hdpi)
Launcher 36 x 36 px 48 x 48 px 72 x 72 px
Menu 36 x 36 px 48 x 48 px 72 x 72 px
Status Bar (Android 2.3 and later) 12w x 19h px
(preferred, width may vary)
16w x 25h px
(preferred, width may vary)
24w x 38h px
(preferred, width may vary)
Status Bar (Android 2.2 and below) 19 x 19 px 25 x 25 px 38 x 38 px
Tab 24 x 24 px 32 x 32 px 48 x 48 px
Dialog 24 x 24 px 32 x 32 px 48 x 48 px
List View 24 x 24 px 32 x 32 px 48 x 48 px

I aim for all the icons I use to be in SVG format simply because they scale well and and can be easily converted to the desired format, PNG in this case. I use Gimp for windows to convert all the SVG files I have to the various different PNG's. This process is very manual and very time consuming which got me thinking......

After a little Google I stumbled across an Apache project for XML image manipulation called Batik. It seemed vast and very comprehensive but thought I'd give it ago.



I created a simple Groovy script which wraps Batik, exposing some Android orientated functionality cutting down the time to convert images from minutes to seconds, and when you start trying to convert larger numbers of SVG's to PNG in various sizes with the same name outputting them in different folders it can take hours.


I simply define various required image size groups which hides the mess and allows me to simply say I want this SVG converted to the required ANDROID_TAB dimensions.



Below is what I ended up with.


class SvgImageCreator {

 public static void main(String[] args) {
  new SvgImageCreator().convert(SizeGroups.ANDROID_DIALOG, [
   "menu_bug",
   "menu_clear_stats",
   "menu_credits",
   "menu_email",
   "menu_improvement",
   "menu_play_again",
   "menu_settings",
   "menu_manage_groups",
   "menu_add_group"
  ])
 }

 def convert(def sizes, def filesToConvert){
  filesToConvert.each{ file ->
   sizes.eachWithIndex { i, index ->
    println """Converting ${file} to W:${i[0]} H:${i[1]} for folder: ${SizeGroups.FOLDERS[index]}"""
    convertToPng(file, SizeGroups.FOLDERS[index], i[0], i[1])
   }
  }
 }

 def convertToPng(def name, def folder, def width, def height){
  final SVGConverter svgConverter = new SVGConverter();
  svgConverter.setSources(["images/svg/${name}.svg"]as String[]);
  svgConverter.setHeight(height);
  svgConverter.setWidth(width);
  svgConverter.setDst(new File("images/${folder}/${name}.png"));
  svgConverter.execute();
 }
}


At present it consists of a simple Groovy script with a runnable main method. With the aid of some Groovy syntactical sugar making this script easy to read and easy to extend if needs be. I created a static helper class containing definitions of all the various sizes and folder names. All it does is simple loop round the given SVG's and converts each one to the three different sizes specified and places these PNG's in various different folders depending on size. I imagine as a new app features get created and thus maybe further graphics are required you could simply add your new conversion definition and job done. 

After thinking about this over night, you could extend this to be quite intuitive, creating an eclipse plug-in which scans chosen folders outputting images of various sizes depending on file naming conventions. You could also have this as a standalone runnable jar which you booted up when you started development and performed the required actions after looking at a definition files in which would layout the conversions to and from. Obviously it doesn't do that at the moment and to be honest it has solved my problem saying me vast amounts of time as it stands so hopefully someone else may also benefit from it.

Please feel free to check out my GitHub where all the code is available: https://github.com/jamesemorgan/AndroidSvgToPngConverter. As ever comments are always welcome.

To get the project running simple clone the above project and add the missing dependency on Batik by downloading the source files from http://xmlgraphics.apache.org/batik/Groovy Eclipse plugin installed you should be fine.  

An example of the above images used in and Android menu can be seen below: