Search code examples
c#svgbounding-boxinkscape

SVG element to PNG file with C#


I'm trying to convert SVG into a PNG file. My main problem is not the convertion itself (I can do it with few line of code), but is the centering of the SVG element I want to sender into the "window" that get's rendered.

I use SVG engine (https://github.com/vvvv/SVG) and my idea is to get the element I want to render, then reposition it at the origin and then set width and height of the svg document to the width/height of the element. here's the code:

var svgDocument = SvgDocument.Open(filename);
var el =(SvgVisualElement) svgDocument.GetElementById("MyId");

// set in the origin
el.Transforms.Add(new SvgTranslate(-el.Bounds.X, -el.Bounds.Y));

// set doc dimensions
svgDocument.Width = el.Bounds.Width;
svgDocument.Height = el.Bounds.Height;

bitmap.Save("PNGFile", ImageFormat.Png);

Unfortunally it doesn't work that way. Here's an example of svg that doesn't work (it's lenthy, so I cut the relevant parts):

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="70.125473"
   height="190.98564"
   id="svg6678"
   version="1.1">
   <g id="MyId">
    <g
       transform="translate(-2375.7448,475.88408)"
       id="Texture:door_single_rocks_gear">
      <path
         id="path9179-8-2-8-71-4-2-7"
         d="..." style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#5b3636;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.53245842;marker:none;enable-background:accumulate" />
      <path
         id="path9179-8-2-8-71-4-6"
         d="..." style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#815656;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.53245842;marker:none;enable-background:accumulate" />
      <path
         id="path4080-5-2"
         d="..."
         style="fill:#866262;fill-opacity:1;stroke:none" />
      <path
         id="path7662-1-1-4-9"
         d="..."
         style="fill:#5b3636;fill-opacity:1;stroke:none" />
      <path
         id="path7662-1-1-4-5-5"
         d="..."
         style="fill:#5b3636;fill-opacity:1;stroke:none" />
    </g>
    <g
       id="Texture:door_single_rocks"
       inkscape:label="#g5299"
       inkscape:export-filename="C:\Users\stefano.liboni\Dropbox\AndroidStudio\AsteroidRage\scenes_source\door_single_rocks.png"
       inkscape:export-xdpi="199.88191"
       inkscape:export-ydpi="199.88191">
      <path style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#5b3636;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
         d="..."
         id="rect4972-3-8-9" />
      <path
         id="rect4972-9"
         d="..." style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#815656;fill-opacity:1;fill-rule:nonzero;stroke:#5b3636;stroke-width:1.0026859;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" />
      <path
         style="fill:#5b3636;fill-opacity:1;stroke:none"
         d="..."
         id="path7662-1-1-4-5-5-0" />
      <path
         style="fill:#5b3636;fill-opacity:1;stroke:none"
         d="..."
         id="path7662-1-1-4-5-5-03-9" />
      <path
         style="fill:#5b3636;fill-opacity:1;stroke:none"
         d="..."
         id="path7662-1-1-4-5-5-03" />
    </g>
    <g
       id="AnimatedTexture:door_single_rocks_led"
       inkscape:label="#g5295">
      <path
         id="path9095-7"
         d="..."
         style="fill:#9486ff;fill-opacity:1;stroke:#000000;stroke-width:1.07693017;stroke-opacity:1" />
      <path
         id="path9095-7-5-1"
         d="..."
         style="fill:#9486ff;fill-opacity:1;stroke:#000000;stroke-width:1.07693017;stroke-opacity:1" />
    </g>
  </g>
</svg>

As you can see there is a g element MyId full of other g elements and some paths. I add an image of it rendered in inkscapethe svg rendered in inkscape.

Once I get the bounds of the element (which is the one at the bottom left) in my code I get: {X = -1502.69763 Y = 668.7914 Width = 2514.11938 Height = 870.0564}

It seems wrong since the element is just 141px of width and 395px of height... If I run the code on that file the output is: enter image description here

So the PNG has a lot of unused space, both y, width and height of the png are wrong. The right ones would be:

svgDocument.X = 0;
svgDocument.Y = -476;
svgDocument.Width = 141;
svgDocument.Height = 395;

Any idea of what I'm doing wrong?

Note: I know that inkscape would do it right (I used to use it), but there's a bug since at least 3years that they don't bother to solve that prevents inkscape to run in silent mode if you specify "verb" in the command line. So uning it is a pain because for every file it opens the UI and takes 3-4secs to do it...


Solution

  • pushed by the comment of ccprog I found out that the UI was openend by inkscape because I was doing also other stuff in the same command I run.

    Actually running inkscape as:

    MyFile.svg --export-id=ElementIdToRender --export-id-only --export-dpi=200 --export-png="TargetFile"

    Does the job.

    Still to understand why the SVG library gives strange numbers as Bounds for g elements containing one or more children with transform attribute set, but at the moment I can go on. Tnx