piferrari
piferrari

Reputation: 149

Remote svg image .NET MAUI

I can't display remote svg images in <Image> control.

Example:

When I try to display this image, I don't see anything.

<Image Source="https://www.meteosuisse.admin.ch/static/product/resources/weather-symbols/120.svg" />

It's the same with this image

<Image Source="https://en.wikipedia.org/wiki/Scalable_Vector_Graphics#/media/File:SVG_Logo.svg" />

But if I only change the url of the image with this one which is of type JPG, everything works

<Image Source="https://aka.ms/campus.jpg" />

Am I doing something wrong?

.NET MAUI Version: 6.0.548 Microsoft Visual Studio Enterprise 2022 (64 bits) - Current Version 17.4.3

Best Regards

Tested on

I have see this question but here, the problem is only with SVG remote image.

Upvotes: 1

Views: 695

Answers (1)

BBHoodsta
BBHoodsta

Reputation: 1

I made this. It doesnt load from a URL but it does load SVG data as a string ("<svg ..... "): https://gist.github.com/andressbarajas/c2248d5925087f5b769aacb9af8f74a8

using System.Reflection;
using System.Xml.Linq;

using SkiaSharp.Views.Maui;
using SkiaSharp.Views.Maui.Controls;
using SKSvg = SkiaSharp.Extended.Svg.SKSvg;

namespace Project.Views;

public class SvgImage : SKCanvasView
{
    private Dictionary<string, string> _color_mappings = new Dictionary<string, string>();

    public static BindableProperty SourceProperty = BindableProperty.Create(nameof(Source), typeof(string), typeof(SvgImage), default(string), propertyChanged: OnPropertyChanged);

    public string Source
    {
        get => (string)GetValue(SourceProperty);
        set => SetValue(SourceProperty, value);
    }

    public static BindableProperty ColorMappingProperty = BindableProperty.Create(nameof(ColorMapping), typeof(string), typeof(SvgImage), default(string), defaultBindingMode: BindingMode.Default, propertyChanged: OnPropertyChanged);

    public string ColorMapping
    {
        get => (string)GetValue(ColorMappingProperty);
        set => SetValue(ColorMappingProperty, value);
    }

    public SvgImage()
    {
        BackgroundColor = Colors.Transparent;
    }

    protected override void OnPaintSurface(SKPaintSurfaceEventArgs args)
    {
        base.OnPaintSurface(args);

        try
        {
            if (!String.IsNullOrEmpty(Content))
            {
                using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(Content)))
                {
                    if (stream == null)
                        throw new Exception("SVG Stream is NULL for Content");

                    CreateSVG(stream, args);
                }
            }
        }
        catch (Exception ex)
        {
            throw new Exception("An error occured when reading the Svg Resource: " + ex.Message);
        }
    }

    private void CreateSVG(Stream stream, SKPaintSurfaceEventArgs args)
    {
        try
        {
            var canvas = args.Surface.Canvas;
            canvas.Clear();

            var svg = new SKSvg();

            // Clear all mappings
            _color_mappings.Clear();

            // Populate mappings
            if(!String.IsNullOrEmpty(ColorMapping))
            {
                var mappings = ColorMapping.Split(';');
                foreach (var map in mappings)
                {
                    var key_and_value = map.Split('=');
                    _color_mappings.Add(key_and_value[0], key_and_value[1]);
                }
            }

            if (_color_mappings.Count > 0)
            {
                using (var sr = new StreamReader(stream))
                {
                    var svg_xml = XDocument.Load(sr);

                    var fill_color_elements = svg_xml.Root.Descendants().Where(x => x.Attribute("fill") != null).ToList();
                    foreach (var element in fill_color_elements)
                    {
                        var key = element.Attribute("fill").Value;
                        if (_color_mappings.ContainsKey(key))
                            element.Attribute("fill").Value = _color_mappings[key];
                    }

                    var style_elements = svg_xml.Root.Descendants().Where(x => x.Attribute("style") != null).ToList();
                    foreach (var element in style_elements)
                    {
                        var style_key = element.Attribute("style").Value;
                        var keys = style_key.Split(';');

                        for (var i = 0; i < keys.Count(); i++)
                        {
                            if (keys[i].Contains("fill"))
                            {
                                var key_split = keys[i].Split("fill:");
                                if (_color_mappings.ContainsKey(key_split[1]))
                                {
                                    keys[i] = "fill:" + _color_mappings[key_split[1]];
                                }
                            }
                        }

                        element.Attribute("style").Value = String.Join(';', keys);
                    }

                    using (var mem_stream = new MemoryStream())
                    {
                        svg_xml.Save(mem_stream);
                        mem_stream.Position = 0;
                        svg.Load(mem_stream);
                    }
                }
            }
            else
            {
                stream.Position = 0;
                svg.Load(stream);
            }

            var info = args.Info;
            canvas.Translate(info.Width / 2f, info.Height / 2f);

            var bounds = svg.ViewBox;
            float xRatio = info.Width / bounds.Width;
            float yRatio = info.Height / bounds.Height;

            var ratio = Math.Min(xRatio, yRatio);

            canvas.Scale(ratio);
            canvas.Translate(-bounds.MidX, -bounds.MidY);
            canvas.DrawPicture(svg.Picture);
        }
        catch (Exception ex)
        {
            throw new Exception("An error occured when reading the Svg Resource: " + ex.Message);
        }
    }

    public void Refresh()
    {
        InvalidateSurface();
    }

    private static void OnPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var skCanvasView = bindable as SKCanvasView;
        skCanvasView?.InvalidateSurface();
    }

    protected override void OnBindingContextChanged()
    {
        base.OnBindingContextChanged();

        InvalidateSurface();
    }

    protected override void OnSizeAllocated(double width, double height)
    {
        base.OnSizeAllocated(width, height);

        InvalidateSurface();
    }
}

Upvotes: 0

Related Questions