001: /*
002: * $RCSfile: RotateDescriptor.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:43 $
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.image.RenderedImage;
019: import java.awt.image.renderable.ParameterBlock;
020: import java.awt.image.renderable.RenderableImage;
021: import javax.media.jai.GeometricOpImage;
022: import javax.media.jai.Interpolation;
023: import javax.media.jai.InterpolationNearest;
024: import javax.media.jai.JAI;
025: import javax.media.jai.OperationDescriptorImpl;
026: import javax.media.jai.ParameterBlockJAI;
027: import javax.media.jai.PlanarImage;
028: import javax.media.jai.PropertyGenerator;
029: import javax.media.jai.ROI;
030: import javax.media.jai.ROIShape;
031: import javax.media.jai.RenderableOp;
032: import javax.media.jai.RenderedOp;
033: import javax.media.jai.registry.RenderableRegistryMode;
034: import javax.media.jai.registry.RenderedRegistryMode;
035:
036: /**
037: * This property generator computes the properties for the operation
038: * "Rotate" dynamically.
039: */
040: class RotatePropertyGenerator extends PropertyGeneratorImpl {
041:
042: /** Constructor. */
043: public RotatePropertyGenerator() {
044: super (new String[] { "ROI" }, new Class[] { ROI.class },
045: new Class[] { RenderedOp.class });
046: }
047:
048: /**
049: * Returns the specified property.
050: *
051: * @param name Property name.
052: * @param opNode Operation node.
053: */
054: public Object getProperty(String name, Object opNode) {
055: validate(name, opNode);
056:
057: if (opNode instanceof RenderedOp
058: && name.equalsIgnoreCase("roi")) {
059: RenderedOp op = (RenderedOp) opNode;
060:
061: ParameterBlock pb = op.getParameterBlock();
062:
063: // Retrieve the rendered source image and its ROI.
064: RenderedImage src = pb.getRenderedSource(0);
065: Object property = src.getProperty("ROI");
066: if (property == null
067: || property
068: .equals(java.awt.Image.UndefinedProperty)
069: || !(property instanceof ROI)) {
070: return java.awt.Image.UndefinedProperty;
071: }
072: ROI srcROI = (ROI) property;
073:
074: // Retrieve the Interpolation object.
075: Interpolation interp = (Interpolation) pb
076: .getObjectParameter(3);
077:
078: // Determine the effective source bounds.
079: Rectangle srcBounds = null;
080: PlanarImage dst = op.getRendering();
081: if (dst instanceof GeometricOpImage
082: && ((GeometricOpImage) dst).getBorderExtender() == null) {
083: srcBounds = new Rectangle(src.getMinX()
084: + interp.getLeftPadding(), src.getMinY()
085: + interp.getTopPadding(), src.getWidth()
086: - interp.getWidth() + 1, src.getHeight()
087: - interp.getHeight() + 1);
088: } else {
089: srcBounds = new Rectangle(src.getMinX(), src.getMinY(),
090: src.getWidth(), src.getHeight());
091: }
092:
093: // If necessary, clip the ROI to the effective source bounds.
094: if (!srcBounds.contains(srcROI.getBounds())) {
095: srcROI = srcROI.intersect(new ROIShape(srcBounds));
096: }
097:
098: // Retrieve the translation and rotation angle.
099: double xorig = (double) pb.getFloatParameter(0);
100: double yorig = (double) pb.getFloatParameter(1);
101: double angle = (double) pb.getFloatParameter(2);
102:
103: // Create an transform representing the rotation.
104: AffineTransform transform = AffineTransform
105: .getRotateInstance(angle, xorig, yorig);
106:
107: // Create the rotated/translated ROI.
108: ROI dstROI = srcROI.transform(transform);
109:
110: // Retrieve the destination bounds.
111: Rectangle dstBounds = op.getBounds();
112:
113: // If necessary, clip the rotated ROI to the destination bounds.
114: if (!dstBounds.contains(dstROI.getBounds())) {
115: dstROI = dstROI.intersect(new ROIShape(dstBounds));
116: }
117:
118: // Return the rotated and possibly clipped ROI.
119: return dstROI;
120: }
121:
122: return java.awt.Image.UndefinedProperty;
123: }
124: }
125:
126: /**
127: * An <code>OperationDescriptor</code> describing the "Rotate" operation.
128: *
129: * <p> The "Rotate" operation rotates an image about a given point by
130: * a given angle, specified in radians. The origin defaults to (0, 0).
131: *
132: * <p> The parameter, "backgroundValues", is defined to
133: * fill the background with the user-specified background
134: * values. These background values will be translated into background
135: * colors by the <code>ColorModel</code> when the image is displayed.
136: * With the default value, <code>{0.0}</code>, of this parameter,
137: * the background pixels are filled with 0s. If the provided array
138: * length is smaller than the number of bands, the first element of
139: * the provided array is used for all the bands. If the provided values
140: * are out of the data range of the destination image, they will be clamped
141: * into the proper range.
142: *
143: * <p> It may be noted that the minX, minY, width and height hints as
144: * specified through the <code>JAI.KEY_IMAGE_LAYOUT</code> hint in the
145: * <code>RenderingHints</code> object are not honored, as this operator
146: * calculates the destination image bounds itself. The other
147: * <code>ImageLayout</code> hints, like tileWidth and tileHeight,
148: * however are honored.
149: *
150: * <p> It should be noted that this operation automatically adds a
151: * value of <code>Boolean.TRUE</code> for the
152: * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> to the given
153: * <code>configuration</code> so that the operation is performed
154: * on the pixel values instead of being performed on the indices into
155: * the color map if the source(s) have an <code>IndexColorModel</code>.
156: * This addition will take place only if a value for the
157: * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> has not already been
158: * provided by the user. Note that the <code>configuration</code> Map
159: * is cloned before the new hint is added to it. The operation can be
160: * smart about the value of the <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code>
161: * <code>RenderingHints</code>, i.e. while the default value for the
162: * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> is
163: * <code>Boolean.TRUE</code>, in some cases the operator could set the
164: * default.
165: *
166: * <p> "Rotate" defines a PropertyGenerator that performs an
167: * identical transformation on the "ROI" property of the source image,
168: * which can be retrieved by calling the <code>getProperty</code>
169: * method with "ROI" as the property name.
170: *
171: * <p><table border=1>
172: * <caption>Resource List</caption>
173: * <tr><th>Name</th> <th>Value</th></tr>
174: * <tr><td>GlobalName</td> <td>Rotate</td></tr>
175: * <tr><td>LocalName</td> <td>Rotate</td></tr>
176: * <tr><td>Vendor</td> <td>com.sun.media.jai</td></tr>
177: * <tr><td>Description</td> <td>Rotate an image.</td></tr>
178: * <tr><td>DocURL</td> <td>http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/RotateDescriptor.html</td></tr>
179: * <tr><td>Version</td> <td>1.0</td></tr>
180: * <tr><td>arg0Desc</td> <td>The X origin to rotate about.</td></tr>
181: * <tr><td>arg1Desc</td> <td>The Y origin to rotate about.</td></tr>
182: * <tr><td>arg2Desc</td> <td>The rotation angle in radians.</td></tr>
183: * <tr><td>arg3Desc</td> <td>The interpolation method.</td></tr>
184: * </table></p>
185: *
186: * <p><table border=1>
187: * <caption>Parameter List</caption>
188: * <tr><th>Name</th> <th>Class Type</th>
189: * <th>Default Value</th></tr>
190: * <tr><td>xOrigin</td> <td>java.lang.Float</td>
191: * <td>0.0F</td>
192: * <tr><td>yOrigin</td> <td>java.lang.Float</td>
193: * <td>0.0F</td>
194: * <tr><td>angle</td> <td>java.lang.Float</td>
195: * <td>0.0F</td>
196: * <tr><td>interpolation</td> <td>javax.media.jai.Interpolation</td>
197: * <td>InterpolationNearest</td>
198: * <tr><td>backgroundValues</td> <td>double[]</td>
199: * <td>{0.0}</td>
200: * </table></p>
201: *
202: * @see javax.media.jai.Interpolation
203: * @see javax.media.jai.OperationDescriptor
204: */
205: public class RotateDescriptor extends OperationDescriptorImpl {
206:
207: /**
208: * The resource strings that provide the general documentation and
209: * specify the parameter list for the "Rotate" operation.
210: */
211: private static final String[][] resources = {
212: { "GlobalName", "Rotate" },
213: { "LocalName", "Rotate" },
214: { "Vendor", "com.sun.media.jai" },
215: { "Description", JaiI18N.getString("RotateDescriptor0") },
216: {
217: "DocURL",
218: "http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/RotateDescriptor.html" },
219: { "Version", JaiI18N.getString("DescriptorVersion") },
220: { "arg0Desc", JaiI18N.getString("RotateDescriptor1") },
221: { "arg1Desc", JaiI18N.getString("RotateDescriptor2") },
222: { "arg2Desc", JaiI18N.getString("RotateDescriptor3") },
223: { "arg3Desc", JaiI18N.getString("RotateDescriptor4") },
224: { "arg4Desc", JaiI18N.getString("RotateDescriptor5") } };
225:
226: /** The parameter names for the "Rotate" operation. */
227: private static final String[] paramNames = { "xOrigin", "yOrigin",
228: "angle", "interpolation", "backgroundValues" };
229:
230: /** The parameter class types for the "Rotate" operation. */
231: private static final Class[] paramClasses = {
232: java.lang.Float.class, java.lang.Float.class,
233: java.lang.Float.class, javax.media.jai.Interpolation.class,
234: double[].class };
235:
236: /** The parameter default values for the "Rotate" operation. */
237: private static final Object[] paramDefaults = { new Float(0.0F),
238: new Float(0.0F), new Float(0.0F),
239: Interpolation.getInstance(Interpolation.INTERP_NEAREST),
240: new double[] { 0.0 } };
241:
242: /** Constructor. */
243: public RotateDescriptor() {
244: super (resources, 1, paramClasses, paramNames, paramDefaults);
245: }
246:
247: /** Returns <code>true</code> since renderable operation is supported. */
248: public boolean isRenderableSupported() {
249: return true;
250: }
251:
252: /**
253: * Returns an array of <code>PropertyGenerators</code> implementing
254: * property inheritance for the "Rotate" operation.
255: *
256: * @return An array of property generators.
257: */
258: public PropertyGenerator[] getPropertyGenerators() {
259: PropertyGenerator[] pg = new PropertyGenerator[1];
260: pg[0] = new RotatePropertyGenerator();
261: return pg;
262: }
263:
264: /**
265: * Rotates an image.
266: *
267: * <p>Creates a <code>ParameterBlockJAI</code> from all
268: * supplied arguments except <code>hints</code> and invokes
269: * {@link JAI#create(String,ParameterBlock,RenderingHints)}.
270: *
271: * @see JAI
272: * @see ParameterBlockJAI
273: * @see RenderedOp
274: *
275: * @param source0 <code>RenderedImage</code> source 0.
276: * @param xOrigin The X origin to rotate about.
277: * May be <code>null</code>.
278: * @param yOrigin The Y origin to rotate about.
279: * May be <code>null</code>.
280: * @param angle The rotation angle in radians.
281: * May be <code>null</code>.
282: * @param interpolation The interpolation method.
283: * May be <code>null</code>.
284: * @param backgroundValues The user-specified background values.
285: * May be <code>null</code>.
286: * @param hints The <code>RenderingHints</code> to use.
287: * May be <code>null</code>.
288: * @return The <code>RenderedOp</code> destination.
289: * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
290: */
291: public static RenderedOp create(RenderedImage source0,
292: Float xOrigin, Float yOrigin, Float angle,
293: Interpolation interpolation, double[] backgroundValues,
294: RenderingHints hints) {
295: ParameterBlockJAI pb = new ParameterBlockJAI("Rotate",
296: RenderedRegistryMode.MODE_NAME);
297:
298: pb.setSource("source0", source0);
299:
300: pb.setParameter("xOrigin", xOrigin);
301: pb.setParameter("yOrigin", yOrigin);
302: pb.setParameter("angle", angle);
303: pb.setParameter("interpolation", interpolation);
304: pb.setParameter("backgroundValues", backgroundValues);
305:
306: return JAI.create("Rotate", pb, hints);
307: }
308:
309: /**
310: * Rotates an image.
311: *
312: * <p>Creates a <code>ParameterBlockJAI</code> from all
313: * supplied arguments except <code>hints</code> and invokes
314: * {@link JAI#createRenderable(String,ParameterBlock,RenderingHints)}.
315: *
316: * @see JAI
317: * @see ParameterBlockJAI
318: * @see RenderableOp
319: *
320: * @param source0 <code>RenderableImage</code> source 0.
321: * @param xOrigin The X origin to rotate about.
322: * May be <code>null</code>.
323: * @param yOrigin The Y origin to rotate about.
324: * May be <code>null</code>.
325: * @param angle The rotation angle in radians.
326: * May be <code>null</code>.
327: * @param interpolation The interpolation method.
328: * May be <code>null</code>.
329: * @param backgroundValues The user-specified background values.
330: * May be <code>null</code>.
331: * @param hints The <code>RenderingHints</code> to use.
332: * May be <code>null</code>.
333: * @return The <code>RenderableOp</code> destination.
334: * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
335: */
336: public static RenderableOp createRenderable(
337: RenderableImage source0, Float xOrigin, Float yOrigin,
338: Float angle, Interpolation interpolation,
339: double[] backgroundValues, RenderingHints hints) {
340: ParameterBlockJAI pb = new ParameterBlockJAI("Rotate",
341: RenderableRegistryMode.MODE_NAME);
342:
343: pb.setSource("source0", source0);
344:
345: pb.setParameter("xOrigin", xOrigin);
346: pb.setParameter("yOrigin", yOrigin);
347: pb.setParameter("angle", angle);
348: pb.setParameter("interpolation", interpolation);
349: pb.setParameter("backgroundValues", backgroundValues);
350:
351: return JAI.createRenderable("Rotate", pb, hints);
352: }
353: }
|