diff --git a/src/modules/peek/Peek.Common/Models/Win32/IShellItemImageFactory.cs b/src/modules/peek/Peek.Common/Models/Win32/IShellItemImageFactory.cs index b2b72394f2..7df3a41561 100644 --- a/src/modules/peek/Peek.Common/Models/Win32/IShellItemImageFactory.cs +++ b/src/modules/peek/Peek.Common/Models/Win32/IShellItemImageFactory.cs @@ -20,20 +20,11 @@ namespace Peek.Common.Models } [StructLayout(LayoutKind.Sequential)] - public struct NativeSize + public struct NativeSize(int width, int height) { - private int width; - private int height; + public int Width { get; set; } = width; - public int Width - { - set { width = value; } - } - - public int Height - { - set { height = value; } - } + public int Height { get; set; } = height; } [Flags] diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Drive/DrivePreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Drive/DrivePreviewer.cs index 02446e49f4..2ce5c927a4 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/Drive/DrivePreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/Drive/DrivePreviewer.cs @@ -83,7 +83,7 @@ namespace Peek.FilePreviewer.Previewers.Drive } cancellationToken.ThrowIfCancellationRequested(); - var iconBitmap = await IconHelper.GetIconAsync(Item.Path, cancellationToken); + var iconBitmap = await ThumbnailHelper.GetIconAsync(Item.Path, cancellationToken); preview.IconPreview = iconBitmap ?? new SvgImageSource(new Uri("ms-appx:///Assets/Peek/DefaultFileIcon.svg")); Preview = preview; diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Helpers/IconHelper.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Helpers/IconHelper.cs deleted file mode 100644 index f1a4227e67..0000000000 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/Helpers/IconHelper.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) Microsoft Corporation -// The Microsoft Corporation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; - -using Microsoft.UI.Xaml.Media; -using Peek.Common; -using Peek.Common.Models; - -namespace Peek.FilePreviewer.Previewers.Helpers -{ - public static class IconHelper - { - // 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 async Task GetIconAsync(string fileName, CancellationToken cancellationToken) - { - return await GetImageAsync(fileName, ThumbnailOptions.BiggerSizeOk | ThumbnailOptions.IconOnly, true, cancellationToken); - } - - public static async Task GetThumbnailAsync(string fileName, CancellationToken cancellationToken) - { - return await GetImageAsync(fileName, ThumbnailOptions.ThumbnailOnly, true, cancellationToken); - } - - public static async Task GetImageAsync(string fileName, ThumbnailOptions options, bool isSupportingTransparency, CancellationToken cancellationToken) - { - if (string.IsNullOrEmpty(fileName)) - { - return null; - } - - ImageSource? imageSource = null; - IShellItem? nativeShellItem = null; - IntPtr hbitmap = IntPtr.Zero; - - try - { - 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 }; - - HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(large, options, out hbitmap); - - cancellationToken.ThrowIfCancellationRequested(); - - imageSource = hr == HResult.Ok ? await BitmapHelper.GetBitmapFromHBitmapAsync(hbitmap, isSupportingTransparency, cancellationToken) : null; - - hbitmap = IntPtr.Zero; - } - finally - { - if (hbitmap != IntPtr.Zero) - { - NativeMethods.DeleteObject(hbitmap); - } - - if (nativeShellItem != null) - { - Marshal.ReleaseComObject(nativeShellItem); - } - } - - return imageSource; - } - } -} diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/Helpers/ThumbnailHelper.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/Helpers/ThumbnailHelper.cs new file mode 100644 index 0000000000..05ddd395bf --- /dev/null +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/Helpers/ThumbnailHelper.cs @@ -0,0 +1,103 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.UI.Xaml.Media; +using Peek.Common; +using Peek.Common.Models; + +namespace Peek.FilePreviewer.Previewers.Helpers; + +/// +/// Create thumbnail or icon images for a file, or retrieve them from the Windows Explorer thumbnail and icon caches. +/// +/// Inspired by https://stackoverflow.com/questions/21751747/extract-thumbnail-for-any-file-in-windows +public static class ThumbnailHelper +{ + // The maximum size Explorer's thumbnail cache currently supports. Used for cache retrieval. + private static readonly NativeSize MaxThumbnailSize = new(2560, 2560); + + // Default size for all previewers except ImagePreviewer. + private static readonly NativeSize DefaultThumbnailSize = new(256, 256); + + // Used to retrieve the Shell Item for a given Windows Explorer resource, so its thumbnail/icon can be retrieved. + private static Guid _shellItem2Guid = new("7E9FB0D3-919F-4307-AB2E-9B1860310C93"); + + /// + /// Get a file's icon bitmap. + /// + /// Path to the file. + /// The async task cancellation token. + /// An corresponding to the file's icon bitmap, or null if retrieval failed. + /// If a cached icon cannot be found, a new icon will be created and added to the Explorer icon cache. + public static async Task GetIconAsync(string path, CancellationToken cancellationToken) + { + return await GetImageAsync(path, ThumbnailOptions.BiggerSizeOk | ThumbnailOptions.IconOnly, true, cancellationToken); + } + + /// + /// Get a file's thumbnail bitmap. + /// + /// Path to the file. + /// The async task cancellation token. + /// An corresponding to the file's thumbnail bitmap, or null if retrieval failed. + /// If a cached thumbnail cannot be found, a new thumbnail will be created and added to the Explorer thumbnail cache. + public static async Task GetThumbnailAsync(string path, CancellationToken cancellationToken) + { + return await GetImageAsync(path, ThumbnailOptions.BiggerSizeOk | ThumbnailOptions.ThumbnailOnly, true, cancellationToken); + } + + /// + /// Get the highest-resolution image available for a file from the Explorer thumbnail and icon caches. + /// + /// Path to the file. + /// Whether the file's type supports transparency. Set to true for PNG image files. + /// The async task cancellation token. + /// An corresponding to the thumbnail or icon, or null if there is no icon or thumbnail cached for the file. + public static async Task GetCachedThumbnailAsync(string path, bool supportsTransparency, CancellationToken cancellationToken) + { + return await GetImageAsync(path, ThumbnailOptions.InCacheOnly, supportsTransparency, cancellationToken); + } + + private static async Task GetImageAsync(string path, ThumbnailOptions options, bool supportsTransparency, CancellationToken cancellationToken) + { + IntPtr hBitmap = IntPtr.Zero; + IShellItem? nativeShellItem = null; + bool checkCacheOnly = options.HasFlag(ThumbnailOptions.InCacheOnly); + + try + { + int retCode = NativeMethods.SHCreateItemFromParsingName(path, IntPtr.Zero, ref _shellItem2Guid, out nativeShellItem); + if (retCode != 0) + { + throw Marshal.GetExceptionForHR(retCode)!; + } + + cancellationToken.ThrowIfCancellationRequested(); + + HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(checkCacheOnly ? MaxThumbnailSize : DefaultThumbnailSize, options, out hBitmap); + + cancellationToken.ThrowIfCancellationRequested(); + + return hr == HResult.Ok ? await BitmapHelper.GetBitmapFromHBitmapAsync(hBitmap, supportsTransparency, cancellationToken) : null; + } + finally + { + // Delete the unmanaged bitmap resource. + if (hBitmap != IntPtr.Zero) + { + NativeMethods.DeleteObject(hBitmap); + } + + if (nativeShellItem != null) + { + Marshal.ReleaseComObject(nativeShellItem); + } + } + } +} diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/AudioPreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/AudioPreviewer.cs index a4246edbd3..586b92ed75 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/AudioPreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/AudioPreviewer.cs @@ -88,8 +88,8 @@ namespace Peek.FilePreviewer.Previewers.MediaPreviewer { cancellationToken.ThrowIfCancellationRequested(); - var thumbnail = await IconHelper.GetThumbnailAsync(Item.Path, cancellationToken) - ?? await IconHelper.GetIconAsync(Item.Path, cancellationToken); + var thumbnail = await ThumbnailHelper.GetThumbnailAsync(Item.Path, cancellationToken) + ?? await ThumbnailHelper.GetIconAsync(Item.Path, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/Helpers/ThumbnailHelper.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/Helpers/ThumbnailHelper.cs deleted file mode 100644 index 8154a70818..0000000000 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/Helpers/ThumbnailHelper.cs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) Microsoft Corporation -// The Microsoft Corporation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Threading.Tasks; - -using Microsoft.UI.Xaml.Media.Imaging; -using Peek.Common; -using Peek.Common.Models; -using Windows.Storage; - -namespace Peek.FilePreviewer.Previewers -{ - public static class ThumbnailHelper - { - // 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 readonly NativeSize HighQualityThumbnailSize = new NativeSize { Width = 720, Height = 720, }; - public static readonly NativeSize LowQualityThumbnailSize = new NativeSize { Width = 256, Height = 256, }; - - private static readonly NativeSize FallBackThumbnailSize = new NativeSize { Width = 96, Height = 96, }; - private static readonly NativeSize LastFallBackThumbnailSize = new NativeSize { Width = 32, Height = 32, }; - - private static readonly List ThumbnailFallBackSizes = new List - { - HighQualityThumbnailSize, - LowQualityThumbnailSize, - FallBackThumbnailSize, - LastFallBackThumbnailSize, - }; - - // TODO: Add a re-try system if there is no thumbnail of requested size. - public static HResult GetThumbnail(string filename, out IntPtr hbitmap, NativeSize thumbnailSize) - { - Guid shellItem2Guid = new Guid(IShellItem2Guid); - int retCode = NativeMethods.SHCreateItemFromParsingName(filename, IntPtr.Zero, ref shellItem2Guid, out IShellItem nativeShellItem); - - if (retCode != 0) - { - throw Marshal.GetExceptionForHR(retCode)!; - } - - var options = ThumbnailOptions.BiggerSizeOk | ThumbnailOptions.ThumbnailOnly | ThumbnailOptions.ScaleUp; - - HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(thumbnailSize, options, out hbitmap); - - // Try to get thumbnail using the fallback sizes order - if (hr != HResult.Ok) - { - var currentThumbnailFallBackIndex = ThumbnailFallBackSizes.IndexOf(thumbnailSize); - var nextThumbnailFallBackIndex = currentThumbnailFallBackIndex + 1; - if (nextThumbnailFallBackIndex < ThumbnailFallBackSizes.Count - 1) - { - hr = GetThumbnail(filename, out hbitmap, ThumbnailFallBackSizes[nextThumbnailFallBackIndex]); - } - } - - Marshal.ReleaseComObject(nativeShellItem); - - return hr; - } - - public static async Task GetThumbnailAsync(StorageFile? storageFile, uint size) - { - BitmapImage? bitmapImage = null; - - var imageStream = await storageFile?.GetThumbnailAsync( - Windows.Storage.FileProperties.ThumbnailMode.SingleItem, - size, - Windows.Storage.FileProperties.ThumbnailOptions.None); - - if (imageStream == null) - { - return bitmapImage; - } - - bitmapImage = new BitmapImage(); - bitmapImage.SetSource(imageStream); - - return bitmapImage; - } - } -} diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/ImagePreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/ImagePreviewer.cs index da871c6e5e..9698e43f5a 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/ImagePreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/MediaPreviewer/ImagePreviewer.cs @@ -14,7 +14,6 @@ using Microsoft.PowerToys.FilePreviewCommon; using Microsoft.UI.Dispatching; using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Media.Imaging; -using Peek.Common; using Peek.Common.Extensions; using Peek.Common.Helpers; using Peek.Common.Models; @@ -26,7 +25,7 @@ using Windows.Foundation; namespace Peek.FilePreviewer.Previewers { - public partial class ImagePreviewer : ObservableObject, IImagePreviewer, IDisposable + public partial class ImagePreviewer : ObservableObject, IImagePreviewer { [ObservableProperty] private ImageSource? preview; @@ -51,41 +50,24 @@ namespace Peek.FilePreviewer.Previewers private IFileSystemItem Item { get; } + private bool IsPng() => Item.Extension == ".png"; + + private bool IsSvg() => Item.Extension == ".svg"; + + private bool IsQoi() => Item.Extension == ".qoi"; + private DispatcherQueue Dispatcher { get; } - private Task? LowQualityThumbnailTask { get; set; } - - private Task? HighQualityThumbnailTask { get; set; } - - private Task? FullQualityImageTask { get; set; } - - private bool IsHighQualityThumbnailLoaded => HighQualityThumbnailTask?.Status == TaskStatus.RanToCompletion; - - private bool IsFullImageLoaded => FullQualityImageTask?.Status == TaskStatus.RanToCompletion; - - private IntPtr lowQualityThumbnail; - - private ImageSource? lowQualityThumbnailPreview; - - private IntPtr highQualityThumbnail; - - private ImageSource? highQualityThumbnailPreview; - public static bool IsItemSupported(IFileSystemItem item) { return _supportedFileTypes.Contains(item.Extension); } - public void Dispose() - { - Clear(); - GC.SuppressFinalize(this); - } - public async Task GetPreviewSizeAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - if (IsSvg(Item)) + + if (IsSvg()) { var size = await Task.Run(Item.GetSvgSize); if (size != null) @@ -93,7 +75,7 @@ namespace Peek.FilePreviewer.Previewers ImageSize = size.Value; } } - else if (IsQoi(Item)) + else if (IsQoi()) { var size = await Task.Run(Item.GetQoiSize); if (size != null) @@ -115,30 +97,12 @@ namespace Peek.FilePreviewer.Previewers public async Task LoadPreviewAsync(CancellationToken cancellationToken) { - Clear(); - State = PreviewState.Loading; - - LowQualityThumbnailTask = LoadLowQualityThumbnailAsync(cancellationToken); - HighQualityThumbnailTask = LoadHighQualityThumbnailAsync(cancellationToken); - FullQualityImageTask = LoadFullQualityImageAsync(cancellationToken); cancellationToken.ThrowIfCancellationRequested(); - await Task.WhenAll(LowQualityThumbnailTask, HighQualityThumbnailTask, FullQualityImageTask); + State = PreviewState.Loading; - // If Preview is still null, FullQualityImage was not available. Preview the thumbnail instead. - if (Preview == null) - { - if (highQualityThumbnailPreview != null) - { - Preview = highQualityThumbnailPreview; - } - else - { - Preview = lowQualityThumbnailPreview; - } - } - - if (Preview == null && HasFailedLoadingPreview()) + if (!await LoadFullQualityImageAsync(cancellationToken) && + !await LoadThumbnailAsync(cancellationToken)) { State = PreviewState.Error; } @@ -173,69 +137,23 @@ namespace Peek.FilePreviewer.Previewers private void UpdateMaxImageSize() { - var imageWidth = ImageSize?.Width ?? 0; - var imageHeight = ImageSize?.Height ?? 0; + double imageWidth = ImageSize?.Width ?? 0; + double imageHeight = ImageSize?.Height ?? 0; - if (ScalingFactor != 0) - { - MaxImageSize = new Size(imageWidth / ScalingFactor, imageHeight / ScalingFactor); - } - else - { - MaxImageSize = new Size(imageWidth, imageHeight); - } + MaxImageSize = ScalingFactor != 0 ? + new Size(imageWidth / ScalingFactor, imageHeight / ScalingFactor) : + new Size(imageWidth, imageHeight); } - private Task LoadLowQualityThumbnailAsync(CancellationToken cancellationToken) + private Task LoadThumbnailAsync(CancellationToken cancellationToken) { + cancellationToken.ThrowIfCancellationRequested(); + return TaskExtension.RunSafe(async () => { - cancellationToken.ThrowIfCancellationRequested(); - - var hr = ThumbnailHelper.GetThumbnail(Item.Path, out lowQualityThumbnail, ThumbnailHelper.LowQualityThumbnailSize); - if (hr != HResult.Ok) - { - Logger.LogError("Error loading low quality thumbnail - hresult: " + hr); - throw new ImageLoadingException(nameof(lowQualityThumbnail)); - } - - cancellationToken.ThrowIfCancellationRequested(); - await Dispatcher.RunOnUiThread(async () => { - cancellationToken.ThrowIfCancellationRequested(); - if (!IsFullImageLoaded && !IsHighQualityThumbnailLoaded) - { - var thumbnailBitmap = await BitmapHelper.GetBitmapFromHBitmapAsync(lowQualityThumbnail, IsPng(Item), cancellationToken); - lowQualityThumbnailPreview = thumbnailBitmap; - } - }); - }); - } - - private Task LoadHighQualityThumbnailAsync(CancellationToken cancellationToken) - { - return TaskExtension.RunSafe(async () => - { - cancellationToken.ThrowIfCancellationRequested(); - - var hr = ThumbnailHelper.GetThumbnail(Item.Path, out highQualityThumbnail, ThumbnailHelper.HighQualityThumbnailSize); - if (hr != HResult.Ok) - { - Logger.LogError("Error loading high quality thumbnail - hresult: " + hr); - throw new ImageLoadingException(nameof(highQualityThumbnail)); - } - - cancellationToken.ThrowIfCancellationRequested(); - - await Dispatcher.RunOnUiThread(async () => - { - cancellationToken.ThrowIfCancellationRequested(); - if (!IsFullImageLoaded) - { - var thumbnailBitmap = await BitmapHelper.GetBitmapFromHBitmapAsync(highQualityThumbnail, IsPng(Item), cancellationToken); - highQualityThumbnailPreview = thumbnailBitmap; - } + Preview = await ThumbnailHelper.GetCachedThumbnailAsync(Item.Path, IsPng(), cancellationToken); }); }); } @@ -252,7 +170,7 @@ namespace Peek.FilePreviewer.Previewers using FileStream stream = ReadHelper.OpenReadOnly(Item.Path); - if (IsSvg(Item)) + if (IsSvg()) { var source = new SvgImageSource(); source.RasterizePixelHeight = ImageSize?.Height ?? 0; @@ -267,7 +185,7 @@ namespace Peek.FilePreviewer.Previewers Preview = source; } - else if (IsQoi(Item)) + else if (IsQoi()) { using var bitmap = QoiImage.FromStream(stream); @@ -275,55 +193,13 @@ namespace Peek.FilePreviewer.Previewers } else { - var bitmap = new BitmapImage(); - Preview = bitmap; - await bitmap.SetSourceAsync(stream.AsRandomAccessStream()); + Preview = new BitmapImage(); + await ((BitmapImage)Preview).SetSourceAsync(stream.AsRandomAccessStream()); } }); }); } - private bool HasFailedLoadingPreview() - { - var hasFailedLoadingLowQualityThumbnail = !(LowQualityThumbnailTask?.Result ?? true); - var hasFailedLoadingHighQualityThumbnail = !(HighQualityThumbnailTask?.Result ?? true); - var hasFailedLoadingFullQualityImage = !(FullQualityImageTask?.Result ?? true); - - return hasFailedLoadingLowQualityThumbnail && hasFailedLoadingHighQualityThumbnail && hasFailedLoadingFullQualityImage; - } - - private bool IsPng(IFileSystemItem item) - { - return item.Extension == ".png"; - } - - private bool IsSvg(IFileSystemItem item) - { - return item.Extension == ".svg"; - } - - private bool IsQoi(IFileSystemItem item) - { - return item.Extension == ".qoi"; - } - - private void Clear() - { - lowQualityThumbnailPreview = null; - highQualityThumbnailPreview = null; - Preview = null; - - if (lowQualityThumbnail != IntPtr.Zero) - { - NativeMethods.DeleteObject(lowQualityThumbnail); - } - - if (highQualityThumbnail != IntPtr.Zero) - { - NativeMethods.DeleteObject(highQualityThumbnail); - } - } - private static readonly HashSet _supportedFileTypes = new HashSet { // Image types diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/SpecialFolderPreviewer/SpecialFolderPreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/SpecialFolderPreviewer/SpecialFolderPreviewer.cs index 40702287a2..0003b79f2d 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/SpecialFolderPreviewer/SpecialFolderPreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/SpecialFolderPreviewer/SpecialFolderPreviewer.cs @@ -106,7 +106,7 @@ public partial class SpecialFolderPreviewer : ObservableObject, ISpecialFolderPr { cancellationToken.ThrowIfCancellationRequested(); - var iconBitmap = await IconHelper.GetIconAsync(Item.ParsingName, cancellationToken); + var iconBitmap = await ThumbnailHelper.GetIconAsync(Item.ParsingName, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/UnsupportedFilePreviewer/UnsupportedFilePreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/UnsupportedFilePreviewer/UnsupportedFilePreviewer.cs index 10ac551084..8644422f9f 100644 --- a/src/modules/peek/Peek.FilePreviewer/Previewers/UnsupportedFilePreviewer/UnsupportedFilePreviewer.cs +++ b/src/modules/peek/Peek.FilePreviewer/Previewers/UnsupportedFilePreviewer/UnsupportedFilePreviewer.cs @@ -108,8 +108,8 @@ namespace Peek.FilePreviewer.Previewers { cancellationToken.ThrowIfCancellationRequested(); - var iconBitmap = await IconHelper.GetThumbnailAsync(Item.Path, cancellationToken) - ?? await IconHelper.GetIconAsync(Item.Path, cancellationToken); + var iconBitmap = await ThumbnailHelper.GetThumbnailAsync(Item.Path, cancellationToken) + ?? await ThumbnailHelper.GetIconAsync(Item.Path, cancellationToken); cancellationToken.ThrowIfCancellationRequested();