Skip to main content

How to convert SVG files to PNGs using C#

How to convert SVG files to PNGs using C#

or... how to convert vector images to normal images using C# with a good DPI that is better than the default of 96 DPI.


SVG files seem to be becoming more and more relevant in the Web and also other applications are using them. However, I was surprised to find that its NOT that easy to get a PNG out of a SVG file.

There are some tools out there, but they require python or the use of browsers... both not really perfect for my needs.
And my needs were that I needed a GUI that I can give my non-programmer colleages and that would just run on a windows PC.


When I was done I therefore figured out some of you out there might appreciate some help/info if you have similar problems: So I began to look if there are some C# libraries around and I stumbled upon several and two looked especially promising

SVG Rendering Engine    https://svg.codeplex.com

and


SharpVectors - SVG# Reloaded    https://sharpvectors.codeplex.com/


both also available via nuget.


Both support conversion to PNGs, though it feels like its just a side-effect of what the libraries actually want to accomplish.

WHICH of the two you use is up to you, what we are going to do works with both, but I personally prefer SharpVectors because of the better documentation, and cleaner code structure (imho, but ymmv).

So in sharpvectors you would now do the following:

 var converter = new ImageSvgConverter(null);  
 string temporary = file + ".tmp.png";  
 converter.Convert(file, temporary);  

so far so good, above code would create me a PNG file out of my SVG.
ALAS, the resolution sucks and via (both of) the library(ies) its not possible to just set the resolution (now i am talking about width and height in pixels) & DPI. or it SHOULD work but the result is not what I expected. In my researches I found quite many dead-ends. from what I read on the internet it may also be down to some GDI+ bug in Windows 7+, whatever it is, i needed some fix:

My PNG needed to have a resolution of 1200 DPI instead of the default 96.

So what did I do? First, I changed my SVG files. Inside the SVG files which are just XMLs, you have definitions for the width and height in pixels. With some calculations I upscaled the pixels there, in my case from

  <?xml version="1.0" encoding="UTF-8"?><svg version="1.2" baseProfil="full" width="1011px" height="638px" viewBox="0 0 1011 638" xmlns="http://www.w3.org/2000/svg">  
   <rect x="0" y="0" width="1011" height="638" fill="#FFFFFF"/>  
to
  <?xml version="1.0" encoding="UTF-8"?><svg version="1.2" baseProfil="full" width="4044px" height="2552px" viewBox="0 0 4044 2552" xmlns="http://www.w3.org/2000/svg">  
   <rect x="0" y="0" width="4044" height="2552" fill="#FFFFFF"/>  

Then in SVG you can scale around and do some other crazy stuff. I therefore changed the next XML node, which is a plain

 <g>   

to

 <g transform="scale(4.0, 4.0)">  

more or less meaning every child node that he renders he should render 4 times as big.


that now helped that the PNGs were printed out big enough in a good resolution, but for printers that rely on the DPI, where you dont want to use "fit to scale" when printing, but use the actual DPI information of the file we now still need to set the DPI from 96 to the correct 1200 DPI.

I ended up with a workaround to archieve that by creating a temporary Bitmap instance. Because it turns out, when i just set the resolution (DPI) of my image that i just created, it did not change anything.

so my final code looked like this

 private void SaveImage(uint dpi,string file)  
 {  
      var converter = new ImageSvgConverter(null);  
      string temporary = file + ".tmp.png";  
      string convertedFileName = file.Replace(".svg", "").Replace(".SVG", "") + ".png";  
      converter.Convert(file, temporary);  
      using (Bitmap bitmap = (Bitmap)Image.FromFile(temporary))  
      {  
           using (Bitmap newBitmap = new Bitmap(bitmap))  
           {  
                newBitmap.SetResolution(dpi, dpi);          //dpi could be 96, 300, 600, 1200, whatever floats your boat  
                newBitmap.Save(convertedFileName, ImageFormat.Png);  
           }  
      }  
      File.Delete(temporary);  
 }  
This finally archieved what I looked for:
photoshop, illustrator und irfanview finally correctly read out the 1200 DPI.

Satisfied, I created a small GUI around it and was able to provide the solution I was looking for:

Creating a PNG out of an SVG in any desired resolution (my case 4044px times 2552px) and DPI (1200 instead of 96)



Happy Coding

Comments

G said…
Excellent solution! Thanks
I used NuGet and got Magick.Net. Solved all my problems. Check it out.