4

I have a big svg image.
I would like to crop it to a rectangle, using coordinates, and convert it to png image.

I have to say that I'm not used to drawing with c#.
Surface, Canvas and other notions are new to me.

I have figured out how to load the svg, using SkiaShark and SkiaShark.Svg:

var svg = new SkiaSharp.Extended.Svg.SKSvg();
svg.Load(tmpPath);

And found a gist that saves a png. But this is "Chinese" for me.

var imageInfo = new SKImageInfo(100, 100);
using (var surface = SKSurface.Create(imageInfo))
using (var canvas = surface.Canvas)
{
    // calculate the scaling need to fit to screen
    var scaleX = 100 / svg.Picture.CullRect.Width;
    var scaleY = 100 / svg.Picture.CullRect.Height;
    var matrix = SKMatrix.CreateScale((float)scaleX, (float)scaleY);

    // draw the svg
    canvas.Clear(SKColors.Transparent);
    canvas.DrawPicture(svg.Picture, ref matrix);
    canvas.Flush();

    using (var data = surface.Snapshot())
    using (var pngImage = data.Encode(SKEncodedImageFormat.Png, 100))
    {
        tmpPath = Path.ChangeExtension(tmpPath, "PNG");
        using var imageStream = new FileStream(tmpPath, FileMode.Create);
        pngImage.SaveTo(imageStream);
    }
}

If someone could show me the directions, it would be much appreciated.

EDIT


I've come to this implentation myself, though it is not working... The result bitmap is transparent and empty.

private string ConvertSVGToPNGRectangleWithSkiaSharpExtended(string path, double left, double top, double right, double bottom)
{
    var svg = new SkiaSharp.Extended.Svg.SKSvg();
    var picture = svg.Load(path);

    // Get the initial map size
    var source = new SKRect(picture.CullRect.Left, picture.CullRect.Top, picture.CullRect.Width, picture.CullRect.Height);

    // Cropping Rect
    var cropRect = new SKRect((int)left, (int)top, (int)right, (int)bottom);

    var croppedBitmap = new SKBitmap((int)cropRect.Width, (int)cropRect.Height);

    using var canvas = new SKCanvas(croppedBitmap);
    canvas.Clear(SKColors.Transparent);
    canvas.DrawBitmap(croppedBitmap, source, cropRect);

    var data = croppedBitmap.Encode(SKEncodedImageFormat.Png, 100);

    path = Path.ChangeExtension(path, "PNG");
    using var imageStream = new FileStream(path, FileMode.Create);
    data.SaveTo(imageStream);

    return path;
}

EDIT 2: I'm sorry , if it is not clear. You can refer to this question for doing so on Android.

  • The gist code works fine, what do you need to do exactly when you say "I would like to crop it to a rectangle, using coordinates"? can you post a source image and the expected result. – Simon Mourier Aug 30 '22 at 17:17
  • The gist is using desiredSizes values, which seems to implies to save the whole svg to a png. I'd like to save a part of the svg image, the famous rectangle in question. –  Aug 31 '22 at 09:56
  • What you want to do is unclear. Can you give what asked? – Simon Mourier Aug 31 '22 at 10:18
  • I've added a link to an equivalent question on Android –  Aug 31 '22 at 11:56
  • An SVG is a picture (not an image, they are not the same type of objects), it can't be cropped, so you must convert it to an image first and draw a portion of that image (DrawImage can do that while DrawPicture cannot) to another one. Check this code, it should do what you want: https://pastebin.com/raw/2rFFWN64 – Simon Mourier Aug 31 '22 at 16:48
  • I have set up a private github repo whith a source SVG and the PNG outputed by your code, to play with if you want. you can ask at omatrot_arobase_free.fr for me to invite you if you please. –  Sep 01 '22 at 08:07
  • Not sure I want to do that. My provided code just crops an SVG image and saves it as a PNG image, as requested in the question. – Simon Mourier Sep 01 '22 at 13:41
  • I tested your code against my svg file. It produces a transparent (or blank) png. My github repo contains the SVG for you to test the code you provided. –  Sep 01 '22 at 13:48
  • You should provide everything related to the question (code, svg, files, etc.) publicly here when possible (should be in this case) or under a public repo https://stackoverflow.com/help/minimal-reproducible-example – Simon Mourier Sep 01 '22 at 14:23
  • Unfortunately It is not the case. The SVG is 3532KB in size. Hence the github repo. –  Sep 01 '22 at 14:38
  • If my code works on a normal svg and doesn't work for a special particular one, this is a pure SKIA problem that you should report to google. – Simon Mourier Sep 01 '22 at 15:53

1 Answers1

0

Disclaimer: I'm not an expert with SkiaSharp, but I do know about drawing and canvases and I looked up the documentation at https://learn.microsoft.com/en-us/dotnet/api/skiasharp.skcanvas.drawpicture

I think the problem is this line:

canvas.DrawBitmap(croppedBitmap, source, cropRect);

I think you need:

canvas.DrawPicture(picture, -cropRect.Left, -cropRect.Top);
canvas.Flush();

I might have the coordinates wrong, but the problem behind your failure is that you are never drawing picture to the canvas.

To help with your confusion about what a canvas is: SKCanvas(croppedBitmap) is making it so that every time you draw to canvas, what you are actually drawing on is the bitmap. So in order to draw your picture onto the bitmap, you have to draw picture onto canvas. Using negative coordinates make it so the top and left of the svg picture are above and to the left of the top-left corner of the bitmap, which is the equivalent of having the bitmap start somewhere in the middle of the svg picture.

Hope this helps!

clnoel
  • 22
  • 5