From 9cab49196368d72fe210dc0a06af7ec9a7ae7987 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 11 Jul 2025 15:51:13 +0200 Subject: [PATCH 1/2] Proposing changes to the autognerated API --- src/Directory.Packages.props | 1 + .../IconPacks.Avalonia.csproj | 1 + .../PackIconControlDataFactory.cs | 95 +++++++++++++++++++ 3 files changed, 97 insertions(+) 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..2707a6c 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,97 @@ static PackIconControlDataFactory() DataIndex = new Lazy>(() => new ReadOnlyDictionary(GetAllIcons())); } + public static string ProvideSvgPathData(Enum kind) + { + string data = null; + DataIndex.Value?.TryGetValue(kind, out data); + 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 scaleX, scaleY; + scaleX = scaleY = Math.Min(width / originalBounds.Width, height / originalBounds.Height); + + // 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: + scaleY *= -1; + break; + } + + skPath.Transform(SKMatrix.CreateScale(scaleX, scaleY)); + 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 * scaleX; + 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(); From a0ef94ff3736b4adae255c4edf000cbf91b52f77 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 11 Jul 2025 16:02:39 +0200 Subject: [PATCH 2/2] when reading the data, flip it already if needed --- .../PackIconControlDataFactory.cs | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/src/IconPacks.Avalonia/PackIconControlDataFactory.cs b/src/IconPacks.Avalonia/PackIconControlDataFactory.cs index 2707a6c..5b62be6 100644 --- a/src/IconPacks.Avalonia/PackIconControlDataFactory.cs +++ b/src/IconPacks.Avalonia/PackIconControlDataFactory.cs @@ -65,7 +65,31 @@ public static string ProvideSvgPathData(Enum kind) { string data = null; DataIndex.Value?.TryGetValue(kind, out data); - return 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) @@ -90,31 +114,10 @@ await Task.Run(() => if (width < 0) width = (int)(Math.Ceiling(originalBounds.Width)); if (height < 0) height = (int)(Math.Ceiling(originalBounds.Height)); - float scaleX, scaleY; - scaleX = scaleY = Math.Min(width / originalBounds.Width, height / originalBounds.Height); - - // 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: - scaleY *= -1; - break; - } + float scale = Math.Min(width / originalBounds.Width, height / originalBounds.Height); + - skPath.Transform(SKMatrix.CreateScale(scaleX, scaleY)); + 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 )); @@ -132,7 +135,7 @@ await Task.Run(() => case PackIconFeatherIconsKind: skPaint.IsStroke = true; skPaint.StrokeCap = SKStrokeCap.Round; - skPaint.StrokeWidth = 2 * scaleX; + skPaint.StrokeWidth = 2 * scale; break; }