Thursday, September 27, 2012

How to convert SVG data to a Png Image file Using InkScape

Introduction

The project required the need to put the visual pie chart on a web page on the client and in a Pdf file created on the server. I eventually choose to use a Telerik Kendo DataViz Chart control on the client, and use a PNG file on the server for the Pdf file. This blog post will explain the process and code to convert the client-side pie chart Svg data to a Png file, and provide a download to the working code.

Prerequisites

You need to have a trial version of the Telerik Kendo library installed in order to make the sample code work. You also need InkScape installed. InkScape is the application that does the actual conversion. You will need to change the Web.config appSetting of “ExeDirectoryForInkscape” to represent your own installation location.

Any SVG Data Will Work

The pie chart was created using the Telerik Kendo DataViz chart control. While I name a specific control, as long as you have access to the SVG data, the same conversion process on the server will work.

The Sample App

The sample application is a Asp.Net MVC 4.0 C# application with a pie chart via the Kendo JavaScript library. Above the pie chart is a convert button and to the right of the JavaScript pie chart is the final converted Png image.

 

image

Not Pixel-Perfect

You can see from the image above that the conversion is close but not perfect. The title of the chart, the date and time, is larger on the left than on the right. If you need pixel-perfect conversion, this method is not for you. If you can tolerate minor discrepancies, InkScape is a great conversion tool.

Grab the SVG Data

Since the Telerik Kendo UI pie chart is on the client, the JavaScript needs to grab the data and send it to the server for conversion.

 

function getPieChartPngImage() {

    "use strict";

    // get svg data from Telerik Kendo Pie Chart
   
var piechart = $("#piechart").data("kendoChart");

    // prepare string by escaping it
   
var svgPieString = escape(piechart.svg());

    // send svg data to server
   
$.ajax({
        url: '/Home/SvgToPng/',
        type: 'POST',
        data: {
            // actual data
           
svgpie: svgPieString
        },
        // webImageFileLocation is the UNC path to the converted image
       
success: function (webImageFileLocation) {

            // load UNC path into image's src attribute
           
$('#image').attr('src', webImageFileLocation);

        },
        error: function () {
            alert('error in call to /Home/SvgToPng/');
        }
    });
}

The Controller & Method

The SvgToPng controller method gets the UrlDecoded string and passes it to the SvgToPng.Save method along with the Server.MapPath of the location of where to save the converted file. It returns a file path which is then converted into the UNC path. Then the UNC path is returned to the client for use in an <IMAGE> src attribute.

[HttpPost]
public JsonResult SvgToPng(string svgpie)
{
    SvgToPng svgToPng = new SvgToPng(null);

    // convert svg data to png file
    string gridPngFileLocation = svgToPng.Save(HttpUtility.UrlDecode(svgpie), "sample", "pie", Server.MapPath("~/Content/Images"));

    // convert file path back to unc
    string uncPath = gridPngFileLocation.Replace(Request.ServerVariables["APPL_PHYSICAL_PATH"], "/").Replace(@"\", "/");

    return Json(uncPath);
}

Using InkScape

The InkScape code is in a separate class library in the application. There are several things it needs to do

 

  1. Set the file name
  2. Grab the Exe location from the Web.config for InkScape
  3. Save SVG data to a file
  4. Convert SVG file to a PNG file

I’m going to assume you can read the code for yourself for the first three steps. I’ll skip to the last step.

Conversion Process

The conversion process is in Convert(string fileAndPathToSvg, string newFileAndPathToPng). The command line arguments for InkScape are built up:

this.CmdLineArgs = "-f " + fileAndPathToSvg + " -e " + newFileAndPathToPng;

 

Then the InkScape location and command line arguments are passed into the CommandLineThread(this.ExeLocation, this.CmdLineArgs) method where a new process is created to execute in the shell.

private void CommandLineThread(string inkscapeCmdLine, string cmdLineArgs)
{
    if ((string.IsNullOrEmpty(inkscapeCmdLine)) || (!inkscapeCmdLine.Contains(".exe")))
    {
        throw new Exception("command line empty or doesn't contain exe: " + inkscapeCmdLine);
    }

    Process inkscape = new Process();

    inkscape.StartInfo.FileName = inkscapeCmdLine;
    inkscape.StartInfo.Arguments = cmdLineArgs;
    inkscape.StartInfo.UseShellExecute = false;
   inkscape.Start();

    inkscape.WaitForExit();
}

At this point the Png file and the Svg file should both be on the file system. All the application has to return is the location of the Png file as a UNC path that the <IMAGE> tag can use.

 

Download The Code

The Visual Studio 2010 project is available on Github.

Summary

The conversion of a Svg data string to a Png file is easy with the InkScape application. Calling InkScape from a process using the shell is the actual conversion process. Then the location of the converted file is the only information the client browser needs to display it.

2 comments:

  1. Not working under VS2012

    ReplyDelete
  2. Awesome post!!

    Thank you!! http://www.code-sample.com/

    ReplyDelete