We're currently using NGraphics for exporting vector images for the various platforms. We'd really like to be able to output an SVG file and Skia looks promising. We'd give SkiaSharp a try if this feature ever makes it.
I don't think this is going to be done at all anytime soon.
Here is my code (it binds all that there is to bind):
I did a check to see what's what and this is what I found:
SkSVGCanvas is a thing, but it is very limited:I don't think I will be merging these changes into the main branch anytime soon. We have to wait for SVG to become something in Skia.
A SKSvgCanvas can be created on the fly, requiring only a bounds and an SKXmlWriter:
// create a writeable stream
// SKFileWStream skStream = ...
// SKDynamicMemoryWStream skStream = ...
System.IO.Stream stream = ...
SkiaSharp.SKManagedWStream skStream = new SKManagedWStream(stream);
// now create the xml writer and the canvas
using (var writer = new SKXmlStreamWriter(skStream))
using (var canvas = SKSvgCanvas.Create(SKRect.Create(0, 0, (int)Bounds.Width, (int)Bounds.Height), writer))
{
// draw as normal since "canvas" is just a "SKCanvas"
}
// you may have to:
//skStream.Flush();
Awesome job on getting those bindings.
basically just paths, shapes, text and images
That's basically all I need for what we are using NGraphics for. Hopefully we'll get a chance to try it out soon. Thanks!
@zone117x Make sure you use the svg betas as they haven't been merged into master/stable yet
I have run some tests using Version 1.53.2 (SVG Beta 1) and generally works great!
Found one bug when drawing paths with multiple figure.
The following path is not drawn correctly in Svg:
M210,150L330,150L330,210L210,210z M225,165L315,165L315,195L225,195z
Below is the Svg output using SkiaSharp:
<?xml version="1.0" encoding="utf-8" ?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="840" height="600">
<rect fill="rgb(255,255,255)" stroke="none" width="840" height="600"/>
<path fill="rgb(0,0,0)" fill-opacity="0.3137255" stroke="none" d="M210 150L330 150L330 210L210 210L210 150ZM225 165L315 165L315 195L225 195L225 165Z"/>
<path fill="none" stroke="rgb(0,0,0)" stroke-width="2" stroke-linecap="round" stroke-miterlimit="4" d="M210 150L330 150L330 210L210 210L210 150ZM225 165L315 165L315 195L225 195L225 165Z"/>
</svg>
In above Svg you can see that there are two paths, one with fill and one with stroke only, but they do not combine as they should.
Code:
var presenter = new ContainerPresenter(); // MY DRAWING CODE
using (SKFileWStream stream = new SKFileWStream(path))
using (var writer = new SKXmlStreamWriter(stream))
using (var canvas = SKSvgCanvas.Create(SKRect.Create(0, 0, (int)container.Width, (int)container.Height), writer))
{
presenter.Render(canvas, renderer, container, 0, 0); // MY DRAWING CODE
}
I use same drawing code for creating Pdf's using SkiaSharp and output is correct.
Pdf:

Svg:

I found the issue, the svg canvas backend does not set proper fill-rule, this is fixed version as it should be (the only difference is fill-rule="evenodd"):
<?xml version="1.0" encoding="utf-8" ?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="840" height="600">
<rect fill="rgb(255,255,255)" stroke="none" width="840" height="600"/>
<path fill-rule="evenodd" fill="rgb(0,0,0)" fill-opacity="0.3137255" stroke="none" d="M210 150L330 150L330 210L210 210L210 150ZM225 165L315 165L315 195L225 195L225 165Z"/>
<path fill="none" stroke="rgb(0,0,0)" stroke-width="2" stroke-linecap="round" stroke-miterlimit="4" d="M210 150L330 150L330 210L210 210L210 150ZM225 165L315 165L315 195L225 195L225 165Z"/>
</svg>
This is related to the fact that to use different color for fill and stroke using SKPaint you have to issue two separate draw calls:
``` C#
private void DrawPathInternal(SKCanvas canvas, SKPaint brush, SKPaint pen, bool isStroked, bool isFilled, SKPath path)
{
if (isFilled)
{
canvas.DrawPath(path, brush);
}
if (isStroked)
{
canvas.DrawPath(path, pen);
}
}
```
The fix should probably be implemented in Skia?
@wieslawsoltes I think @zone117x is correct. If you look here: https://github.com/google/skia/blob/589a39eb81d25fa7af95e7366db17ac7a70a7d03/src/svg/SkSVGDevice.cpp#L348 they only do a few things.
I would suggest opening an issue on http://bugs.skia.org and maybe creating a fiddle (https://fiddle.skia.org/) showing what you are trying to do.
Here is "more" information on the SVG plans by Google:
https://bugs.chromium.org/p/skia/issues/detail?id=5596
Spoilers: they are looking into it :)
@mattleibow Opened issue https://bugs.chromium.org/p/skia/issues/detail?id=5712
That is awesome!
Just repo-ing the C# code for "testing" purposes:
using (var stream = new SKFileWStream("test.svg"))
using (var streamWriter = new SKXmlStreamWriter(stream))
using (var canvas = SKSvgCanvas.Create(new SKRect(0, 0, 100, 100), streamWriter))
{
var p1 = new SKPaint();
p1.Color = SKColors.Red;
p1.IsAntialias = true;
p1.Style = SKPaintStyle.Fill;
p1.StrokeWidth = 1;
var p2 = new SKPaint();
p2.Color = SKColors.Black;
p2.IsAntialias = true;
p2.Style = SKPaintStyle.Stroke;
p2.StrokeWidth = 2;
var path = new SKPath();
path.FillType = SKPathFillType.EvenOdd;
path.MoveTo(10.0f, 10.0f);
path.LineTo(90.0f, 10.0f);
path.LineTo(90.0f, 90.0f);
path.LineTo(10.0f, 90.0f);
path.Close();
path.MoveTo(20.0f, 20.0f);
path.LineTo(80.0f, 20.0f);
path.LineTo(80.0f, 80.0f);
path.LineTo(20.0f, 80.0f);
path.Close();
canvas.DrawPath(path, p1);
canvas.DrawPath(path, p2);
}
<svg width='50' height='50' viewBox='0 0 50 50'><rect width='50' height='50' fill='#000' opacity='0.5' /></svg>
<svg width='50' height='50' viewBox='0 0 50 50'><rect width='50' height='50' fill='#000' fill-opacity='0.5' /></svg>
More here: https://github.com/luberda-molinet/FFImageLoading/issues/436
@daniel-luberda I have added support for "opacity" in this commit: https://github.com/mono/SkiaSharp/commit/cfe6afbf8aece4a2d4b835b727073cc50a0015da
I have merged the svg branch into the master, but please note that this area (svg canvas) is still very much in beta on the native side. Thus, it is a beta state in SkiaSharp.
@mattleibow Thanks for committing to this and getting it done. Great work!
Most helpful comment
@daniel-luberda I have added support for "opacity" in this commit: https://github.com/mono/SkiaSharp/commit/cfe6afbf8aece4a2d4b835b727073cc50a0015da