Gridarta Editor
MapImageCacheEntry.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2023 The Gridarta Developers.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 package net.sf.gridarta.gui.mapimagecache;
21 
22 import java.awt.Graphics;
23 import java.awt.Image;
24 import java.awt.image.BufferedImage;
25 import java.io.File;
26 import java.io.IOException;
27 import java.lang.ref.WeakReference;
28 import java.util.HashMap;
29 import java.util.Map;
30 import javax.imageio.ImageIO;
33 import org.apache.log4j.Category;
34 import org.apache.log4j.Logger;
35 import org.jetbrains.annotations.NotNull;
36 import org.jetbrains.annotations.Nullable;
37 
42 public class MapImageCacheEntry {
43 
47  @NotNull
48  private static final Category LOG = Logger.getLogger(MapImageCacheEntry.class);
49 
54  @NotNull
55  private final CacheFiles cacheFiles;
56 
60  @NotNull
61  private final Image defaultImage;
62 
66  private final String prefix;
67 
71  @NotNull
72  private final Map<File, WeakReference<Image>> images = new HashMap<>();
73 
77  @NotNull
78  private final Map<File, Long> timestamps = new HashMap<>();
79 
87  public MapImageCacheEntry(@NotNull final CacheFiles cacheFiles, @NotNull final Image defaultImage, @NotNull final String prefix) {
88  this.cacheFiles = cacheFiles;
89  this.defaultImage = defaultImage;
90  this.prefix = prefix;
91  }
92 
98  public void flush(@NotNull final File mapFile) {
99  images.remove(mapFile);
100  final File cacheFile = cacheFiles.getCacheFile(mapFile, prefix);
101  deleteCacheFile(cacheFile);
102  }
103 
109  private static void deleteCacheFile(@NotNull final File cacheFile) {
110  if (cacheFile.exists() && !cacheFile.delete()) {
111  LOG.warn("cannot delete cache file: " + cacheFile);
112  }
113  }
114 
120  @Nullable
121  private Image getImageIcon(@NotNull final File mapFile) {
122  final WeakReference<Image> ref = images.get(mapFile);
123  if (ref != null) {
124  final Image image = ref.get();
125  if (image != null && mapFile.lastModified() <= timestamps.get(mapFile)) {
126  return image;
127  }
128 
129  images.remove(mapFile);
130  }
131 
132  return null;
133  }
134 
140  private void saveImageFile(@NotNull final File mapFile, @NotNull final Image image) {
141  final File imageFile = cacheFiles.getCacheFile(mapFile, prefix);
142 
143  final File imageDir = imageFile.getParentFile();
144  if (imageDir != null && !imageDir.exists() && !imageDir.mkdirs()) {
145  LOG.warn("cannot create cache directory: " + imageDir);
146  }
147 
148  final int width = image.getWidth(null);
149  if (width == -1) {
150  return;
151  }
152  final int height = image.getHeight(null);
153  if (height == -1) {
154  return;
155  }
156  final BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
157  final Graphics graphics = bufferedImage.getGraphics();
158  try {
159  graphics.drawImage(image, 0, 0, null);
160  } finally {
161  graphics.dispose();
162  }
163 
164  try {
165  ImageIO.write(bufferedImage, "png", imageFile);
166  timestamps.put(mapFile, imageFile.lastModified());
167  } catch (final IOException e) {
168  LOG.warn("Cannot create icon file " + imageFile + ": " + e.getMessage());
169  }
170  }
171 
178  @Nullable
179  private Image loadImageFile(@NotNull final File mapFile) {
180  final File imageFile = cacheFiles.getCacheFile(mapFile, prefix);
181 
182  if (!imageFile.exists()) {
183  // image file does not exist
184  return null;
185  }
186 
187  final long imageLastModified = imageFile.lastModified();
188  if (imageLastModified == 0L) {
189  // image file does not exist or is unreadable
190  return null;
191  }
192 
193  final long mapLastModified = mapFile.lastModified();
194  if (mapLastModified == 0L || mapLastModified >= imageLastModified) {
195  // image file is older than map file ==> outdated
196  deleteCacheFile(imageFile);
197  return null;
198  }
199 
200  final Image image;
201  try {
202  image = ImageIO.read(imageFile);
203  } catch (final IOException ignored) {
204  return null;
205  }
206  if (image.getWidth(null) <= 0 || image.getHeight(null) <= 0) {
207  // image file is invalid
208  deleteCacheFile(imageFile);
209  return null;
210  }
211 
212  timestamps.put(mapFile, imageFile.lastModified());
213  return image;
214  }
215 
222  @Nullable
223  public Image lookupCache(@NotNull final File mapFile) {
224  if (mapFile.isDirectory()) {
225  return null;
226  }
227 
228  final Image image = getImageIcon(mapFile);
229  if (image != null) {
230  return image;
231  }
232 
233  final Image image2 = loadImageFile(mapFile);
234  if (image2 == null) {
235  return null;
236  }
237 
238  if (mapFile.lastModified() <= timestamps.get(mapFile)) {
239  images.put(mapFile, new WeakReference<>(image2));
240  }
241 
242  return image2;
243  }
244 
249  @NotNull
250  public Image getDefaultImage() {
251  return defaultImage;
252  }
253 
263  @NotNull
264  public Image scaleImage(@Nullable final File mapFile, @NotNull final Image image, final int width, final int height) {
265  Image result;
266  //noinspection ErrorNotRethrown
267  try {
268  result = ImageUtils.scaleImage(image, width, height);
269  } catch (final InterruptedException ignored) {
270  Thread.currentThread().interrupt();
271  result = defaultImage;
272  } catch (final OutOfMemoryError ignored) {
273  result = defaultImage;
274  }
275  if (mapFile != null) {
276  images.put(mapFile, new WeakReference<>(result));
277  timestamps.put(mapFile, mapFile.lastModified());
278  saveImageFile(mapFile, result);
279  }
280  return result;
281  }
282 
283 }
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.getImageIcon
Image getImageIcon(@NotNull final File mapFile)
Returns the Image for a given map file.
Definition: MapImageCacheEntry.java:121
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.deleteCacheFile
static void deleteCacheFile(@NotNull final File cacheFile)
Deletes a cache file if it exists.
Definition: MapImageCacheEntry.java:109
net.sf.gridarta
Base package of all Gridarta classes.
net.sf
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.getDefaultImage
Image getDefaultImage()
Returns the default image.
Definition: MapImageCacheEntry.java:250
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.cacheFiles
final CacheFiles cacheFiles
The CacheFiles for generating files for cached icons and previews.
Definition: MapImageCacheEntry.java:55
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.defaultImage
final Image defaultImage
The default image.
Definition: MapImageCacheEntry.java:61
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.LOG
static final Category LOG
The logger for printing log messages.
Definition: MapImageCacheEntry.java:48
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.timestamps
final Map< File, Long > timestamps
The timestamps of the cached icons.
Definition: MapImageCacheEntry.java:78
net
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.images
final Map< File, WeakReference< Image > > images
The cached icons.
Definition: MapImageCacheEntry.java:72
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.MapImageCacheEntry
MapImageCacheEntry(@NotNull final CacheFiles cacheFiles, @NotNull final Image defaultImage, @NotNull final String prefix)
Creates a new instance.
Definition: MapImageCacheEntry.java:87
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.loadImageFile
Image loadImageFile(@NotNull final File mapFile)
Loads an image file from disk.
Definition: MapImageCacheEntry.java:179
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.saveImageFile
void saveImageFile(@NotNull final File mapFile, @NotNull final Image image)
Saves an PNG image file for a map file.
Definition: MapImageCacheEntry.java:140
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.flush
void flush(@NotNull final File mapFile)
Removes the cached image for a map file.
Definition: MapImageCacheEntry.java:98
net.sf.gridarta.model.io.CacheFiles.getCacheFile
File getCacheFile(@NotNull File file, @Nullable String prefix)
Returns the File for caching a given file.
net.sf.gridarta.model.io
Reading and writing of maps, handling of paths.
Definition: AbstractAnimationObjectsReader.java:20
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.lookupCache
Image lookupCache(@NotNull final File mapFile)
Looks up an image from the cache.
Definition: MapImageCacheEntry.java:223
net.sf.gridarta.model
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry
An image cache entry for one ImageType.
Definition: MapImageCacheEntry.java:42
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.prefix
final String prefix
The directory prefix name for the cache directory.
Definition: MapImageCacheEntry.java:66
net.sf.gridarta.model.io.CacheFiles
Creates derived files for caching files.
Definition: CacheFiles.java:30
net.sf.gridarta.utils.ImageUtils
Utility class for image related functions.
Definition: ImageUtils.java:31
net.sf.gridarta.utils.ImageUtils.scaleImage
static Image scaleImage(@NotNull final Image image, final int w, final int h)
Returns a scaled version of an Image.
Definition: ImageUtils.java:68
net.sf.gridarta.utils
Definition: ActionBuilderUtils.java:20
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry.scaleImage
Image scaleImage(@Nullable final File mapFile, @NotNull final Image image, final int width, final int height)
Scales an Image to the given size and updates the cache.
Definition: MapImageCacheEntry.java:264