Add thumbnail cache to improve performance and make lifetime management easier

This commit is contained in:
Ben Olden-Cooligan 2016-01-10 21:54:09 -05:00
parent 49d7e54d30
commit 4ac72ef8db
4 changed files with 100 additions and 24 deletions

View File

@ -91,6 +91,7 @@
<Compile Include="Scan\Batch\BatchScanPerformer.cs" />
<Compile Include="Scan\Batch\BatchSettings.cs" />
<Compile Include="Scan\Exceptions\NoDuplexSupportException.cs" />
<Compile Include="Scan\Images\ThumbnailCache.cs" />
<Compile Include="Scan\Images\Transforms\TrueContrastTransform.cs" />
<Compile Include="Scan\PatchCode.cs" />
<Compile Include="Scan\ProfileNameTracker.cs" />

View File

@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using NAPS2.Config;
namespace NAPS2.Scan.Images
{
public class ThumbnailCache : IDisposable
{
private readonly Dictionary<ScannedImage, CacheItem> cache = new Dictionary<ScannedImage,CacheItem>();
private readonly IUserConfigManager userConfigManager;
public ThumbnailCache(IUserConfigManager userConfigManager)
{
this.userConfigManager = userConfigManager;
}
~ThumbnailCache()
{
Dispose();
}
public void Dispose()
{
foreach (var item in cache.Values)
{
item.Thumbnail.Dispose();
}
cache.Clear();
}
public Bitmap this[ScannedImage scannedImage]
{
get
{
var newState = scannedImage.GetThumbnailState();
if (cache.ContainsKey(scannedImage))
{
// Cache hit
var item = cache[scannedImage];
if (item.State != newState)
{
// Invalidated
item.Thumbnail.Dispose();
item.Thumbnail = scannedImage.GetThumbnail(userConfigManager.Config.ThumbnailSize);
item.State = newState;
}
return item.Thumbnail;
}
else
{
// Cache miss
var item = new CacheItem
{
Thumbnail = scannedImage.GetThumbnail(userConfigManager.Config.ThumbnailSize),
State = newState
};
return item.Thumbnail;
}
}
}
public void TrimCache(IEnumerable<ScannedImage> currentImages)
{
foreach (var key in cache.Keys.Except(currentImages).ToList())
{
cache[key].Thumbnail.Dispose();
cache.Remove(key);
}
}
private class CacheItem
{
public Bitmap Thumbnail { get; set; }
public object State { get; set; }
}
}
}

View File

@ -1546,7 +1546,7 @@ namespace NAPS2.WinForms
int index = imageList.Images.IndexOf(img);
if (index != -1)
{
thumbnailList1.ReplaceThumbnail(index, thumbnail);
thumbnailList1.ReplaceThumbnail(index, img);
}
});
}

View File

@ -30,13 +30,21 @@ namespace NAPS2.WinForms
{
public partial class ThumbnailList : ListView
{
private ThumbnailCache thumbnails;
public ThumbnailList()
{
InitializeComponent();
LargeImageList = ilThumbnailList;
}
public IUserConfigManager UserConfigManager { get; set; }
public IUserConfigManager UserConfigManager
{
set
{
thumbnails = new ThumbnailCache(value);
}
}
public Size ThumbnailSize
{
@ -46,46 +54,31 @@ namespace NAPS2.WinForms
public void UpdateImages(List<ScannedImage> images)
{
ClearImages();
ilThumbnailList.Images.Clear();
Clear();
foreach (ScannedImage img in images)
{
AppendImage(img);
}
thumbnails.TrimCache(images);
}
public void AppendImage(ScannedImage img)
{
ilThumbnailList.Images.Add(img.GetThumbnail(UserConfigManager.Config.ThumbnailSize));
ilThumbnailList.Images.Add(thumbnails[img]);
Items.Add("", ilThumbnailList.Images.Count - 1);
}
public void ClearItems()
public void ReplaceThumbnail(int index, ScannedImage img)
{
ClearImages();
Clear();
}
private void ClearImages()
{
foreach (Image img in ilThumbnailList.Images)
{
img.Dispose();
}
ilThumbnailList.Images.Clear();
}
public void ReplaceThumbnail(int index, Bitmap thumbnail)
{
ilThumbnailList.Images[index].Dispose();
ilThumbnailList.Images[index] = thumbnail;
ilThumbnailList.Images[index] = thumbnails[img];
Invalidate(Items[index].Bounds);
}
public void RegenerateThumbnailList(List<ScannedImage> images)
{
var thumbnails = images.Select(x => (Image)x.GetThumbnail(UserConfigManager.Config.ThumbnailSize)).ToArray();
ilThumbnailList.Images.AddRange(thumbnails);
var thumbnailArray = images.Select(x => (Image)thumbnails[x]).ToArray();
ilThumbnailList.Images.AddRange(thumbnailArray);
}
}
}