diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs
index 33f47678f4..4ec3826cac 100644
--- a/installer/PowerToysSetup/Product.wxs
+++ b/installer/PowerToysSetup/Product.wxs
@@ -128,7 +128,7 @@
-
+
diff --git a/src/modules/peek/Peek.FilePreviewer/UnsupportedFilePreview.xaml b/src/modules/peek/Peek.FilePreviewer/Controls/UnsupportedFilePreview.xaml
similarity index 95%
rename from src/modules/peek/Peek.FilePreviewer/UnsupportedFilePreview.xaml
rename to src/modules/peek/Peek.FilePreviewer/Controls/UnsupportedFilePreview.xaml
index f82033de80..08fb341d2b 100644
--- a/src/modules/peek/Peek.FilePreviewer/UnsupportedFilePreview.xaml
+++ b/src/modules/peek/Peek.FilePreviewer/Controls/UnsupportedFilePreview.xaml
@@ -2,7 +2,7 @@
@@ -34,7 +34,7 @@
Source="{x:Bind BrowserPreviewer.Preview, Mode=OneWay}"
Visibility="{x:Bind IsPreviewVisible(BrowserPreviewer, Previewer.State), Mode=OneWay, FallbackValue=Collapsed}" />
- GetBitmapFromHBitmapAsync(IntPtr hbitmap, bool isSupportingTransparency, CancellationToken cancellationToken)
+ {
+ try
+ {
+ var bitmap = System.Drawing.Image.FromHbitmap(hbitmap);
+ if (isSupportingTransparency)
+ {
+ bitmap.MakeTransparent();
+ }
+
+ var bitmapImage = new BitmapImage();
+
+ cancellationToken.ThrowIfCancellationRequested();
+ using (var stream = new MemoryStream())
+ {
+ bitmap.Save(stream, isSupportingTransparency ? ImageFormat.Png : ImageFormat.Bmp);
+ stream.Position = 0;
+
+ cancellationToken.ThrowIfCancellationRequested();
+ await bitmapImage.SetSourceAsync(stream.AsRandomAccessStream());
+ }
+
+ return bitmapImage;
+ }
+ finally
+ {
+ // delete HBitmap to avoid memory leaks
+ NativeMethods.DeleteObject(hbitmap);
+ }
+ }
+ }
+}
diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Helpers/IconHelper.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Helpers/IconHelper.cs
index 2e703ed197..0f54a45ecd 100644
--- a/src/modules/peek/Peek.FilePreviewer/Previewers/Helpers/IconHelper.cs
+++ b/src/modules/peek/Peek.FilePreviewer/Previewers/Helpers/IconHelper.cs
@@ -5,6 +5,10 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Media.Imaging;
using Peek.Common;
using Peek.Common.Models;
@@ -15,29 +19,46 @@ namespace Peek.FilePreviewer.Previewers.Helpers
// Based on https://stackoverflow.com/questions/21751747/extract-thumbnail-for-any-file-in-windows
private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93";
- public static HResult GetIcon(string fileName, out IntPtr hbitmap)
+ public static async Task GetIconAsync(string fileName, CancellationToken cancellationToken)
{
- Guid shellItem2Guid = new Guid(IShellItem2Guid);
- int retCode = NativeMethods.SHCreateItemFromParsingName(fileName, IntPtr.Zero, ref shellItem2Guid, out IShellItem nativeShellItem);
-
- if (retCode != 0)
+ ImageSource? imageSource = null;
+ IShellItem? nativeShellItem = null;
+ try
{
- throw Marshal.GetExceptionForHR(retCode)!;
+ Guid shellItem2Guid = new(IShellItem2Guid);
+ int retCode = NativeMethods.SHCreateItemFromParsingName(fileName, IntPtr.Zero, ref shellItem2Guid, out nativeShellItem);
+
+ if (retCode != 0)
+ {
+ throw Marshal.GetExceptionForHR(retCode)!;
+ }
+
+ NativeSize large = new NativeSize { Width = 256, Height = 256 };
+ var options = ThumbnailOptions.BiggerSizeOk | ThumbnailOptions.IconOnly;
+
+ HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(large, options, out IntPtr hbitmap);
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (hr == HResult.Ok)
+ {
+ imageSource = await BitmapHelper.GetBitmapFromHBitmapAsync(hbitmap, true, cancellationToken);
+ }
+ else
+ {
+ var svgImageSource = new SvgImageSource(new Uri("ms-appx:///Assets/DefaultFileIcon.svg"));
+ imageSource = svgImageSource;
+ }
+ }
+ finally
+ {
+ if (nativeShellItem != null)
+ {
+ Marshal.ReleaseComObject(nativeShellItem);
+ }
}
- NativeSize large = new NativeSize { Width = 256, Height = 256 };
- var options = ThumbnailOptions.BiggerSizeOk | ThumbnailOptions.IconOnly;
-
- HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(large, options, out hbitmap);
-
- if (hr != HResult.Ok)
- {
- // TODO: fallback to a generic icon
- }
-
- Marshal.ReleaseComObject(nativeShellItem);
-
- return hr;
+ return imageSource;
}
}
}
diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/IUnsupportedFilePreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/IUnsupportedFilePreviewer.cs
index a1733b48ac..8c90d54ca3 100644
--- a/src/modules/peek/Peek.FilePreviewer/Previewers/IUnsupportedFilePreviewer.cs
+++ b/src/modules/peek/Peek.FilePreviewer/Previewers/IUnsupportedFilePreviewer.cs
@@ -2,13 +2,13 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Microsoft.UI.Xaml.Media.Imaging;
+using Microsoft.UI.Xaml.Media;
namespace Peek.FilePreviewer.Previewers
{
public interface IUnsupportedFilePreviewer : IPreviewer
{
- public BitmapSource? IconPreview { get; }
+ public ImageSource? IconPreview { get; }
public string? FileName { get; }
diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/ImagePreviewer/ImagePreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/ImagePreviewer/ImagePreviewer.cs
index 5690c43d36..610904ad14 100644
--- a/src/modules/peek/Peek.FilePreviewer/Previewers/ImagePreviewer/ImagePreviewer.cs
+++ b/src/modules/peek/Peek.FilePreviewer/Previewers/ImagePreviewer/ImagePreviewer.cs
@@ -14,6 +14,7 @@ using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml.Media.Imaging;
using Peek.Common;
using Peek.Common.Extensions;
+using Peek.FilePreviewer.Previewers.Helpers;
using Windows.ApplicationModel.DataTransfer;
using Windows.Foundation;
using Windows.Storage;
@@ -153,7 +154,7 @@ namespace Peek.FilePreviewer.Previewers
await Dispatcher.RunOnUiThread(async () =>
{
cancellationToken.ThrowIfCancellationRequested();
- var thumbnailBitmap = await GetBitmapFromHBitmapAsync(hbitmap, cancellationToken);
+ var thumbnailBitmap = await BitmapHelper.GetBitmapFromHBitmapAsync(hbitmap, false, cancellationToken);
if (!IsFullImageLoaded && !IsHighQualityThumbnailLoaded)
{
Preview = thumbnailBitmap;
@@ -181,7 +182,7 @@ namespace Peek.FilePreviewer.Previewers
await Dispatcher.RunOnUiThread(async () =>
{
cancellationToken.ThrowIfCancellationRequested();
- var thumbnailBitmap = await GetBitmapFromHBitmapAsync(hbitmap, cancellationToken);
+ var thumbnailBitmap = await BitmapHelper.GetBitmapFromHBitmapAsync(hbitmap, false, cancellationToken);
if (!IsFullImageLoaded)
{
Preview = thumbnailBitmap;
@@ -229,32 +230,6 @@ namespace Peek.FilePreviewer.Previewers
return bitmap;
}
- private static async Task GetBitmapFromHBitmapAsync(IntPtr hbitmap, CancellationToken cancellationToken)
- {
- try
- {
- var bitmap = System.Drawing.Image.FromHbitmap(hbitmap);
- var bitmapImage = new BitmapImage();
-
- cancellationToken.ThrowIfCancellationRequested();
- using (var stream = new MemoryStream())
- {
- bitmap.Save(stream, ImageFormat.Bmp);
- stream.Position = 0;
-
- cancellationToken.ThrowIfCancellationRequested();
- await bitmapImage.SetSourceAsync(stream.AsRandomAccessStream());
- }
-
- return bitmapImage;
- }
- finally
- {
- // delete HBitmap to avoid memory leaks
- NativeMethods.DeleteObject(hbitmap);
- }
- }
-
public static bool IsFileTypeSupported(string fileExt)
{
return _supportedFileTypes.Contains(fileExt);
diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/UnsupportedFilePreviewer/UnsupportedFilePreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/UnsupportedFilePreviewer/UnsupportedFilePreviewer.cs
index b3410040bd..70b2d8a828 100644
--- a/src/modules/peek/Peek.FilePreviewer/Previewers/UnsupportedFilePreviewer/UnsupportedFilePreviewer.cs
+++ b/src/modules/peek/Peek.FilePreviewer/Previewers/UnsupportedFilePreviewer/UnsupportedFilePreviewer.cs
@@ -10,7 +10,7 @@ using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.UI.Dispatching;
-using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using Peek.Common;
using Peek.Common.Extensions;
@@ -26,7 +26,7 @@ namespace Peek.FilePreviewer.Previewers
public partial class UnsupportedFilePreviewer : ObservableObject, IUnsupportedFilePreviewer, IDisposable
{
[ObservableProperty]
- private BitmapSource? iconPreview;
+ private ImageSource? iconPreview;
[ObservableProperty]
private string? fileName;
@@ -123,15 +123,11 @@ namespace Peek.FilePreviewer.Previewers
{
return TaskExtension.RunSafe(async () =>
{
- cancellationToken.ThrowIfCancellationRequested();
-
- IconHelper.GetIcon(Path.GetFullPath(File.Path), out IntPtr hbitmap);
-
cancellationToken.ThrowIfCancellationRequested();
await Dispatcher.RunOnUiThread(async () =>
{
cancellationToken.ThrowIfCancellationRequested();
- var iconBitmap = await GetBitmapFromHBitmapWithTransparencyAsync(hbitmap, cancellationToken);
+ var iconBitmap = await IconHelper.GetIconAsync(Path.GetFullPath(File.Path), cancellationToken);
IconPreview = iconBitmap;
});
});
@@ -175,35 +171,5 @@ namespace Peek.FilePreviewer.Previewers
return hasFailedLoadingIconPreview && hasFailedLoadingDisplayInfo;
}
-
- // TODO: Move this to a common helper file and make transparency a parameter (ImagePrevier uses the same code)
- private static async Task GetBitmapFromHBitmapWithTransparencyAsync(IntPtr hbitmap, CancellationToken cancellationToken)
- {
- try
- {
- cancellationToken.ThrowIfCancellationRequested();
- var bitmap = System.Drawing.Image.FromHbitmap(hbitmap);
- bitmap.MakeTransparent();
-
- var bitmapImage = new BitmapImage();
-
- cancellationToken.ThrowIfCancellationRequested();
- using (var stream = new MemoryStream())
- {
- bitmap.Save(stream, ImageFormat.Png);
- stream.Position = 0;
-
- cancellationToken.ThrowIfCancellationRequested();
- await bitmapImage.SetSourceAsync(stream.AsRandomAccessStream());
- }
-
- return bitmapImage;
- }
- finally
- {
- // delete HBitmap to avoid memory leaks
- NativeMethods.DeleteObject(hbitmap);
- }
- }
}
}
diff --git a/src/modules/peek/Peek.UI/Assets/DefaultFileIcon.svg b/src/modules/peek/Peek.UI/Assets/DefaultFileIcon.svg
new file mode 100644
index 0000000000..afea45d77a
--- /dev/null
+++ b/src/modules/peek/Peek.UI/Assets/DefaultFileIcon.svg
@@ -0,0 +1,5 @@
+