mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Respect loadFullImage Option in ImageCache.cs
This commit is contained in:
parent
0fd127ab98
commit
cf9dd4addb
2 changed files with 40 additions and 37 deletions
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue