diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 18b8bf2..b83f9f3 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -15,6 +15,7 @@ + diff --git a/src/IconPacks.Avalonia/IconPacks.Avalonia.csproj b/src/IconPacks.Avalonia/IconPacks.Avalonia.csproj index b5852f2..9314015 100644 --- a/src/IconPacks.Avalonia/IconPacks.Avalonia.csproj +++ b/src/IconPacks.Avalonia/IconPacks.Avalonia.csproj @@ -8,6 +8,7 @@ + diff --git a/src/IconPacks.Avalonia/PackIconControlDataFactory.cs b/src/IconPacks.Avalonia/PackIconControlDataFactory.cs index 26c0ec5..5b62be6 100644 --- a/src/IconPacks.Avalonia/PackIconControlDataFactory.cs +++ b/src/IconPacks.Avalonia/PackIconControlDataFactory.cs @@ -2,7 +2,10 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.IO; using System.Threading.Tasks; +using Avalonia.Media; +using Avalonia.Media.Imaging; using IconPacks.Avalonia.Core; using IconPacks.Avalonia.BootstrapIcons; using IconPacks.Avalonia.BoxIcons; @@ -42,6 +45,7 @@ using IconPacks.Avalonia.VaadinIcons; using IconPacks.Avalonia.WeatherIcons; using IconPacks.Avalonia.Zondicons; +using SkiaSharp; namespace IconPacks.Avalonia { @@ -57,6 +61,100 @@ static PackIconControlDataFactory() DataIndex = new Lazy>(() => new ReadOnlyDictionary(GetAllIcons())); } + public static string ProvideSvgPathData(Enum kind) + { + string data = null; + DataIndex.Value?.TryGetValue(kind, out data); + + // For some icons we need to flip them + switch (kind) + { + case PackIconBootstrapIconsKind: + case PackIconBoxIconsKind: + case PackIconCodiconsKind: + case PackIconCooliconsKind: + case PackIconEvaIconsKind: + case PackIconFileIconsKind: + case PackIconFontaudioKind: + case PackIconFontistoKind: + case PackIconForkAwesomeKind: + case PackIconJamIconsKind: + case PackIconLucideKind: + case PackIconRPGAwesomeKind: + case PackIconTypiconsKind: + case PackIconVaadinIconsKind: + var skPath = SKPath.ParseSvgPathData(data); + skPath.Transform(SKMatrix.CreateScale(1,-1)); + return skPath.ToSvgPathData(); + + default: + return data; + } + } + + public static async Task GetIconAsBitmapAsync(Enum kind, Color foreground, int width = 48, int height = 48) + { + try + { + await using var ms = new MemoryStream(); + + await Task.Run(() => + { + var data = ProvideSvgPathData(kind); + var skPath = SKPath.ParseSvgPathData(data); + var originalBounds = skPath.Bounds; + + switch (kind) + { + case PackIconFeatherIconsKind: + originalBounds.Inflate(2f, 2f); + break; + } + + if (width < 0) width = (int)(Math.Ceiling(originalBounds.Width)); + if (height < 0) height = (int)(Math.Ceiling(originalBounds.Height)); + + float scale = Math.Min(width / originalBounds.Width, height / originalBounds.Height); + + + skPath.Transform(SKMatrix.CreateScale(scale, scale)); + skPath.Transform(SKMatrix.CreateTranslation( + - skPath.Bounds.Left + (width - skPath.Bounds.Width ) / 2, + - skPath.Bounds.Top + (height - skPath.Bounds.Height ) / 2 )); + + var skBitmap = new SKBitmap(width, height, SKColorType.Bgra8888, SKAlphaType.Premul); + + using var skCanvas = new SKCanvas(skBitmap); + + using var skPaint = new SKPaint(); + skPaint.IsAntialias = true; + skPaint.Color = new SKColor(foreground.ToUInt32()); + + switch (kind) + { + case PackIconFeatherIconsKind: + skPaint.IsStroke = true; + skPaint.StrokeCap = SKStrokeCap.Round; + skPaint.StrokeWidth = 2 * scale; + break; + } + + skCanvas.DrawPath(skPath, skPaint); + + skBitmap.Encode(ms, SKEncodedImageFormat.Png, 100); + + ms.Seek(0, SeekOrigin.Begin); + }); + + return new Bitmap(ms); + } + catch (Exception e) + { + Console.WriteLine(e); + return null; + } + } + internal static IDictionary GetAllIcons() { var allIcons = new ConcurrentDictionary();