001: /*
002: * $RCSfile: SubsampleBinaryToGrayDescriptor.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:44 $
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.JAI;
022: import javax.media.jai.OpImage;
023: import javax.media.jai.OperationDescriptorImpl;
024: import javax.media.jai.ParameterBlockJAI;
025: import javax.media.jai.PixelAccessor;
026: import javax.media.jai.PropertyGenerator;
027: import javax.media.jai.ROI;
028: import javax.media.jai.ROIShape;
029: import javax.media.jai.RenderableOp;
030: import javax.media.jai.RenderedOp;
031: import javax.media.jai.registry.RenderableRegistryMode;
032: import javax.media.jai.registry.RenderedRegistryMode;
033:
034: /**
035: * This property generator computes the properties for the operation
036: * "SubsampleBinaryToGray" dynamically.
037: */
038: class SubsampleBinaryToGrayPropertyGenerator extends
039: PropertyGeneratorImpl {
040:
041: /** Constructor. */
042: public SubsampleBinaryToGrayPropertyGenerator() {
043: super (new String[] { "ROI" }, new Class[] { ROI.class },
044: new Class[] { RenderedOp.class });
045: }
046:
047: /**
048: * Returns the specified property.
049: *
050: * @param name Property name.
051: * @param opNode Operation node.
052: */
053: public Object getProperty(String name, Object opNode) {
054: validate(name, opNode);
055:
056: if (opNode instanceof RenderedOp
057: && name.equalsIgnoreCase("roi")) {
058: RenderedOp op = (RenderedOp) opNode;
059:
060: ParameterBlock pb = op.getParameterBlock();
061:
062: // Retrieve the rendered source image and its ROI.
063: RenderedImage src = pb.getRenderedSource(0);
064:
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: // Determine the effective source bounds.
075: Rectangle srcBounds = new Rectangle(src.getMinX(), src
076: .getMinY(), src.getWidth(), src.getHeight());
077:
078: // If necessary, clip the ROI to the effective source bounds.
079: if (!srcBounds.contains(srcROI.getBounds())) {
080: srcROI = srcROI.intersect(new ROIShape(srcBounds));
081: }
082:
083: // Retrieve the scale factors and translation values.
084: float sx = pb.getFloatParameter(0);
085: float sy = pb.getFloatParameter(1);
086:
087: // Create an equivalent transform.
088: AffineTransform transform = new AffineTransform(sx, 0.0,
089: 0.0, sy, 0.0, 0.0);
090:
091: // Create the scaled ROI.
092: ROI dstROI = srcROI.transform(transform);
093:
094: // Retrieve the destination bounds.
095: Rectangle dstBounds = op.getBounds();
096:
097: // If necessary, clip the warped ROI to the destination bounds.
098: if (!dstBounds.contains(dstROI.getBounds())) {
099: dstROI = dstROI.intersect(new ROIShape(dstBounds));
100: }
101:
102: // Return the warped and possibly clipped ROI.
103: return dstROI;
104: }
105:
106: return java.awt.Image.UndefinedProperty;
107: }
108: }
109:
110: /**
111: * An <code>OperationDescriptor</code> describing the "SubsampleBinaryToGray"
112: * operation.
113: *
114: * <p> The "SubsampleBinaryToGray" operation collects a Binary image pixels
115: * into a gray scale image. Roughly speaking, each pixel (x, y) of
116: * the destination, is the sum of the source pixel values of the source
117: * pixel matrix of size 1/xScale by 1/yScale. In the noninteger case, the
118: * next bigger inter is used. Thus when xScale = yScale = 1/2.2,
119: * a 3 x 3 pixel matrix into a single destination pixel, resulting in 10
120: * levels [0..9]. The resulting gray values are then normalized to have
121: * gray values in [0..255].
122: *
123: * <p> The source is a Binary image and the result of the operation is
124: * a grayscale image. The scale factors <code> xScale</code>
125: * and <code> yScale</code> must be between (0, 1] and strictly bigger
126: * than 0.
127: *
128: * <p> The destination image is a byte image whose
129: * dimensions are:
130: *
131: * <code><pre>
132: * dstWidth = floor(srcWidth * xScale)
133: * dstHeight = floor(srcHeight * yScale)
134: * </pre></code>
135: *
136: * <p> It may be noted that the minX, minY, width and height hints as
137: * specified through the <code>JAI.KEY_IMAGE_LAYOUT</code> hint in the
138: * <code>RenderingHints</code> object are not honored, as this operator
139: * calculates the destination image bounds itself. The other
140: * <code>ImageLayout</code> hints, like tileWidth and tileHeight,
141: * however, are honored.
142: *
143: * <p> It should be noted that this operation automatically adds a
144: * value of <code>Boolean.FALSE</code> for the
145: * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> to the given
146: * <code>configuration</code> since this operation is capable of
147: * dealing correctly with a source that has an <code>IndexColorModel</code>,
148: * without having to expand the <code>IndexColorModel</code>.
149: * This addition will take place only if a value for the
150: * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> has not already been
151: * provided by the user. Note that the <code>configuration</code> Map
152: * is cloned before the new hint is added to it.
153: *
154: * <p> Specifying a scale factor of greater than 1 or less than 0
155: * will cause an exception. To scale image sizes up or down,
156: * see <code>Scale</code> operator.
157: *
158: * <p><table border=1>
159: * <caption>Resource List</caption>
160: * <tr><th>Name</th> <th>Value</th></tr>
161: * <tr><td>GlobalName</td> <td>SubsampleBinaryToGray</td></tr>
162: * <tr><td>LocalName</td> <td>SubsampleBinaryToGray</td></tr>
163: * <tr><td>Vendor</td> <td>com.sun.media.jai</td></tr>
164: * <tr><td>Description</td> <td>Subsamples a binary image into a gray scale image.</td></tr>
165: * <tr><td>DocURL</td> <td>http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/SubsampleBinaryToGrayDescriptor.html</td></tr>
166: * <tr><td>Version</td> <td>1.0</td></tr>
167: * <tr><td>arg0Desc</td> <td>The X scale factor.</td></tr>
168: * <tr><td>arg1Desc</td> <td>The Y scale factor.</td></tr>
169: * </table></p>
170: *
171: * <p><table border=1>
172: * <caption>Parameter List</caption>
173: * <tr><th>Name</th> <th>Class Type</th>
174: * <th>Default Value</th></tr>
175: * <tr><td>xScale</td> <td>java.lang.Float</td>
176: * <td>1.0F</td>
177: * <tr><td>yScale</td> <td>java.lang.Float</td>
178: * <td>1.0F</td>
179: * </table></p>
180: *
181: * @see javax.media.jai.OperationDescriptor
182: *
183: * @since JAI 1.1
184: */
185: public class SubsampleBinaryToGrayDescriptor extends
186: OperationDescriptorImpl {
187:
188: /**
189: * The resource strings that provide the general documentation
190: * and specify the parameter list for this operation.
191: */
192: private static final String[][] resources = {
193: { "GlobalName", "SubsampleBinaryToGray" },
194: { "LocalName", "SubsampleBinaryToGray" },
195: { "Vendor", "com.sun.media.jai" },
196: { "Description",
197: JaiI18N.getString("SubsampleBinaryToGray0") },
198: {
199: "DocURL",
200: "http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/SubsampleBinaryToGrayDescriptor.html" },
201: { "Version", JaiI18N.getString("DescriptorVersion") },
202: { "arg0Desc", JaiI18N.getString("SubsampleBinaryToGray1") },
203: { "arg1Desc", JaiI18N.getString("SubsampleBinaryToGray2") } };
204:
205: /** The parameter class list for this operation. */
206: private static final Class[] paramClasses = {
207: java.lang.Float.class, java.lang.Float.class };
208:
209: /** The parameter name list for this operation. */
210: private static final String[] paramNames = { "xScale", "yScale" };
211:
212: /** The parameter default value list for this operation. */
213: private static final Object[] paramDefaults = { new Float(1.0F),
214: new Float(1.0F) };
215:
216: /** Constructor. */
217: public SubsampleBinaryToGrayDescriptor() {
218: super (resources, 1, paramClasses, paramNames, paramDefaults);
219: }
220:
221: /** Returns <code>true</code> since renderable operation is supported. */
222: public boolean isRenderableSupported() {
223: return true;
224: }
225:
226: /**
227: * Returns an array of <code>PropertyGenerators</code> implementing
228: * property inheritance for the "SubsampleBinaryToGray" operation.
229: *
230: * @return An array of property generators.
231: */
232: public PropertyGenerator[] getPropertyGenerators() {
233: PropertyGenerator[] pg = new PropertyGenerator[1];
234: pg[0] = new SubsampleBinaryToGrayPropertyGenerator();
235: return pg;
236: }
237:
238: /**
239: * Validates the input parameters.
240: *
241: * <p> In addition to the standard checks performed by the
242: * superclass method, this method checks that "xScale" and "yScale"
243: * are both greater than 0 and less than or equal to 1.
244: *
245: * <p> The src image must be a binary, a one band, one bit
246: * per pixel image with a <code> MultiPixelPackedSampleModel</code>.
247: */
248: protected boolean validateParameters(ParameterBlock args,
249: StringBuffer msg) {
250: if (!super .validateParameters(args, msg)) {
251: return false;
252: }
253:
254: // Checks for source to be Binary and Dest Grayscale
255: // to be in the RIF
256:
257: RenderedImage src = (RenderedImage) args.getSource(0);
258:
259: PixelAccessor srcPA = new PixelAccessor(src);
260: if (!srcPA.isPacked || !srcPA.isMultiPixelPackedSM) {
261: msg.append(getName() + " "
262: + JaiI18N.getString("SubsampleBinaryToGray3"));
263: return false;
264: }
265:
266: float xScale = args.getFloatParameter(0);
267: float yScale = args.getFloatParameter(1);
268: if (xScale <= 0.0F || yScale <= 0.0F || xScale > 1.0F
269: || yScale > 1.0F) {
270: msg.append(getName() + " "
271: + JaiI18N.getString("SubsampleBinaryToGray1")
272: + " or "
273: + JaiI18N.getString("SubsampleBinaryToGray2"));
274: return false;
275: }
276:
277: return true;
278: }
279:
280: /**
281: * Returns the minimum legal value of a specified numeric parameter
282: * for this operation.
283: *
284: * <p> For the minimum value of "xScale" and "yScale", this method
285: * returns 0. However, the scale factors must be a positive floating
286: * number and can not be 0.
287: */
288: public Number getParamMinValue(int index) {
289: if (index == 0 || index == 1) {
290: return new Float(0.0F);
291: } else {
292: throw new ArrayIndexOutOfBoundsException();
293: }
294: }
295:
296: /**
297: * To subsamples binary image to gray; reverse of dithering.
298: *
299: * <p>Creates a <code>ParameterBlockJAI</code> from all
300: * supplied arguments except <code>hints</code> and invokes
301: * {@link JAI#create(String,ParameterBlock,RenderingHints)}.
302: *
303: * @see JAI
304: * @see ParameterBlockJAI
305: * @see RenderedOp
306: *
307: * @param source0 <code>RenderedImage</code> source 0.
308: * @param xScale scaleX must be between 0 and 1, excluding 0.
309: * May be <code>null</code>.
310: * @param yScale scaleY must be between 0 and 1, excluding 0.
311: * May be <code>null</code>.
312: * @param hints The <code>RenderingHints</code> to use.
313: * May be <code>null</code>.
314: * @return The <code>RenderedOp</code> destination.
315: * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
316: */
317: public static RenderedOp create(RenderedImage source0,
318: Float xScale, Float yScale, RenderingHints hints) {
319: ParameterBlockJAI pb = new ParameterBlockJAI(
320: "SubsampleBinaryToGray", RenderedRegistryMode.MODE_NAME);
321:
322: pb.setSource("source0", source0);
323:
324: pb.setParameter("xScale", xScale);
325: pb.setParameter("yScale", yScale);
326:
327: return JAI.create("SubsampleBinaryToGray", pb, hints);
328: }
329:
330: /**
331: * To subsamples binary image to gray; reverse of dithering.
332: *
333: * <p>Creates a <code>ParameterBlockJAI</code> from all
334: * supplied arguments except <code>hints</code> and invokes
335: * {@link JAI#createRenderable(String,ParameterBlock,RenderingHints)}.
336: *
337: * @see JAI
338: * @see ParameterBlockJAI
339: * @see RenderableOp
340: *
341: * @param source0 <code>RenderableImage</code> source 0.
342: * @param xScale scaleX must be between 0 and 1, excluding 0.
343: * May be <code>null</code>.
344: * @param yScale scaleY must be between 0 and 1, excluding 0.
345: * May be <code>null</code>.
346: * @param hints The <code>RenderingHints</code> to use.
347: * May be <code>null</code>.
348: * @return The <code>RenderableOp</code> destination.
349: * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
350: */
351: public static RenderableOp createRenderable(
352: RenderableImage source0, Float xScale, Float yScale,
353: RenderingHints hints) {
354: ParameterBlockJAI pb = new ParameterBlockJAI(
355: "SubsampleBinaryToGray",
356: RenderableRegistryMode.MODE_NAME);
357:
358: pb.setSource("source0", source0);
359:
360: pb.setParameter("xScale", xScale);
361: pb.setParameter("yScale", yScale);
362:
363: return JAI.createRenderable("SubsampleBinaryToGray", pb, hints);
364: }
365: }
|