1 /* 2 * $RCSfile: PiecewiseDescriptor.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:43 $ 10 * $State: Exp $ 11 */ 12 package com.lightcrafts.mediax.jai.operator; 13 14 import java.awt.RenderingHints; 15 import java.awt.image.RenderedImage; 16 import java.awt.image.renderable.ParameterBlock; 17 import java.awt.image.renderable.RenderableImage; 18 import com.lightcrafts.mediax.jai.JAI; 19 import com.lightcrafts.mediax.jai.OperationDescriptorImpl; 20 import com.lightcrafts.mediax.jai.ParameterBlockJAI; 21 import com.lightcrafts.mediax.jai.RenderableOp; 22 import com.lightcrafts.mediax.jai.RenderedOp; 23 import com.lightcrafts.mediax.jai.registry.RenderableRegistryMode; 24 import com.lightcrafts.mediax.jai.registry.RenderedRegistryMode; 25 26 /** 27 * An <code>OperationDescriptor</code> describing the "Piecewise" operation. 28 * 29 * <p> The "Piecewise" operation performs a piecewise linear mapping of the 30 * pixel values of an image. The piecewise linear mapping is described by a 31 * set of breakpoints which are provided as an array of the form 32 * <pre>float breakPoints[N][2][numBreakPoints]</pre> where the value of 33 * <i>N</i> may be either unity or the number of bands in the source image. 34 * If <i>N</i> is unity then the same set of breakpoints will be applied to 35 * all bands in the image. The abscissas of the supplied breakpoints must 36 * be monotonically increasing. 37 * 38 * <p> The pixel values of the destination image are defined by the pseudocode: 39 * 40 * <pre> 41 * if (src[x][y][b] < breakPoints[b][0][0]) { 42 * dst[x][y][b] = breakPoints[b][1][0]); 43 * } else if (src[x][y][b] > breakPoints[b][0][numBreakPoints-1]) { 44 * dst[x][y][b] = breakPoints[b][1][numBreakPoints-1]); 45 * } else { 46 * int i = 0; 47 * while(breakPoints[b][0][i+1] < src[x][y][b]) { 48 * i++; 49 * } 50 * dst[x][y][b] = breakPoints[b][1][i] + 51 * (src[x][y][b] - breakPoints[b][0][i])* 52 * (breakPoints[b][1][i+1] - breakPoints[b][1][i])/ 53 * (breakPoints[b][0][i+1] - breakPoints[b][0][i]); 54 * } 55 * </pre> 56 * 57 * <p><table border=1> 58 * <caption>Resource List</caption> 59 * <tr><th>Name</th> <th>Value</th></tr> 60 * <tr><td>GlobalName</td> <td>Piecewise</td></tr> 61 * <tr><td>LocalName</td> <td>Piecewise</td></tr> 62 * <tr><td>Vendor</td> <td>com.lightcrafts.media.jai</td></tr> 63 * <tr><td>Description</td> <td>Applies a piecewise pixel value mapping.</td></tr> 64 * <tr><td>DocURL</td> <td>http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/PiecewiseDescriptor.html</td></tr> 65 * <tr><td>Version</td> <td>1.0</td></tr> 66 * <tr><td>arg0Desc</td> <td>The breakpoint array.</td></tr> 67 * </table></p> 68 * 69 * <p><table border=1> 70 * <caption>Parameter List</caption> 71 * <tr><th>Name</th> <th>Class Type</th> 72 * <th>Default Value</th></tr> 73 * <tr><td>breakPoints</td> <td>float[][][]</td> 74 * <td>identity mapping on [0, 255]</td> 75 * </table></p> 76 * 77 * @see java.awt.image.DataBuffer 78 * @see com.lightcrafts.mediax.jai.ImageLayout 79 * @see com.lightcrafts.mediax.jai.OperationDescriptor 80 */ 81 public class PiecewiseDescriptor extends OperationDescriptorImpl { 82 83 /** 84 * The resource strings that provide the general documentation 85 * and specify the parameter list for this operation. 86 */ 87 private static final String[][] resources = { 88 {"GlobalName", "Piecewise"}, 89 {"LocalName", "Piecewise"}, 90 {"Vendor", "com.lightcrafts.media.jai"}, 91 {"Description", JaiI18N.getString("PiecewiseDescriptor0")}, 92 {"DocURL", "http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/PiecewiseDescriptor.html"}, 93 {"Version", JaiI18N.getString("DescriptorVersion")}, 94 {"arg0Desc", "The breakpoint array."} 95 }; 96 97 /** The parameter class list for this operation. */ 98 private static final Class[] paramClasses = { 99 float[][][].class 100 }; 101 102 /** The parameter name list for this operation. */ 103 private static final String[] paramNames = { 104 "breakPoints" 105 }; 106 107 /** The parameter default value list for this operation. */ 108 private static final Object[] paramDefaults = { 109 new float[][][]{{{0.0f, 255.0f}, {0.0f, 255.0f}}} 110 }; 111 112 private static final String[] supportedModes = { 113 "rendered", 114 "renderable" 115 }; 116 117 /** Constructor. */ PiecewiseDescriptor()118 public PiecewiseDescriptor() { 119 super(resources, supportedModes, 1, 120 paramNames, paramClasses, paramDefaults, null); 121 } 122 123 /** 124 * Validates the input source and parameter. 125 * 126 * <p> In addition to the standard checks performed by the 127 * superclass method, this method checks that the number of bands 128 * in "breakPoints" is either 1 or the number of bands in the 129 * source image, the second breakpoint array dimension is 2, 130 * the third dimension is the same for abscissas and ordinates, 131 * and that the absicssas are monotonically increasing. 132 */ validateArguments(String modeName, ParameterBlock args, StringBuffer msg)133 public boolean validateArguments(String modeName, 134 ParameterBlock args, 135 StringBuffer msg) { 136 if (!super.validateArguments(modeName, args, msg)) { 137 return false; 138 } 139 140 if (!modeName.equalsIgnoreCase("rendered")) 141 return true; 142 143 // Get the source and the breakpoint array. 144 RenderedImage src = args.getRenderedSource(0); 145 146 float[][][] breakPoints = 147 (float[][][])args.getObjectParameter(0); 148 149 // Ensure that the number of breakpoint bands is either 1 or 150 // the number of bands in the source image, the second 151 // breakpoint array dimension is 2, the third dimension is 152 // the same for abscissas and ordinates, and that the absicssas 153 // are monotonically increasing. 154 if (breakPoints.length != 1 && 155 breakPoints.length != src.getSampleModel().getNumBands()) { 156 // Number of breakpoints not 1 nor numBands. 157 msg.append(getName() + " " + 158 JaiI18N.getString("PiecewiseDescriptor1")); 159 return false; 160 } else { 161 int numBands = breakPoints.length; 162 for (int b = 0; b < numBands; b++) { 163 if (breakPoints[b].length != 2) { 164 // Second breakpoint dimension not 2. 165 msg.append(getName() + " " + 166 JaiI18N.getString("PiecewiseDescriptor2")); 167 return false; 168 } else if (breakPoints[b][0].length != 169 breakPoints[b][1].length) { 170 // Differing numbers of abscissas and ordinates. 171 msg.append(getName() + " " + 172 JaiI18N.getString("PiecewiseDescriptor3")); 173 return false; 174 } 175 } 176 for (int b = 0; b < numBands; b++) { 177 int count = breakPoints[b][0].length - 1; 178 float[] x = breakPoints[b][0]; 179 for (int i = 0; i < count; i++) { 180 if (x[i] >= x[i+1]) { 181 // Abscissas not monotonically increasing. 182 msg.append(getName() + " " + 183 JaiI18N.getString("PiecewiseDescriptor4")); 184 return false; 185 } 186 } 187 } 188 } 189 190 return true; 191 } 192 193 194 /** 195 * Applies a piecewise pixel value mapping. 196 * 197 * <p>Creates a <code>ParameterBlockJAI</code> from all 198 * supplied arguments except <code>hints</code> and invokes 199 * {@link JAI#create(String,ParameterBlock,RenderingHints)}. 200 * 201 * @see JAI 202 * @see ParameterBlockJAI 203 * @see RenderedOp 204 * 205 * @param source0 <code>RenderedImage</code> source 0. 206 * @param breakPoints The breakpoint array. 207 * May be <code>null</code>. 208 * @param hints The <code>RenderingHints</code> to use. 209 * May be <code>null</code>. 210 * @return The <code>RenderedOp</code> destination. 211 * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>. 212 */ create(RenderedImage source0, float[][][] breakPoints, RenderingHints hints)213 public static RenderedOp create(RenderedImage source0, 214 float[][][] breakPoints, 215 RenderingHints hints) { 216 ParameterBlockJAI pb = 217 new ParameterBlockJAI("Piecewise", 218 RenderedRegistryMode.MODE_NAME); 219 220 pb.setSource("source0", source0); 221 222 pb.setParameter("breakPoints", breakPoints); 223 224 return JAI.create("Piecewise", pb, hints); 225 } 226 227 /** 228 * Applies a piecewise pixel value mapping. 229 * 230 * <p>Creates a <code>ParameterBlockJAI</code> from all 231 * supplied arguments except <code>hints</code> and invokes 232 * {@link JAI#createRenderable(String,ParameterBlock,RenderingHints)}. 233 * 234 * @see JAI 235 * @see ParameterBlockJAI 236 * @see RenderableOp 237 * 238 * @param source0 <code>RenderableImage</code> source 0. 239 * @param breakPoints The breakpoint array. 240 * May be <code>null</code>. 241 * @param hints The <code>RenderingHints</code> to use. 242 * May be <code>null</code>. 243 * @return The <code>RenderableOp</code> destination. 244 * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>. 245 */ createRenderable(RenderableImage source0, float[][][] breakPoints, RenderingHints hints)246 public static RenderableOp createRenderable(RenderableImage source0, 247 float[][][] breakPoints, 248 RenderingHints hints) { 249 ParameterBlockJAI pb = 250 new ParameterBlockJAI("Piecewise", 251 RenderableRegistryMode.MODE_NAME); 252 253 pb.setSource("source0", source0); 254 255 pb.setParameter("breakPoints", breakPoints); 256 257 return JAI.createRenderable("Piecewise", pb, hints); 258 } 259 } 260