001: /*
002: * $RCSfile: WarpDescriptor.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:46 $
010: * $State: Exp $
011: */
012: package javax.media.jai.operator;
013:
014: import com.sun.media.jai.util.PropertyGeneratorImpl;
015: import java.awt.Rectangle;
016: import java.awt.RenderingHints;
017: import java.awt.geom.AffineTransform;
018: import java.awt.geom.Point2D;
019: import java.awt.image.RenderedImage;
020: import java.awt.image.renderable.ParameterBlock;
021: import javax.media.jai.GeometricOpImage;
022: import javax.media.jai.ImageLayout;
023: import javax.media.jai.Interpolation;
024: import javax.media.jai.InterpolationNearest;
025: import javax.media.jai.JAI;
026: import javax.media.jai.OperationDescriptorImpl;
027: import javax.media.jai.ParameterBlockJAI;
028: import javax.media.jai.PlanarImage;
029: import javax.media.jai.PropertyGenerator;
030: import javax.media.jai.ROI;
031: import javax.media.jai.ROIShape;
032: import javax.media.jai.RenderableOp;
033: import javax.media.jai.RenderedOp;
034: import javax.media.jai.Warp;
035: import javax.media.jai.registry.RenderedRegistryMode;
036:
037: /**
038: * This property generator computes the properties for the operation
039: * "Warp" dynamically.
040: */
041: class WarpPropertyGenerator extends PropertyGeneratorImpl {
042:
043: /** Constructor. */
044: public WarpPropertyGenerator() {
045: super (new String[] { "ROI" }, new Class[] { ROI.class },
046: new Class[] { RenderedOp.class });
047: }
048:
049: /**
050: * Returns the specified property.
051: *
052: * @param name Property name.
053: * @param opNode Operation node.
054: */
055: public Object getProperty(String name, Object opNode) {
056: validate(name, opNode);
057:
058: if (opNode instanceof RenderedOp
059: && name.equalsIgnoreCase("roi")) {
060: RenderedOp op = (RenderedOp) opNode;
061:
062: ParameterBlock pb = op.getParameterBlock();
063:
064: // Retrieve the rendered source image and its ROI.
065: RenderedImage src = (RenderedImage) pb.getRenderedSource(0);
066: Object property = src.getProperty("ROI");
067: if (property == null
068: || property
069: .equals(java.awt.Image.UndefinedProperty)
070: || !(property instanceof ROI)) {
071: return java.awt.Image.UndefinedProperty;
072: }
073:
074: // Return undefined also if source ROI is empty.
075: ROI srcROI = (ROI) property;
076: if (srcROI.getBounds().isEmpty()) {
077: return java.awt.Image.UndefinedProperty;
078: }
079:
080: // Retrieve the Interpolation object.
081: Interpolation interp = (Interpolation) pb
082: .getObjectParameter(1);
083:
084: // Determine the effective source bounds.
085: Rectangle srcBounds = null;
086: PlanarImage dst = op.getRendering();
087: if (dst instanceof GeometricOpImage
088: && ((GeometricOpImage) dst).getBorderExtender() == null) {
089: srcBounds = new Rectangle(src.getMinX()
090: + interp.getLeftPadding(), src.getMinY()
091: + interp.getTopPadding(), src.getWidth()
092: - interp.getWidth() + 1, src.getHeight()
093: - interp.getHeight() + 1);
094: } else {
095: srcBounds = new Rectangle(src.getMinX(), src.getMinY(),
096: src.getWidth(), src.getHeight());
097: }
098:
099: // If necessary, clip the ROI to the effective source bounds.
100: if (!srcBounds.contains(srcROI.getBounds())) {
101: srcROI = srcROI.intersect(new ROIShape(srcBounds));
102: }
103:
104: // Set the nearest neighbor interpolation object.
105: Interpolation interpNN = interp instanceof InterpolationNearest ? interp
106: : Interpolation
107: .getInstance(Interpolation.INTERP_NEAREST);
108:
109: // Retrieve the Warp object.
110: Warp warp = (Warp) pb.getObjectParameter(0);
111:
112: // Create the warped ROI.
113: ROI dstROI = new ROI(JAI.create("warp",
114: srcROI.getAsImage(), warp, interpNN));
115:
116: // Retrieve the destination bounds.
117: Rectangle dstBounds = op.getBounds();
118:
119: // If necessary, clip the warped ROI to the destination bounds.
120: if (!dstBounds.contains(dstROI.getBounds())) {
121: dstROI = dstROI.intersect(new ROIShape(dstBounds));
122: }
123:
124: // Return the warped and possibly clipped ROI.
125: return dstROI;
126: }
127:
128: return java.awt.Image.UndefinedProperty;
129: }
130: }
131:
132: /**
133: * An <code>OperationDescriptor</code> describing the "Warp" operation.
134: *
135: * <p> The "Warp" operation performs (possibly filtered) general
136: * warping on an image.
137: *
138: * <p> The destination bounds may be specified by an {@link ImageLayout}
139: * hint provided via a {@link RenderingHints} supplied to the operation. If
140: * no bounds are so specified, then the destination bounds will be set to
141: * the minimum bounding rectangle of the forward mapped source bounds
142: * calculated using {@link Warp#mapSourceRect(Rectangle)} or, failing that,
143: * {@link Warp#mapSourcePoint(Point2D)} applied to the vertices of the
144: * source bounds. If forward mapping by both methods is not viable, then
145: * an approximate affine mapping will be created and used to determine the
146: * destination bounds by forward mapping the source bounds. If this approach
147: * also fails, then the destination bounds will be set to the source bounds.
148: *
149: * <p> "Warp" defines a PropertyGenerator that
150: * performs an identical transformation on the "ROI" property of the
151: * source image, which can be retrieved by calling the
152: * <code>getProperty</code> method with "ROI" as the property name.
153: *
154: * <p> The parameter, "backgroundValues", is defined to
155: * fill the background with the user-specified background
156: * values. These background values will be translated into background
157: * colors by the <code>ColorModel</code> when the image is displayed.
158: * With the default value, <code>{0.0}</code>, of this parameter,
159: * the background pixels are filled with 0s. If the provided array
160: * length is smaller than the number of bands, the first element of
161: * the provided array is used for all the bands. If the provided values
162: * are out of the data range of the destination image, they will be clamped
163: * into the proper range.
164: *
165: * <p> It should be noted that this operation automatically adds a
166: * value of <code>Boolean.TRUE</code> for the
167: * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> to the given
168: * <code>configuration</code> so that the operation is performed
169: * on the pixel values instead of being performed on the indices into
170: * the color map if the source(s) have an <code>IndexColorModel</code>.
171: * This addition will take place only if a value for the
172: * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> has not already been
173: * provided by the user. Note that the <code>configuration</code> Map
174: * is cloned before the new hint is added to it. The operation can be
175: * smart about the value of the <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code>
176: * <code>RenderingHints</code>, i.e. while the default value for the
177: * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> is
178: * <code>Boolean.TRUE</code>, in some cases the operator could set the
179: * default.
180: *
181: * <p><table border=1>
182: * <caption>Resource List</caption>
183: * <tr><th>Name</th> <th>Value</th></tr>
184: * <tr><td>GlobalName</td> <td>Warp</td></tr>
185: * <tr><td>LocalName</td> <td>Warp</td></tr>
186: * <tr><td>Vendor</td> <td>com.sun.media.jai</td></tr>
187: * <tr><td>Description</td> <td>Warps an image according
188: * to a specified Warp object.</td></tr>
189: * <tr><td>DocURL</td> <td>http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/WarpDescriptor.html</td></tr>
190: * <tr><td>Version</td> <td>1.0</td></tr>
191: * <tr><td>arg0Desc</td> <td>The Warp object.</td></tr>
192: * <tr><td>arg1Desc</td> <td>The interpolation method.</td></tr>
193: * </table></p>
194: *
195: * <p><table border=1>
196: * <caption>Parameter List</caption>
197: * <tr><th>Name</th> <th>Class Type</th>
198: * <th>Default Value</th></tr>
199: * <tr><td>warp</td> <td>javax.media.jai.Warp</td>
200: * <td>NO_PARAMETER_DEFAULT</td>
201: * <tr><td>interpolation</td> <td>javax.media.jai.Interpolation</td>
202: * <td>InterpolationNearest</td>
203: * <tr><td>backgroundValues</td> <td>double[]</td>
204: * <td>{0.0}</td>
205: * </table></p>
206: *
207: * @see javax.media.jai.Interpolation
208: * @see javax.media.jai.Warp
209: * @see javax.media.jai.OperationDescriptor
210: */
211: public class WarpDescriptor extends OperationDescriptorImpl {
212:
213: /**
214: * The resource strings that provide the general documentation and
215: * specify the parameter list for the "Warp" operation.
216: */
217: private static final String[][] resources = {
218: { "GlobalName", "Warp" },
219: { "LocalName", "Warp" },
220: { "Vendor", "com.sun.media.jai" },
221: { "Description", JaiI18N.getString("WarpDescriptor0") },
222: {
223: "DocURL",
224: "http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/WarpDescriptor.html" },
225: { "Version", JaiI18N.getString("DescriptorVersion") },
226: { "arg0Desc", JaiI18N.getString("WarpDescriptor1") },
227: { "arg1Desc", JaiI18N.getString("WarpDescriptor2") },
228: { "arg2Desc", JaiI18N.getString("WarpDescriptor3") } };
229:
230: /** The parameter names for the "Warp" operation. */
231: private static final String[] paramNames = { "warp",
232: "interpolation", "backgroundValues" };
233:
234: /** The parameter class types for the "Warp" operation. */
235: private static final Class[] paramClasses = {
236: javax.media.jai.Warp.class,
237: javax.media.jai.Interpolation.class, double[].class };
238:
239: /** The parameter default values for the "Warp" operation. */
240: private static final Object[] paramDefaults = {
241: NO_PARAMETER_DEFAULT,
242: Interpolation.getInstance(Interpolation.INTERP_NEAREST),
243: new double[] { 0.0 } };
244:
245: /** Constructor. */
246: public WarpDescriptor() {
247: super (resources, 1, paramClasses, paramNames, paramDefaults);
248: }
249:
250: /**
251: * Returns an array of <code>PropertyGenerators</code> implementing
252: * property inheritance for the "Warp" operation.
253: *
254: * @return An array of property generators.
255: */
256: public PropertyGenerator[] getPropertyGenerators() {
257: PropertyGenerator[] pg = new PropertyGenerator[1];
258: pg[0] = new WarpPropertyGenerator();
259: return pg;
260: }
261:
262: /**
263: * Warps an image according to a specified Warp object.
264: *
265: * <p>Creates a <code>ParameterBlockJAI</code> from all
266: * supplied arguments except <code>hints</code> and invokes
267: * {@link JAI#create(String,ParameterBlock,RenderingHints)}.
268: *
269: * @see JAI
270: * @see ParameterBlockJAI
271: * @see RenderedOp
272: *
273: * @param source0 <code>RenderedImage</code> source 0.
274: * @param warp The warp object.
275: * @param interpolation The interpolation method.
276: * May be <code>null</code>.
277: * @param backgroundValues The user-specified background values.
278: * May be <code>null</code>.
279: * @param hints The <code>RenderingHints</code> to use.
280: * May be <code>null</code>.
281: * @return The <code>RenderedOp</code> destination.
282: * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
283: * @throws IllegalArgumentException if <code>warp</code> is <code>null</code>.
284: */
285: public static RenderedOp create(RenderedImage source0, Warp warp,
286: Interpolation interpolation, double[] backgroundValues,
287: RenderingHints hints) {
288: ParameterBlockJAI pb = new ParameterBlockJAI("Warp",
289: RenderedRegistryMode.MODE_NAME);
290:
291: pb.setSource("source0", source0);
292:
293: pb.setParameter("warp", warp);
294: pb.setParameter("interpolation", interpolation);
295: pb.setParameter("backgroundValues", backgroundValues);
296:
297: return JAI.create("Warp", pb, hints);
298: }
299: }
|