001: /*
002: * $RCSfile: PiecewiseDescriptor.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 java.awt.RenderingHints;
015: import java.awt.image.RenderedImage;
016: import java.awt.image.renderable.ParameterBlock;
017: import java.awt.image.renderable.RenderableImage;
018: import javax.media.jai.JAI;
019: import javax.media.jai.OperationDescriptorImpl;
020: import javax.media.jai.ParameterBlockJAI;
021: import javax.media.jai.RenderableOp;
022: import javax.media.jai.RenderedOp;
023: import javax.media.jai.registry.RenderableRegistryMode;
024: import javax.media.jai.registry.RenderedRegistryMode;
025:
026: /**
027: * An <code>OperationDescriptor</code> describing the "Piecewise" operation.
028: *
029: * <p> The "Piecewise" operation performs a piecewise linear mapping of the
030: * pixel values of an image. The piecewise linear mapping is described by a
031: * set of breakpoints which are provided as an array of the form
032: * <pre>float breakPoints[N][2][numBreakPoints]</pre> where the value of
033: * <i>N</i> may be either unity or the number of bands in the source image.
034: * If <i>N</i> is unity then the same set of breakpoints will be applied to
035: * all bands in the image. The abscissas of the supplied breakpoints must
036: * be monotonically increasing.
037: *
038: * <p> The pixel values of the destination image are defined by the pseudocode:
039: *
040: * <pre>
041: * if (src[x][y][b] < breakPoints[b][0][0]) {
042: * dst[x][y][b] = breakPoints[b][1][0]);
043: * } else if (src[x][y][b] > breakPoints[b][0][numBreakPoints-1]) {
044: * dst[x][y][b] = breakPoints[b][1][numBreakPoints-1]);
045: * } else {
046: * int i = 0;
047: * while(breakPoints[b][0][i+1] < src[x][y][b]) {
048: * i++;
049: * }
050: * dst[x][y][b] = breakPoints[b][1][i] +
051: * (src[x][y][b] - breakPoints[b][0][i])*
052: * (breakPoints[b][1][i+1] - breakPoints[b][1][i])/
053: * (breakPoints[b][0][i+1] - breakPoints[b][0][i]);
054: * }
055: * </pre>
056: *
057: * <p><table border=1>
058: * <caption>Resource List</caption>
059: * <tr><th>Name</th> <th>Value</th></tr>
060: * <tr><td>GlobalName</td> <td>Piecewise</td></tr>
061: * <tr><td>LocalName</td> <td>Piecewise</td></tr>
062: * <tr><td>Vendor</td> <td>com.sun.media.jai</td></tr>
063: * <tr><td>Description</td> <td>Applies a piecewise pixel value mapping.</td></tr>
064: * <tr><td>DocURL</td> <td>http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/PiecewiseDescriptor.html</td></tr>
065: * <tr><td>Version</td> <td>1.0</td></tr>
066: * <tr><td>arg0Desc</td> <td>The breakpoint array.</td></tr>
067: * </table></p>
068: *
069: * <p><table border=1>
070: * <caption>Parameter List</caption>
071: * <tr><th>Name</th> <th>Class Type</th>
072: * <th>Default Value</th></tr>
073: * <tr><td>breakPoints</td> <td>float[][][]</td>
074: * <td>identity mapping on [0, 255]</td>
075: * </table></p>
076: *
077: * @see java.awt.image.DataBuffer
078: * @see javax.media.jai.ImageLayout
079: * @see javax.media.jai.OperationDescriptor
080: */
081: public class PiecewiseDescriptor extends OperationDescriptorImpl {
082:
083: /**
084: * The resource strings that provide the general documentation
085: * and specify the parameter list for this operation.
086: */
087: private static final String[][] resources = {
088: { "GlobalName", "Piecewise" },
089: { "LocalName", "Piecewise" },
090: { "Vendor", "com.sun.media.jai" },
091: { "Description", JaiI18N.getString("PiecewiseDescriptor0") },
092: {
093: "DocURL",
094: "http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/PiecewiseDescriptor.html" },
095: { "Version", JaiI18N.getString("DescriptorVersion") },
096: { "arg0Desc", "The breakpoint array." } };
097:
098: /** The parameter class list for this operation. */
099: private static final Class[] paramClasses = { float[][][].class };
100:
101: /** The parameter name list for this operation. */
102: private static final String[] paramNames = { "breakPoints" };
103:
104: /** The parameter default value list for this operation. */
105: private static final Object[] paramDefaults = { new float[][][] { {
106: { 0.0f, 255.0f }, { 0.0f, 255.0f } } } };
107:
108: private static final String[] supportedModes = { "rendered",
109: "renderable" };
110:
111: /** Constructor. */
112: public PiecewiseDescriptor() {
113: super (resources, supportedModes, 1, paramNames, paramClasses,
114: paramDefaults, null);
115: }
116:
117: /**
118: * Validates the input source and parameter.
119: *
120: * <p> In addition to the standard checks performed by the
121: * superclass method, this method checks that the number of bands
122: * in "breakPoints" is either 1 or the number of bands in the
123: * source image, the second breakpoint array dimension is 2,
124: * the third dimension is the same for abscissas and ordinates,
125: * and that the absicssas are monotonically increasing.
126: */
127: public boolean validateArguments(String modeName,
128: ParameterBlock args, StringBuffer msg) {
129: if (!super .validateArguments(modeName, args, msg)) {
130: return false;
131: }
132:
133: if (!modeName.equalsIgnoreCase("rendered"))
134: return true;
135:
136: // Get the source and the breakpoint array.
137: RenderedImage src = args.getRenderedSource(0);
138:
139: float[][][] breakPoints = (float[][][]) args
140: .getObjectParameter(0);
141:
142: // Ensure that the number of breakpoint bands is either 1 or
143: // the number of bands in the source image, the second
144: // breakpoint array dimension is 2, the third dimension is
145: // the same for abscissas and ordinates, and that the absicssas
146: // are monotonically increasing.
147: if (breakPoints.length != 1
148: && breakPoints.length != src.getSampleModel()
149: .getNumBands()) {
150: // Number of breakpoints not 1 nor numBands.
151: msg.append(getName() + " "
152: + JaiI18N.getString("PiecewiseDescriptor1"));
153: return false;
154: } else {
155: int numBands = breakPoints.length;
156: for (int b = 0; b < numBands; b++) {
157: if (breakPoints[b].length != 2) {
158: // Second breakpoint dimension not 2.
159: msg
160: .append(getName()
161: + " "
162: + JaiI18N
163: .getString("PiecewiseDescriptor2"));
164: return false;
165: } else if (breakPoints[b][0].length != breakPoints[b][1].length) {
166: // Differing numbers of abscissas and ordinates.
167: msg
168: .append(getName()
169: + " "
170: + JaiI18N
171: .getString("PiecewiseDescriptor3"));
172: return false;
173: }
174: }
175: for (int b = 0; b < numBands; b++) {
176: int count = breakPoints[b][0].length - 1;
177: float[] x = breakPoints[b][0];
178: for (int i = 0; i < count; i++) {
179: if (x[i] >= x[i + 1]) {
180: // Abscissas not monotonically increasing.
181: msg
182: .append(getName()
183: + " "
184: + JaiI18N
185: .getString("PiecewiseDescriptor4"));
186: return false;
187: }
188: }
189: }
190: }
191:
192: return true;
193: }
194:
195: /**
196: * Applies a piecewise pixel value mapping.
197: *
198: * <p>Creates a <code>ParameterBlockJAI</code> from all
199: * supplied arguments except <code>hints</code> and invokes
200: * {@link JAI#create(String,ParameterBlock,RenderingHints)}.
201: *
202: * @see JAI
203: * @see ParameterBlockJAI
204: * @see RenderedOp
205: *
206: * @param source0 <code>RenderedImage</code> source 0.
207: * @param breakPoints The breakpoint array.
208: * May be <code>null</code>.
209: * @param hints The <code>RenderingHints</code> to use.
210: * May be <code>null</code>.
211: * @return The <code>RenderedOp</code> destination.
212: * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
213: */
214: public static RenderedOp create(RenderedImage source0,
215: float[][][] breakPoints, RenderingHints hints) {
216: ParameterBlockJAI pb = new ParameterBlockJAI("Piecewise",
217: RenderedRegistryMode.MODE_NAME);
218:
219: pb.setSource("source0", source0);
220:
221: pb.setParameter("breakPoints", breakPoints);
222:
223: return JAI.create("Piecewise", pb, hints);
224: }
225:
226: /**
227: * Applies a piecewise pixel value mapping.
228: *
229: * <p>Creates a <code>ParameterBlockJAI</code> from all
230: * supplied arguments except <code>hints</code> and invokes
231: * {@link JAI#createRenderable(String,ParameterBlock,RenderingHints)}.
232: *
233: * @see JAI
234: * @see ParameterBlockJAI
235: * @see RenderableOp
236: *
237: * @param source0 <code>RenderableImage</code> source 0.
238: * @param breakPoints The breakpoint array.
239: * May be <code>null</code>.
240: * @param hints The <code>RenderingHints</code> to use.
241: * May be <code>null</code>.
242: * @return The <code>RenderableOp</code> destination.
243: * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
244: */
245: public static RenderableOp createRenderable(
246: RenderableImage source0, float[][][] breakPoints,
247: RenderingHints hints) {
248: ParameterBlockJAI pb = new ParameterBlockJAI("Piecewise",
249: RenderableRegistryMode.MODE_NAME);
250:
251: pb.setSource("source0", source0);
252:
253: pb.setParameter("breakPoints", breakPoints);
254:
255: return JAI.createRenderable("Piecewise", pb, hints);
256: }
257: }
|