/* * $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; /** * An abstract representation of an operation which may be applied to an * {@link Image}. <code>ImageOp</code> is the interface 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, no images retrieved from * an <code>ImageOp</code> are returned defensively. 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 interface ImageOp extends VASSAL.tools.opcache.Op<BufferedImage> { /** * The image computation itself happens in this method. * * <p><b>Warning:</b> This method is not intended to be called from * anywhere except {@link #getImage}.</p> * * @throws Exception The operation represented by this <code>ImageOp</code> * could be anything, so any exception may be thrown. */ public BufferedImage eval() throws Exception; /** * Calculates the <code>BufferedImage</code> produced by this operation. * Calls to this method are memoized to prevent redundant computations. * * <p><b>Warning:</b> <code>BufferedImage</code>s returned by this method * <em>must not</em> be modified.</p> * * @return the resulting <code>BufferedImage</code> */ public BufferedImage getImage(); /** * Calculates the <code>BufferedImage</code> produced by this operation, and * reports completion or failure to the specified * <code>ImageOpObserver</code>. Calls to this method are memoized * to prevent redundant computations. If a non-<code>null</code> observer * is given, then the operation may be done asynchronously. If the * observer is <code>null</code>, then this method will block on * completion of the operation. * * <p> When a non-blocking call is made (i.e., when * <code>obs != null</code>), the cache is checked and if the image is * found, it is returned immediately. If the image is already being * calculated, <code>obs</code> is notified when the pre-existing request * completes. Otherwise, a new request is queued and <code>obs</code> is * notified when that completes.</p> * * <p>When a blocking call is made (i.e., when <code>obs == null</code>), * the cache is checked and if the image is found, it is returned * immediately. If the image is already being calculated, this method * blocks on the completion of the existing calculation. Otherwise, * a new calculation is started and this method blocks on it. In * all cases, when a calculation is completed, the result is cached.</p> * * <p><b>Warning:</b> <code>BufferedImage</code>s returned by this method * <em>must not</em> be modified.</p> * * @param obs the observer to be notified on completion * @return the resulting <code>BufferedImage</code> * @throws CancellationException if the operation was cancelled * @throws InterruptedException if the operation was interrupted * @throws ExecutionException if the operation failed * @see #getTile * @see #getFutureTile * @see #getFutureImage */ public BufferedImage getImage(ImageOpObserver obs) throws CancellationException, InterruptedException, ExecutionException; /** * Submits a request for the <code>BufferedImage</code> produced by this * operation, and returns a reference to that request. * * If a non-<code>null</code> observer is given, then the operation may * be done asynchronously. If the observer is <code>null</code>, then * this method will block on completion of the operation. * * <p>This implementaion uses a memory-sensitive cache to memoize * calls to <code>getFutureImage</code>. It returns a * {@code Future<BufferedImage>} so that the request may be cancelled if no * longer needed.</p> * * <p><code>Future</code>s are returned immediately, except in the * case where the is no observer and no pre-existing <code>Future</code> * for this <code>ImageOp</code>'s <code>BufferedImage</code>, in which * case this method blocks on completion of the computation.</p> * * <p><b>Warning:</b> <code>BufferedImage</code>s obtained from the * <code>Future</code>s returned by this method <em>must not</em> be * modified.</p> * * @param obs the observer to be notified on completion * @return a <code>Future</code> for the resulting <code>BufferedImage</code> * @throws ExecutionException if the operation failed * @see #getTile * @see #getFutureTile * @see #getImage */ public Future<BufferedImage> getFutureImage(ImageOpObserver obs) throws ExecutionException; /** * Returns the size of the <code>BufferedImage</code> which would be returned * by {@link #getImage}. The size is cached so that it need not be * recalculated on each call. * * @return the size of the resulting <code>BufferedImage</code> in pixels * @see #getHeight * @see #getWidth */ public Dimension getSize(); /** * Returns the width of the <code>BufferedImage</code> which would be * returned by {@link #getImage}. The width is cached so that it need not * be recalculated on each call. * * @return the width of the resulting <code>BufferedImage</code> in pixels * @see #getHeight * @see #getSize */ public int getWidth(); /** * Returns the height of the <code>BufferedImage</code> which would be * returned by {@link #getImage}. The height is cached so that it need * not be recalculated on each call. * * @return the height of the resulting <code>BufferedImage</code> in pixels * @see #getWidth * @see #getSize */ public int getHeight(); /** * Returns the standard size of the <code>BufferedImage</code> tiles * which are returned by {@link #getTile}. Tiles which are in the extreme * right column will not have full width if the <code>BufferedImage</code> * width is not an integral multiple of the tile width. Similarly, tiles in * the bottom row will not have full height if the <code>BufferedImage</code> * height is not an integral multiple of the tile height. * * @return the size of <code>BufferedImage</code> tiles in pixels * @see #getTileHeight * @see #getTileWidth */ public Dimension getTileSize(); /** * Returns the standard height of the <code>BufferedImage</code> tiles * which are returned by {@link #getTile}. * * @return the height of <code>BufferedImage</code> tiles in pixels * @see #getTileSize * @see #getTileWidth */ public int getTileHeight(); /** * Returns the standard width of the <code>BufferedImage</code> tiles which * are returned by {@link #getTile}. * * @return the width of <code>BufferedImage</code> tiles in pixels * @see #getTileSize * @see #getTileHeight */ public int getTileWidth(); /** * Returns the number of tiles along the x-axis. There will always be at * least one column of tiles. The number of columns <em>should</em> * equal <code>(int) Math.ceil((double) getWidth() / getTileWidth())</code>. * * @return the number of tiles along the x-axis */ public int getNumXTiles(); /** * Returns the number of tiles along the y-axis. There will always be at * least one row of tiles. The number of rows <em>should</em> equal * <code>(int) Math.ceil((double) getHeight() / getTileHeight())</code>. * * @return the number of tiles along the y-axis */ public int getNumYTiles(); /** * Calculates tile <code>(p.x,p.y)</code>, and reports * completion or failure to the specified <code>ImageOpObserver</code>. * If a non-<code>null</code> observer is given, then the operation may * be done asynchronously. If the observer is <code>null</code>, then * this method will block on completion of the operation. Tiles are * numbered from zero, so the tile in the upper-left corner of the main * <code>BufferedImage</code> is <code>(0,0)</code>. Note that * <code>p.x</code> and <code>p.y</code> are indices into the tile array, * not pixel locations. * * <p>This convenience method is equivalent to * <code>getTile(p.x, p.y, obs)</code>.</p> * * <p><b>Warning:</b> <code>BufferedImage</code>s returned by this method * <em>must not</em> be modified.</p> * * @param p the position of the requested tile * @param obs the observer * @return the resulting <code>BufferedImage</code> * @throws CancellationException if the operation was cancelled * @throws InterruptedException if the operation was interrupted * @throws ExecutionException if the operation failed */ public BufferedImage getTile(Point p, ImageOpObserver obs) throws CancellationException, InterruptedException, ExecutionException; /** * Calculates tile <code>(tileX,tileY)</code>, and reports * completion or failure to the specified <code>ImageOpObserver</code>. * If a non-<code>null</code> observer is given, then the operation may * be done asynchronously. If the observer is <code>null</code>, then * this method will block on completion of the operation. Tiles are * numbered from zero, so the tile in the upper-left corner of the main * <code>BufferedImage</code> is <code>(0,0)</code>. Note that * <code>tileX</code> and <code>tileY</code> are indices into the tile * array, not pixel locations. * * <p><b>Warning:</b> <code>BufferedImage</code>s returned by this method * <em>must not</em> be modified.</p> * * @param tileX the x position of the requested tile * @param tileY the y position of the requested tile * @param obs the observer to be notified on completion * @return the resulting <code>BufferedImage</code> * @throws CancellationException if the operation was cancelled * @throws InterruptedException if the operation was interrupted * @throws ExecutionException if the operation failed */ public BufferedImage getTile(int tileX, int tileY, ImageOpObserver obs) throws CancellationException, InterruptedException, ExecutionException; /** * Submits a request for tile <code>(tileX,tileY)</code>, and returns a * reference to that request. If a non-<code>null</code> observer is given, * then the operation may be done asynchronously. If the observer is * <code>null</code>, then this method will block on completion of the * operation. Tiles are numbered from zero, so the tile in the upper-left * corner of the main <code>BufferedImage</code> is <code>(0,0)</code>. * Note that <code>tileX</code> and <code>tileY</code> are indices into the * tile array, not pixel locations. * * <p>This convenience method is equivalent to * <code>getFutureTile(p.x, p.y, obs)</code>.</p> * * <p><b>Warning:</b> <code>BufferedImage</code>s obtained from the * <code>Future</code>s returned by this method <em>must not</em> be * modified.</p> * * @param p the position of the requested tile * @param obs the observer to be notified on completion * @return a <code>Future</code> for the resulting <code>BufferedImage</code> * @throws ExecutionException if the operation failed */ public Future<BufferedImage> getFutureTile(Point p, ImageOpObserver obs) throws ExecutionException; /** * Submits a request for tile <code>(tileX,tileY)</code>, and returns a * reference to that request. If a non-<code>null</code> observer is given, * then the operation may be done asynchronously. If the observer is * <code>null</code>, then this method will block on completion of the * operation. Tiles are numbered from zero, so the tile in the upper-left * corner of the main <code>BufferedImage</code> is <code>(0,0)</code>. * Note that <code>tileX</code> and <code>tileY</code> are indices into the * tile array, not pixel locations. * * <p><b>Warning:</b> <code>BufferedImage</code>s obtained from the * <code>Future</code>s returned by this method <em>must not</em> be * modified.</p> * * @param tileX the x position of the requested tile * @param tileY the y position of the requested tile * @param obs the observer to be notified on completion * @return a <code>Future</code> for the resulting <code>BufferedImage</code> * @throws ExecutionException if the operation failed */ public Future<BufferedImage> getFutureTile( int tileX, int tileY, ImageOpObserver obs) throws ExecutionException; /** * Returns an <code>ImageOp</code> which can produce the requested tile. * * <p>This convenience method is equivalent to * <code>getTileOp(p.x, p.y)</code>.</p> * * @param p the position of the requested tile * @return the <code>ImageOp</code> which produces the requested tile */ public ImageOp getTileOp(Point p); /** * Returns an <code>ImageOp</code> which can produce the requested tile. * * @param tileX the x position of the requested tile * @param tileY the y position of the requested tile * @return the <code>ImageOp</code> which produces the requested tile */ public ImageOp getTileOp(int tileX, int tileY); /** * Returns an array of <code>Point</code>s representing the tiles * intersecting the given <code>Rectangle</code>. * * @param rect the rectangle * @return the positions of the tiles hit by the rectangle * @throws IllegalArgumentException if <code>rect == null</code>. */ public Point[] getTileIndices(Rectangle rect); }