1

I have searched high and low for this and can't find anything.

I open an SVG file, iterate the elements and change a color, simply as so:

child.Fill = new SvgColourServer(Color.Red);

When I save the SVG to file, it saves it in some odd format I have never seen before:

<rect ... style="fill:255, 0, 0;" />

It should look like this:

<rect ... style="fill:#ff0000" />

I thought maybe this is some new format I wasn't aware of, but no, Chrome also complains:

chrome

How do you get Svg.Skia (0.5.18) to render colors correctly instead of whatever it's doing now?

Andy
  • 12,859
  • 5
  • 41
  • 56
  • 1
    https://github.com/wieslawsoltes/Svg.Skia/issues/100 – Robert Longson Jan 11 '23 at 17:13
  • 1
    @RobertLongson -- holy crap it's a bug that started in 0.5.11 and exists today even in preview versions. I really appreciate your help on your research. If you want to add an answer, i'll accept it. [This](https://github.com/wieslawsoltes/Svg.Skia/issues/100#issuecomment-1221625318) is the post that has the proof. I rolled back to 0.5.10 and it works fine now. – Andy Jan 11 '23 at 17:30
  • Not sure a link to a github issue counts as an answer. Doesn't look too difficult to fix though. – Robert Longson Jan 11 '23 at 17:31
  • In the meantime, you should report this issue to the GitHub repository. – Peter O. Jan 11 '23 at 22:54

1 Answers1

0

My workaround to this problem was to make sure the color is always passed to Svg.Skia as a known (named) color, because Svg.Skia then seems to generate a valid SVG element.

ColorTranslator is calling Color.FromArgb(int, int, int) which will return an unnamed Color, like "128, 64, 32". As pointed out in the comments already, due to a change in Svg.Skia version 0.5.11, this RGB value will be used and a corrupt SVG element is created:

<path ... style="fill:0, 128, 64, 32;" />

However, if color is a known (named) Color, then Svg.Skia will insert a SVG element which seems to be valid:

<path ... style="fill:Red;" />

To support all possible colors, I calculate the closest known color, by using the code from this answer.

public static Color FromHtml(string htmlColor)
{
    ArgumentException.ThrowIfNullOrEmpty(htmlColor);
 
    var color = ColorTranslator.FromHtml(htmlColor);
    var closestDistance = double.MaxValue;
    
    var closest = Color.White;
    var knownColors = Enum.GetValues<KnownColor>().Select(Color.FromKnownColor);
    
    foreach (var knownColor in knownColors)
    {
        // Calculate Euclidean distance
        var rDistSqrd = Math.Pow(color.R - knownColor.R, 2);
        var gDistSqrd = Math.Pow(color.G - knownColor.G, 2);
        var bDistSqrd = Math.Pow(color.B - knownColor.B, 2);
        var distance = Math.Sqrt(rDistSqrd + gDistSqrd + bDistSqrd);

        if (!(distance < closestDistance))
        {
            continue;
        }

        closestDistance = distance;
        closest = knownColor;
    }

    if (!closest.IsNamedColor)
    {
        throw new ArgumentException("HTML color cannot be converted to a named color.", nameof(htmlColor));
    }

    return closest;
}

And tests:

[DataTestMethod]
[DataRow("#FFEBCD", KnownColor.BlanchedAlmond)]
[DataRow("#ffebcd", KnownColor.BlanchedAlmond)]
[DataRow("#ff6e6e", KnownColor.Salmon)]
[DataRow("#8ccbff", KnownColor.LightSkyBlue)]
[DataRow("#210ca5", KnownColor.DarkBlue)]
public void CanCallFromHtml(string htmlColor, KnownColor expected)
{
    // Act
    var knownColor = KnownColorHelper.FromHtml(htmlColor);

    // Assert
    Assert.AreEqual(Color.FromKnownColor(expected), knownColor);
}
Kristoffer Jälén
  • 4,112
  • 3
  • 30
  • 54