diff -r d95bc71a5732 -r 7952521a4ad3 jdk/src/share/classes/java/awt/image/renderable/RenderableImageOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/renderable/RenderableImageOp.java Thu Apr 10 16:28:45 2008 -0700 @@ -0,0 +1,350 @@ +/* + * Portions Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* ******************************************************************** + ********************************************************************** + ********************************************************************** + *** COPYRIGHT (c) Eastman Kodak Company, 1997 *** + *** As an unpublished work pursuant to Title 17 of the United *** + *** States Code. All rights reserved. *** + ********************************************************************** + ********************************************************************** + **********************************************************************/ + +package java.awt.image.renderable; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.RenderedImage; +import java.awt.RenderingHints; +import java.util.Hashtable; +import java.util.Vector; + +/** + * This class handles the renderable aspects of an operation with help + * from its associated instance of a ContextualRenderedImageFactory. + */ +public class RenderableImageOp implements RenderableImage { + + /** A ParameterBlock containing source and parameters. */ + ParameterBlock paramBlock; + + /** The associated ContextualRenderedImageFactory. */ + ContextualRenderedImageFactory myCRIF; + + /** The bounding box of the results of this RenderableImageOp. */ + Rectangle2D boundingBox; + + + /** + * Constructs a RenderedImageOp given a + * ContextualRenderedImageFactory object, and + * a ParameterBlock containing RenderableImage sources and other + * parameters. Any RenderedImage sources referenced by the + * ParameterBlock will be ignored. + * + * @param CRIF a ContextualRenderedImageFactory object + * @param paramBlock a ParameterBlock containing this operation's source + * images and other parameters necessary for the operation + * to run. + */ + public RenderableImageOp(ContextualRenderedImageFactory CRIF, + ParameterBlock paramBlock) { + this.myCRIF = CRIF; + this.paramBlock = (ParameterBlock) paramBlock.clone(); + } + + /** + * Returns a vector of RenderableImages that are the sources of + * image data for this RenderableImage. Note that this method may + * return an empty vector, to indicate that the image has no sources, + * or null, to indicate that no information is available. + * + * @return a (possibly empty) Vector of RenderableImages, or null. + */ + public Vector getSources() { + return getRenderableSources(); + } + + private Vector getRenderableSources() { + Vector sources = null; + + if (paramBlock.getNumSources() > 0) { + sources = new Vector(); + int i = 0; + while (i < paramBlock.getNumSources()) { + Object o = paramBlock.getSource(i); + if (o instanceof RenderableImage) { + sources.add((RenderableImage)o); + i++; + } else { + break; + } + } + } + return sources; + } + + /** + * Gets a property from the property set of this image. + * If the property name is not recognized, java.awt.Image.UndefinedProperty + * will be returned. + * + * @param name the name of the property to get, as a String. + * @return a reference to the property Object, or the value + * java.awt.Image.UndefinedProperty. + */ + public Object getProperty(String name) { + return myCRIF.getProperty(paramBlock, name); + } + + /** + * Return a list of names recognized by getProperty. + * @return a list of property names. + */ + public String[] getPropertyNames() { + return myCRIF.getPropertyNames(); + } + + /** + * Returns true if successive renderings (that is, calls to + * createRendering() or createScaledRendering()) with the same arguments + * may produce different results. This method may be used to + * determine whether an existing rendering may be cached and + * reused. The CRIF's isDynamic method will be called. + * @return true if successive renderings with the + * same arguments might produce different results; + * false otherwise. + */ + public boolean isDynamic() { + return myCRIF.isDynamic(); + } + + /** + * Gets the width in user coordinate space. By convention, the + * usual width of a RenderableImage is equal to the image's aspect + * ratio (width divided by height). + * + * @return the width of the image in user coordinates. + */ + public float getWidth() { + if (boundingBox == null) { + boundingBox = myCRIF.getBounds2D(paramBlock); + } + return (float)boundingBox.getWidth(); + } + + /** + * Gets the height in user coordinate space. By convention, the + * usual height of a RenderedImage is equal to 1.0F. + * + * @return the height of the image in user coordinates. + */ + public float getHeight() { + if (boundingBox == null) { + boundingBox = myCRIF.getBounds2D(paramBlock); + } + return (float)boundingBox.getHeight(); + } + + /** + * Gets the minimum X coordinate of the rendering-independent image data. + */ + public float getMinX() { + if (boundingBox == null) { + boundingBox = myCRIF.getBounds2D(paramBlock); + } + return (float)boundingBox.getMinX(); + } + + /** + * Gets the minimum Y coordinate of the rendering-independent image data. + */ + public float getMinY() { + if (boundingBox == null) { + boundingBox = myCRIF.getBounds2D(paramBlock); + } + return (float)boundingBox.getMinY(); + } + + /** + * Change the current ParameterBlock of the operation, allowing + * editing of image rendering chains. The effects of such a + * change will be visible when a new rendering is created from + * this RenderableImageOp or any dependent RenderableImageOp. + * + * @param paramBlock the new ParameterBlock. + * @return the old ParameterBlock. + * @see #getParameterBlock + */ + public ParameterBlock setParameterBlock(ParameterBlock paramBlock) { + ParameterBlock oldParamBlock = this.paramBlock; + this.paramBlock = (ParameterBlock)paramBlock.clone(); + return oldParamBlock; + } + + /** + * Returns a reference to the current parameter block. + * @return the ParameterBlock of this + * RenderableImageOp. + * @see #setParameterBlock(ParameterBlock) + */ + public ParameterBlock getParameterBlock() { + return paramBlock; + } + + /** + * Creates a RenderedImage instance of this image with width w, and + * height h in pixels. The RenderContext is built automatically + * with an appropriate usr2dev transform and an area of interest + * of the full image. All the rendering hints come from hints + * passed in. + * + *

If w == 0, it will be taken to equal + * Math.round(h*(getWidth()/getHeight())). + * Similarly, if h == 0, it will be taken to equal + * Math.round(w*(getHeight()/getWidth())). One of + * w or h must be non-zero or else an IllegalArgumentException + * will be thrown. + * + *

The created RenderedImage may have a property identified + * by the String HINTS_OBSERVED to indicate which RenderingHints + * were used to create the image. In addition any RenderedImages + * that are obtained via the getSources() method on the created + * RenderedImage may have such a property. + * + * @param w the width of rendered image in pixels, or 0. + * @param h the height of rendered image in pixels, or 0. + * @param hints a RenderingHints object containg hints. + * @return a RenderedImage containing the rendered data. + */ + public RenderedImage createScaledRendering(int w, int h, + RenderingHints hints) { + // DSR -- code to try to get a unit scale + double sx = (double)w/getWidth(); + double sy = (double)h/getHeight(); + if (Math.abs(sx/sy - 1.0) < 0.01) { + sx = sy; + } + AffineTransform usr2dev = AffineTransform.getScaleInstance(sx, sy); + RenderContext newRC = new RenderContext(usr2dev, hints); + return createRendering(newRC); + } + + /** + * Gets a RenderedImage instance of this image with a default + * width and height in pixels. The RenderContext is built + * automatically with an appropriate usr2dev transform and an area + * of interest of the full image. All the rendering hints come + * from hints passed in. Implementors of this interface must be + * sure that there is a defined default width and height. + * + * @return a RenderedImage containing the rendered data. + */ + public RenderedImage createDefaultRendering() { + AffineTransform usr2dev = new AffineTransform(); // Identity + RenderContext newRC = new RenderContext(usr2dev); + return createRendering(newRC); + } + + /** + * Creates a RenderedImage which represents this + * RenderableImageOp (including its Renderable sources) rendered + * according to the given RenderContext. + * + *

This method supports chaining of either Renderable or + * RenderedImage operations. If sources in + * the ParameterBlock used to construct the RenderableImageOp are + * RenderableImages, then a three step process is followed: + * + *

    + *
  1. mapRenderContext() is called on the associated CRIF for + * each RenderableImage source; + *
  2. createRendering() is called on each of the RenderableImage sources + * using the backwards-mapped RenderContexts obtained in step 1, + * resulting in a rendering of each source; + *
  3. ContextualRenderedImageFactory.create() is called + * with a new ParameterBlock containing the parameters of + * the RenderableImageOp and the RenderedImages that were created by the + * createRendering() calls. + *
+ * + *

If the elements of the source Vector of + * the ParameterBlock used to construct the RenderableImageOp are + * instances of RenderedImage, then the CRIF.create() method is + * called immediately using the original ParameterBlock. + * This provides a basis case for the recursion. + * + *

The created RenderedImage may have a property identified + * by the String HINTS_OBSERVED to indicate which RenderingHints + * (from the RenderContext) were used to create the image. + * In addition any RenderedImages + * that are obtained via the getSources() method on the created + * RenderedImage may have such a property. + * + * @param renderContext The RenderContext to use to perform the rendering. + * @return a RenderedImage containing the desired output image. + */ + public RenderedImage createRendering(RenderContext renderContext) { + RenderedImage image = null; + RenderContext rcOut = null; + + // Clone the original ParameterBlock; if the ParameterBlock + // contains RenderableImage sources, they will be replaced by + // RenderedImages. + ParameterBlock renderedParamBlock = (ParameterBlock)paramBlock.clone(); + Vector sources = getRenderableSources(); + + try { + // This assumes that if there is no renderable source, that there + // is a rendered source in paramBlock + + if (sources != null) { + Vector renderedSources = new Vector(); + for (int i = 0; i < sources.size(); i++) { + rcOut = myCRIF.mapRenderContext(i, renderContext, + paramBlock, this); + RenderedImage rdrdImage = + ((RenderableImage)sources.elementAt(i)).createRendering(rcOut); + if (rdrdImage == null) { + return null; + } + + // Add this rendered image to the ParameterBlock's + // list of RenderedImages. + renderedSources.addElement(rdrdImage); + } + + if (renderedSources.size() > 0) { + renderedParamBlock.setSources(renderedSources); + } + } + + return myCRIF.create(renderContext, renderedParamBlock); + } catch (ArrayIndexOutOfBoundsException e) { + // This should never happen + return null; + } + } +}