Create CSS Sprites with ImageMagick

After colorizing the SVG icons I needed to create images suitable for CSS sprites out of them. The first step is rasterizing the SVG files, as I described in the previous article.

We now have a bundle of PNG files, which lay around and wait to be joined in one single image. Fortunately, the command line cure for this problem is clear. It’s called ImageMagick.

The following small script does the needed magic. Let’s go through it line by line.

ICONIDS=$(sed -n '/id=/p' icons.svg | grep transform= | \
sed 's/.*id="\([^"]\+\)".*/\1/')

for item in $ICONIDS; do
montage -background transparent -tile 1x7 -geometry 24x24 \
bookmark/static/$item.e60042.png \
bookmark/static/$item.ffffff.png \
bookmark/static/$item.95002b.png \
bookmark/static/$item.ff9fbc.png \
pngcrush -b bookmark/static/$item.uncrushed.png bookmark/static/$item.png

The SVG file is marked up with the following assumption holding: Each icon has an attribute id="icon name" and the attribute transform. (The later is used to translate the icon away from (0,0) for better viewing in SVG editors.) Both attributes are on the same line. (In general this is a strong assumption for an XML file, but in this case it’s useful.)

Then the first line filters out all icon IDs. Find all lines with an attribute id, filter them for lines with the attribute transform and finally print only the ID. Store the result in ICONIDS.

The for loop goes through all icons. We will create a sprite image for each of these IDs. I assume, that there are four images per ID already ready: <ID>.ffffff.png is the white icon <ID>, <ID>.e60042.png the dark-red and so on.

The magic happens in the call to montage(1). The sprite components should be separated by one empty tile between each color, because the HTML element, where the sprite is applied, is higher than the icon height.

I achieved this with the combination of -geometry 24x24, which sets the tile dimensions, and the NULL: pseudo-image, that ImageMagick uses in cases, where no real image data is there.

So the call to montage simply joins the images in the given order, with empty space, where a NULL: stands. The result wanders into <ID>.uncrushed.png.

Finally we use pngcrush(1) to reduce the file size of the generated sprite images. The -b switch lets pngcrush try with brute force to find optimal reduction.

É voila! Ready are our CSS sprites. Now, if we find an error in the SVG source, it’s a matter of one Makefile rule to regenerate all buttons.