1010using CommunityToolkit . Mvvm . DependencyInjection ;
1111using Flow . Launcher . Infrastructure . Storage ;
1212using Flow . Launcher . Plugin ;
13+ using SharpVectors . Converters ;
14+ using SharpVectors . Renderers . Wpf ;
1315
1416namespace Flow . Launcher . Infrastructure . Image
1517{
@@ -32,8 +34,10 @@ public static class ImageLoader
3234 public static ImageSource LoadingImage { get ; } = new BitmapImage ( new Uri ( Constant . LoadingImgIcon ) ) ;
3335 public const int SmallIconSize = 64 ;
3436 public const int FullIconSize = 256 ;
37+ public const int FullImageSize = 320 ;
3538
3639 private static readonly string [ ] ImageExtensions = { ".png" , ".jpg" , ".jpeg" , ".gif" , ".bmp" , ".tiff" , ".ico" } ;
40+ private static readonly string SvgExtension = ".svg" ;
3741
3842 public static async Task InitializeAsync ( )
3943 {
@@ -235,10 +239,11 @@ private static ImageResult GetThumbnailResult(ref string path, bool loadFullImag
235239 image = LoadFullImage ( path ) ;
236240 type = ImageType . FullImageFile ;
237241 }
238- catch ( NotSupportedException )
242+ catch ( NotSupportedException ex )
239243 {
240244 image = Image ;
241245 type = ImageType . Error ;
246+ API . LogException ( ClassName , $ "Failed to load image file from path { path } : { ex . Message } ", ex ) ;
242247 }
243248 }
244249 else
@@ -251,6 +256,20 @@ private static ImageResult GetThumbnailResult(ref string path, bool loadFullImag
251256 image = GetThumbnail ( path , ThumbnailOptions . ThumbnailOnly ) ;
252257 }
253258 }
259+ else if ( extension == SvgExtension )
260+ {
261+ try
262+ {
263+ image = LoadSvgImage ( path , loadFullImage ) ;
264+ type = ImageType . FullImageFile ;
265+ }
266+ catch ( System . Exception ex )
267+ {
268+ image = Image ;
269+ type = ImageType . Error ;
270+ API . LogException ( ClassName , $ "Failed to load SVG image from path { path } : { ex . Message } ", ex ) ;
271+ }
272+ }
254273 else
255274 {
256275 type = ImageType . File ;
@@ -324,7 +343,7 @@ public static async ValueTask<ImageSource> LoadAsync(string path, bool loadFullI
324343 return img ;
325344 }
326345
327- private static BitmapImage LoadFullImage ( string path )
346+ private static ImageSource LoadFullImage ( string path )
328347 {
329348 BitmapImage image = new BitmapImage ( ) ;
330349 image . BeginInit ( ) ;
@@ -333,24 +352,24 @@ private static BitmapImage LoadFullImage(string path)
333352 image . CreateOptions = BitmapCreateOptions . IgnoreColorProfile ;
334353 image . EndInit ( ) ;
335354
336- if ( image . PixelWidth > 320 )
355+ if ( image . PixelWidth > FullImageSize )
337356 {
338357 BitmapImage resizedWidth = new BitmapImage ( ) ;
339358 resizedWidth . BeginInit ( ) ;
340359 resizedWidth . CacheOption = BitmapCacheOption . OnLoad ;
341360 resizedWidth . UriSource = new Uri ( path ) ;
342361 resizedWidth . CreateOptions = BitmapCreateOptions . IgnoreColorProfile ;
343- resizedWidth . DecodePixelWidth = 320 ;
362+ resizedWidth . DecodePixelWidth = FullImageSize ;
344363 resizedWidth . EndInit ( ) ;
345364
346- if ( resizedWidth . PixelHeight > 320 )
365+ if ( resizedWidth . PixelHeight > FullImageSize )
347366 {
348367 BitmapImage resizedHeight = new BitmapImage ( ) ;
349368 resizedHeight . BeginInit ( ) ;
350369 resizedHeight . CacheOption = BitmapCacheOption . OnLoad ;
351370 resizedHeight . UriSource = new Uri ( path ) ;
352371 resizedHeight . CreateOptions = BitmapCreateOptions . IgnoreColorProfile ;
353- resizedHeight . DecodePixelHeight = 320 ;
372+ resizedHeight . DecodePixelHeight = FullImageSize ;
354373 resizedHeight . EndInit ( ) ;
355374 return resizedHeight ;
356375 }
@@ -360,5 +379,50 @@ private static BitmapImage LoadFullImage(string path)
360379
361380 return image ;
362381 }
382+
383+ private static ImageSource LoadSvgImage ( string path , bool loadFullImage = false )
384+ {
385+ // Set up drawing settings
386+ var desiredHeight = loadFullImage ? FullImageSize : SmallIconSize ;
387+ var drawingSettings = new WpfDrawingSettings
388+ {
389+ IncludeRuntime = true ,
390+ // Set IgnoreRootViewbox to false to respect the SVG's viewBox
391+ IgnoreRootViewbox = false
392+ } ;
393+
394+ // Load and render the SVG
395+ var converter = new FileSvgReader ( drawingSettings ) ;
396+ var drawing = converter . Read ( new Uri ( path ) ) ;
397+
398+ // Calculate scale to achieve desired height
399+ var drawingBounds = drawing . Bounds ;
400+ if ( drawingBounds . Height <= 0 )
401+ {
402+ throw new InvalidOperationException ( $ "Invalid SVG dimensions: Height must be greater than zero in { path } ") ;
403+ }
404+ var scale = desiredHeight / drawingBounds . Height ;
405+ var scaledWidth = drawingBounds . Width * scale ;
406+ var scaledHeight = drawingBounds . Height * scale ;
407+
408+ // Convert the Drawing to a Bitmap
409+ var drawingVisual = new DrawingVisual ( ) ;
410+ using ( DrawingContext drawingContext = drawingVisual . RenderOpen ( ) )
411+ {
412+ drawingContext . PushTransform ( new ScaleTransform ( scale , scale ) ) ;
413+ drawingContext . DrawDrawing ( drawing ) ;
414+ }
415+
416+ // Create a RenderTargetBitmap to hold the rendered image
417+ var bitmap = new RenderTargetBitmap (
418+ ( int ) Math . Ceiling ( scaledWidth ) ,
419+ ( int ) Math . Ceiling ( scaledHeight ) ,
420+ 96 , // DpiX
421+ 96 , // DpiY
422+ PixelFormats . Pbgra32 ) ;
423+ bitmap . Render ( drawingVisual ) ;
424+
425+ return bitmap ;
426+ }
363427 }
364428}
0 commit comments