001: /*
002: * $RCSfile: CompositeDescriptor.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:32 $
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 java.awt.image.renderable.RenderableImage;
019: import javax.media.jai.EnumeratedParameter;
020: import javax.media.jai.JAI;
021: import javax.media.jai.OperationDescriptorImpl;
022: import javax.media.jai.ParameterBlockJAI;
023: import javax.media.jai.RenderableOp;
024: import javax.media.jai.RenderedOp;
025: import javax.media.jai.operator.CompositeDestAlpha;
026: import javax.media.jai.registry.RenderableRegistryMode;
027: import javax.media.jai.registry.RenderedRegistryMode;
028:
029: /**
030: * An <code>OperationDescriptor</code> describing the "Composite" operation.
031: *
032: * <p> The "Composite" operation combines two images based on their alpha
033: * values at each pixel. It is done on a per-band basis, and the two source
034: * images are expected to have the same number of bands and the same data
035: * type. The destination image has the same data type as the two sources.
036: *
037: * <p> The <code>destAlpha</code> parameter indicates if the destination
038: * image should have an extra alpha channel. If this parameter is set to
039: * <code>NO_DESTINATION_ALPHA</code>, then the destination image does not
040: * include an alpha band, and it should have the same number of bands as
041: * the two source images. If it is set to <code>DESTINATION_ALPHA_FIRST</code>,
042: * then the destination image has one extra band than the source images,
043: * which represents the result alpha channel, and this band is the first
044: * band (band 0) of the destination. If it is set to
045: * <code>DESTINATION_ALPHA_LAST</code>, then the destination image also
046: * has the extra alpha channel, but this band is the last band of the
047: * destination.
048: *
049: * <p> The destination pixel values may be viewed as representing a fractional
050: * pixel coverage or transparency factor. Specifically, Composite implements
051: * the Porter-Duff "over" rule (see <i>Computer Graphics</i>, July 1984 pp.
052: * 253-259), in which the output color of a pixel with source value/alpha
053: * tuples <code>(A, a)</code> and <code>(B, b)</code> is given by
054: * <code>a*A + (1 - a)*(b*B)</code>. The output alpha value is given
055: * by <code>a + (1 - a)*b</code>. For premultiplied sources tuples
056: * <code>(a*A, a)</code> and <code>(b*B, b)</code>, the premultiplied output
057: * value is simply <code>(a*A) + (1 - a)*(b*B)</code>.
058: *
059: * <p> The color channels of the two source images are supplied via
060: * <code>source1</code> and <code>source2</code>. The two sources must
061: * be either both pre-multiplied by alpha or not. Alpha channel should
062: * not be included in <code>source1</code> and <code>source2</code>.
063: *
064: * <p> The alpha channel of the first source images must be supplied
065: * via the <code>source1Alpha</code> parameter. This parameter may not
066: * be null. The alpha channel of the second source image may be supplied
067: * via the <code>source2Alpha</code> parameter. This parameter may be
068: * null, in which case the second source is considered completely opaque.
069: * The alpha images should be single-banded, and have the same data type
070: * as well as dimensions as their corresponding source images.
071: *
072: * <p> The <code>alphaPremultiplied</code> parameter indicates whether
073: * or not the supplied alpha image is premultiplied to both the source
074: * images. It also indicates whether the destination image color channels
075: * have the alpha values multiplied to the pixel color values.
076: *
077: * <p> It should be noted that the <code>source1Alpha</code> and
078: * <code>source1Alpha</code> parameters are <code>RenderedImage</code>s in
079: * the "rendered" mode and are <code>RenderableImage</code>s in the
080: * "renderable" mode.
081: *
082: * <p> The destination image is the combination of the two source images.
083: * It has the color channels, and if specified, one additional alpha channel
084: * (the band index depends on the value of the <code>destAlpha</code>
085: * parameter). Whether alpha value is pre-multiplied to the color channels
086: * also depend on the value of <code>alphaPremultiplied</code> (pre-multiplied
087: * if true).
088: *
089: * <p><table border=1>
090: * <caption>Resource List</caption>
091: * <tr><th>Name</th> <th>Value</th></tr>
092: * <tr><td>GlobalName</td> <td>composite</td></tr>
093: * <tr><td>LocallName</td> <td>composite</td></tr>
094: * <tr><td>Vendor</td> <td>com.sun.media.jai</td></tr>
095: * <tr><td>Description</td> <td>Composites two images based on an alpha mask.</td></tr>
096: * <tr><td>DocURL</td> <td>http://java.sun.com/products/java-media/jai/forDevelopers/jaiapi/javax.media.jai.operator.CompositeDescriptor.html</td></tr>
097: * <tr><td>Version</td> <td>1.0</td></tr>
098: * <tr><td>arg0Desc</td> <td>The alpha image for the first source.</td></tr>
099: * <tr><td>arg1Desc</td> <td>The alpha image for the second source.</td></tr>
100: * <tr><td>arg2Desc</td> <td>True if alpha has been premultiplied to both
101: * sources and the destination.</td></tr>
102: * <tr><td>arg3Desc</td> <td>Indicates if the destination image should
103: * include an extra alpha channel, and if so,
104: * should it be the first or last band.</td></tr>
105: * </table></p>
106: *
107: * <p><table border=1>
108: * <caption>Parameter List</caption>
109: * <tr>
110: * <th>Name</th>
111: * <th COLSPAN=2>Class Type</th>
112: * <th>Default Value</th>
113: * </tr>
114: * <tr>
115: * <td ROWSPAN=2>source1Alpha</td>
116: * <td>Rendered mode</td>
117: * <td>java.awt.image.RenderedImage</td>
118: * <td ROWSPAN=2>NO_PARAMETER_DEFAULT</td>
119: * </tr>
120: * <tr>
121: * <td>Renderable mode</td>
122: * <td>java.awt.image.renderable.RenderableImage</td>
123: *</tr>
124: * <tr>
125: * <td ROWSPAN=2>source2Alpha</td>
126: * <td>Rendered mode</td>
127: * <td>java.awt.image.RenderedImage</td>
128: * <td ROWSPAN=2>null</td>
129: * </tr>
130: * <tr>
131: * <td>Renderable mode</td>
132: * <td>java.awt.image.renderable.RenderableImage</td>
133: *</tr>
134: * <tr>
135: * <td>alphaPremultiplied</td>
136: * <td COLSPAN=2>java.lang.Boolean</td>
137: * <td>false</td>
138: * </tr>
139: * <tr>
140: * <td>destAlpha</td>
141: * <td COLSPAN=2>javax.media.jai.operator.CompositeDestAlpha</td>
142: * <td>NO_DESTINATION_ALPHA</td>
143: * </tr>
144: * </table></p>
145: *
146: * @see CompositeDestAlpha
147: * @see java.awt.image.ColorModel
148: * @see javax.media.jai.OperationDescriptor
149: */
150: public class CompositeDescriptor extends OperationDescriptorImpl {
151:
152: /** The destination image does not have the alpha channel. */
153: public static final CompositeDestAlpha NO_DESTINATION_ALPHA = new CompositeDestAlpha(
154: "NO_DESTINATION_ALPHA", 0);
155:
156: /** The destination image has the channel, and it is the first band. */
157: public static final CompositeDestAlpha DESTINATION_ALPHA_FIRST = new CompositeDestAlpha(
158: "DESTINATION_ALPHA_FIRST", 1);
159:
160: /** The destination image has the channel, and it is the last band. */
161: public static final CompositeDestAlpha DESTINATION_ALPHA_LAST = new CompositeDestAlpha(
162: "DESTINATION_ALPHA_LAST", 2);
163:
164: /**
165: * The resource strings that provide the general documentation
166: * and specify the parameter list for this operation.
167: */
168: protected static final String[][] resources = {
169: { "GlobalName", "Composite" },
170: { "LocalName", "Composite" },
171: { "Vendor", "com.sun.media.jai" },
172: { "Description", JaiI18N.getString("CompositeDescriptor0") },
173: {
174: "DocURL",
175: "http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/CompositeDescriptor.html" },
176: { "Version", JaiI18N.getString("DescriptorVersion2") },
177: { "arg0Desc", JaiI18N.getString("CompositeDescriptor1") },
178: { "arg1Desc", JaiI18N.getString("CompositeDescriptor2") },
179: { "arg2Desc", JaiI18N.getString("CompositeDescriptor3") },
180: { "arg3Desc", JaiI18N.getString("CompositeDescriptor4") } };
181:
182: private static final Class[][] sourceClasses = {
183: { java.awt.image.RenderedImage.class,
184: java.awt.image.RenderedImage.class },
185: { java.awt.image.renderable.RenderableImage.class,
186: java.awt.image.renderable.RenderableImage.class } };
187:
188: /** The parameter class list for this operation. */
189: private static final Class[][] paramClasses = {
190: { java.awt.image.RenderedImage.class,
191: java.awt.image.RenderedImage.class,
192: java.lang.Boolean.class, CompositeDestAlpha.class },
193: { java.awt.image.renderable.RenderableImage.class,
194: java.awt.image.renderable.RenderableImage.class,
195: java.lang.Boolean.class, CompositeDestAlpha.class } };
196:
197: /** The parameter name list for this operation. */
198: private static final String[] paramNames = { "source1Alpha",
199: "source2Alpha", "alphaPremultiplied", "destAlpha" };
200:
201: /** The parameter default value list for this operation. */
202: private static final Object[][] paramDefaults = {
203: { NO_PARAMETER_DEFAULT, null, Boolean.FALSE,
204: NO_DESTINATION_ALPHA },
205: { NO_PARAMETER_DEFAULT, null, Boolean.FALSE,
206: NO_DESTINATION_ALPHA } };
207:
208: private static final String[] supportedModes = { "rendered",
209: "renderable" };
210:
211: /** Constructor. */
212: public CompositeDescriptor() {
213: super (resources, supportedModes, null, sourceClasses,
214: paramNames, paramClasses, paramDefaults, null);
215: }
216:
217: /**
218: * Validates the input sources and parameters.
219: *
220: * <p> In addition to the standard checks performed by the
221: * superclass method, this method checks that the source image
222: * <code>samplemodel</code>s have the same number of bands and
223: * transfer type, and that the alpha images have the same bounds
224: * as the corresponding sources and the correct transfer type.
225: */
226: public boolean validateArguments(String modeName,
227: ParameterBlock args, StringBuffer msg) {
228: if (!super .validateArguments(modeName, args, msg)) {
229: return false;
230: }
231:
232: if (!modeName.equalsIgnoreCase("rendered"))
233: return true;
234:
235: RenderedImage src1 = args.getRenderedSource(0);
236: RenderedImage src2 = args.getRenderedSource(1);
237:
238: SampleModel s1sm = src1.getSampleModel();
239: SampleModel s2sm = src2.getSampleModel();
240: if (s1sm.getNumBands() != s2sm.getNumBands()
241: || s1sm.getTransferType() != s2sm.getTransferType()) {
242: msg.append(getName() + " "
243: + JaiI18N.getString("CompositeDescriptor8"));
244: return false;
245: }
246:
247: /* Validate Parameters. */
248: RenderedImage afa1 = (RenderedImage) args.getObjectParameter(0);
249: if (src1.getMinX() != afa1.getMinX()
250: || src1.getMinY() != afa1.getMinY()
251: || src1.getWidth() != afa1.getWidth()
252: || src1.getHeight() != afa1.getHeight()) {
253: msg.append(getName() + " "
254: + JaiI18N.getString("CompositeDescriptor12"));
255: return false;
256: }
257:
258: SampleModel a1sm = afa1.getSampleModel();
259: if (s1sm.getTransferType() != a1sm.getTransferType()) {
260: msg.append(getName() + " "
261: + JaiI18N.getString("CompositeDescriptor13"));
262: return false;
263: }
264:
265: RenderedImage afa2 = (RenderedImage) args.getObjectParameter(1);
266: if (afa2 != null) {
267: if (src2.getMinX() != afa2.getMinX()
268: || src2.getMinY() != afa2.getMinY()
269: || src2.getWidth() != afa2.getWidth()
270: || src2.getHeight() != afa2.getHeight()) {
271: msg.append(getName() + " "
272: + JaiI18N.getString("CompositeDescriptor15"));
273: return false;
274: }
275:
276: SampleModel a2sm = afa2.getSampleModel();
277: if (s2sm.getTransferType() != a2sm.getTransferType()) {
278: msg.append(getName() + " "
279: + JaiI18N.getString("CompositeDescriptor16"));
280: return false;
281: }
282: }
283:
284: return true;
285: }
286:
287: /**
288: * Composites two images based on an alpha mask.
289: *
290: * <p>Creates a <code>ParameterBlockJAI</code> from all
291: * supplied arguments except <code>hints</code> and invokes
292: * {@link JAI#create(String,ParameterBlock,RenderingHints)}.
293: *
294: * @see JAI
295: * @see ParameterBlockJAI
296: * @see RenderedOp
297: *
298: * @param source0 <code>RenderedImage</code> source 0.
299: * @param source1 <code>RenderedImage</code> source 1.
300: * @param source1Alpha The alpha image for the first source.
301: * @param source2Alpha The alpha image for the second source.
302: * May be <code>null</code>.
303: * @param alphaPremultiplied True if alpha has been premultiplied to both sources and the destination.
304: * May be <code>null</code>.
305: * @param destAlpha Indicates if the destination image should include an extra alpha channel, and if so, should it be the first or last band.
306: * May be <code>null</code>.
307: * @param hints The <code>RenderingHints</code> to use.
308: * May be <code>null</code>.
309: * @return The <code>RenderedOp</code> destination.
310: * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
311: * @throws IllegalArgumentException if <code>source1</code> is <code>null</code>.
312: * @throws IllegalArgumentException if <code>source1Alpha</code> is <code>null</code>.
313: */
314: public static RenderedOp create(RenderedImage source0,
315: RenderedImage source1, RenderedImage source1Alpha,
316: RenderedImage source2Alpha, Boolean alphaPremultiplied,
317: CompositeDestAlpha destAlpha, RenderingHints hints) {
318: ParameterBlockJAI pb = new ParameterBlockJAI("Composite",
319: RenderedRegistryMode.MODE_NAME);
320:
321: pb.setSource("source0", source0);
322: pb.setSource("source1", source1);
323:
324: pb.setParameter("source1Alpha", source1Alpha);
325: pb.setParameter("source2Alpha", source2Alpha);
326: pb.setParameter("alphaPremultiplied", alphaPremultiplied);
327: pb.setParameter("destAlpha", destAlpha);
328:
329: return JAI.create("Composite", pb, hints);
330: }
331:
332: /**
333: * Composites two images based on an alpha mask.
334: *
335: * <p>Creates a <code>ParameterBlockJAI</code> from all
336: * supplied arguments except <code>hints</code> and invokes
337: * {@link JAI#createRenderable(String,ParameterBlock,RenderingHints)}.
338: *
339: * @see JAI
340: * @see ParameterBlockJAI
341: * @see RenderableOp
342: *
343: * @param source0 <code>RenderableImage</code> source 0.
344: * @param source1 <code>RenderableImage</code> source 1.
345: * @param source1Alpha The alpha image for the first source.
346: * @param source2Alpha The alpha image for the second source.
347: * May be <code>null</code>.
348: * @param alphaPremultiplied True if alpha has been premultiplied to both sources and the destination.
349: * May be <code>null</code>.
350: * @param destAlpha Indicates if the destination image should include an extra alpha channel, and if so, should it be the first or last band.
351: * May be <code>null</code>.
352: * @param hints The <code>RenderingHints</code> to use.
353: * May be <code>null</code>.
354: * @return The <code>RenderableOp</code> destination.
355: * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
356: * @throws IllegalArgumentException if <code>source1</code> is <code>null</code>.
357: * @throws IllegalArgumentException if <code>source1Alpha</code> is <code>null</code>.
358: */
359: public static RenderableOp createRenderable(
360: RenderableImage source0, RenderableImage source1,
361: RenderableImage source1Alpha, RenderableImage source2Alpha,
362: Boolean alphaPremultiplied, CompositeDestAlpha destAlpha,
363: RenderingHints hints) {
364: ParameterBlockJAI pb = new ParameterBlockJAI("Composite",
365: RenderableRegistryMode.MODE_NAME);
366:
367: pb.setSource("source0", source0);
368: pb.setSource("source1", source1);
369:
370: pb.setParameter("source1Alpha", source1Alpha);
371: pb.setParameter("source2Alpha", source2Alpha);
372: pb.setParameter("alphaPremultiplied", alphaPremultiplied);
373: pb.setParameter("destAlpha", destAlpha);
374:
375: return JAI.createRenderable("Composite", pb, hints);
376: }
377: }
|