.net SkiaSharp将SVG转换为PNG -图像不完全适合画布大小

vmdwslir  于 2023-10-21  发布在  .NET
关注(0)|答案(1)|浏览(192)

我尝试使用SkiaSharp将SVG图像转换为PNG,并返回一个带有图像的PdfSharp XImage对象,以便将其添加到PDF页面(因为PdfSharp不直接支持SVG格式)。
这是我的代码:

private XImage LoadSvgIcon(string iconUrl)
{
    XElement root = XElement.Load(iconUrl);

    using (Stream xmlStream = new MemoryStream())
    {
        root.Save(xmlStream);
        xmlStream.Flush();
        xmlStream.Position = 0;
                
        var svg = new SkiaSharp.Extended.Svg.SKSvg();
        svg.Load(xmlStream);
                
        var bitmap = new SKBitmap((int)svg.CanvasSize.Width, (int)svg.CanvasSize.Height);
        var canvas = new SKCanvas(bitmap);
                
        var p = new SKPaint();
        p.Color = SKColor.Parse("#219de1");
        canvas.DrawPaint(p);

        canvas.DrawPicture(svg.Picture);

        using (var skData = SKImage.FromBitmap(bitmap).Encode(SKEncodedImageFormat.Png, 100))
        {
            Stream stream = new MemoryStream();
            skData.SaveTo(stream);
            return XImage.FromStream(stream);
        }
    }
}

即使我将画布的大小设置为SVG的大小,SVG也不会占用画布的整个空间(可以看到画布的背景是蓝色的,而SVG本身的背景是红色的,里面有图标-您可以看到它并没有占用整个画布空间)。
我错过了什么?

cuxqih21

cuxqih211#

可以尝试从弃用的Extended.Svg切换到Svg.Skia nuget。你想缩放svg来填充所需的画布大小,这个过程实际上和缩放加载的位图来填充画布是一样的,有很多例子。只是一些代码,来说明这个想法:

if (Svg != null) // this is your loaded svg
        {
            SKMatrix matrix = CreateSvgMatrix(area, scale); //SKRect area you wont to use/fill
            
            using (var paint = new SKPaint())
            {
                paint.IsAntialias = true;

                //could also tint the svg:
                paint.ColorFilter = SKColorFilter.CreateBlendMode(TintColor.ToSKColor(), SKBlendMode.SrcIn); 

                ctx.Canvas.DrawPicture(Svg.Picture, ref matrix, paint);
            }
        }

    SKMatrix CreateSvgMatrix(SKRect destination, double scale)
    {

        #region Layout

        SKRect contentSize = Svg.Picture.CullRect;
        float scaledContentWidth = (float)(contentSize.Width); 
        float scaledContentHeight = (float)(contentSize.Height); 

        //multipliers to reduce
        float xRatio = destination.Width / scaledContentWidth;
        float yRatio = destination.Height / scaledContentHeight;

        var aspectX = xRatio;
        var aspectY = yRatio;
        var adjustX = 0f;
        var adjustY = 0f;

        if (Aspect == TransformAspect.Fill)
        {

            //multipliers to enlarge
            if (destination.Width > scaledContentWidth && aspectX < 1)
            {
                aspectX = 1 + (1 - aspectX);
            }
            if (destination.Height > scaledContentHeight && aspectY < 1)
            {
                aspectY = 1 + (1 - aspectY);
            }

            adjustX = (destination.Width - scaledContentWidth * aspectX) / 2.0f;
            adjustY = (destination.Height - scaledContentHeight * aspectY) / 2.0f;

        }
        else
        if (Aspect == TransformAspect.AspectFill)
        {
            var needMoreY = destination.Height - scaledContentHeight * xRatio;
            var needMoreX = destination.Width - scaledContentWidth * yRatio;
            var needMore = Math.Max(needMoreX, needMoreY);
            if (needMore > 0)
            {
                var moreX = needMore / scaledContentWidth;
                var moreY = needMore / scaledContentHeight;
                xRatio += moreX;
                yRatio += moreY;
            }

            if (destination.Width < destination.Height)
            {
                aspectX = xRatio;
                aspectY = xRatio;
            }
            else
            {
                aspectX = yRatio;
                aspectY = yRatio;
            }

            adjustX = (destination.Width - scaledContentWidth * aspectX) / 2.0f;
            adjustY = (destination.Height - scaledContentHeight * aspectY) / 2.0f;

        }
        else //FIT
        {
            //keep aspect
            var aspectFit = Math.Min(xRatio / ZoomX, yRatio / ZoomY);

            var aspectFitX = (float)(aspectFit * ZoomX * Zoom);
            var aspectFitY = (float)(aspectFit * ZoomY * Zoom);

            if (yRatio == aspectFit) // was fit for by height, need to center x
            {
                adjustX = (destination.Width - scaledContentWidth * aspectFitX) / 2.0f;
            }
            else// was fit for by width, need to center y
            {
                adjustY = (destination.Height - scaledContentHeight * aspectFitY) / 2.0f;
            }

            aspectX = aspectFitX;
            aspectY = aspectFitY;
        }

        var matrix = new SKMatrix
        {
            ScaleX = aspectX,
            SkewX = 0,
            TransX = destination.Left + adjustX + (float)Math.Round(HorizontalOffset * scale),
            SkewY = 0,
            ScaleY = aspectY,
            TransY = destination.Top + adjustY + (float)Math.Round(VerticalOffset * scale),
            Persp0 = 0,
            Persp1 = 0,
            Persp2 = 1
        };

        return matrix;

        #endregion

    }

相关问题