[Peek] show thumbnail and fallback to icon on unsupported files (#27979)

This commit is contained in:
Pedro Lamas
2023-08-24 11:10:45 +01:00
committed by GitHub
parent efee03eb99
commit c1316fc9f8
3 changed files with 41 additions and 14 deletions

View File

@@ -17,12 +17,23 @@ namespace Peek.FilePreviewer.Previewers.Helpers
{ {
public static async Task<BitmapSource> GetBitmapFromHBitmapAsync(IntPtr hbitmap, bool isSupportingTransparency, CancellationToken cancellationToken) public static async Task<BitmapSource> GetBitmapFromHBitmapAsync(IntPtr hbitmap, bool isSupportingTransparency, CancellationToken cancellationToken)
{ {
Bitmap? bitmap = null;
try try
{ {
var bitmap = Image.FromHbitmap(hbitmap); bitmap = Image.FromHbitmap(hbitmap);
if (isSupportingTransparency)
cancellationToken.ThrowIfCancellationRequested();
if (isSupportingTransparency && bitmap.PixelFormat == PixelFormat.Format32bppRgb)
{ {
bitmap.MakeTransparent(); var bitmapRectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
var bitmapData = bitmap.LockBits(bitmapRectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat);
var transparentBitmap = new Bitmap(bitmapData.Width, bitmapData.Height, bitmapData.Stride, PixelFormat.Format32bppArgb, bitmapData.Scan0);
bitmap.Dispose();
bitmap = transparentBitmap;
} }
var bitmapImage = new BitmapImage(); var bitmapImage = new BitmapImage();
@@ -41,6 +52,8 @@ namespace Peek.FilePreviewer.Previewers.Helpers
} }
finally finally
{ {
bitmap?.Dispose();
// delete HBitmap to avoid memory leaks // delete HBitmap to avoid memory leaks
NativeMethods.DeleteObject(hbitmap); NativeMethods.DeleteObject(hbitmap);
} }
@@ -50,8 +63,8 @@ namespace Peek.FilePreviewer.Previewers.Helpers
{ {
try try
{ {
var icon = (Icon)Icon.FromHandle(hicon).Clone(); using var icon = (Icon)Icon.FromHandle(hicon).Clone();
var bitmap = icon.ToBitmap(); using var bitmap = icon.ToBitmap();
var bitmapImage = new BitmapImage(); var bitmapImage = new BitmapImage();

View File

@@ -7,9 +7,7 @@ using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using Peek.Common; using Peek.Common;
using Peek.Common.Extensions;
using Peek.Common.Models; using Peek.Common.Models;
namespace Peek.FilePreviewer.Previewers.Helpers namespace Peek.FilePreviewer.Previewers.Helpers
@@ -20,6 +18,16 @@ namespace Peek.FilePreviewer.Previewers.Helpers
private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93"; private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93";
public static async Task<ImageSource?> GetIconAsync(string fileName, CancellationToken cancellationToken) public static async Task<ImageSource?> GetIconAsync(string fileName, CancellationToken cancellationToken)
{
return await GetImageAsync(fileName, ThumbnailOptions.BiggerSizeOk | ThumbnailOptions.IconOnly, true, cancellationToken);
}
public static async Task<ImageSource?> GetThumbnailAsync(string fileName, CancellationToken cancellationToken)
{
return await GetImageAsync(fileName, ThumbnailOptions.ThumbnailOnly, true, cancellationToken);
}
public static async Task<ImageSource?> GetImageAsync(string fileName, ThumbnailOptions options, bool isSupportingTransparency, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(fileName)) if (string.IsNullOrEmpty(fileName))
{ {
@@ -28,6 +36,7 @@ namespace Peek.FilePreviewer.Previewers.Helpers
ImageSource? imageSource = null; ImageSource? imageSource = null;
IShellItem? nativeShellItem = null; IShellItem? nativeShellItem = null;
IntPtr hbitmap = IntPtr.Zero;
try try
{ {
@@ -40,16 +49,22 @@ namespace Peek.FilePreviewer.Previewers.Helpers
} }
NativeSize large = new NativeSize { Width = 256, Height = 256 }; NativeSize large = new NativeSize { Width = 256, Height = 256 };
var options = ThumbnailOptions.BiggerSizeOk | ThumbnailOptions.IconOnly;
HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(large, options, out IntPtr hbitmap); HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(large, options, out hbitmap);
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
imageSource = hr == HResult.Ok ? await BitmapHelper.GetBitmapFromHBitmapAsync(hbitmap, true, cancellationToken) : null; imageSource = hr == HResult.Ok ? await BitmapHelper.GetBitmapFromHBitmapAsync(hbitmap, isSupportingTransparency, cancellationToken) : null;
hbitmap = IntPtr.Zero;
} }
finally finally
{ {
if (hbitmap != IntPtr.Zero)
{
NativeMethods.DeleteObject(hbitmap);
}
if (nativeShellItem != null) if (nativeShellItem != null)
{ {
Marshal.ReleaseComObject(nativeShellItem); Marshal.ReleaseComObject(nativeShellItem);

View File

@@ -4,11 +4,9 @@
using System; using System;
using System.Globalization; using System.Globalization;
using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.UI.Dispatching; using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml.Media.Imaging; using Microsoft.UI.Xaml.Media.Imaging;
using Peek.Common.Extensions; using Peek.Common.Extensions;
@@ -76,7 +74,7 @@ namespace Peek.FilePreviewer.Previewers
else else
{ {
State = PreviewState.Loaded; State = PreviewState.Loaded;
} }
} }
public async Task CopyAsync() public async Task CopyAsync()
@@ -99,7 +97,8 @@ namespace Peek.FilePreviewer.Previewers
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
var iconBitmap = await IconHelper.GetIconAsync(Item.Path, cancellationToken); var iconBitmap = await IconHelper.GetThumbnailAsync(Item.Path, cancellationToken)
?? await IconHelper.GetIconAsync(Item.Path, cancellationToken);
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();