115

I've been trying to convert SVG images to PNG using C#, without having to write too much code. Can anyone recommend a library or example code for doing this?

harriyott
  • 10,505
  • 10
  • 64
  • 103
  • 1
    i found a good and simple library that you can use in c# https://github.com/ElinamLLC/SharpVectors , it can convert many type of svg to bmp, jpeg or png – Mahdi Jan 07 '19 at 07:45
  • 2
    May I say: those solutions are bad, including wkhtml2pdf/wkhtml2image etc. The SVG specification is complex and evolving, so is CSS-styles, and on top of that, it should look the same as in the browser. wkhtml2X, for example, has massive problems with fonts, and the webkit engine inside is just too old. Fortunately, there is a solution: Chrome has headless-mode, and with its Debugging-API, you can get PNG-images and PDFs from Headless-Chrome itselfs, with MasterDevs/ChromeDevTools in C#: Example: https://github.com/ststeiger/ChromeDevTools/blob/master/source/SampleNet4/ConverterTest.cs – Stefan Steiger Sep 05 '19 at 06:54

6 Answers6

89

There is a much easier way using the library http://svg.codeplex.com/ (Newer version @GIT, @NuGet). Here is my code

var byteArray = Encoding.ASCII.GetBytes(svgFileContents);
using (var stream = new MemoryStream(byteArray))
{
    var svgDocument = SvgDocument.Open(stream);
    var bitmap = svgDocument.Draw();
    bitmap.Save(path, ImageFormat.Png);
}
AxelEckenberger
  • 16,628
  • 3
  • 48
  • 70
Anish
  • 3,045
  • 3
  • 27
  • 29
72

You can call the command-line version of inkscape to do this:

http://harriyott.com/2008/05/converting-svg-images-to-png-in-c.aspx

Also there is a C# SVG rendering engine, primarily designed to allow SVG files to be used on the web on codeplex that might suit your needs if that is your problem:

Original Project
http://www.codeplex.com/svg

Fork with fixes and more activity: (added 7/2013)
https://github.com/vvvv/SVG

harriyott
  • 10,505
  • 10
  • 64
  • 103
