001: /*
002: * $RCSfile: CRIFImpl.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:57:05 $
010: * $State: Exp $
011: */
012: package javax.media.jai;
013:
014: import java.awt.RenderingHints;
015: import java.awt.geom.Rectangle2D;
016: import java.awt.geom.Rectangle2D.Float;
017: import java.awt.image.RenderedImage;
018: import java.awt.image.renderable.ContextualRenderedImageFactory;
019: import java.awt.image.renderable.ParameterBlock;
020: import java.awt.image.renderable.RenderableImage;
021: import java.awt.image.renderable.RenderContext;
022: import javax.media.jai.ImageLayout;
023: import javax.media.jai.JAI;
024: import javax.media.jai.RenderedOp;
025: import javax.media.jai.registry.RenderedRegistryMode;
026: import javax.media.jai.util.ImagingException;
027: import javax.media.jai.util.ImagingListener;
028: import com.sun.media.jai.util.ImageUtil;
029:
030: /**
031: * A utility class to minimize in most cases the effort required to implement
032: * the <code>ContextualRenderedImageFactory</code> (CRIF) of an operation.
033: * An extender of this class is required to implement only the method
034: * <code>RenderedImage create(ParameterBlock, RenderingHints)</code>
035: * defined in the <code>RenderedImageFactory</code> interface. The remaining
036: * methods may be overridden insofar as this is necessary to obtain behavior
037: * different from that provided by default.
038: *
039: * @see java.awt.image.renderable.ContextualRenderedImageFactory
040: * @see java.awt.image.renderable.RenderedImageFactory
041: * @since JAI 1.1
042: */
043: // This class was actually added in JAI EA2 but was then in
044: // com.sun.media.jai.opimage. It was moved to the public API in JAI 1.1.
045: public abstract class CRIFImpl implements
046: ContextualRenderedImageFactory {
047:
048: /**
049: * If non-<code>null</code>, this name will be used as a parameter to
050: * <code>JAI.create()</code> in
051: * <code>create(RenderContext,ParameterBlock)</code>; otherwise the RIF
052: * <code>create(ParameterBlock,RenderingHints)</code> method implemented
053: * in the extending class will be invoked.
054: */
055: protected String operationName = null;
056:
057: /**
058: * Default constructor. The operation name is set to <code>null</code>.
059: */
060: public CRIFImpl() {
061: this .operationName = null;
062: }
063:
064: /**
065: * Constructor. The operation name is set to the specified value
066: * which may be <code>null</code>.
067: */
068: public CRIFImpl(String operationName) {
069: this .operationName = operationName;
070: }
071:
072: /**
073: * The <code>RenderedImageFactory</code> <code>create()</code> method
074: * which must be implemented by concrete subclasses.
075: */
076: public abstract RenderedImage create(ParameterBlock paramBlock,
077: RenderingHints renderHints);
078:
079: /**
080: * Creates a <code>RenderedImage</code> from the renderable layer.
081: *
082: * <p> If <code>operationName</code> is non-<code>null</code>,
083: * <code>JAI.create()</code> will be invoked using the supplied
084: * <code>ParameterBlock</code> and the <code>RenderingHints</code>
085: * contained in the <code>RenderContext</code>. If
086: * <code>operationName</code> is <code>null</code>, or
087: * <code>JAI.create()</code> returns <code>null</code>, the
088: * <code>create(ParameterBlock,RenderingHints)</code> method defined
089: * in the extending class will be invoked.
090: *
091: * @param renderContext The rendering information associated with
092: * this rendering.
093: * @param paramBlock The parameters used to create the image.
094: * @return A <code>RenderedImage</code>.
095: */
096: public RenderedImage create(RenderContext renderContext,
097: ParameterBlock paramBlock) {
098: RenderingHints renderHints = renderContext.getRenderingHints();
099: if (operationName != null) {
100: OperationRegistry registry = renderHints == null ? null
101: : (OperationRegistry) renderHints
102: .get(JAI.KEY_OPERATION_REGISTRY);
103:
104: RenderedImage rendering;
105:
106: if (registry == null) {
107: // Call the JAI.create method to get the best implementation
108: rendering = JAI.create(operationName, paramBlock,
109: renderHints);
110: } else { // registry != null
111: // NB: This section is lifted pretty much verbatim from
112: // JAI.createNS().
113:
114: // Get the OperationDescriptor registered under the
115: // specified name.
116: OperationDescriptor odesc = (OperationDescriptor) registry
117: .getDescriptor(OperationDescriptor.class,
118: operationName);
119: if (odesc == null) {
120: throw new IllegalArgumentException(operationName
121: + ": " + JaiI18N.getString("JAI0"));
122: }
123:
124: // Does this operation support rendered mode?
125: if (!odesc
126: .isModeSupported(RenderedRegistryMode.MODE_NAME)) {
127: throw new IllegalArgumentException(operationName
128: + ": " + JaiI18N.getString("JAI1"));
129: }
130:
131: // Check the destination image type.
132: if (!RenderedImage.class.isAssignableFrom(odesc
133: .getDestClass(RenderedRegistryMode.MODE_NAME))) {
134: throw new IllegalArgumentException(operationName
135: + ": " + JaiI18N.getString("JAI2"));
136: }
137:
138: // Validate input arguments. The ParameterBlock is cloned here
139: // because OperationDescriptor.validateArguments() may change
140: // its content.
141: StringBuffer msg = new StringBuffer();
142: paramBlock = (ParameterBlock) paramBlock.clone();
143: if (!odesc
144: .validateArguments(
145: RenderedRegistryMode.MODE_NAME,
146: paramBlock, msg)) {
147: throw new IllegalArgumentException(msg.toString());
148: }
149:
150: // Create the rendered operation node.
151: rendering = new RenderedOp(registry, operationName,
152: paramBlock, renderHints);
153: }
154:
155: // Return the rendering if possible.
156: if (rendering != null) {
157: // If the rendering is a rendered chain, replace it by its
158: // rendering which will likely be an OpImage chain.
159: if (rendering instanceof RenderedOp) {
160: try {
161: rendering = ((RenderedOp) rendering)
162: .getRendering();
163: } catch (Exception e) {
164: ImagingListener listener = ImageUtil
165: .getImagingListener(renderHints);
166: String message = JaiI18N.getString("CRIFImpl0")
167: + operationName;
168: listener.errorOccurred(message, e, this , false);
169: // e.printStackTrace();
170: }
171: }
172: return rendering;
173: }
174: }
175:
176: // Call the RIF create method of the extending class
177: return create(paramBlock, renderHints);
178: }
179:
180: /**
181: * Maps the destination <code>RenderContext</code> into a
182: * <code>RenderContext</code> for each source. The
183: * implementation in this class simply returns the
184: * <code>RenderContext</code> passed in by the caller.
185: *
186: * @param i The index of the source image.
187: * @param renderContext The <code>RenderContext</code> being applied to
188: * the operation.
189: * @param paramBlock A <code>ParameterBlock</code> containing the
190: * sources and parameters of the operation.
191: * @param image The <code>RenderableImage</code> being rendered.
192: *
193: * @return The <code>RenderContext</code> to be used to render the
194: * given source.
195: */
196: public RenderContext mapRenderContext(int i,
197: RenderContext renderContext, ParameterBlock paramBlock,
198: RenderableImage image) {
199: return renderContext;
200: }
201:
202: /**
203: * Returns the bounding box for the output of the operation. The
204: * implementation in this class computes the bounding box as the
205: * intersection the bounding boxes of all the (renderable sources).
206: *
207: * @param paramBlock A <code>ParameterBlock</code> containing the
208: * sources and parameters of the operation.
209: * @return A <code>Rectangle2D</code> specifying the bounding box.
210: */
211: public Rectangle2D getBounds2D(ParameterBlock paramBlock) {
212: int numSources = paramBlock.getNumSources();
213:
214: if (numSources == 0) {
215: return null;
216: }
217:
218: RenderableImage src = paramBlock.getRenderableSource(0);
219: Rectangle2D.Float box1 = new Rectangle2D.Float(src.getMinX(),
220: src.getMinY(), src.getWidth(), src.getHeight());
221:
222: for (int i = 1; i < numSources; i++) {
223: src = paramBlock.getRenderableSource(i);
224: Rectangle2D.Float box2 = new Rectangle2D.Float(src
225: .getMinX(), src.getMinY(), src.getWidth(), src
226: .getHeight());
227: box1 = (Rectangle2D.Float) box1.createIntersection(box2);
228: if (box1.isEmpty()) {
229: break;
230: }
231: }
232:
233: return box1;
234: }
235:
236: /**
237: * Returns the appropriate instance of the property with the indicated
238: * name.
239: *
240: * <p> The implementation in this class always returns
241: * <code>java.awt.Image.UndefinedProperty</code> since
242: * no properties are defined by default.
243: *
244: * @param paramBlock A <code>ParameterBlock</code> containing the
245: * sources and parameters of the operation.
246: * @param name A <code>String</code> containing the desired property name.
247: *
248: * @return the value <code>java.awt.Image.UndefinedProperty</code>
249: * indicating that the property is undefined.
250: */
251: public Object getProperty(ParameterBlock paramBlock, String name) {
252: return java.awt.Image.UndefinedProperty;
253: }
254:
255: /**
256: * Returns the valid property names for the operation. The
257: * implementation in this class always returns <code>null</code>
258: * since no properties are associated with the operation by
259: * default.
260: *
261: * @return <code>null</code> indicating that no properties are defined.
262: */
263: public String[] getPropertyNames() {
264: return null;
265: }
266:
267: /**
268: * Returns <code>true</code> if successive renderings with the same
269: * arguments may produce different results. The implementation in this
270: * class always returns <code>false</code> so as to enable caching
271: * of renderings by default. CRIFs that do implement dynamic
272: * rendering behavior must override this method.
273: *
274: * @return <code>false</code> indicating that the rendering is static.
275: */
276: public boolean isDynamic() {
277: return false;
278: }
279: }
|