harriyott.com

Converting SVG images to PNG in C#

I've been dynamically generating SVG images for the intranet I'm working on. I initially chose SVG, as it's an XML format, which is easy to manipulate in C#. I've started with the template picture, and added elements based on the data pulled from the database. These elements are lines and text, positioned according to the data.

There have been two minor problems so far. Firstly, although FireFox displays SVG files beautifully, IE just shows the XML. No biggie, as there's only a few users, and I can tell them to use FireFox (a pragmatic bug fix!). The other problem is that one of the users wants to copy and paste the image into PowerPoint. With a BMP, JPEG or PNG image, the context menu has a copy option that just isn't there with SVG, so there's no simple way to get it into PowerPoint. Time to bite the bullet (whatever that means) and convert the image to PNG.

I decided not to convert my code to use the System.Drawing to generate PNGs from the database data, as I'd already solved that problem. Surely conversion would be easier...

The obvious first step is to Google for a free SVG to PNG library, or example code on CodePlex or something, but I couldn't see anything amongst the noise of shareware apps that did conversions through a GUI. I did however, find mention of inkscape's command line interface. Inkscape is an open source SVG editor, which I used to create the image template.

I tried it out, and it was really quick, and the resultant PNG file was indistinguishable (that's a longer word than it sounds) from the original. Now to call it from the .ashx. This was quite simple, but I'll put the code here for any future Googlers (and there'll be some, there always is. If it's you, then hello and welcome. You're the reason I wrote this post). First, the "spec":
  1. Write the SVG file to disk
  2. Start inkscape as a process with the correct parameters
  3. Send the PNG file back to the browser


Now the code:

public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "image/png";

String svgXml = GetSvgImageXml(context);
string svgFileName = GetSvgFileName(context);
using (StreamWriter writer = new StreamWriter(svgFileName, false))
{
writer.Write(svgXml);
}

string pngFileName = GetPngFileName(context);

string inkscapeArgs =
"-f " + svgFileName + " -e \"" +
context.Server.MapPath(PngRelativeDirectory) + "\\" +
pngFileName + "\"";

Process inkscape = Process.Start(
new ProcessStartInfo(
"C:\\program files\\inkscape\\inkscape.exe",
inkscapeArgs));
inkscape.WaitForExit(3000);
context.Server.Transfer(PngRelativeDirectory + pngFileName);
}


There's only one drawback that I can see, and that's having to install inkscape on the server. It's fine for me and my intranet, but may not be possible on hosted servers.
23 May 2008