/* * $Id$ * * Copyright (c) 2007-2008 by Joel Uckelman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License (LGPL) as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, copies are available * at http://www.opensource.org. */ package VASSAL.tools.imageop; import java.awt.Dimension; import java.awt.Point; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import VASSAL.tools.ErrorDialog; import VASSAL.tools.opcache.OpCache; /** * An abstract representation of an operation which may be applied to an * {@link Image}. <code>ImageOp</code> is the base class for all such * operations. The results of all operations are memoized (using a * memory-sensitive cache), so retrieving results is both fast and * memory-efficient. * * <p><b>Warning:</b> For efficiency reasons, the methods {@link #getImage} * and {@link #getTile} do <em>not</em> return <code>Image</code>s * defensively, nor do the {@code Future<Image>}s returned by * {@link #getFutureImage} and {@link #getFutureTile}. That is, the * <code>Image</code> returned is possibly the one retained internally by * the <code>ImageOp</code>. Therefore, <code>Image</code>s obtained from * an <code>ImageOp</code> <em>must not</em> be altered, as this might * interfere with image caching. If an <code>Image</code> obtained this way * needs to be modified, copy the <code>Image</code> first and alter the * copy.</p> * * @since 3.1.0 * @author Joel Uckelman */ public abstract class AbstractOpImpl extends VASSAL.tools.opcache.AbstractOpImpl<BufferedImage> implements ImageOp { /** The cached size of this operation's resulting <code>Image</code>. */ protected Dimension size; /** The cache which contains calculated <code>Image</code>s. */ protected static final OpCache cache = new OpCache(); public static void clearCache() { cache.clear(); } public AbstractOpImpl() { super(cache); } /** {@inheritDoc} */ public abstract BufferedImage eval() throws Exception; /** {@inheritDoc} */ public BufferedImage getImage() { try { return getImage(null); } catch (CancellationException e) { // FIXME: bug until we permit cancellation ErrorDialog.bug(e); } catch (InterruptedException e) { ErrorDialog.bug(e); } catch (ExecutionException e) { if (!Op.handleException(e)) ErrorDialog.bug(e); } return null; } /** {@inheritDoc} */ public BufferedImage getImage(ImageOpObserver obs) throws CancellationException, InterruptedException, ExecutionException { return get(obs); } /** {@inheritDoc} */ public Future<BufferedImage> getFutureImage(ImageOpObserver obs) throws ExecutionException { return getFuture(obs); } /** * A utility method for retrieving the size of the computed * <code>Image</code> from the cache if the <code>Image</code> * is cached. * * @return the size of the cached <code>Image</code>, or * <code>null</code> if the <code>Image</code> isn't cached */ protected Dimension getSizeFromCache() { final BufferedImage im = cache.getIfDone(newKey()); return im == null ? null : new Dimension(im.getWidth(), im.getHeight()); } /** * Sets the <code>size</code> which is used by {@link getSize}, * {@link getHeight}, and {@link getWidth}. */ protected abstract void fixSize(); /** {@inheritDoc} */ public Dimension getSize() { if (size == null) fixSize(); return new Dimension(size); } /** {@inheritDoc} */ public int getWidth() { if (size == null) fixSize(); return size.width; } /** {@inheritDoc} */ public int getHeight() { if (size == null) fixSize(); return size.height; } /** {@inheritDoc} */ public abstract Dimension getTileSize(); /** {@inheritDoc} */ public abstract int getTileHeight(); /** {@inheritDoc} */ public abstract int getTileWidth(); /** {@inheritDoc} */ public abstract int getNumXTiles(); /** {@inheritDoc} */ public abstract int getNumYTiles(); /** {@inheritDoc} */ public BufferedImage getTile(Point p, ImageOpObserver obs) throws CancellationException, InterruptedException, ExecutionException { return getTile(p.x, p.y, obs); } /** {@inheritDoc} */ public abstract BufferedImage getTile(int tileX, int tileY, ImageOpObserver obs) throws CancellationException, InterruptedException, ExecutionException; /** {@inheritDoc} */ public Future<BufferedImage> getFutureTile(Point p, ImageOpObserver obs) throws ExecutionException { return getFutureTile(p.x, p.y, obs); } /** {@inheritDoc} */ public abstract Future<BufferedImage> getFutureTile( int tileX, int tileY, ImageOpObserver obs) throws ExecutionException; /** {@inheritDoc} */ public ImageOp getTileOp(Point p) { return getTileOp(p.x, p.y); } /** {@inheritDoc} */ public abstract ImageOp getTileOp(int tileX, int tileY); /** {@inheritDoc} */ public abstract Point[] getTileIndices(Rectangle rect); }