diff --git a/Dalamud/Interface/Textures/Internal/TextureManager.BlameTracker.cs b/Dalamud/Interface/Textures/Internal/TextureManager.BlameTracker.cs
index ed1824e5c..e5ea2911c 100644
--- a/Dalamud/Interface/Textures/Internal/TextureManager.BlameTracker.cs
+++ b/Dalamud/Interface/Textures/Internal/TextureManager.BlameTracker.cs
@@ -58,7 +58,7 @@ internal sealed partial class TextureManager
/// The texture.
/// The plugin.
/// Same .
- public unsafe IDalamudTextureWrap Blame(IDalamudTextureWrap textureWrap, LocalPlugin? ownerPlugin)
+ public unsafe IDalamudTextureWrap Blame(IDalamudTextureWrap? textureWrap, LocalPlugin? ownerPlugin)
{
if (!this.dalamudConfiguration.UseTexturePluginTracking)
return textureWrap;
diff --git a/Dalamud/Interface/Textures/Internal/TextureManager.cs b/Dalamud/Interface/Textures/Internal/TextureManager.cs
index 982b5c58d..216a07c0a 100644
--- a/Dalamud/Interface/Textures/Internal/TextureManager.cs
+++ b/Dalamud/Interface/Textures/Internal/TextureManager.cs
@@ -1,5 +1,7 @@
+using System.Drawing;
using System.IO;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
@@ -17,13 +19,21 @@ using Dalamud.Plugin.Services;
using Dalamud.Storage.Assets;
using Dalamud.Utility;
using Dalamud.Utility.TerraFxCom;
-
using Lumina.Data;
using Lumina.Data.Files;
-
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
+using static TerraFX.Interop.Windows.COINIT;
+using static TerraFX.Interop.Windows.SIIGBF;
+using static TerraFX.Interop.Windows.Windows;
+
+using BitmapData = System.Drawing.Imaging.BitmapData;
+using HBITMAP = TerraFX.Interop.Windows.HBITMAP;
+using ImageLockMode = System.Drawing.Imaging.ImageLockMode;
+using IShellItemImageFactory = TerraFX.Interop.Windows.IShellItemImageFactory;
+using SIZE = TerraFX.Interop.Windows.SIZE;
+
namespace Dalamud.Interface.Textures.Internal;
/// Service responsible for loading and disposing ImGui texture wraps.
@@ -303,6 +313,42 @@ internal sealed partial class TextureManager
return (supported & required) == required;
}
+ ///
+ public unsafe IDalamudTextureWrap? TryGetFileThumbnail(string path)
+ {
+ const int size = 256;
+ HRESULT hr = CoInitializeEx(null, (uint)(COINIT_DISABLE_OLE1DDE | COINIT_MULTITHREADED));
+ if (hr.FAILED)
+ return null;
+
+ IShellItemImageFactory* imageFact;
+ fixed (char* pstr = path)
+ {
+ hr = SHCreateItemFromParsingName(pstr, null, __uuidof(), (void**)&imageFact);
+ }
+
+ if (hr.FAILED)
+ return null;
+
+ HBITMAP hbmp;
+ imageFact->GetImage(new SIZE(cx: size, cy: size), (int)SIIGBF_BIGGERSIZEOK, &hbmp);
+ var image = Image.FromHbitmap(hbmp);
+ BitmapData bd = image.LockBits(new(Point.Empty, image.Size), ImageLockMode.ReadOnly, image.PixelFormat);
+ var rowSize = bd.Stride < 0 ? -bd.Stride : bd.Stride;
+ var pixels = new byte[bd.Height * rowSize];
+ var iptr = bd.Scan0;
+
+ for (int y = 0; y < bd.Height; y++)
+ {
+ Marshal.Copy(IntPtr.Add(iptr, y * bd.Stride),
+ pixels, y * rowSize,
+ rowSize);
+ }
+
+ image.UnlockBits(bd);
+ return this.CreateFromRaw(new RawImageSpecification(bd.Width, bd.Height, (int)DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM), pixels.AsSpan());
+ }
+
///
internal unsafe IDalamudTextureWrap NoThrottleCreateFromRaw(
RawImageSpecification specs,
diff --git a/Dalamud/Interface/Textures/Internal/TextureManagerPluginScoped.cs b/Dalamud/Interface/Textures/Internal/TextureManagerPluginScoped.cs
index ac6de7dd7..e87d8af43 100644
--- a/Dalamud/Interface/Textures/Internal/TextureManagerPluginScoped.cs
+++ b/Dalamud/Interface/Textures/Internal/TextureManagerPluginScoped.cs
@@ -454,6 +454,15 @@ internal sealed class TextureManagerPluginScoped
await manager.CopyToClipboardAsync(wrap, preferredFileNameWithoutExtension, leaveWrapOpen, cancellationToken);
}
+ ///
+ public IDalamudTextureWrap? TryGetFileThumbnail(string path)
+ {
+ var manager = this.ManagerOrThrow;
+ var textureWrap = manager.TryGetFileThumbnail(path);
+ manager.Blame(textureWrap, this.plugin);
+ return textureWrap;
+ }
+
private void ResultOnInterceptTexDataLoad(string path, ref string? replacementPath) =>
this.InterceptTexDataLoad?.Invoke(path, ref replacementPath);
}
diff --git a/Dalamud/Plugin/Services/ITextureProvider.cs b/Dalamud/Plugin/Services/ITextureProvider.cs
index 63a463613..b4acbca28 100644
--- a/Dalamud/Plugin/Services/ITextureProvider.cs
+++ b/Dalamud/Plugin/Services/ITextureProvider.cs
@@ -330,4 +330,9 @@ public interface ITextureProvider : IDalamudService
/// ((delegate* unmanaged<nint, void>)(*(nint**)ptr)[3](ptr).
///
nint ConvertToKernelTexture(IDalamudTextureWrap wrap, bool leaveWrapOpen = false);
+
+ /// Tries to get a files thumbnail from the Win32 API
+ /// Path to file you want to preview.
+ /// A TextureWrap or null.
+ IDalamudTextureWrap? TryGetFileThumbnail(string filePath);
}