001: /*
002: * $RCSfile: BoxFilterDescriptor.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.2 $
009: * $Date: 2007/08/27 21:33:23 $
010: * $State: Exp $
011: */
012: package javax.media.jai.operator;
013:
014: import com.sun.media.jai.util.AreaOpPropertyGenerator;
015: import java.awt.RenderingHints;
016: import java.awt.image.RenderedImage;
017: import java.awt.image.renderable.ParameterBlock;
018: import javax.media.jai.JAI;
019: import javax.media.jai.OperationDescriptorImpl;
020: import javax.media.jai.ParameterBlockJAI;
021: import javax.media.jai.PropertyGenerator;
022: import javax.media.jai.RenderedOp;
023: import javax.media.jai.registry.RenderedRegistryMode;
024:
025: /**
026: * An <code>OperationDescriptor</code> describing the "BoxFilter" operation.
027: *
028: * <p> The "BoxFilter" operation determines the intensity of a pixel
029: * in an image by averaging the source pixels within a rectangular
030: * area around the pixel. This is a special case of the convolution
031: * operation, in which each source pixel contributes the same weight
032: * to the destination pixel. The pixel values of the destination image
033: * are defined by the pseudocode:
034: *
035: * <pre>
036: * int count = width * height; // # of pixels in the box
037: * for (int b = 0; b < numBands; b++) {
038: * int total = 0;
039: * for (int j = -yKey; j < -yKey + height; j++) {
040: * for (int i = -xKey; i < -xKey + width; i++) {
041: * total += src[x+i][y+j][b];
042: * }
043: * }
044: * dst[x][y][b] = (total + count/2) / count; // round
045: * }
046: * </pre>
047: *
048: * <p> Convolution, like any neighborhood operation, leaves a band of
049: * pixels around the edges undefined. For example, for a 3x3 kernel
050: * only four kernel elements and four source pixels contribute to the
051: * convolution pixel at the corners of the source image. Pixels that
052: * do not allow the full kernel to be applied to the source are not
053: * included in the destination image. A "Border" operation may be used
054: * to add an appropriate border to the source image in order to avoid
055: * shrinkage of the image boundaries.
056: *
057: * <p> The kernel may not be bigger in any dimension than the image data.
058: *
059: * <p><table border=1>
060: * <caption>Resource List</caption>
061: * <tr><th>Name</th> <th>Value</th></tr>
062: * <tr><td>GlobalName</td> <td>BoxFilter</td></tr>
063: * <tr><td>LocalName</td> <td>BoxFilter</td></tr>
064: * <tr><td>Vendor</td> <td>com.sun.media.jai</td></tr>
065: * <tr><td>Description</td> <td>Performs special case convolution where each
066: * source pixel contributes equally to the
067: * intensity of the destination pixel.</td></tr>
068: * <tr><td>DocURL</td> <td>http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/BoxFilterDescriptor.html</td></tr>
069: * <tr><td>Version</td> <td>1.0</td></tr>
070: * <tr><td>arg0Desc</td> <td>The width of the box.</td></tr>
071: * <tr><td>arg1Desc</td> <td>The height of the box.</td></tr>
072: * <tr><td>arg2Desc</td> <td>The X position of the key element.</td></tr>
073: * <tr><td>arg3Desc</td> <td>The Y position of the key element.</td></tr>
074: * </table></p>
075: *
076: * <p><table border=1>
077: * <caption>Parameter List</caption>
078: * <tr><th>Name</th> <th>Class Type</th>
079: * <th>Default Value</th></tr>
080: * <tr><td>width</td> <td>java.lang.Integer</td>
081: * <td>3</td>
082: * <tr><td>height</td> <td>java.lang.Integer</td>
083: * <td>width</td>
084: * <tr><td>xKey</td> <td>java.lang.Integer</td>
085: * <td>width/2</td>
086: * <tr><td>yKey</td> <td>java.lang.Integer</td>
087: * <td>height/2</td>
088: * </table></p>
089: *
090: * @see javax.media.jai.OperationDescriptor
091: */
092: public class BoxFilterDescriptor extends OperationDescriptorImpl {
093:
094: /**
095: * The resource strings that provide the general documentation
096: * and specify the parameter list for this operation.
097: */
098: private static final String[][] resources = {
099: { "GlobalName", "BoxFilter" },
100: { "LocalName", "BoxFilter" },
101: { "Vendor", "com.sun.media.jai" },
102: { "Description", JaiI18N.getString("BoxFilterDescriptor0") },
103: {
104: "DocURL",
105: "http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/BoxFilterDescriptor.html" },
106: { "Version", JaiI18N.getString("DescriptorVersion") },
107: { "arg0Desc", JaiI18N.getString("BoxFilterDescriptor1") },
108: { "arg1Desc", JaiI18N.getString("BoxFilterDescriptor2") },
109: { "arg2Desc", JaiI18N.getString("BoxFilterDescriptor3") },
110: { "arg3Desc", JaiI18N.getString("BoxFilterDescriptor4") } };
111:
112: /** The parameter class list for this operation. */
113: private static final Class[] paramClasses = {
114: java.lang.Integer.class, java.lang.Integer.class,
115: java.lang.Integer.class, java.lang.Integer.class };
116:
117: /** The parameter name list for this operation. */
118: private static final String[] paramNames = { "width", "height",
119: "xKey", "yKey" };
120:
121: /** The parameter default value list for this operation. */
122: private static final Object[] paramDefaults = { new Integer(3),
123: null, null, null };
124:
125: /** Constructor. */
126: public BoxFilterDescriptor() {
127: super (resources, 1, paramClasses, paramNames, paramDefaults);
128: }
129:
130: /**
131: * Returns the minimum legal value of a specified numeric parameter
132: * for this operation.
133: */
134: public Number getParamMinValue(int index) {
135: if (index == 0 || index == 1) {
136: return new Integer(1);
137: } else if (index == 2 || index == 3) {
138: return new Integer(Integer.MIN_VALUE);
139: } else {
140: throw new ArrayIndexOutOfBoundsException();
141: }
142: }
143:
144: protected boolean validateParameters(ParameterBlock args,
145: StringBuffer msg) {
146: // The number of parameters supplied.
147: int argNumParams = args.getNumParameters();
148:
149: if (argNumParams == 0) {
150: // set width to default
151: args.add(paramDefaults[0]);
152: argNumParams++;
153: }
154:
155: if (argNumParams > 0
156: && args.getObjectParameter(0) instanceof Integer) {
157: Object obj;
158: if (argNumParams < 2) {
159: obj = args.getObjectParameter(0);
160: if (obj instanceof Integer) {
161: // set height to width
162: args.add(obj);
163: }
164: }
165:
166: if (argNumParams < 3) {
167: obj = args.getObjectParameter(0);
168: if (obj instanceof Integer) {
169: // set xKey to width/2
170: args.add(((Integer) obj).intValue() / 2);
171: }
172: }
173:
174: if (argNumParams < 4) {
175: obj = args.getObjectParameter(1);
176: if (obj instanceof Integer) {
177: // set yKey to height/2
178: args.add(((Integer) obj).intValue() / 2);
179: }
180: }
181: }
182:
183: return super .validateParameters(args, msg);
184: }
185:
186: /**
187: * Returns an array of <code>PropertyGenerators</code> implementing
188: * property inheritance for the "BoxFilter" operation.
189: *
190: * @return An array of property generators.
191: */
192: public PropertyGenerator[] getPropertyGenerators() {
193: PropertyGenerator[] pg = new PropertyGenerator[1];
194: pg[0] = new AreaOpPropertyGenerator();
195: return pg;
196: }
197:
198: /**
199: * Performs special case convolution where each source pixel contributes equally to the intensity of the destination pixel.
200: *
201: * <p>Creates a <code>ParameterBlockJAI</code> from all
202: * supplied arguments except <code>hints</code> and invokes
203: * {@link JAI#create(String,ParameterBlock,RenderingHints)}.
204: *
205: * @see JAI
206: * @see ParameterBlockJAI
207: * @see RenderedOp
208: *
209: * @param source0 <code>RenderedImage</code> source 0.
210: * @param width The width of the box.
211: * May be <code>null</code>.
212: * @param height The height of the box.
213: * May be <code>null</code>.
214: * @param xKey The X position of the key element.
215: * May be <code>null</code>.
216: * @param yKey The Y position of the key element.
217: * May be <code>null</code>.
218: * @param hints The <code>RenderingHints</code> to use.
219: * May be <code>null</code>.
220: * @return The <code>RenderedOp</code> destination.
221: * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
222: */
223: public static RenderedOp create(RenderedImage source0,
224: Integer width, Integer height, Integer xKey, Integer yKey,
225: RenderingHints hints) {
226: ParameterBlockJAI pb = new ParameterBlockJAI("BoxFilter",
227: RenderedRegistryMode.MODE_NAME);
228:
229: pb.setSource("source0", source0);
230:
231: pb.setParameter("width", width);
232: pb.setParameter("height", height);
233: pb.setParameter("xKey", xKey);
234: pb.setParameter("yKey", yKey);
235:
236: return JAI.create("BoxFilter", pb, hints);
237: }
238: }
|