Recipe for SVG to PNG with svg2png
The SVG files generated by Lineform have a
viewBox attribute and
height attributes on the outermost
svg element. This
is good because it means that is necessary to get Webkit browsers (at
least) to treat them as scalable (apparently the S in SVG was not enough
of a hint). Alas! the
svg2png utility I want to use to downgrade SVG
files to PNG requires
height attributes or it assumes
nonsensical values. Here’s my silly recipe for achieving this without
having two copies of every SVG file.
Background: Scaling SVG
Hundreds of thousands of years ago when SVG was first tried, the most
used implementation was Adobe’s SVG Viewer plug-in (which Adobe dropped
when Mozilla changed one of its APIs so that it stopped working). You
embed SVG in a web page using the
embed tag, like so:
<embed src="http://static.alleged.org.uk/logo/logo.svg" type="image/svg+xml" width="120" height="120" />
The SVG recommendation has rules for scaling the contents of an
element: it may be shrunk to fit within the viewport (that is, the width
and height specified), expanded to cover the viewport, or scaled
anamorphically. Adobe’s plug in took the viewport size from the
tag, even if
height are specified on the SVG file's root
When Mozilla belatedly added SVG support to Gecko (and hence Firefox),
they took a different approach from Adobe’s. The
attributes of the
embed tag no longer set the viewport; instead the
height of the SVG document are used. The result is that if
the above logo were to have its width and height specified as 512 then
what you see embeded would be only its top corner:
When Webkit gained SVG support they followed this new convention.
In order to use my graphic at a variety of sizes, I either need to have
a different file for each size, or I can instead omit the
height attributes, in which case Mozilla and Webkit assume the SVG
graphic should fill the viewport (which is usually what you want).
brew install svg2png
Doubtless you can install it using your favourite package manager with
some effort. (Also, there are dozens of other apps also called
I should be able to generate a 275×100 PNG of the word ‘alleged’ from the SVG by doing
svg2png -w275 -h100 alleged.svg alleged-275x100.png
height attributes in the file, it seems that
svg2png assumes the natural size of the SVG document is 450×450.
The logo ends up squashed up in to a square in the middle of the image.
You can fix this by setting the
height attributes to match
the width and height of the
This leaves us with the nasty requirement to have two copies of every SVG file: one with those attributes and one without.
Here’s how I have worked around this problem. I store the SVG files
height. This is conveniently how they are
generated by Lineform, and how they need to be for the web server.
When generating the PNG versions for legacy browsers, I use this incantation:
sed -e 's/viewBox="0 0 \([0-9.]*\) \([0-9.]*\)"/& width="\1" height="\2"/' \ < alleged.svg | svg2png -w275 -h100 > alleged-275x100.png
This creates a temporary version of the document with the attributes inserted,
svg2png's ability to operate as a filter.
There are two under-appreciated aspects of Unix in play here.
Using plain-text file formats wherever possible means that you can fix problems using generic tools like
Converters that can read from standard input and write to standard output—called a filter in Unix parlance—allow you to fix things by stacking commands in a pipeline without even needing create temporary files.
The SVG format has annoyed some people by being based on XML rather than binary. This is an example of how being an application of XML, itself an application of plain text, is invaluable when things go wrong.