1 /*
2  * $RCSfile: FormatDescriptor.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:36 $
10  * $State: Exp $
11  */
12 package com.lightcrafts.mediax.jai.operator;
13 import java.awt.RenderingHints;
14 import java.awt.image.DataBuffer;
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 "Format" operation.
28  *
29  * <p> The "Format" operation performs reformatting on an image.  It
30  * is capable of casting the pixel values of an image to a given data
31  * type, replacing the SampleModel and ColorModel of an image, and
32  * restructuring the image's tile grid layout.  The pixel values of
33  * the destination image are defined by the pseudocode:
34  *
35  * <pre>dst[x][y][b] = cast(src[x][y][b], dataType)</pre>
36  *
37  * where "dataType" is one of the constants TYPE_BYTE, TYPE_SHORT,
38  * TYPE_USHORT, TYPE_INT, TYPE_FLOAT, or TYPE_DOUBLE from
39  * <code>java.awt.image.DataBuffer</code>.
40  *
41  * <p> The output SampleModel, ColorModel and tile grid layout are
42  * specified by passing an ImageLayout object as a RenderingHint named
43  * "ImageLayout".  The output image will have a SampleModel compatible
44  * with the one specified in the layout hint wherever possible;
45  * however, for output data types of <code>float</code> and
46  * </code>double a <code>ComponentSampleModel</code> will be used
47  * regardless of the value of the hint parameter.
48  *
49  * <p> One of the common uses of the format operator is to cast the
50  * pixel values of an image to a given data type. In such a case, if
51  * the source image provided has an <code>IndexColorModel</code>, a
52  * <code>RenderingHints</code> object for
53  * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> with the value of
54  * <code>Boolean.TRUE</code> will automatically be added to the
55  * configuration <code>Map</code> for the operation. This addition
56  * will only take place if a value for the
57  * <code>JAI.KEY_REPLACE_INDEX_COLOR_MODEL</code> has not already been
58  * provided by the user. Note that the <code>configuration</code> Map
59  * is cloned before the new hint is added to it. Due to the addition
60  * of this new <code>RenderingHint</code>, using the "format" operation
61  * with source(s) that have an <code>IndexColorModel</code> will cause
62  * the destination to have an expanded non-<code>IndexColorModel</code>
63  * <code>ColorModel</code>. This expansion ensures that the conversion
64  * to a different data type, <code>ColorModel</code> or
65  * <code>SampleModel</code> happens correctly such that the indices
66  * into the color map (for <code>IndexColorModel</code> images) are
67  * not treated as pixel data.  If the format operator is not being used
68  * to cast the pixel values of an image to a given data type, the
69  * expansion will not take place, the resultant image will still have
70  * an <code>IndexColorModel</code>.
71  *
72  * <p> The ImageLayout may also specify a tile grid origin and size
73  * which will be respected.
74  *
75  * <p> The typecasting performed by the <code>Format</code> function
76  * is defined by the following set of expressions, dependent on the
77  * data types of the source and destination.  Casting an image to its
78  * current data type is a no-op.  See <a
79  * href=http://java.sun.com/docs/books/jls/html/5.doc.html#25222> The
80  * Java Language Specification</a> for the definition of type
81  * conversions between primitive types.
82  *
83  * <p> In most cases, it is not necessary to explictly perform widening
84  * typecasts since they will be performed automatically by image
85  * operators when handed source images having different datatypes.
86  *
87  * <p><table border=1>
88  * <tr><th>Source Type</th> <th>Destination Type</th> <th>Action</th></tr>
89  * <tr><td>BYTE</td>   <td>SHORT</td>  <td>(short)(x & 0xff)</td></tr>
90  * <tr><td>BYTE</td>   <td>USHORT</td> <td>(short)(x & 0xff)</td></tr>
91  * <tr><td>BYTE</td>   <td>INT</td>    <td>(int)(x & 0xff)</td></tr>
92  * <tr><td>BYTE</td>   <td>FLOAT</td>  <td>(float)(x & 0xff)</td></tr>
93  * <tr><td>BYTE</td>   <td>DOUBLE</td> <td>(double)(x & 0xff)</td></tr>
94  * <tr><td>SHORT</td>  <td>BYTE</td>   <td>(byte)clamp((int)x, 0, 255)</td></tr>
95  * <tr><td>SHORT</td>  <td>USHORT</td> <td>(short)clamp((int)x, 0, 32767)</td></tr>
96  * <tr><td>SHORT</td>  <td>INT</td>    <td>(int)x</td></tr>
97  * <tr><td>SHORT</td>  <td>FLOAT</td>  <td>(float)x</td></tr>
98  * <tr><td>SHORT</td>  <td>DOUBLE</td> <td>(double)x</td></tr>
99  * <tr><td>USHORT</td> <td>BYTE</td>   <td>(byte)clamp((int)x & 0xffff, 0, 255)</td></tr>
100  * <tr><td>USHORT</td> <td>SHORT</td>  <td>(short)clamp((int)x & 0xffff, 0, 32767)</td></tr>
101  * <tr><td>USHORT</td> <td>INT</td>    <td>(int)(x & 0xffff)</td></tr>
102  * <tr><td>USHORT</td> <td>FLOAT</td>  <td>(float)(x & 0xffff)</td></tr>
103  * <tr><td>USHORT</td> <td>DOUBLE</td> <td>(double)(x & 0xffff)</td></tr>
104  * <tr><td>INT</td>    <td>BYTE</td>   <td>(byte)clamp(x, 0, 255)</td></tr>
105  * <tr><td>INT</td>    <td>SHORT</td>  <td>(short)clamp(x, -32768, 32767)</td></tr>
106  * <tr><td>INT</td>    <td>USHORT</td> <td>(short)clamp(x, 0, 65535)</td></tr>
107  * <tr><td>INT</td>    <td>FLOAT</td>  <td>(float)x</td></tr>
108  * <tr><td>INT</td>    <td>DOUBLE</td> <td>(double)x</td></tr>
109  * <tr><td>FLOAT</td>  <td>BYTE</td>   <td>(byte)clamp((int)x, 0, 255)</td></tr>
110  * <tr><td>FLOAT</td>  <td>SHORT</td>  <td>(short)clamp((int)x, -32768, 32767)</td></tr>
111  * <tr><td>FLOAT</td>  <td>USHORT</td> <td>(short)clamp((int)x, 0, 65535)</td></tr>
112  * <tr><td>FLOAT</td>  <td>INT</td>    <td>(int)x</td></tr>
113  * <tr><td>FLOAT</td>  <td>DOUBLE</td> <td>(double)x</td></tr>
114  * <tr><td>DOUBLE</td> <td>BYTE</td>   <td>(byte)clamp((int)x, 0, 255)</td></tr>
115  * <tr><td>DOUBLE</td> <td>SHORT</td>  <td>(short)clamp((int)x, -32768, 32767)</td></tr>
116  * <tr><td>DOUBLE</td> <td>USHORT</td> <td>(short)clamp((int)x, 0, 65535)</td></tr>
117  * <tr><td>DOUBLE</td> <td>INT</td>    <td>(int)x</td></tr>
118  * <tr><td>DOUBLE</td> <td>FLOAT</td>  <td>(float)x</td></tr>
119  * </table></p>
120  *
121  * The <code>clamp</code> function may be defined as:
122  * <pre>
123  * int clamp(int x, int low, int high) {
124  *     return (x < low) ? low : ((x > high) ? high : x);
125  * }
126  * </pre>
127  *
128  * <p><table border=1>
129  * <caption>Resource List</caption>
130  * <tr><th>Name</th>        <th>Value</th></tr>
131  * <tr><td>GlobalName</td>  <td>Format</td></tr>
132  * <tr><td>LocalName</td>   <td>Format</td></tr>
133  * <tr><td>Vendor</td>      <td>com.lightcrafts.media.jai</td></tr>
134  * <tr><td>Description</td> <td>Reformats an image.</td></tr>
135  * <tr><td>DocURL</td>      <td>http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/FormatDescriptor.html</td></tr>
136  * <tr><td>Version</td>     <td>1.0</td></tr>
137  * <tr><td>arg0Desc</td>    <td>The output data type (from java.awt.image.DataBuffer).</td></tr>
138  * </table></p>
139  *
140  * <p><table border=1>
141  * <caption>Parameter List</caption>
142  * <tr><th>Name</th>      <th>Class Type</th>
143  *                        <th>Default Value</th></tr>
144  * <tr><td>dataType</td>  <td>java.lang.Integer</td>
145  *                        <td>DataBuffer.TYPE_BYTE</td>
146  * </table></p>
147  *
148  * @see java.awt.image.DataBuffer
149  * @see com.lightcrafts.mediax.jai.ImageLayout
150  * @see com.lightcrafts.mediax.jai.OperationDescriptor
151  */
152 public class FormatDescriptor extends OperationDescriptorImpl {
153 
154     /**
155      * The resource strings that provide the general documentation
156      * and specify the parameter list for this operation.
157      */
158     private static final String[][] resources = {
159         {"GlobalName",  "Format"},
160         {"LocalName",   "Format"},
161         {"Vendor",      "com.lightcrafts.media.jai"},
162         {"Description", JaiI18N.getString("FormatDescriptor0")},
163         {"DocURL",      "http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/FormatDescriptor.html"},
164         {"Version",     JaiI18N.getString("DescriptorVersion")},
165 	{"arg0Desc",    "The output data type (from java.awt.image.DataBuffer)."}
166     };
167 
168     /** The parameter class list for this operation. */
169     private static final Class[] paramClasses = {
170         java.lang.Integer.class
171     };
172 
173     /** The parameter name list for this operation. */
174     private static final String[] paramNames = {
175         "dataType"
176     };
177 
178     /** The parameter default value list for this operation. */
179     private static final Object[] paramDefaults = {
180         new Integer(DataBuffer.TYPE_BYTE)
181     };
182 
183     /** Constructor. */
FormatDescriptor()184     public FormatDescriptor() {
185         super(resources, 1, paramClasses, paramNames, paramDefaults);
186     }
187 
188     /** Returns <code>true</code> since renderable operation is supported. */
isRenderableSupported()189     public boolean isRenderableSupported() {
190         return true;
191     }
192 
193     /**
194      * Returns the minimum legal value of a specified numeric parameter
195      * for this operation.
196      */
getParamMinValue(int index)197     public Number getParamMinValue(int index) {
198         if (index == 0) {
199             return new Integer(DataBuffer.TYPE_BYTE);
200         } else {
201             throw new ArrayIndexOutOfBoundsException();
202         }
203     }
204 
205     /**
206      * Returns the maximum legal value of a specified numeric parameter
207      * for this operation.
208      */
getParamMaxValue(int index)209     public Number getParamMaxValue(int index) {
210         if (index == 0) {
211             return new Integer(DataBuffer.TYPE_DOUBLE);
212         } else {
213             throw new ArrayIndexOutOfBoundsException();
214         }
215     }
216 
217 
218     /**
219      * Reformats an image.
220      *
221      * <p>Creates a <code>ParameterBlockJAI</code> from all
222      * supplied arguments except <code>hints</code> and invokes
223      * {@link JAI#create(String,ParameterBlock,RenderingHints)}.
224      *
225      * @see JAI
226      * @see ParameterBlockJAI
227      * @see RenderedOp
228      *
229      * @param source0 <code>RenderedImage</code> source 0.
230      * @param dataType The output data type (from java.awt.image.DataBuffer).
231      * May be <code>null</code>.
232      * @param hints The <code>RenderingHints</code> to use.
233      * May be <code>null</code>.
234      * @return The <code>RenderedOp</code> destination.
235      * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
236      */
create(RenderedImage source0, Integer dataType, RenderingHints hints)237     public static RenderedOp create(RenderedImage source0,
238                                     Integer dataType,
239                                     RenderingHints hints)  {
240         ParameterBlockJAI pb =
241             new ParameterBlockJAI("Format",
242                                   RenderedRegistryMode.MODE_NAME);
243 
244         pb.setSource("source0", source0);
245 
246         pb.setParameter("dataType", dataType);
247 
248         return JAI.create("Format", pb, hints);
249     }
250 
251     /**
252      * Reformats an image.
253      *
254      * <p>Creates a <code>ParameterBlockJAI</code> from all
255      * supplied arguments except <code>hints</code> and invokes
256      * {@link JAI#createRenderable(String,ParameterBlock,RenderingHints)}.
257      *
258      * @see JAI
259      * @see ParameterBlockJAI
260      * @see RenderableOp
261      *
262      * @param source0 <code>RenderableImage</code> source 0.
263      * @param dataType The output data type (from java.awt.image.DataBuffer).
264      * May be <code>null</code>.
265      * @param hints The <code>RenderingHints</code> to use.
266      * May be <code>null</code>.
267      * @return The <code>RenderableOp</code> destination.
268      * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
269      */
createRenderable(RenderableImage source0, Integer dataType, RenderingHints hints)270     public static RenderableOp createRenderable(RenderableImage source0,
271                                                 Integer dataType,
272                                                 RenderingHints hints)  {
273         ParameterBlockJAI pb =
274             new ParameterBlockJAI("Format",
275                                   RenderableRegistryMode.MODE_NAME);
276 
277         pb.setSource("source0", source0);
278 
279         pb.setParameter("dataType", dataType);
280 
281         return JAI.createRenderable("Format", pb, hints);
282     }
283 }
284