From 6411d24b5a4543c7d406e470b1c50affccc885ef Mon Sep 17 00:00:00 2001 From: Victor Date: Mon, 4 Jan 2021 20:16:12 +0200 Subject: [PATCH] Add caching and config for it --- build.gradle | 1 + .../java/com/annimon/imagetagger/Main.java | 4 +- .../imagetagger/beans/CacheConfig.java | 35 +++++++++++++ .../com/annimon/imagetagger/beans/Config.java | 5 ++ .../logic/CacheableFilesProvider.java | 52 +++++++++++++++++++ .../imagetagger/logic/ImageProcessor.java | 2 + 6 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/annimon/imagetagger/beans/CacheConfig.java create mode 100644 src/main/java/com/annimon/imagetagger/logic/CacheableFilesProvider.java diff --git a/build.gradle b/build.gradle index 613c70f..4ebb865 100644 --- a/build.gradle +++ b/build.gradle @@ -18,5 +18,6 @@ dependencies { implementation "com.fasterxml.jackson.core:jackson-core:$jacksonVersion" implementation "com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion" implementation "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion" + implementation 'com.github.ben-manes.caffeine:caffeine:2.8.8' testImplementation 'junit:junit:4.13.1' } diff --git a/src/main/java/com/annimon/imagetagger/Main.java b/src/main/java/com/annimon/imagetagger/Main.java index 421307c..4004c07 100644 --- a/src/main/java/com/annimon/imagetagger/Main.java +++ b/src/main/java/com/annimon/imagetagger/Main.java @@ -1,7 +1,7 @@ package com.annimon.imagetagger; import com.annimon.imagetagger.beans.Config; -import com.annimon.imagetagger.logic.FilesProvider; +import com.annimon.imagetagger.logic.CacheableFilesProvider; import com.annimon.imagetagger.logic.ImageProcessor; import com.annimon.imagetagger.logic.KeyProcessor; import com.annimon.imagetagger.views.ImagePanel; @@ -34,7 +34,7 @@ public class Main extends JFrame { final var tagButtons = config.getButtons(config.getProfile()); final var tagPanel = new TagPanel(tagButtons); - final var files = new FilesProvider(config.getDir()); + final var files = new CacheableFilesProvider(config.getDir(), config.getCache()); final var imageProcessor = new ImageProcessor(files, config.getFilter(), config.getSort()); final var imagePanel = new ImagePanel(imageProcessor); final var keyProcessor = new KeyProcessor(tagButtons); diff --git a/src/main/java/com/annimon/imagetagger/beans/CacheConfig.java b/src/main/java/com/annimon/imagetagger/beans/CacheConfig.java new file mode 100644 index 0000000..ac1dc9c --- /dev/null +++ b/src/main/java/com/annimon/imagetagger/beans/CacheConfig.java @@ -0,0 +1,35 @@ +package com.annimon.imagetagger.beans; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.Objects; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class CacheConfig { + + public static final CacheConfig DEFAULT = new CacheConfig(20, 1920, 1080); + + private Integer size; + private Integer width; + private Integer height; + + public CacheConfig() { + } + + public CacheConfig(Integer size, Integer width, Integer height) { + this.size = size; + this.width = width; + this.height = height; + } + + public int getSize() { + return Objects.requireNonNullElse(size, DEFAULT.size); + } + + public int getWidth() { + return Objects.requireNonNullElse(width, DEFAULT.width); + } + + public int getHeight() { + return Objects.requireNonNullElse(height, DEFAULT.height); + } +} diff --git a/src/main/java/com/annimon/imagetagger/beans/Config.java b/src/main/java/com/annimon/imagetagger/beans/Config.java index bc1e315..edd4471 100644 --- a/src/main/java/com/annimon/imagetagger/beans/Config.java +++ b/src/main/java/com/annimon/imagetagger/beans/Config.java @@ -11,6 +11,7 @@ import java.util.Objects; public class Config { private String dir; + private CacheConfig cache; private String filter; private String sort; private String profile; @@ -23,6 +24,10 @@ public class Config { return dir; } + public CacheConfig getCache() { + return Objects.requireNonNullElse(cache, CacheConfig.DEFAULT); + } + public String getFilter() { return Objects.requireNonNullElse(filter, ""); } diff --git a/src/main/java/com/annimon/imagetagger/logic/CacheableFilesProvider.java b/src/main/java/com/annimon/imagetagger/logic/CacheableFilesProvider.java new file mode 100644 index 0000000..40828eb --- /dev/null +++ b/src/main/java/com/annimon/imagetagger/logic/CacheableFilesProvider.java @@ -0,0 +1,52 @@ +package com.annimon.imagetagger.logic; + +import com.annimon.imagetagger.beans.CacheConfig; +import com.annimon.imagetagger.views.ResizableImage; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import java.io.File; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class CacheableFilesProvider extends FilesProvider { + + private final Executor exe; + private final LoadingCache cache; + private final int maxWidth, maxHeight; + + public CacheableFilesProvider(String dir, CacheConfig cacheConfig) { + super(dir); + maxWidth = Math.max(cacheConfig.getWidth(), 100); + maxHeight = Math.max(cacheConfig.getHeight(), 100); + exe = Executors.newSingleThreadExecutor(); + cache = Caffeine.newBuilder() + .executor(exe) + .maximumSize(Math.max(cacheConfig.getSize(), 1)) + .expireAfterWrite(10, TimeUnit.MINUTES) + .softValues() + .build(this::loadAndResize); + } + + @Override + public ResizableImage loadImage(File file) { + final var image = cache.get(file); + if (image != null) { + return image; + } else { + final var result = loadAndResize(file); + cache.put(file, result); + return result; + } + } + + @Override + public void preloadImage(File file) { + exe.execute(() -> cache.get(file)); + } + + private ResizableImage loadAndResize(File file) { + final var image = super.loadImage(file); + return new ResizableImage(image.getResized(maxWidth, maxHeight)); + } +} diff --git a/src/main/java/com/annimon/imagetagger/logic/ImageProcessor.java b/src/main/java/com/annimon/imagetagger/logic/ImageProcessor.java index 4c75d94..2f15efe 100644 --- a/src/main/java/com/annimon/imagetagger/logic/ImageProcessor.java +++ b/src/main/java/com/annimon/imagetagger/logic/ImageProcessor.java @@ -103,6 +103,8 @@ public class ImageProcessor { if (imagesCount > 0) { index = 0; loadImage(); + preloadImage(1); + preloadImage(-1); } }