You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
351 lines
13 KiB
351 lines
13 KiB
/*
|
|
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
/* ********************************************************************
|
|
**********************************************************************
|
|
**********************************************************************
|
|
*** 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;
|
|
}
|
|
}
|
|
}
|