Avalonia 渲染svg文件

Xaml部分代码

  <ScrollViewer Grid.Row="3" Padding="0 0 -16 0" VerticalScrollBarVisibility="Auto"
                                  Background="{Binding Vo.MuteTotal, Converter={StaticResource DataBg}, 
                 ConverterParameter=#ffffff|avares://xxxx.Pc.Desktop/Assets/Chat/Group/empty_mute_member.svg}">

Avalonia版本小于等于11.3.2

public class DataBackgroundConverter: MarkupExtension, IValueConverter {
    private static DataBackgroundConverter ? _instance;

    public override object ProvideValue(IServiceProvider serviceProvider) => _instance ??= new();

    public object ? Convert(object ? value, Type targetType, object ? parameter, CultureInfo culture) {
        // 参数格式:Color|ImagePath
        var param = parameter as string;
        if (string.IsNullOrEmpty(param))
            return new SolidColorBrush(Colors.Transparent);

        var parts = param.Split('|', StringSplitOptions.RemoveEmptyEntries);
        if (parts.Length < 2)
            return new SolidColorBrush(Colors.Transparent);

        var colorHex = parts[0].Trim();
        var imageAsset = parts[1].Trim();

        bool hasData = false;

        if (value is null) {
            hasData = false;
        } else if (value is int total) {
            hasData = total > 0;
        } else if (value is IEnumerable collection) {
            // 尝试判断集合是否为空
            var enumerator = collection.GetEnumerator();
            hasData = enumerator.MoveNext(); // 只要能 MoveNext 就说明有元素
        } else {
            // 非集合对象:只要不为 null 就算有数据
            hasData = true;
        }

        if (hasData) {
            // ✅ 有数据:返回颜色
            if (Color.TryParse(colorHex, out
                               var color)) {
                return new SolidColorBrush(color);
            }

            return new SolidColorBrush(Colors.White);
        } else {
            // ❌ 无数据:返回背景图
            try {

                if (imageAsset.EndsWith("svg")) {
                    return LoadSvgAsBrush(imageAsset);
                }
                var stream = AssetLoader.Open(new Uri(imageAsset));
                var bitmap = new Bitmap(stream);
                return new ImageBrush(bitmap) {
                    Stretch = Stretch.Uniform, AlignmentX = AlignmentX.Center, AlignmentY = AlignmentY.Center,
                };
            } catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine($ "加载背景图失败: {ex.Message}");
            }

            return new SolidColorBrush(Colors.LightGray);
        }
    }
    public static ImageBrush LoadSvgAsBrush(string assetPath, PixelSize ? pixelSize = null) {
        // 1. 加载 SVG
        var svgSource = SvgSource.Load(assetPath);
        var svgImage = new SvgImage {
            Source = svgSource
        };

        // 2. 渲染目标像素大小
        var size = pixelSize ?? new PixelSize(800, 800);
        var rtb = new RenderTargetBitmap(size);

        using(var ctx = rtb.CreateDrawingContext(false)) // ⚡ 注意这里传 false
        {
            // 目标矩形(以像素为单位)
            var destRect = new Rect(0, 0, size.Width, size.Height);

            // 源矩形(SVG 原始大小,如果没有,就用目标大小)
            var srcSize = svgImage.Size;
            var srcRect = new Rect(0, 0, srcSize.Width, srcSize.Height);

            // 绘制 SVG -> 位图
            ctx.DrawImage((IImage) svgImage, srcRect, destRect);
        }

        // 3. 返回 ImageBrush
        return new ImageBrush(rtb);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
        throw new NotSupportedException("不支持反向转换");
    }
}

Avalonia版本大于等于11.3.6

使用Svg.Controls.Skia.Avalonia,版本11.3.6.2
地址为:https://libraries.io/nuget/Svg.Controls.Skia.Avalonia/11.3.6.2

public class DataBackgroundConverter: MarkupExtension, IValueConverter {
    private static DataBackgroundConverter ? _instance;

    public override object ProvideValue(IServiceProvider serviceProvider) => _instance ??= new();

    public object ? Convert(object ? value, Type targetType, object ? parameter, CultureInfo culture) {
        // 参数格式:Color|ImagePath
        var param = parameter as string;
        if (string.IsNullOrEmpty(param))
            return new SolidColorBrush(Colors.Transparent);

        var parts = param.Split('|', StringSplitOptions.RemoveEmptyEntries);
        if (parts.Length < 2)
            return new SolidColorBrush(Colors.Transparent);

        var colorHex = parts[0].Trim();
        var imageAsset = parts[1].Trim();

        bool hasData = false;

        if (value is null) {
            hasData = false;
        } else if (value is int total) {
            hasData = total > 0;
        } else if (value is IEnumerable collection) {
            // 尝试判断集合是否为空
            var enumerator = collection.GetEnumerator();
            hasData = enumerator.MoveNext(); // 只要能 MoveNext 就说明有元素
        } else {
            // 非集合对象:只要不为 null 就算有数据
            hasData = true;
        }

        if (hasData) {
            // ✅ 有数据:返回颜色
            if (Color.TryParse(colorHex, out
                               var color)) {
                return new SolidColorBrush(color);
            }

            return new SolidColorBrush(Colors.White);
        } else {
            // ❌ 无数据:返回背景图
            try {

                if (imageAsset.EndsWith("svg")) {
                    //     // var fromPath = SvgResourceExtension.CreateBrush(
                    //     //     "avares://MyAssembly/Assets/Icon.svg",
                    //     //     stretch: Stretch.Fill,
                    //     //     alignmentX: AlignmentX.Right,
                    //     //     alignmentY: AlignmentY.Bottom);
                    return SvgResourceExtension.CreateBrush(
                        imageAsset,
                        stretch: Stretch.Uniform,
                        alignmentX: AlignmentX.Center,
                        alignmentY: AlignmentY.Center);
                }
                var stream = AssetLoader.Open(new Uri(imageAsset));
                var bitmap = new Bitmap(stream);
                return new ImageBrush(bitmap) {
                    Stretch = Stretch.Uniform, AlignmentX = AlignmentX.Center, AlignmentY = AlignmentY.Center,
                };
            } catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine($ "加载背景图失败: {ex.Message}");
            }

            return new SolidColorBrush(Colors.LightGray);
        }
    }
    public static ImageBrush LoadSvgAsBrush(string assetPath, PixelSize ? pixelSize = null) {
        // 1. 加载 SVG
        var svgSource = SvgSource.Load(assetPath);
        var svgImage = new SvgImage {
            Source = svgSource
        };

        // 2. 渲染目标像素大小
        var size = pixelSize ?? new PixelSize(800, 800);
        var rtb = new RenderTargetBitmap(size);

        using(var ctx = rtb.CreateDrawingContext(false)) // ⚡ 注意这里传 false
        {
            // 目标矩形(以像素为单位)
            var destRect = new Rect(0, 0, size.Width, size.Height);

            // 源矩形(SVG 原始大小,如果没有,就用目标大小)
            var srcSize = svgImage.Size;
            var srcRect = new Rect(0, 0, srcSize.Width, srcSize.Height);

            // 绘制 SVG -> 位图
            ctx.DrawImage((IImage) svgImage, srcRect, destRect);
        }

        // 3. 返回 ImageBrush
        return new ImageBrush(rtb);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
        throw new NotSupportedException("不支持反向转换");
    }
}
 xmlns:skia="using:Avalonia.Svg.Skia"
<skia:Svg Path="avares://Resources/Assets/Workspace/Gear.svg"/>
posted @ 2025-09-25 14:12  Timskt  阅读(42)  评论(0)    收藏  举报