Respect loadFullImage Option in ImageCache.cs

This commit is contained in:
Hongtao Zhang 2022-10-30 14:39:57 -05:00
parent 0fd127ab98
commit cf9dd4addb
No known key found for this signature in database
GPG key ID: 75F655B91C7AC9BB
2 changed files with 40 additions and 37 deletions

View file

@ -25,11 +25,11 @@ namespace Flow.Launcher.Infrastructure.Image
public class ImageCache public class ImageCache
{ {
private const int MaxCached = 50; private const int MaxCached = 50;
public ConcurrentDictionary<string, ImageUsage> Data { get; private set; } = new ConcurrentDictionary<string, ImageUsage>(); public ConcurrentDictionary<(string, bool), ImageUsage> Data { get; } = new();
private const int permissibleFactor = 2; private const int permissibleFactor = 2;
private SemaphoreSlim semaphore = new(1, 1); private SemaphoreSlim semaphore = new(1, 1);
public void Initialization(Dictionary<string, int> usage) public void Initialization(Dictionary<(string, bool), int> usage)
{ {
foreach (var key in usage.Keys) foreach (var key in usage.Keys)
{ {
@ -37,29 +37,29 @@ namespace Flow.Launcher.Infrastructure.Image
} }
} }
public ImageSource this[string path] public ImageSource this[string path, bool isFullImage = false]
{ {
get get
{ {
if (Data.TryGetValue(path, out var value)) if (!Data.TryGetValue((path, isFullImage), out var value))
{ {
value.usage++; return null;
return value.imageSource;
} }
value.usage++;
return value.imageSource;
return null;
} }
set set
{ {
Data.AddOrUpdate( Data.AddOrUpdate(
path, (path, isFullImage),
new ImageUsage(0, value), new ImageUsage(0, value),
(k, v) => (k, v) =>
{ {
v.imageSource = value; v.imageSource = value;
v.usage++; v.usage++;
return v; return v;
} }
); );
SliceExtra(); SliceExtra();
@ -82,9 +82,9 @@ namespace Flow.Launcher.Infrastructure.Image
} }
} }
public bool ContainsKey(string key) public bool ContainsKey(string key, bool isFullImage)
{ {
return key is not null && Data.ContainsKey(key) && Data[key].imageSource != null; return key is not null && Data.ContainsKey((key, isFullImage)) && Data[(key, isFullImage)].imageSource != null;
} }
public int CacheSize() public int CacheSize()

View file

@ -17,7 +17,7 @@ namespace Flow.Launcher.Infrastructure.Image
public static class ImageLoader public static class ImageLoader
{ {
private static readonly ImageCache ImageCache = new(); private static readonly ImageCache ImageCache = new();
private static BinaryStorage<Dictionary<string, int>> _storage; private static BinaryStorage<Dictionary<(string, bool), int>> _storage;
private static readonly ConcurrentDictionary<string, string> GuidToKey = new(); private static readonly ConcurrentDictionary<string, string> GuidToKey = new();
private static IImageHashGenerator _hashGenerator; private static IImageHashGenerator _hashGenerator;
private static readonly bool EnableImageHash = true; private static readonly bool EnableImageHash = true;
@ -32,7 +32,7 @@ namespace Flow.Launcher.Infrastructure.Image
public static void Initialize() public static void Initialize()
{ {
_storage = new BinaryStorage<Dictionary<string, int>>("Image"); _storage = new BinaryStorage<Dictionary<(string, bool), int>>("Image");
_hashGenerator = new ImageHashGenerator(); _hashGenerator = new ImageHashGenerator();
var usage = LoadStorageToConcurrentDictionary(); var usage = LoadStorageToConcurrentDictionary();
@ -44,16 +44,16 @@ namespace Flow.Launcher.Infrastructure.Image
{ {
ImageSource img = new BitmapImage(new Uri(icon)); ImageSource img = new BitmapImage(new Uri(icon));
img.Freeze(); img.Freeze();
ImageCache[icon] = img; ImageCache[icon, false] = img;
} }
_ = Task.Run(async () => _ = Task.Run(async () =>
{ {
await Stopwatch.NormalAsync("|ImageLoader.Initialize|Preload images cost", async () => await Stopwatch.NormalAsync("|ImageLoader.Initialize|Preload images cost", async () =>
{ {
foreach (var imageUsage in ImageCache.Data) foreach (var ((path, isFullImage), _) in ImageCache.Data)
{ {
await LoadAsync(imageUsage.Key); await LoadAsync(path, isFullImage);
} }
}); });
Log.Info($"|ImageLoader.Initialize|Number of preload images is <{ImageCache.CacheSize()}>, Images Number: {ImageCache.CacheSize()}, Unique Items {ImageCache.UniqueImagesInCache()}"); Log.Info($"|ImageLoader.Initialize|Number of preload images is <{ImageCache.CacheSize()}>, Images Number: {ImageCache.CacheSize()}, Unique Items {ImageCache.UniqueImagesInCache()}");
@ -64,17 +64,20 @@ namespace Flow.Launcher.Infrastructure.Image
{ {
lock (_storage) lock (_storage)
{ {
_storage.Save(ImageCache.Data.Select(x => (x.Key, x.Value.usage)).ToDictionary(x => x.Key, x => x.usage)); _storage.Save(ImageCache.Data
.ToDictionary(
x => x.Key,
x => x.Value.usage));
} }
} }
private static ConcurrentDictionary<string, int> LoadStorageToConcurrentDictionary() private static ConcurrentDictionary<(string, bool), int> LoadStorageToConcurrentDictionary()
{ {
lock (_storage) lock (_storage)
{ {
var loaded = _storage.TryLoad(new Dictionary<string, int>()); var loaded = _storage.TryLoad(new Dictionary<(string, bool), int>());
return new ConcurrentDictionary<string, int>(loaded); return new ConcurrentDictionary<(string, bool), int>(loaded);
} }
} }
@ -108,17 +111,17 @@ namespace Flow.Launcher.Infrastructure.Image
{ {
if (string.IsNullOrEmpty(path)) if (string.IsNullOrEmpty(path))
{ {
return new ImageResult(ImageCache[Constant.MissingImgIcon], ImageType.Error); return new ImageResult(ImageCache[Constant.MissingImgIcon, false], ImageType.Error);
} }
if (ImageCache.ContainsKey(path)) if (ImageCache.ContainsKey(path, loadFullImage))
{ {
return new ImageResult(ImageCache[path], ImageType.Cache); return new ImageResult(ImageCache[path, loadFullImage], ImageType.Cache);
} }
if (Uri.TryCreate(path, UriKind.RelativeOrAbsolute, out var uriResult) if (Uri.TryCreate(path, UriKind.RelativeOrAbsolute, out var uriResult)
&& (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps)) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps))
{ {
var image = await LoadRemoteImageAsync(loadFullImage, uriResult); var image = await LoadRemoteImageAsync(loadFullImage, uriResult);
ImageCache[path] = image; ImageCache[path, false] = image;
return new ImageResult(image, ImageType.ImageFile); return new ImageResult(image, ImageType.ImageFile);
} }
if (path.StartsWith("data:", StringComparison.OrdinalIgnoreCase)) if (path.StartsWith("data:", StringComparison.OrdinalIgnoreCase))
@ -147,8 +150,8 @@ namespace Flow.Launcher.Infrastructure.Image
Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path} on first try", e); Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path} on first try", e);
Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path} on second try", e2); Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path} on second try", e2);
ImageSource image = ImageCache[Constant.MissingImgIcon]; ImageSource image = ImageCache[Constant.MissingImgIcon, false];
ImageCache[path] = image; ImageCache[path, false] = image;
imageResult = new ImageResult(image, ImageType.Error); imageResult = new ImageResult(image, ImageType.Error);
} }
} }
@ -220,7 +223,7 @@ namespace Flow.Launcher.Infrastructure.Image
} }
else else
{ {
image = ImageCache[Constant.MissingImgIcon]; image = ImageCache[Constant.MissingImgIcon, false];
path = Constant.MissingImgIcon; path = Constant.MissingImgIcon;
} }
@ -243,7 +246,7 @@ namespace Flow.Launcher.Infrastructure.Image
public static bool CacheContainImage(string path) public static bool CacheContainImage(string path)
{ {
return ImageCache.ContainsKey(path) && ImageCache[path] != null; return ImageCache.ContainsKey(path, false) && ImageCache[path, false] != null;
} }
public static async ValueTask<ImageSource> LoadAsync(string path, bool loadFullImage = false) public static async ValueTask<ImageSource> LoadAsync(string path, bool loadFullImage = false)
@ -259,7 +262,7 @@ namespace Flow.Launcher.Infrastructure.Image
if (GuidToKey.TryGetValue(hash, out string key)) if (GuidToKey.TryGetValue(hash, out string key))
{ // image already exists { // image already exists
img = ImageCache[key] ?? img; img = ImageCache[key, false] ?? img;
} }
else else
{ // new guid { // new guid
@ -268,7 +271,7 @@ namespace Flow.Launcher.Infrastructure.Image
} }
// update cache // update cache
ImageCache[path] = img; ImageCache[path, false] = img;
} }
return img; return img;