The SVG files generated by Lineform have a viewBox
attribute and
no width
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 width
and 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 svg
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 embed
tag, even if width
and height
are specified on the SVG file's root
element.
When Mozilla belatedly added SVG support to Gecko (and hence Firefox),
they took a different approach from Adobe’s. The width
and height
attributes of the embed
tag no longer set the viewport; instead the
width
and 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 width
and
height
attributes, in which case Mozilla and Webkit assume the SVG
graphic should fill the viewport (which is usually what you want).
Background: svg2png
The command-line program svg2png
is fallout of the Cairo
project. On Mac OS X, I can install it by installing Homebrew and doing
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
svg2png
.)
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
But without width
and 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 width
and height
attributes to match
the width and height of the viewBox
attribute.
This leaves us with the nasty requirement to have two copies of every SVG file: one with those attributes and one without.
Workaround
Here’s how I have worked around this problem. I store the SVG files
without width
and 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,
and exploits svg2png
's ability to operate as a filter.
Moral
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
sed
andawk
. -
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.