1 /* 2 * $RCSfile: WarpDescriptor.java,v $ 3 * 4 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 5 * 6 * Use is subject to license terms. 7 * 8 * $Revision: 1.1 $ 9 * $Date: 2005/02/11 04:57:46 $ 10 * $State: Exp $ 11 */ 12 package com.lightcrafts.mediax.jai.operator; 13 import com.lightcrafts.media.jai.util.PropertyGeneratorImpl; 14 import java.awt.Rectangle; 15 import java.awt.RenderingHints; 16 import java.awt.geom.Point2D; 17 import java.awt.image.RenderedImage; 18 import java.awt.image.renderable.ParameterBlock; 19 import com.lightcrafts.mediax.jai.GeometricOpImage; 20 import com.lightcrafts.mediax.jai.ImageLayout; 21 import com.lightcrafts.mediax.jai.Interpolation; 22 import com.lightcrafts.mediax.jai.InterpolationNearest; 23 import com.lightcrafts.mediax.jai.JAI; 24 import com.lightcrafts.mediax.jai.OperationDescriptorImpl; 25 import com.lightcrafts.mediax.jai.ParameterBlockJAI; 26 import com.lightcrafts.mediax.jai.PlanarImage; 27 import com.lightcrafts.mediax.jai.PropertyGenerator; 28 import com.lightcrafts.mediax.jai.ROI; 29 import com.lightcrafts.mediax.jai.ROIShape; 30 import com.lightcrafts.mediax.jai.RenderedOp; 31 import com.lightcrafts.mediax.jai.Warp; 32 import com.lightcrafts.mediax.jai.registry.RenderedRegistryMode; 33 34 /** 35 * This property generator computes the properties for the operation 36 * "Warp" dynamically. 37 */ 38 class WarpPropertyGenerator extends PropertyGeneratorImpl { 39 40 /** Constructor. */ WarpPropertyGenerator()41 public WarpPropertyGenerator() { 42 super(new String[] {"ROI"}, 43 new Class[] {ROI.class}, 44 new Class[] {RenderedOp.class}); 45 } 46 47 /** 48 * Returns the specified property. 49 * 50 * @param name Property name. 51 * @param opNode Operation node. 52 */ getProperty(String name, Object opNode)53 public Object getProperty(String name, 54 Object opNode) { 55 validate(name, opNode); 56 57 if(opNode instanceof RenderedOp && 58 name.equalsIgnoreCase("roi")) { 59 RenderedOp op = (RenderedOp)opNode; 60 61 ParameterBlock pb = op.getParameterBlock(); 62 63 // Retrieve the rendered source image and its ROI. 64 RenderedImage src = (RenderedImage)pb.getRenderedSource(0); 65 Object property = src.getProperty("ROI"); 66 if (property == null || 67 property.equals(java.awt.Image.UndefinedProperty) || 68 !(property instanceof ROI)) { 69 return java.awt.Image.UndefinedProperty; 70 } 71 72 // Return undefined also if source ROI is empty. 73 ROI srcROI = (ROI)property; 74 if (srcROI.getBounds().isEmpty()) { 75 return java.awt.Image.UndefinedProperty; 76 } 77 78 // Retrieve the Interpolation object. 79 Interpolation interp = (Interpolation)pb.getObjectParameter(1); 80 81 // Determine the effective source bounds. 82 Rectangle srcBounds = null; 83 PlanarImage dst = op.getRendering(); 84 if (dst instanceof GeometricOpImage && 85 ((GeometricOpImage)dst).getBorderExtender() == null) { 86 srcBounds = 87 new Rectangle(src.getMinX() + interp.getLeftPadding(), 88 src.getMinY() + interp.getTopPadding(), 89 src.getWidth() - interp.getWidth() + 1, 90 src.getHeight() - interp.getHeight() + 1); 91 } else { 92 srcBounds = new Rectangle(src.getMinX(), 93 src.getMinY(), 94 src.getWidth(), 95 src.getHeight()); 96 } 97 98 // If necessary, clip the ROI to the effective source bounds. 99 if(!srcBounds.contains(srcROI.getBounds())) { 100 srcROI = srcROI.intersect(new ROIShape(srcBounds)); 101 } 102 103 // Set the nearest neighbor interpolation object. 104 Interpolation interpNN = interp instanceof InterpolationNearest ? 105 interp : 106 Interpolation.getInstance(Interpolation.INTERP_NEAREST); 107 108 // Retrieve the Warp object. 109 Warp warp = (Warp)pb.getObjectParameter(0); 110 111 // Create the warped ROI. 112 ROI dstROI = new ROI(JAI.create("warp", srcROI.getAsImage(), 113 warp, interpNN)); 114 115 // Retrieve the destination bounds. 116 Rectangle dstBounds = op.getBounds(); 117 118 // If necessary, clip the warped ROI to the destination bounds. 119 if(!dstBounds.contains(dstROI.getBounds())) { 120 dstROI = dstROI.intersect(new ROIShape(dstBounds)); 121 } 122 123 // Return the warped and possibly clipped ROI. 124 return dstROI; 125 } 126 127 return java.awt.Image.UndefinedProperty; 128 } 129 } 130 131 /** 132 * An <code>OperationDescriptor</code> describing the "Warp" operation. 133 * 134 * <p> The "Warp" operation performs (possibly filtered) general 135 * warping on an image. 136 * 137 * <p> The destination bounds may be specified by an {@link ImageLayout} 138 * hint provided via a {@link RenderingHints} supplied to the operation. If 139 * no bounds are so specified, then the destination bounds will be set to 140 * the minimum bounding rectangle of the forward mapped source bounds 141 * calculated using {@link Warp#mapSourceRect(Rectangle)} or, failing that, 142 * {@link Warp#mapSourcePoint(Point2D)} applied to the vertices of the 143 * source bounds. If forward mapping by both methods is not viable, then 144 * an approximate affine mapping will be created and used to determine the 145 * destination bounds by forward mapping the source bounds. If this approach 146 * also fails, then the destination bounds will be set to the source bounds. 147 * 148 * <p> "Warp" defines a PropertyGenerator that 149 * performs an identical transformation on the "ROI" property of the 150 * source image, which can be retrieved by calling the 151 * <code>getProperty</code> method with "ROI" as the property name. 152 * 153 * <p> The parameter, "backgroundValues", is defined to 154 * fill the background with the user-specified background 155 * values. These background values will be translated into background 156 * colors by the <code>ColorModel</code> when the image is displayed. 157 * With the default value, <code>{0.0}</code>, of this parameter, 158 * the background pixels are filled with 0s. If the provided array 159 * length is smaller than the number of bands, the first element of 160 * the provided array is used for all the bands. If the provided values 161 * are out of the data range of the destination image, they will be clamped 162 * into the proper range. 163 * 164 * <p> It should be noted that this operation automatically adds a 165 * value of <code>Boolean.TRUE</code> for the 166 * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> to the given 167 * <code>configuration</code> so that the operation is performed 168 * on the pixel values instead of being performed on the indices into 169 * the color map if the source(s) have an <code>IndexColorModel</code>. 170 * This addition will take place only if a value for the 171 * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> has not already been 172 * provided by the user. Note that the <code>configuration</code> Map 173 * is cloned before the new hint is added to it. The operation can be 174 * smart about the value of the <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> 175 * <code>RenderingHints</code>, i.e. while the default value for the 176 * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> is 177 * <code>Boolean.TRUE</code>, in some cases the operator could set the 178 * default. 179 * 180 * <p><table border=1> 181 * <caption>Resource List</caption> 182 * <tr><th>Name</th> <th>Value</th></tr> 183 * <tr><td>GlobalName</td> <td>Warp</td></tr> 184 * <tr><td>LocalName</td> <td>Warp</td></tr> 185 * <tr><td>Vendor</td> <td>com.lightcrafts.media.jai</td></tr> 186 * <tr><td>Description</td> <td>Warps an image according 187 * to a specified Warp object.</td></tr> 188 * <tr><td>DocURL</td> <td>http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/WarpDescriptor.html</td></tr> 189 * <tr><td>Version</td> <td>1.0</td></tr> 190 * <tr><td>arg0Desc</td> <td>The Warp object.</td></tr> 191 * <tr><td>arg1Desc</td> <td>The interpolation method.</td></tr> 192 * </table></p> 193 * 194 * <p><table border=1> 195 * <caption>Parameter List</caption> 196 * <tr><th>Name</th> <th>Class Type</th> 197 * <th>Default Value</th></tr> 198 * <tr><td>warp</td> <td>com.lightcrafts.mediax.jai.Warp</td> 199 * <td>NO_PARAMETER_DEFAULT</td> 200 * <tr><td>interpolation</td> <td>com.lightcrafts.mediax.jai.Interpolation</td> 201 * <td>InterpolationNearest</td> 202 * <tr><td>backgroundValues</td> <td>double[]</td> 203 * <td>{0.0}</td> 204 * </table></p> 205 * 206 * @see com.lightcrafts.mediax.jai.Interpolation 207 * @see com.lightcrafts.mediax.jai.Warp 208 * @see com.lightcrafts.mediax.jai.OperationDescriptor 209 */ 210 public class WarpDescriptor extends OperationDescriptorImpl { 211 212 /** 213 * The resource strings that provide the general documentation and 214 * specify the parameter list for the "Warp" operation. 215 */ 216 private static final String[][] resources = { 217 {"GlobalName", "Warp"}, 218 {"LocalName", "Warp"}, 219 {"Vendor", "com.lightcrafts.media.jai"}, 220 {"Description", JaiI18N.getString("WarpDescriptor0")}, 221 {"DocURL", "http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/WarpDescriptor.html"}, 222 {"Version", JaiI18N.getString("DescriptorVersion")}, 223 {"arg0Desc", JaiI18N.getString("WarpDescriptor1")}, 224 {"arg1Desc", JaiI18N.getString("WarpDescriptor2")}, 225 {"arg2Desc", JaiI18N.getString("WarpDescriptor3")} 226 }; 227 228 /** The parameter names for the "Warp" operation. */ 229 private static final String[] paramNames = { 230 "warp", "interpolation", "backgroundValues" 231 }; 232 233 /** The parameter class types for the "Warp" operation. */ 234 private static final Class[] paramClasses = { 235 com.lightcrafts.mediax.jai.Warp.class, com.lightcrafts.mediax.jai.Interpolation.class, 236 double[].class 237 }; 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 246 /** Constructor. */ WarpDescriptor()247 public WarpDescriptor() { 248 super(resources, 1, paramClasses, paramNames, paramDefaults); 249 } 250 251 /** 252 * Returns an array of <code>PropertyGenerators</code> implementing 253 * property inheritance for the "Warp" operation. 254 * 255 * @return An array of property generators. 256 */ getPropertyGenerators()257 public PropertyGenerator[] getPropertyGenerators() { 258 PropertyGenerator[] pg = new PropertyGenerator[1]; 259 pg[0] = new WarpPropertyGenerator(); 260 return pg; 261 } 262 263 264 /** 265 * Warps an image according to a specified Warp object. 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 warp The warp object. 277 * @param interpolation The interpolation method. 278 * May be <code>null</code>. 279 * @param backgroundValues The user-specified background values. 280 * May be <code>null</code>. 281 * @param hints The <code>RenderingHints</code> to use. 282 * May be <code>null</code>. 283 * @return The <code>RenderedOp</code> destination. 284 * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>. 285 * @throws IllegalArgumentException if <code>warp</code> is <code>null</code>. 286 */ create(RenderedImage source0, Warp warp, Interpolation interpolation, double[] backgroundValues, RenderingHints hints)287 public static RenderedOp create(RenderedImage source0, 288 Warp warp, 289 Interpolation interpolation, 290 double[] backgroundValues, 291 RenderingHints hints) { 292 ParameterBlockJAI pb = 293 new ParameterBlockJAI("Warp", 294 RenderedRegistryMode.MODE_NAME); 295 296 pb.setSource("source0", source0); 297 298 pb.setParameter("warp", warp); 299 pb.setParameter("interpolation", interpolation); 300 pb.setParameter("backgroundValues", backgroundValues); 301 302 return JAI.create("Warp", pb, hints); 303 } 304 } 305