]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.maps/src/org/simantics/maps/eclipse/DiskCachingTileProvider.java
Ensure ITileProviders return BufferedImages with compatible ColorModel
[simantics/district.git] / org.simantics.district.maps / src / org / simantics / maps / eclipse / DiskCachingTileProvider.java
1 /*******************************************************************************
2  * Copyright (c) 2012 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.maps.eclipse;
13
14 import java.awt.Image;
15 import java.awt.geom.Rectangle2D;
16 import java.awt.image.BufferedImage;
17 import java.awt.image.RenderedImage;
18 import java.io.File;
19 import java.io.IOException;
20 import java.net.URI;
21 import java.util.concurrent.ForkJoinPool;
22
23 import javax.imageio.ImageIO;
24
25 import org.eclipse.core.runtime.IPath;
26 import org.eclipse.core.runtime.Platform;
27 import org.osgi.framework.Bundle;
28 import org.simantics.maps.ProvisionException;
29 import org.simantics.maps.internal.ImageUtil;
30 import org.simantics.maps.tile.ITileProvider;
31 import org.simantics.maps.tile.TileKey;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * @author Tuukka Lehtonen
37  */
38 public class DiskCachingTileProvider implements ITileProvider {
39
40     private static final Logger LOGGER = LoggerFactory.getLogger(DiskCachingTileProvider.class);
41
42     private final String CACHED_IMAGE_FORMAT = "png";
43
44     ITileProvider provider;
45
46     IPath         cachePath;
47
48     boolean supportAlpha;
49
50     public DiskCachingTileProvider(ITileProvider provider, Boolean supportAlpha) {
51         this.provider = provider;
52         this.supportAlpha = supportAlpha;
53         initCache();
54     }
55
56     @Override
57     public URI getSource() {
58         return provider.getSource();
59     }
60
61     @Override
62     public Rectangle2D getExtent() {
63         return provider.getExtent();
64     }
65
66     private void initCache() {
67         Bundle b = Platform.getBundle("org.simantics.maps");
68         if (b == null)
69             return;
70         IPath statePath = Platform.getStateLocation(b);
71         URI source = provider.getSource();
72         IPath cache = statePath.append("cache").append(source.getScheme()).append(source.getHost());
73
74         // Create the cache directory if it doesn't exist.
75         File f = cache.toFile();
76         if (!f.exists()) {
77             f.mkdirs();
78         } else if (!f.isDirectory()) {
79             LOGGER.error("Tile cache directory " + f.toString() + " already exists as a file, cannot use it as a cache directory", new Exception());
80             return;
81         }
82
83         this.cachePath = cache;
84 //        System.out.println("MAP DATA CACHE: " + cachePath);
85         
86 //        Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(CACHED_IMAGE_FORMAT);
87 //        writer = writers.next();
88 //        Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(CACHED_IMAGE_FORMAT);
89 //        reader = readers.next();
90     }
91
92     private IPath toTileCachePath(TileKey key) {
93         return cachePath.append(key.getLevel() + "." + key.getX() + "." + key.getY());
94     }
95
96     private Image lookupFromDisk(TileKey key) {
97         if (cachePath == null)
98             return null;
99
100         IPath cachePath = toTileCachePath(key).addFileExtension(CACHED_IMAGE_FORMAT);
101         File f = cachePath.toFile();
102         if (f.exists()) {
103             try {
104                 BufferedImage img = ImageIO.read(f);
105                 if (img != null) {
106                     //System.out.println("[" + provider + "] Disk cache hit: " + key);
107                     //System.out.println("[" + provider + "]     image:   " + img);
108                     // Need to make sure that the type of the loaded image is
109                     // something that can be rendered in an accelerated fashion.
110                     return ImageUtil.toScreenCompatibleImage(img);
111                 }
112             } catch (IOException e) {
113                 LOGGER.warn("Failed to load cached tile from {}", f.toString(), e);
114             } finally {
115             }
116             // Data is most likely corrupted, just destroy it.
117             f.delete();
118         }
119 //        System.out.println("Disk cache miss: " + key);
120         return null;
121     }
122
123     private void cacheToDisk(TileKey key, Image img) {
124         if (cachePath == null)
125             return;
126
127         if (!(img instanceof RenderedImage))
128             return;
129
130         IPath cachePath = toTileCachePath(key).addFileExtension(CACHED_IMAGE_FORMAT);
131         File f = cachePath.toFile();
132         try {
133             if (ImageIO.write((RenderedImage) img, CACHED_IMAGE_FORMAT, f)) {
134                 //System.out.println("[" + provider + "] Disk cache write: " + key);
135             }
136         } catch (IOException e) {
137             // Caching failed, be silent about it.
138         }
139     }
140
141     @Override
142     public Image get(TileKey key) throws ProvisionException {
143         Image img = lookupFromDisk(key);
144         if (img == null) {
145             img = provider.get(key);
146             final Image image = img;
147             if (cachePath != null) {
148                 // Write image to disk in the background
149                 ForkJoinPool.commonPool().submit(() -> cacheToDisk(key, image));
150             }
151         }
152         return img;
153     }
154
155     @Override
156     public String toString() {
157         return getClass().getSimpleName() + " [" + provider.toString() + "]";
158     }
159
160 }