Espo
  • 41,399
  • 21
  • 132
  • 159
  • 39
    Thanks Espo. I actually wrote that inkscape blog post! Although it "works", it's not a particularly robust solution. I like the codeplex project though - I'll give it a look. Thanks. – harriyott Sep 12 '08 at 13:16
  • 9
    How embarrassing :) Good thing maybe the SVG rendering engine could help you out though. – Espo Sep 12 '08 at 13:19
  • 21
    I take it as a compliment. I've not been quoted to myself before! – harriyott Sep 12 '08 at 13:36
  • have u tried the svg rendering engine? can u share ur solution plz. im trying to make it work but having troubles,[see here](http://stackoverflow.com/questions/8414324/convert-svg-to-image-programatically) – Armance Dec 08 '11 at 10:01
  • astrocybernaute, Svg Rendering Engine is a no go for me to. I get the same error as you. – Frank Hale Dec 13 '11 at 22:08
  • @astrocybernaute Please, try to keep a minimum of proper grammar. – Camilo Martin Dec 15 '11 at 05:17
  • 1
    I have tried [github.com/vvvv/SVG](https://github.com/vvvv/SVG) and it works but with certain limitations. The `image` element has not been implemented - I checked the source code. @FrankHale I had to remove an xmlns from the svg because raphael added it twice. – fireydude Oct 30 '13 at 10:24
  • Some feedback: 1. inkscape works well with my 30 test images, result is correct. But very slow, on Core i7-3520M takes 248 secs. 2. https://github.com/vvvv/SVG ver 1.7, produces incorrect result, have not try http://www.codeplex.com/svg. Plus, I also tried SharpVectorGraphics.0.3, test one file, cannot handle font correctly. – zhaorufei Jun 15 '15 at 06:31
  • + I've just tried CoolUtils's "Total CAD converter" ver 3.1.56 with one svg file, produce incorrect result. – zhaorufei Jun 15 '15 at 07:35
  • Inkscape is unreliable, slow, not multi-threading conformant, and doesn't necessarely handle CSS-styles correctly. Instead, take a look at headless-chrome, chrome-debugging API, and a C# API for the chrome-debugging API: https://github.com/ststeiger/ChromeDevTools/blob/master/source/SampleNet4/ConverterTest.cs – Stefan Steiger Sep 05 '19 at 06:59
  • It doesnt work on linux – Deivydas Voroneckis Feb 11 '20 at 12:26
12

When I had to rasterize svgs on the server, I ended up using P/Invoke to call librsvg functions (you can get the dlls from a windows version of the GIMP image editing program).

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetDllDirectory(string pathname);

[DllImport("libgobject-2.0-0.dll", SetLastError = true)]
static extern void g_type_init(); 

[DllImport("librsvg-2-2.dll", SetLastError = true)]
static extern IntPtr rsvg_pixbuf_from_file_at_size(string file_name, int width, int height, out IntPtr error);

[DllImport("libgdk_pixbuf-2.0-0.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern bool gdk_pixbuf_save(IntPtr pixbuf, string filename, string type, out IntPtr error, __arglist);

public static void RasterizeSvg(string inputFileName, string outputFileName)
{
    bool callSuccessful = SetDllDirectory("C:\\Program Files\\GIMP-2.0\\bin");
    if (!callSuccessful)
    {
        throw new Exception("Could not set DLL directory");
    }
    g_type_init();
    IntPtr error;
    IntPtr result = rsvg_pixbuf_from_file_at_size(inputFileName, -1, -1, out error);
    if (error != IntPtr.Zero)
    {
        throw new Exception(Marshal.ReadInt32(error).ToString());
    }
    callSuccessful = gdk_pixbuf_save(result, outputFileName, "png", out error, __arglist(null));
    if (!callSuccessful)
    {
        throw new Exception(error.ToInt32().ToString());
    }
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
nw.
  • 4,795
  • 8
  • 37
  • 42
  • 1
    librSVG is not bad, but fonts/text, it doesn't handle them correctly. Instead, take a look at headless-chrome, chrome-debugging API, and a C# API for the chrome-debugging API: https://github.com/ststeiger/ChromeDevTools/blob/master/source/SampleNet4/ConverterTest.cs – Stefan Steiger Sep 05 '19 at 07:04
8

I'm using Batik for this. Batik is a graphics library written in Java, with a command line interface. This makes that you can Batik from C#, same as the following example in Delphi:

procedure ExecNewProcess(ProgramName : String; Wait: Boolean);
var
  StartInfo : TStartupInfo;
  ProcInfo : TProcessInformation;
  CreateOK : Boolean;
begin
  FillChar(StartInfo, SizeOf(TStartupInfo), #0);
  FillChar(ProcInfo, SizeOf(TProcessInformation), #0);
  StartInfo.cb := SizeOf(TStartupInfo);
  CreateOK := CreateProcess(nil, PChar(ProgramName), nil, nil, False,
              CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS,
              nil, nil, StartInfo, ProcInfo);
  if CreateOK then begin
    //may or may not be needed. Usually wait for child processes
    if Wait then
      WaitForSingleObject(ProcInfo.hProcess, INFINITE);
  end else
    ShowMessage('Unable to run ' + ProgramName);

  CloseHandle(ProcInfo.hProcess);
  CloseHandle(ProcInfo.hThread);
end;

procedure ConvertSVGtoPNG(aFilename: String);
const
  ExecLine = 'c:\windows\system32\java.exe -jar C:\Apps\batik-1.7\batik-rasterizer.jar ';
begin
  ExecNewProcess(ExecLine + aFilename, True);
end;
stevenvh
  • 2,971
  • 9
  • 41
  • 54
  • @downvoters - Please explain why you downvote. A downvote without an explanation has zero value. – stevenvh Sep 19 '16 at 10:11
  • 7
    i guess downvotes come from the question text which contain "c#" in it. and your proposal is delphi – Denis Sep 20 '17 at 13:56
  • 1
    didn't downvote, but you could edit your answer and make it clear that `Batik` is a Java library that you could call from C# or whatever language (in this case you showed how to call it in Delphi) – ErrCode Aug 23 '18 at 17:16
  • 1
    Starting a new process is slow. Also, how correctly does batik rasterize ? Latest binaries are hard to get. Instead of putting up with that crap, take a look at headless-chrome, chrome-debugging API, and a C# API for the chrome-debugging API: https://github.com/ststeiger/ChromeDevTools/blob/master/source/SampleNet4/ConverterTest.cs - For all Java-users, I'm sure there's also Java-API's around chrome's debugging-API. – Stefan Steiger Sep 05 '19 at 07:06
4

To add to the response from @Anish, if you are having issues with not seeing the text when exporting the SVG to an image, you can create a recursive function to loop through the children of the SVGDocument, try to cast it to a SvgText if possible (add your own error checking) and set the font family and style.

    foreach(var child in svgDocument.Children)
    {
        SetFont(child);
    }

    public void SetFont(SvgElement element)
    {
        foreach(var child in element.Children)
        {
            SetFont(child); //Call this function again with the child, this will loop
                            //until the element has no more children
        }

        try
        {
            var svgText = (SvgText)parent; //try to cast the element as a SvgText
                                           //if it succeeds you can modify the font

            svgText.Font = new Font("Arial", 12.0f);
            svgText.FontSize = new SvgUnit(12.0f);
        }
        catch
        {

        }
    }

Let me know if there are questions.

-4

you can use altsoft xml2pdf lib for this