001: /*
002: * $RCSfile: OrderedDitherDescriptor.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:41 $
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.SampleModel;
017: import java.awt.image.renderable.ParameterBlock;
018: import javax.media.jai.ColorCube;
019: import javax.media.jai.JAI;
020: import javax.media.jai.KernelJAI;
021: import javax.media.jai.OperationDescriptorImpl;
022: import javax.media.jai.ParameterBlockJAI;
023: import javax.media.jai.ROI;
024: import javax.media.jai.RenderedOp;
025: import javax.media.jai.registry.RenderedRegistryMode;
026:
027: /**
028: * An <code>OperationDescriptor</code> describing the "OrderedDither"
029: * operation.
030: *
031: * <p> The "OrderedDither" operation performs color quantization by
032: * finding the nearest color to each pixel in a supplied color cube
033: * and "shifting" the resulting index value by a pseudo-random amount
034: * determined by the values of a supplied dither mask.
035: *
036: * <p> The dither mask is supplied as an array of <code>KernelJAI</code>
037: * objects the length of which must equal the number of bands in the
038: * image. Each element of the array is a <code>KernelJAI</code> object
039: * which represents the dither mask matrix for the corresponding band.
040: * All <code>KernelJAI</code> objects in the array must have the same
041: * dimensions and contain floating point values greater than or equal
042: * to 0.0 and less than or equal to 1.0.
043: *
044: * <p> For all integral data types, the source image samples are presumed
045: * to occupy the full range of the respective types. For floating point data
046: * types it is assumed that the data samples have been scaled to the range
047: * [0.0, 1.0].
048: *
049: * <p><table border=1>
050: * <caption>Resource List</caption>
051: * <tr><th>Name</th> <th>Value</th></tr>
052: * <tr><td>GlobalName</td> <td>OrderedDither</td></tr>
053: * <tr><td>LocalName</td> <td>OrderedDither</td></tr>
054: * <tr><td>Vendor</td> <td>com.sun.media.jai</td></tr>
055: * <tr><td>Description</td> <td>Performs ordered dither color quantization
056: * using a specified color cube and
057: * dither mask.</td></tr>
058: * <tr><td>DocURL</td> <td>http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/OrderedDitherDescriptor.html</td></tr>
059: * <tr><td>Version</td> <td>1.0</td></tr>
060: * <tr><td>arg0Desc</td> <td>The color cube.</td></tr>
061: * <tr><td>arg1Desc</td> <td>The dither mask.</td></tr>
062: * </table></p>
063: *
064: * <p><table border=1>
065: * <caption>Parameter List</caption>
066: * <tr><th>Name</th> <th>Class Type</th>
067: * <th>Default Value</th></tr>
068: * <tr><td>colorMap</td> <td>javax.media.jai.ColorCube</td>
069: * <td>ColorCube.BYTE_496</td>
070: * <tr><td>ditherMask</td> <td>javax.media.jai.KernelJAI[]</td>
071: * <td>KernelJAI.DITHER_MASK_443</td>
072: * </table></p>
073: *
074: * @see javax.media.jai.KernelJAI
075: * @see javax.media.jai.ColorCube
076: * @see javax.media.jai.OperationDescriptor
077: */
078: public class OrderedDitherDescriptor extends OperationDescriptorImpl {
079:
080: /**
081: * The resource strings that provide the general documentation
082: * and specify the parameter list for this operation.
083: */
084: private static final String[][] resources = {
085: { "GlobalName", "OrderedDither" },
086: { "LocalName", "OrderedDither" },
087: { "Vendor", "com.sun.media.jai" },
088: { "Description",
089: JaiI18N.getString("OrderedDitherDescriptor0") },
090: {
091: "DocURL",
092: "http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/OrderedDitherDescriptor.html" },
093: { "Version", JaiI18N.getString("DescriptorVersion") },
094: { "arg0Desc", JaiI18N.getString("OrderedDitherDescriptor1") },
095: { "arg1Desc", JaiI18N.getString("OrderedDitherDescriptor2") } };
096:
097: /** The parameter names for the "OrderedDither" operation. */
098: private static final String[] paramNames = { "colorMap",
099: "ditherMask" };
100:
101: /** The parameter class types for the "OrderedDither" operation. */
102: private static final Class[] paramClasses = {
103: javax.media.jai.ColorCube.class,
104: javax.media.jai.KernelJAI[].class };
105:
106: /** The parameter default values for the "OrderedDither" operation. */
107: private static final Object[] paramDefaults = { ColorCube.BYTE_496,
108: KernelJAI.DITHER_MASK_443 };
109:
110: private static final String[] supportedModes = { "rendered" };
111:
112: /**
113: * Method to check the validity of the color map parameter. The supplied
114: * color cube must have the same data type and number of bands as the
115: * source image.
116: *
117: * @param sourceImage The source image of the operation.
118: * @param colorMap The color cube.
119: * @param msg The buffer to which messages should be appended.
120: *
121: * @return Whether the color map is valid.
122: */
123: private static boolean isValidColorMap(RenderedImage sourceImage,
124: ColorCube colorMap, StringBuffer msg) {
125: SampleModel srcSampleModel = sourceImage.getSampleModel();
126:
127: if (colorMap.getDataType() != srcSampleModel.getTransferType()) {
128: msg.append(JaiI18N.getString("OrderedDitherDescriptor3"));
129: return false;
130: } else if (colorMap.getNumBands() != srcSampleModel
131: .getNumBands()) {
132: msg.append(JaiI18N.getString("OrderedDitherDescriptor4"));
133: return false;
134: }
135:
136: return true;
137: }
138:
139: /**
140: * Method to check the validity of the dither mask parameter. The dither
141: * mask is an array of <code>KernelJAI</code> objects wherein the number
142: * of elements in the array must equal the number of bands in the source
143: * image. Furthermore all kernels in the array must have the same width
144: * and height. Finally all data elements of all kernels must be greater
145: * than or equal to zero and less than or equal to unity.
146: *
147: * @param sourceImage The source image of the operation.
148: * @param ditherMask The dither mask.
149: * @param msg The buffer to which messages should be appended.
150: *
151: * @return Whether the dither mask is valid.
152: */
153: private static boolean isValidDitherMask(RenderedImage sourceImage,
154: KernelJAI[] ditherMask, StringBuffer msg) {
155: if (ditherMask.length != sourceImage.getSampleModel()
156: .getNumBands()) {
157: msg.append(JaiI18N.getString("OrderedDitherDescriptor5"));
158: return false;
159: }
160:
161: int maskWidth = ditherMask[0].getWidth();
162: int maskHeight = ditherMask[0].getHeight();
163: for (int band = 0; band < ditherMask.length; band++) {
164: if (ditherMask[band].getWidth() != maskWidth
165: || ditherMask[band].getHeight() != maskHeight) {
166: msg.append(JaiI18N
167: .getString("OrderedDitherDescriptor6"));
168: return false;
169: }
170: float[] kernelData = ditherMask[band].getKernelData();
171: for (int i = 0; i < kernelData.length; i++) {
172: if (kernelData[i] < 0.0F || kernelData[i] > 1.0) {
173: msg.append(JaiI18N
174: .getString("OrderedDitherDescriptor7"));
175: return false;
176: }
177: }
178: }
179:
180: return true;
181: }
182:
183: /** Constructor. */
184: public OrderedDitherDescriptor() {
185: super (resources, supportedModes, 1, paramNames, paramClasses,
186: paramDefaults, null);
187: }
188:
189: /**
190: * Validates the input source and parameters.
191: *
192: * <p> In addition to the standard checks performed by the
193: * superclass method, this method checks that "colorMap"
194: * and "ditherMask" are valid for the given source image.
195: */
196: public boolean validateArguments(String modeName,
197: ParameterBlock args, StringBuffer msg) {
198: if (!super .validateArguments(modeName, args, msg)) {
199: return false;
200: }
201:
202: if (!modeName.equalsIgnoreCase("rendered"))
203: return true;
204:
205: // Retrieve the operation source and parameters.
206: RenderedImage src = args.getRenderedSource(0);
207: ColorCube colorMap = (ColorCube) args.getObjectParameter(0);
208: KernelJAI[] ditherMask = (KernelJAI[]) args
209: .getObjectParameter(1);
210:
211: // Check color map validity.
212: if (!isValidColorMap(src, colorMap, msg)) {
213: return false;
214: }
215:
216: // Check dither mask validity.
217: if (!isValidDitherMask(src, ditherMask, msg)) {
218: return false;
219: }
220:
221: return true;
222: }
223:
224: /**
225: * Performs ordered dither color quantization using a specified color cube and dither mask.
226: *
227: * <p>Creates a <code>ParameterBlockJAI</code> from all
228: * supplied arguments except <code>hints</code> and invokes
229: * {@link JAI#create(String,ParameterBlock,RenderingHints)}.
230: *
231: * @see JAI
232: * @see ParameterBlockJAI
233: * @see RenderedOp
234: *
235: * @param source0 <code>RenderedImage</code> source 0.
236: * @param colorMap The color cube.
237: * May be <code>null</code>.
238: * @param ditherMask The dither mask.
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>RenderedOp</code> destination.
243: * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
244: */
245: public static RenderedOp create(RenderedImage source0,
246: ColorCube colorMap, KernelJAI[] ditherMask,
247: RenderingHints hints) {
248: ParameterBlockJAI pb = new ParameterBlockJAI("OrderedDither",
249: RenderedRegistryMode.MODE_NAME);
250:
251: pb.setSource("source0", source0);
252:
253: pb.setParameter("colorMap", colorMap);
254: pb.setParameter("ditherMask", ditherMask);
255:
256: return JAI.create("OrderedDither", pb, hints);
257: }
258: }
|