How to render SVG image to single-color bitmap image?

Viewed 1596

Using the SVG.NET NuGet package to render SVG images to bitmap images in .NET, I'm trying to change the color of the image during rendering.

E.g. I have this source SVG image:

enter image description here

and want to render it e.g. as a green bitmap image:

enter image description here

(In my scenario, all source SVG images are single-colored only).

My current, unsuccessful code looks like this:

var svgDoc = SvgDocument.Open<SvgDocument>(svgFilePath, null);

// Tried several things, all without any changes in the resulting bitmap:
svgDoc.Color = new SvgColourServer(Color.DarkGreen);
svgDoc.StopColor = new SvgColourServer(Color.DarkGreen);
svgDoc.Stroke = new SvgColourServer(Color.DarkGreen);
svgDoc.Fill = new SvgColourServer(Color.DarkGreen);

var bitmap = svgDoc.Draw();

I've also checked-out the source code and looked through it, but I still found no way to change the color.

My question:

How to change the color during rendering an SVG image to a bitmap image with SVG.NET?

(I'm asking here on SO and not only on their GitHub page, since it seems that the authors do not respond to questions at all or very seldom only)

Update 1:

What did work is the following fragment:

var svgDoc = SvgDocument.Open<SvgDocument>(svgFilePath, null);

// Recursively change all nodes.
processNodes(svgDoc.Descendants(), new SvgColourServer(Color.DarkGreen));

var bitmap = svgDoc.Draw();

together with this function:

private void processNodes(
    IEnumerable<SvgElement> nodes, SvgPaintServer colorServer)
{
    foreach (var node in nodes)
    {
        if (node.Fill != SvgPaintServer.None) node.Fill = colorServer;
        if (node.Color != SvgPaintServer.None) node.Color = colorServer;
        if (node.StopColor != SvgPaintServer.None) node.StopColor = colorServer;
        if (node.Stroke != SvgPaintServer.None) node.Stroke = colorServer;

        processNodes(node.Descendants(), colorServer);
    }
}

Although I am unsure about the costs of this recursive iteration of all nodes and whether there is a faster way.

1 Answers

It sounds reasonable that your first attempt failed, because you only set fill and stroke on the parent <svg> element, and a parent's fill/stroke doesn't override a child's fill/stroke. Example:

<svg fill="green" stroke="green" xmlns="http://www.w3.org/2000/svg" width="200" height="200" >
    <g stroke="black" stroke-width="2" fill="none" >
        <path d="M90,90 v-80 a80,80 0 0,0 -80,80 z" fill="red" />
        <path d="M100,100 h-80 a80,80 0 1,0 80,-80 z" fill="gold" />
    </g>
</svg>

One alternative to your updated approach is to set fill/stroke via CSS, because CSS will override any fill and stroke attributes. So, if SVG.NET allows you to insert/edit a <style> element in your SVG, you can do this:

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" >
    <style>
        * {
            fill: green;
            stroke: green;
        }
    </style>
    <g stroke="black" stroke-width="2" fill="none" >
        <path d="M90,90 v-80 a80,80 0 0,0 -80,80 z" fill="red" />
        <path d="M100,100 h-80 a80,80 0 1,0 80,-80 z" fill="gold" />
    </g>
</svg>

Related