/******************************************************************************* * Copyright (c) 2012 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.maps.eclipse; import java.awt.Image; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.io.File; import java.io.IOException; import java.net.URI; import javax.imageio.ImageIO; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Platform; import org.osgi.framework.Bundle; import org.simantics.maps.ProvisionException; import org.simantics.maps.tile.ITileProvider; import org.simantics.maps.tile.TileKey; /** * @author Tuukka Lehtonen */ public class DiskCachingTileProvider implements ITileProvider { private final String CACHED_IMAGE_FORMAT = "png"; ITileProvider provider; IPath cachePath; boolean supportAlpha; // private ImageWriter writer; // // private ImageReader reader; // // private ImageTypeSpecifier noAlphaType = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR); // // private ImageTypeSpecifier alphaType = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR); public DiskCachingTileProvider(ITileProvider provider, Boolean supportAlpha) { this.provider = provider; this.supportAlpha = supportAlpha; initCache(); } @Override public URI getSource() { return provider.getSource(); } @Override public Rectangle2D getExtent() { return provider.getExtent(); } private void initCache() { Bundle b = Platform.getBundle("org.simantics.maps"); if (b == null) return; IPath statePath = Platform.getStateLocation(b); URI source = provider.getSource(); IPath cache = statePath.append("cache").append(source.getScheme()).append(source.getHost()); // Create the cache directory if it doesn't exist. File f = cache.toFile(); if (!f.exists()) { f.mkdirs(); } else if (!f.isDirectory()) { // FIXME // ErrorLogger.defaultLogError("Cache directory " + f.toString() + " already exists as a file, cannot use it for cache", new Exception()); return; } this.cachePath = cache; // System.out.println("MAP DATA CACHE: " + cachePath); // Iterator writers = ImageIO.getImageWritersByFormatName(CACHED_IMAGE_FORMAT); // writer = writers.next(); // Iterator readers = ImageIO.getImageReadersByFormatName(CACHED_IMAGE_FORMAT); // reader = readers.next(); } private IPath toTileCachePath(TileKey key) { return cachePath.append(key.getLevel() + "." + key.getX() + "." + key.getY()); } private Image lookupFromDisk(TileKey key) { if (cachePath == null) return null; IPath cachePath = toTileCachePath(key).addFileExtension(CACHED_IMAGE_FORMAT); File f = cachePath.toFile(); if (f.exists()) { // ImageInputStream iis = null; try { // iis = ImageIO.createImageInputStream(f); // ImageReadParam param = reader.getDefaultReadParam(); // param.setDestinationType(supportAlpha ? alphaType : noAlphaType); // reader.setInput(iis, true, true); // BufferedImage img = reader.read(0, param); BufferedImage img = ImageIO.read(f); if (img != null) { //System.out.println("[" + provider + "] Disk cache hit: " + key); //System.out.println("[" + provider + "] image: " + img); // Need to make sure that the type of the loaded image is // something that can be rendered in an accelerated fashion. if (img.getType() != BufferedImage.TYPE_CUSTOM) return img; BufferedImage img2 = null; if (img.getAlphaRaster() != null) { img2 = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_4BYTE_ABGR); } else { img2 = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_3BYTE_BGR); } //System.out.println("[" + provider + "] image2: " + img2); img.copyData(img2.getRaster()); return img2; } } catch (IOException e) { e.printStackTrace(); } finally { // try { // iis.close(); // } catch (IOException e) { // } } // Data is most likely corrupted, just destroy it. f.delete(); } // System.out.println("Disk cache miss: " + key); return null; } private void cacheToDisk(TileKey key, Image img) { if (cachePath == null) return; if (!(img instanceof RenderedImage)) return; IPath cachePath = toTileCachePath(key).addFileExtension(CACHED_IMAGE_FORMAT); File f = cachePath.toFile(); try { if (ImageIO.write((RenderedImage) img, CACHED_IMAGE_FORMAT, f)) { //System.out.println("[" + provider + "] Disk cache write: " + key); } } catch (IOException e) { // Caching failed, be silent about it. } } @Override public Image get(final TileKey key) throws ProvisionException { Image img = lookupFromDisk(key); if (img == null) { img = provider.get(key); final Image image = img; // Write image to disk in the background // TODO: use somekind of worker executor system instead of just threads. new Thread() { @Override public void run() { cacheToDisk(key, image); } }.start(); } return img; } @Override public String toString() { return getClass().getSimpleName() + " [" + provider.toString() + "]"; } }