/* |
|
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. 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. Oracle designates this |
|
* particular file as subject to the "Classpath" exception as provided |
|
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
* or visit www.oracle.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<RenderableImage> 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 <code>true</code> if successive renderings with the |
|
* same arguments might produce different results; |
|
* <code>false</code> 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 <code>ParameterBlock</code> of this |
|
* <code>RenderableImageOp</code>. |
|
* @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. |
|
* |
|
* <p> 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. |
|
* |
|
* <p> 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 containing 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. |
|
* |
|
* <p> 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: |
|
* |
|
* <ol> |
|
* <li> mapRenderContext() is called on the associated CRIF for |
|
* each RenderableImage source; |
|
* <li> 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; |
|
* <li> ContextualRenderedImageFactory.create() is called |
|
* with a new ParameterBlock containing the parameters of |
|
* the RenderableImageOp and the RenderedImages that were created by the |
|
* createRendering() calls. |
|
* </ol> |
|
* |
|
* <p> 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. |
|
* |
|
* <p> 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; |
|
} |
|
} |
|
} |