Skip to content

Commit

Permalink
fix #11 - Add thumbnail generator to images
Browse files Browse the repository at this point in the history
  • Loading branch information
Twometer committed Aug 8, 2021
1 parent 22e599a commit 922c2e9
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 7 deletions.
16 changes: 11 additions & 5 deletions NoFences/FenceWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
using NoFences.Win32;
using Peter;
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
using static NoFences.Win32.WindowUtil;

Expand Down Expand Up @@ -44,6 +42,8 @@ public partial class FenceWindow : Form

private readonly ShellContextMenu shellContextMenu = new ShellContextMenu();

private readonly ThumbnailProvider thumbnailProvider = new ThumbnailProvider();

private void ReloadFonts()
{
var family = new FontFamily("Segoe UI");
Expand All @@ -61,6 +61,7 @@ public FenceWindow(FenceInfo fenceInfo)
//DesktopUtil.PreventMinimize(Handle);
this.titleHeight = fenceInfo.TitleHeight;
this.MouseWheel += FenceWindow_MouseWheel;
thumbnailProvider.IconThumbnailLoaded += ThumbnailProvider_IconThumbnailLoaded;
if (titleHeight < 16 || titleHeight > 100)
titleHeight = 35;

Expand Down Expand Up @@ -305,8 +306,8 @@ private void FenceWindow_Paint(object sender, PaintEventArgs e)

scrollOffset = Math.Min(scrollOffset, scrollHeight);
}



// Click handlers
if (shouldUpdateSelection && !hasSelectionUpdated)
Expand All @@ -323,7 +324,7 @@ private void FenceWindow_Paint(object sender, PaintEventArgs e)

private void RenderEntry(Graphics g, FenceEntry entry, int x, int y)
{
var icon = entry.ExtractIcon();
var icon = entry.ExtractIcon(thumbnailProvider);
var name = entry.Name;

var textPosition = new PointF(x, y + icon.Height + 5);
Expand Down Expand Up @@ -484,6 +485,11 @@ private void FenceWindow_MouseWheel(object sender, MouseEventArgs e)
Invalidate();
}

private void ThumbnailProvider_IconThumbnailLoaded(object sender, EventArgs e)
{
Invalidate();
}

private bool ItemExists(string path)
{
return File.Exists(path) || Directory.Exists(path);
Expand Down
15 changes: 13 additions & 2 deletions NoFences/Model/FenceEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.IO;
using NoFences.Win32;
using NoFences.Util;

namespace NoFences.Model
{
Expand All @@ -30,9 +31,19 @@ public static FenceEntry FromPath(string path)
else return null;
}

public Icon ExtractIcon()
public Icon ExtractIcon(ThumbnailProvider thumbnailProvider)
{
return Type == EntryType.File ? Icon.ExtractAssociatedIcon(Path) : IconUtil.FolderLarge;
if (Type == EntryType.File)
{
if (thumbnailProvider.IsSupported(Path))
return thumbnailProvider.GenerateThumbnail(Path);
else
return Icon.ExtractAssociatedIcon(Path);
}
else
{
return IconUtil.FolderLarge;
}
}

public void Open()
Expand Down
1 change: 1 addition & 0 deletions NoFences/NoFences.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Util\Extensions.cs" />
<Compile Include="Util\ThrottledExecution.cs" />
<Compile Include="Util\ThumbnailProvider.cs" />
<Compile Include="Win32\BlurUtil.cs" />
<Compile Include="Win32\DesktopUtil.cs" />
<Compile Include="Win32\DropShadow.cs" />
Expand Down
78 changes: 78 additions & 0 deletions NoFences/Util/ThumbnailProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace NoFences.Util
{
public class ThumbnailProvider
{
// Supported .NET images as per https://docs.microsoft.com/en-us/dotnet/api/system.drawing.image.fromfile
private static readonly string[] SupportedExtensions =
{
".bmp",
".gif",
".jpg",
".jpeg",
".png",
".tiff",
".tif"
};

private class ThumbnailState
{
public Icon icon;
}

// Only allow 4 concurrent images to be decoded to try and prevent OOM errors
private readonly SemaphoreSlim semaphore = new SemaphoreSlim(4);
private readonly IDictionary<string, ThumbnailState> iconCache = new Dictionary<string, ThumbnailState>();
public event EventHandler IconThumbnailLoaded;

public bool IsSupported(string path)
{
return SupportedExtensions.Any(ext => path.EndsWith(ext));
}

public Icon GenerateThumbnail(string path)
{
if (!iconCache.ContainsKey(path))
{
return SubmitGeneratorTask(path).icon;
}
else
{
return iconCache[path].icon;
}
}

private ThumbnailState SubmitGeneratorTask(string path)
{
var state = new ThumbnailState() { icon = Icon.ExtractAssociatedIcon(path) };
iconCache[path] = state;

Task.Run(() =>
{
semaphore.Wait();
using (MemoryStream ms = new MemoryStream(File.ReadAllBytes(path)))
{
using (var img = Image.FromStream(ms))
{
var thumb = (Bitmap)img.GetThumbnailImage(32, 32, () => false, IntPtr.Zero);
var icon = Icon.FromHandle(thumb.GetHicon());
state.icon = icon;
IconThumbnailLoaded(this, new EventArgs());
semaphore.Release();
return icon;
}
}
});
return state;
}

}
}

0 comments on commit 922c2e9

Please sign in to comment.