001: /*
002: * $RCSfile: BorderDescriptor.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:30 $
010: * $State: Exp $
011: */
012: package javax.media.jai.operator;
013:
014: import java.awt.Rectangle;
015: import java.awt.RenderingHints;
016: import java.awt.Shape;
017: import java.awt.geom.Area;
018: import java.awt.image.RenderedImage;
019: import java.awt.image.renderable.ParameterBlock;
020: import javax.media.jai.BorderExtender;
021: import javax.media.jai.JAI;
022: import javax.media.jai.OperationDescriptorImpl;
023: import javax.media.jai.OperationNode;
024: import javax.media.jai.ParameterBlockJAI;
025: import javax.media.jai.RenderedOp;
026: import javax.media.jai.registry.RenderedRegistryMode;
027:
028: /**
029: * An <code>OperationDescriptor</code> describing the "Border" operation.
030: *
031: * <p> The Border operation adds a border around a rendered image. The
032: * size of the border is specified in pixels by the left, right, top,
033: * and bottom padding parameters, corresponding to the four sides of
034: * the source image. These paddings may not be less than 0.
035: *
036: * <p>The pixel values of the added border area will be set according to
037: * the algorithm of the <code>BorderExtender</code> passed as a parameter.
038: * The <code>BorderExtender</code>s provide the ability to extend the
039: * border by:
040: * <ul>
041: * <li>filling it with zeros (<code>BorderExtenderZero</code>);
042: * <li>filling it with constants (<code>BorderExtenderConstant</code>);
043: * <li>copying the edge and corner pixels (<code>BorderExtenderCopy</code>);
044: * <li>reflecting about the edges of the image
045: * (<code>BorderExtenderReflect</code>); or,
046: * <li>"wrapping" the image plane toroidally, that is, joining opposite
047: * edges of the image (<code>BorderExtenderWrap</code>).
048: * </ul>
049: *
050: * <p><table border=1>
051: * <caption>Resource List</caption>
052: * <tr><th>Name</th> <th>Value</th></tr>
053: * <tr><td>GlobalName</td> <td>Border</td></tr>
054: * <tr><td>LocalName</td> <td>Border</td></tr>
055: * <tr><td>Vendor</td> <td>com.sun.media.jai</td></tr>
056: * <tr><td>Description</td> <td>Adds a border around an image.</td></tr>
057: * <tr><td>DocURL</td> <td>http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/BorderDescriptor.html</td></tr>
058: * <tr><td>Version</td> <td>1.0</td></tr>
059: * <tr><td>arg0Desc</td> <td>The image's left padding.</td></tr>
060: * <tr><td>arg1Desc</td> <td>The image's right padding.</td></tr>
061: * <tr><td>arg2Desc</td> <td>The image's top padding.</td></tr>
062: * <tr><td>arg3Desc</td> <td>The image's bottom padding.</td></tr>
063: * <tr><td>arg4Desc</td> <td>The border extender.</td></tr>
064: * </table></p>
065: *
066: * <p><table border=1>
067: * <caption>Parameter List</caption>
068: * <tr><th>Name</th> <th>Class Type</th>
069: * <th>Default Value</th></tr>
070: * <tr><td>leftPad</td> <td>java.lang.Integer</td>
071: * <td>0</td>
072: * <tr><td>rightPad</td> <td>java.lang.Integer</td>
073: * <td>0</td>
074: * <tr><td>topPad</td> <td>java.lang.Integer</td>
075: * <td>0</td>
076: * <tr><td>bottomPad</td> <td>java.lang.Integer</td>
077: * <td>0</td>
078: * <tr><td>type</td> <td>javax.media.jai.BorderExtender</td>
079: * <td>javax.media.jai.BorderExtenderZero</td>
080: * </table></p>
081: *
082: * @see javax.media.jai.OperationDescriptor
083: */
084: public class BorderDescriptor extends OperationDescriptorImpl {
085:
086: /**
087: * The resource strings that provide the general documentation
088: * and specify the parameter list for this operation.
089: */
090: private static final String[][] resources = {
091: { "GlobalName", "Border" },
092: { "LocalName", "Border" },
093: { "Vendor", "com.sun.media.jai" },
094: { "Description", JaiI18N.getString("BorderDescriptor0") },
095: {
096: "DocURL",
097: "http://java.sun.com/products/java-media/jai/forDevelopers/jai-apidocs/javax/media/jai/operator/BorderDescriptor.html" },
098: { "Version", JaiI18N.getString("DescriptorVersion2") },
099: { "arg0Desc", JaiI18N.getString("BorderDescriptor1") },
100: { "arg1Desc", JaiI18N.getString("BorderDescriptor2") },
101: { "arg2Desc", JaiI18N.getString("BorderDescriptor3") },
102: { "arg3Desc", JaiI18N.getString("BorderDescriptor4") },
103: { "arg4Desc", JaiI18N.getString("BorderDescriptor5") }, };
104:
105: /** The parameter name list for this operation. */
106: private static final String[] paramNames = { "leftPad", "rightPad",
107: "topPad", "bottomPad", "type" };
108:
109: /** The parameter class list for this operation. */
110: private static final Class[] paramClasses = {
111: java.lang.Integer.class, java.lang.Integer.class,
112: java.lang.Integer.class, java.lang.Integer.class,
113: javax.media.jai.BorderExtender.class };
114:
115: /** The parameter default value list for this operation. */
116: private static final Object[] paramDefaults = { new Integer(0),
117: new Integer(0), new Integer(0), new Integer(0),
118: BorderExtender.createInstance(BorderExtender.BORDER_ZERO) };
119:
120: /** Constructor. */
121: public BorderDescriptor() {
122: super (resources, 1, paramClasses, paramNames, paramDefaults);
123: }
124:
125: /**
126: * Calculates the region over which two distinct renderings
127: * of the "Border" operation may be expected to differ.
128: *
129: * <p> The operation returns a <code>Shape</code> or <code>null</code>
130: * in the rendered mode and <code>null</code> in all other modes.
131: *
132: * @param modeName The name of the mode.
133: * @param oldParamBlock The previous sources and parameters.
134: * @param oldHints The previous hints.
135: * @param newParamBlock The current sources and parameters.
136: * @param newHints The current hints.
137: * @param node The affected node in the processing chain (ignored).
138: *
139: * @return The region over which the data of two renderings of this
140: * operation may be expected to be invalid or <code>null</code>
141: * if there is no common region of validity.
142: * A non-<code>null</code> empty region indicates that the
143: * operation would produce identical data over the bounds of the
144: * old rendering although perhaps not over the area occupied by
145: * the <i>tiles</i> of the old rendering.
146: *
147: * @throws IllegalArgumentException if <code>modeName</code>
148: * is <code>null</code> or if the operation requires either
149: * sources or parameters and either <code>oldParamBlock</code>
150: * or <code>newParamBlock</code> is <code>null</code>.
151: * @throws IllegalArgumentException if <code>oldParamBlock</code> or
152: * <code>newParamBlock</code> do not contain sufficient sources
153: * or parameters for the operation in question.
154: */
155: public Object getInvalidRegion(String modeName,
156: ParameterBlock oldParamBlock, RenderingHints oldHints,
157: ParameterBlock newParamBlock, RenderingHints newHints,
158: OperationNode node) {
159: if ((modeName == null)
160: || ((getNumSources() > 0 || getNumParameters() > 0) && (oldParamBlock == null || newParamBlock == null))) {
161:
162: throw new IllegalArgumentException(JaiI18N
163: .getString("BorderDescriptor6"));
164: }
165:
166: int numSources = getNumSources();
167:
168: if ((numSources > 0)
169: && (oldParamBlock.getNumSources() != numSources || newParamBlock
170: .getNumSources() != numSources)) {
171:
172: throw new IllegalArgumentException(JaiI18N
173: .getString("BorderDescriptor7"));
174:
175: }
176:
177: int numParams = getParameterListDescriptor(modeName)
178: .getNumParameters();
179:
180: if ((numParams > 0)
181: && (oldParamBlock.getNumParameters() != numParams || newParamBlock
182: .getNumParameters() != numParams)) {
183:
184: throw new IllegalArgumentException(JaiI18N
185: .getString("BorderDescriptor8"));
186: }
187:
188: // Return null if the RenderingHints, source, left padding, or
189: // top padding changed.
190: if (!modeName.equalsIgnoreCase(RenderedRegistryMode.MODE_NAME)
191: || (oldHints == null && newHints != null)
192: || (oldHints != null && newHints == null)
193: || (oldHints != null && !oldHints.equals(newHints))
194: || !oldParamBlock.getSource(0).equals(
195: newParamBlock.getSource(0))
196: || oldParamBlock.getIntParameter(0) != // left pad
197: newParamBlock.getIntParameter(0)
198: || oldParamBlock.getIntParameter(2) != // top pad
199: newParamBlock.getIntParameter(2)) {
200: return null;
201: }
202:
203: Shape invalidRegion = null;
204:
205: if (!oldParamBlock.getObjectParameter(4).equals(
206: newParamBlock.getObjectParameter(4))) {
207: // BorderExtender changed.
208:
209: // Get source and the left and top padding.
210: RenderedImage src = oldParamBlock.getRenderedSource(0);
211: int leftPad = oldParamBlock.getIntParameter(0);
212: int topPad = oldParamBlock.getIntParameter(2);
213:
214: // Get source bounds.
215: Rectangle srcBounds = new Rectangle(src.getMinX(), src
216: .getMinY(), src.getWidth(), src.getHeight());
217:
218: // Get destination bounds.
219: Rectangle dstBounds = new Rectangle(srcBounds.x - leftPad,
220: srcBounds.y - topPad, srcBounds.width + leftPad
221: + oldParamBlock.getIntParameter(1),
222: srcBounds.height + topPad
223: + oldParamBlock.getIntParameter(3));
224:
225: // Determine invalid area by subtracting source bounds.
226: Area invalidArea = new Area(dstBounds);
227: invalidArea.subtract(new Area(srcBounds));
228: invalidRegion = invalidArea;
229:
230: } else if ((newParamBlock.getIntParameter(1) < // new R < old R
231: oldParamBlock.getIntParameter(1) && newParamBlock
232: .getIntParameter(3) <= // new B <= old B
233: oldParamBlock.getIntParameter(3))
234: || (newParamBlock.getIntParameter(3) < // new B < old B
235: oldParamBlock.getIntParameter(3) && newParamBlock
236: .getIntParameter(1) <= // new R <= old R
237: oldParamBlock.getIntParameter(1))) {
238: // One or both right and bottom padding decreased.
239:
240: // Get source and the left and top padding.
241: RenderedImage src = oldParamBlock.getRenderedSource(0);
242: int leftPad = oldParamBlock.getIntParameter(0);
243: int topPad = oldParamBlock.getIntParameter(2);
244:
245: // Get source bounds.
246: Rectangle srcBounds = new Rectangle(src.getMinX(), src
247: .getMinY(), src.getWidth(), src.getHeight());
248:
249: // Get old destination bounds.
250: Rectangle oldBounds = new Rectangle(srcBounds.x - leftPad,
251: srcBounds.y - topPad, srcBounds.width + leftPad
252: + oldParamBlock.getIntParameter(1),
253: srcBounds.height + topPad
254: + oldParamBlock.getIntParameter(3));
255:
256: // Get new destination bounds.
257: Rectangle newBounds = new Rectangle(srcBounds.x - leftPad,
258: srcBounds.y - topPad, srcBounds.width + leftPad
259: + newParamBlock.getIntParameter(1),
260: srcBounds.height + topPad
261: + newParamBlock.getIntParameter(3));
262:
263: // Determine invalid area by subtracting new from old bounds.
264: Area invalidArea = new Area(oldBounds);
265: invalidArea.subtract(new Area(newBounds));
266: invalidRegion = invalidArea;
267:
268: } else {
269: // Either nothing changed or one or both of the right and bottom
270: // padding was increased.
271: invalidRegion = new Rectangle();
272: }
273:
274: return invalidRegion;
275: }
276:
277: /**
278: * Adds a border around an image.
279: *
280: * <p>Creates a <code>ParameterBlockJAI</code> from all
281: * supplied arguments except <code>hints</code> and invokes
282: * {@link JAI#create(String,ParameterBlock,RenderingHints)}.
283: *
284: * @see JAI
285: * @see ParameterBlockJAI
286: * @see RenderedOp
287: *
288: * @param source0 <code>RenderedImage</code> source 0.
289: * @param leftPad The image's left padding.
290: * May be <code>null</code>.
291: * @param rightPad The image's right padding.
292: * May be <code>null</code>.
293: * @param topPad The image's top padding.
294: * May be <code>null</code>.
295: * @param bottomPad The image's bottom padding.
296: * May be <code>null</code>.
297: * @param type The border type.
298: * May be <code>null</code>.
299: * @param hints The <code>RenderingHints</code> to use.
300: * May be <code>null</code>.
301: * @return The <code>RenderedOp</code> destination.
302: * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
303: */
304: public static RenderedOp create(RenderedImage source0,
305: Integer leftPad, Integer rightPad, Integer topPad,
306: Integer bottomPad, BorderExtender type, RenderingHints hints) {
307: ParameterBlockJAI pb = new ParameterBlockJAI("Border",
308: RenderedRegistryMode.MODE_NAME);
309:
310: pb.setSource("source0", source0);
311:
312: pb.setParameter("leftPad", leftPad);
313: pb.setParameter("rightPad", rightPad);
314: pb.setParameter("topPad", topPad);
315: pb.setParameter("bottomPad", bottomPad);
316: pb.setParameter("type", type);
317:
318: return JAI.create("Border", pb, hints);
319: }
320: }
|