mono / SkiaSharp

SkiaSharp is a cross-platform 2D graphics API for .NET platforms based on Google's Skia Graphics Library. It provides a comprehensive 2D API that can be used across mobile, server and desktop models to render images.
MIT License
4.5k stars 538 forks source link

[QUESTION] SVG not showing up after upgrade to Android 11 / API 30 #1845

Open andysousa opened 3 years ago

andysousa commented 3 years ago

Good day,

We have been using SkiaSharp to render SVG icons as part of our tabbed page icons for quite some time. I recently changed the targeted sdk to 30 from 29, and the icons do not render any longer. I have tried to update to the latest versions of SkiaSharp, but that didn't help.

here is the code we use to load/draw the svg

using System;
using System.IO;
using System.Reflection;
using System.Collections.Generic;
using SkiaSharp;
using SkiaSharp.Views.Forms;
using Xamarin.Forms;

namespace TemptaleApp.Extensions
{
    public class TabSvgIcon : SKCanvasView
    {
        SkiaSharp.Extended.Svg.SKSvg svg;

        static Assembly mainPclAssembly;

        public static Assembly MainPclAssembly
        {
            get
            {
                if (mainPclAssembly == null)
                {
                    if (Application.Current == null)
                        throw new InvalidOperationException();
                    mainPclAssembly = Application.Current.GetType().GetTypeInfo().Assembly;
                }
                return mainPclAssembly;
            }
            set
            {
                mainPclAssembly = value;
            }
        }

        /// <summary>
        /// Cache for SVG icons. Each SVG is kept in memory only once even if it's used multple places in application.
        /// </summary>
        static readonly IDictionary<string, SkiaSharp.Extended.Svg.SKSvg> SvgCache = new Dictionary<string, SkiaSharp.Extended.Svg.SKSvg>();

        /// <summary>
        /// Global prefix for resource ids. Enabled writing cleaner XAML.
        /// </summary>
        public static string ResourceIdsPrefix { get; set; } = string.Empty;

        #region Bindable properties

        public static readonly BindableProperty ResourceIdProperty = BindableProperty.Create(nameof(ResourceId), typeof(string), typeof(SvgIcon), default(string));
        public string ResourceId
        {
            get { return (string)GetValue(ResourceIdProperty); }
            set { SetValue(ResourceIdProperty, value); }
        }

        public static readonly BindableProperty SelectedResourceIdProperty = BindableProperty.Create(nameof(SelectedResourceId), typeof(string), typeof(SvgIcon), default(string));
        public string SelectedResourceId
        {
            get { return (string)GetValue(SelectedResourceIdProperty); }
            set {
                SetValue(SelectedResourceIdProperty, value);
            }
        }

        public static readonly BindableProperty SelectedTabValueProperty = BindableProperty.Create(nameof(SelectedTabValue), typeof(String), typeof(SvgIcon), default(string));
        public string SelectedTabValue
        {
            get { return (string)GetValue(SelectedTabValueProperty); }
            set {

                SetValue(SelectedTabValueProperty, value);
            }
        }

        public string TabValue
        {
            get;
            set;
        }

        public static readonly BindableProperty ColorProperty = BindableProperty.Create(nameof(Color), typeof(Color), typeof(SvgIcon), Color.Black);
        public Color Color
        {
            get { return (Color)GetValue(ColorProperty); }
            set { SetValue(ColorProperty, value); }
        }

        #endregion

        void LoadSvgImage()
        {
            var loadResourceId = (TabValue.Equals(SelectedTabValue) ? SelectedResourceId : ResourceId);

            if (svg != null && loadResourceId == null)
                return;

            if (!SvgCache.TryGetValue(loadResourceId, out svg))
            {
                string fullKey = $"{ResourceIdsPrefix}{loadResourceId}";
                using (Stream stream = MainPclAssembly.GetManifestResourceStream(fullKey))
                {
                    if (stream == null)
                        throw new FileNotFoundException($"SvgIcon : could not load SVG file {fullKey} in assembly {MainPclAssembly}. Make sure the ID is correct, the file is there and it is set to Embedded Resource build action.");
                    svg = new SkiaSharp.Extended.Svg.SKSvg();
                    svg.Load(stream);
                    SvgCache.Add(loadResourceId, svg);
                }
            }
        }

        protected override void OnPaintSurface(SKPaintSurfaceEventArgs e)
        {
            base.OnPaintSurface(e);
            e.Surface.Canvas.Clear();

            LoadSvgImage();
            var matrix = CalculateScale(e.Info);

            using (var paint = new SKPaint())
            {
                // Unlike CreateLighting(), blend mode support alpha channel of the color
                paint.ColorFilter = SKColorFilter.CreateBlendMode(Color.ToSKColor(), SKBlendMode.SrcIn);
                e.Surface.Canvas.DrawPicture(svg.Picture, ref matrix, paint);
            }
        }

        SKMatrix CalculateScale(SKImageInfo info)
        {
            float canvasMin = Math.Min(info.Width, info.Height);
            float svgMax = Math.Max(svg.Picture.CullRect.Width, svg.Picture.CullRect.Height);
            float scale = canvasMin / svgMax;
            return SKMatrix.MakeScale(scale, scale);
        }

        protected override void OnPropertyChanged(string propertyName = null)
        {
            base.OnPropertyChanged(propertyName);

            if (propertyName == ResourceIdProperty.PropertyName)
                svg = null;

            if (propertyName == ResourceIdProperty.PropertyName
             || propertyName == ColorProperty.PropertyName)
                InvalidateSurface();
        }
    }
}

Any thoughts or guidance would be greatly appreciated

charlesroddie commented 1 year ago

Use Svg.Skia instead. The internal svg stuff here hasn't been updated for a very long time and the recommendation for several years has been to move to Svg.Skia for anything serious.