SixLabors.ImageSharp 圆角矩形路径代码

发布时间 2023-12-14 18:04:39作者: 林沐若

原因

因微软抛弃了 System.Drawing.Common
决定重写绘图底层, 在学习绘制时常会用到部分绘图引擎, 参考过几个都有缺陷
例如:
1.SkiaSharp字体布局问题 参考 布局问题
2.opencvsharp 不支持中文文字

于是乎我就用到了imageSharp, 其中看到作者有对于圆角矩形头像的示例代码, 但这样做只能使用图片而不是路径, 也就是无法绘制线条, 只能处理图片,
于是乎我便自己写了个

/// <summary>
    /// 圆角矩形
    /// </summary>
    /// <param name="width"></param>
    /// <param name="height"></param>
    /// <param name="cornerRadius"></param>
    /// <returns></returns>
public static IPath CreateRoundedRectanglePath(int width, int height, float cornerRadius)
    {
        var pathBuilder = new PathBuilder();
        width--;
        height--;

        var radius = 2 * cornerRadius;

        // Make sure the rounded corners are no larger than half the size of the rectangle
        cornerRadius = Math.Min(width * 0.5f, Math.Min(height * 0.5f, cornerRadius));

        // Start drawing path
        pathBuilder.StartFigure()
            .AddLine(cornerRadius, 0, width - cornerRadius, 0)
            .AddArc(new RectangleF(width - radius, 0, radius, radius), 0, 270, 90)
            .AddLine(width, cornerRadius, width, height - cornerRadius)
            .AddArc(new RectangleF(width - radius, height - radius, radius, radius), 0, 0, 90)
            .AddLine(width - cornerRadius, height, cornerRadius, height)
            .AddArc(new RectangleF(0, height - radius, radius, radius), 0, 90, 90)
            .AddLine(0, height - cornerRadius, 0, cornerRadius)
            .AddArc(new RectangleF(0, 0, radius, radius), 0, 180, 90)
            .CloseFigure();

        return pathBuilder.Build();
    }`

测试代码

[Fact]
    public void DrawRound()
    {
        var bg = new Vector2(100, 100);
        var size = new Vector2(50, 50);
        var rect = new Image<Rgb24>(bg.X.ToInt(), bg.Y.ToInt(), Color.White);
        var path = RoundedAlgorithm.CreateRoundedRectanglePath(size.X.ToInt(), size.Y.ToInt(), 10);
        var centerPath = path.Transform(Matrix3x2.CreateTranslation(bg / 2 - size / 2));
        rect.Mutate(w => w.Draw(Color.Black, 2, centerPath));
        rect.Save(AsPng());
    }

结果

我代码里用到的部分

    /// <summary>
    /// 使用固定圆角/预设透明背景/以达到阴影的效果
    /// </summary>
    /// <param name="origin"></param>
    /// <param name="mainIconSize"></param>
    /// <param name="color"></param>
    /// <param name="borderSize"></param>
    /// <returns></returns>
    public static Image<Rgba32> CalcRoundedRectLuminousBorder(this Image<Rgba32> origin, int mainIconSize, Color color,
        int borderSize = 0)
    {
        //取边框
        borderSize = borderSize == 0 ? mainIconSize / 42 : borderSize;
        //边缘大小
        var edgeSize = borderSize * 5;
        //外边距总大小
        var marginSize = mainIconSize + edgeSize;
        //主图+阴影大小
        var borderBoxSize = mainIconSize + borderSize;
        //输出图
        var outputImg = new Image<Rgba32>(marginSize, marginSize, Color.Transparent);
        //计算圆角矩形()
        var borderPath =
            RoundedAlgorithm.CreateRoundedRectanglePath(borderBoxSize, borderBoxSize, borderBoxSize * 0.2f);
        outputImg.Mutate(w =>
        {
            var borderBoxV2Size = new Vector2(borderBoxSize, borderBoxSize);
            //计算中心点
            var center = new Vector2(marginSize, marginSize) / 2;
            //矩阵位移
            var transform = borderPath.Transform(Matrix3x2.CreateTranslation(center - borderBoxV2Size / 2));
            //填充预设透明度阴影
            w.Fill(Color.FromRgba(238, 238, 238, 80), transform);
            //绘制带颜色线条(卡片类型的不同颜色不同)
            w.Draw(color, borderSize, transform);
            //绘制高斯模糊以达到透明毛玻璃效果
            w.GaussianBlur(borderSize);
            //绘制中心图卡片
            w.DrawCenterPoint(origin, 1);
            //重设预设大小到原图
            w.Resize(mainIconSize, mainIconSize);
        });
        //返回输出图
        return outputImg;
    }

我代码实现的效果 (微调边框阴影实现发光的圆角矩形跟随)

图片名称

半圆加直线

    /// <summary>
    /// 半圆+直线
    /// </summary>
    /// <param name="width"></param>
    /// <param name="height"></param>
    /// <returns></returns>
    public static PathBuilder GetCircularSurroundPath(int width, int height)
    {
        width--;
        height--;
        var r = height / 2;
        var pathBuilder = new PathBuilder();
        pathBuilder.MoveTo(new PointF(r, height))
            .ArcTo(r, r, 0, true, true, new Point(r, 0))
            .LineTo(new PointF(width - r, 0))
            .ArcTo(r, r, 0, true, true, new PointF(width - r, height))
            .LineTo(new PointF(r, height))
            .CloseFigure();
        return pathBuilder;
    }

测试代码


    [Fact]
    public void Semicircle()
    {
        var bg = new Vector2(100, 100);
        var size = new Vector2(70, 30);
        var rect = new Image<Rgb24>(bg.X.ToInt(), bg.Y.ToInt(), Color.White);

        var path = RoundedAlgorithm.GetCircularSurroundPath(size.X.ToInt(), size.Y.ToInt()).Build();
        var centerPath = path.Transform(Matrix3x2.CreateTranslation(bg / 2 - size / 2));
        rect.Mutate(w => w.Draw(Color.Black, 2, centerPath));
        rect.Save(AsPng());
    }

效果

测试图

图片名称