Skip to content

Commit 82f6788

Browse files
committed
Support svg image file loading
1 parent f854cd3 commit 82f6788

File tree

4 files changed

+66
-25
lines changed

4 files changed

+66
-25
lines changed

Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
</PackageReference>
6868
<PackageReference Include="NLog" Version="4.7.10" />
6969
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
70+
<PackageReference Include="SharpVectors.Wpf" Version="1.8.4.2" />
7071
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
7172
<!--ToolGood.Words.Pinyin v3.0.2.6 results in high memory usage when search with pinyin is enabled-->
7273
<!--Bumping to it or higher needs to test and ensure this is no longer a problem-->

Flow.Launcher.Infrastructure/Image/ImageLoader.cs

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
using System.Windows.Media.Imaging;
1010
using Flow.Launcher.Infrastructure.Logger;
1111
using Flow.Launcher.Infrastructure.Storage;
12+
using SharpVectors.Converters;
13+
using SharpVectors.Renderers.Wpf;
1214

1315
namespace Flow.Launcher.Infrastructure.Image
1416
{
@@ -25,8 +27,10 @@ public static class ImageLoader
2527
public static ImageSource LoadingImage { get; } = new BitmapImage(new Uri(Constant.LoadingImgIcon));
2628
public const int SmallIconSize = 64;
2729
public const int FullIconSize = 256;
30+
public const int FullImageSize = 320;
2831

2932
private static readonly string[] ImageExtensions = { ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".tiff", ".ico" };
33+
private static readonly string SvgExtension = ".svg";
3034

3135
public static async Task InitializeAsync()
3236
{
@@ -245,6 +249,19 @@ private static ImageResult GetThumbnailResult(ref string path, bool loadFullImag
245249
image = GetThumbnail(path, ThumbnailOptions.ThumbnailOnly);
246250
}
247251
}
252+
else if (extension == SvgExtension)
253+
{
254+
try
255+
{
256+
image = LoadFullSvgImage(path, loadFullImage);
257+
type = ImageType.FullImageFile;
258+
}
259+
catch (System.Exception)
260+
{
261+
image = Image;
262+
type = ImageType.Error;
263+
}
264+
}
248265
else
249266
{
250267
type = ImageType.File;
@@ -318,7 +335,7 @@ public static async ValueTask<ImageSource> LoadAsync(string path, bool loadFullI
318335
return img;
319336
}
320337

321-
private static BitmapImage LoadFullImage(string path)
338+
private static ImageSource LoadFullImage(string path)
322339
{
323340
BitmapImage image = new BitmapImage();
324341
image.BeginInit();
@@ -327,24 +344,24 @@ private static BitmapImage LoadFullImage(string path)
327344
image.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
328345
image.EndInit();
329346

330-
if (image.PixelWidth > 320)
347+
if (image.PixelWidth > FullImageSize)
331348
{
332349
BitmapImage resizedWidth = new BitmapImage();
333350
resizedWidth.BeginInit();
334351
resizedWidth.CacheOption = BitmapCacheOption.OnLoad;
335352
resizedWidth.UriSource = new Uri(path);
336353
resizedWidth.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
337-
resizedWidth.DecodePixelWidth = 320;
354+
resizedWidth.DecodePixelWidth = FullImageSize;
338355
resizedWidth.EndInit();
339356

340-
if (resizedWidth.PixelHeight > 320)
357+
if (resizedWidth.PixelHeight > FullImageSize)
341358
{
342359
BitmapImage resizedHeight = new BitmapImage();
343360
resizedHeight.BeginInit();
344361
resizedHeight.CacheOption = BitmapCacheOption.OnLoad;
345362
resizedHeight.UriSource = new Uri(path);
346363
resizedHeight.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
347-
resizedHeight.DecodePixelHeight = 320;
364+
resizedHeight.DecodePixelHeight = FullImageSize;
348365
resizedHeight.EndInit();
349366
return resizedHeight;
350367
}
@@ -354,5 +371,44 @@ private static BitmapImage LoadFullImage(string path)
354371

355372
return image;
356373
}
374+
375+
private static ImageSource LoadFullSvgImage(string path, bool loadFullImage = false)
376+
{
377+
// Set up drawing settings
378+
var desiredHeight = loadFullImage ? FullImageSize : SmallIconSize;
379+
var drawingSettings = new WpfDrawingSettings
380+
{
381+
IncludeRuntime = true,
382+
// Set IgnoreRootViewbox to false to respect the SVG's viewBox
383+
IgnoreRootViewbox = false
384+
};
385+
386+
// Load and render the SVG
387+
var converter = new FileSvgReader(drawingSettings);
388+
var drawing = converter.Read(path);
389+
390+
// Calculate scale to achieve desired height
391+
var drawingBounds = drawing.Bounds;
392+
var scale = desiredHeight / drawingBounds.Height;
393+
var scaledWidth = drawingBounds.Width * scale;
394+
var scaledHeight = drawingBounds.Height * scale;
395+
396+
// Convert the Drawing to a Bitmap
397+
var drawingVisual = new DrawingVisual();
398+
using DrawingContext drawingContext = drawingVisual.RenderOpen();
399+
drawingContext.PushTransform(new ScaleTransform(scale, scale));
400+
drawingContext.DrawDrawing(drawing);
401+
402+
// Create a RenderTargetBitmap to hold the rendered image
403+
var bitmap = new RenderTargetBitmap(
404+
(int)Math.Ceiling(scaledWidth),
405+
(int)Math.Ceiling(scaledHeight),
406+
96, // DpiX
407+
96, // DpiY
408+
PixelFormats.Pbgra32);
409+
bitmap.Render(drawingVisual);
410+
411+
return bitmap;
412+
}
357413
}
358414
}

Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,9 @@ public interface IPublicAPI
438438
Task SaveCacheBinaryStorageAsync<T>(string cacheName, string cacheDirectory) where T : new();
439439

440440
/// <summary>
441-
/// Load image from path. Support local, remote and data:image url.
441+
/// Load image from path.
442+
/// Support local, remote and data:image url.
443+
/// Support png, jpg, jpeg, gif, bmp, tiff, ico, svg image files.
442444
/// If image path is missing, it will return a missing icon.
443445
/// </summary>
444446
/// <param name="path">The path of the image.</param>

Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -159,16 +159,7 @@ ORDER BY i.width DESC -- Select largest icon available
159159

160160
if (!File.Exists(faviconPath))
161161
{
162-
// SVG 파일인지 확인
163-
if (IsSvgData(imageData))
164-
{
165-
bookmark.FaviconPath = defaultIconPath;
166-
continue;
167-
}
168-
else
169-
{
170-
SaveBitmapData(imageData, faviconPath);
171-
}
162+
SaveBitmapData(imageData, faviconPath);
172163
}
173164

174165
bookmark.FaviconPath = faviconPath;
@@ -199,15 +190,6 @@ ORDER BY i.width DESC -- Select largest icon available
199190
}
200191
}
201192

202-
private static bool IsSvgData(byte[] data)
203-
{
204-
if (data.Length < 5)
205-
return false;
206-
string start = System.Text.Encoding.ASCII.GetString(data, 0, Math.Min(100, data.Length));
207-
return start.Contains("<svg") ||
208-
(start.StartsWith("<?xml") && start.Contains("<svg"));
209-
}
210-
211193
private static void SaveBitmapData(byte[] imageData, string outputPath)
212194
{
213195
try

0 commit comments

Comments
 (0)