001: /*
002: * $RCSfile: RenderedImageAdapter.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:20 $
010: * $State: Exp $
011: */
012: package javax.media.jai;
013:
014: import java.awt.Rectangle;
015: import java.awt.image.Raster;
016: import java.awt.image.RenderedImage;
017: import java.awt.image.WritableRaster;
018: import java.util.Hashtable;
019: import java.util.HashSet;
020: import java.util.Set;
021: import javax.media.jai.util.CaselessStringKey;
022:
023: /**
024: * A <code>PlanarImage</code> wrapper for a non-writable
025: * <code>RenderedImage</code>. The tile layout, sample model, and so forth
026: * are preserved. Calls to <code>getTile()</code>, <code>getData()</code>,
027: * and <code>copyData()</code> are forwarded to the image being adapted.
028: *
029: * <p> The set of properties available on the image will be a combination of
030: * those defined locally via <code>setProperty()</code> and those defined
031: * on the source image with the local properties taking precedence. No
032: * <code>PropertySourceChangeEvent</code> will be generated as a result of
033: * changes to the property set of the source image.
034: *
035: * <p> From JAI's point of view, this image is a <code>PlanarImage</code> of
036: * unknown type, with no sources. The source image is assumed to be
037: * immutable. If the <code>RenderedImage</code> source implements
038: * <code>WritableRenderedImage</code>, a
039: * <code>WritableRenderedImageAdapter</code> should be used.
040: *
041: * <p> The methods are marked 'final' in order to allow dynamic inlining to
042: * take place. This should eliminate any performance penalty associated with
043: * the use of an adapter class.
044: *
045: * <p> Since the methods of this class all derive from
046: * <code>PlanarImage</code>, they are not commented in detail.
047: *
048: * @see PlanarImage
049: * @see WritableRenderedImageAdapter
050: * @see java.awt.image.RenderedImage
051: * @see java.awt.image.WritableRenderedImage
052: */
053: public class RenderedImageAdapter extends PlanarImage {
054:
055: /** The RenderedImage being adapted. */
056: protected RenderedImage theImage;
057:
058: /** Tile index bounds. */
059: private Rectangle tileIndexBounds;
060:
061: /**
062: * Merge the <code>String</code>s in the two arrays with the local names
063: * taking precedence. Comparison is performed independent of case. Both
064: * parameters may be <code>null</code>.
065: *
066: * @return The merged name arrays or <code>null</code>.
067: */
068: static String[] mergePropertyNames(String[] localNames,
069: String[] sourceNames) {
070: // Set the output names to the other array if one array is null
071: // or zero-length.
072: String[] names = null;
073: if (localNames == null || localNames.length == 0) {
074: names = sourceNames;
075: } else if (sourceNames == null || sourceNames.length == 0) {
076: names = localNames;
077: } else {
078: // Merge the name arrays.
079:
080: // Allocate a Set.
081: Set nameSet = new HashSet(
082: (localNames.length + sourceNames.length) / 2);
083:
084: // Add source names first as they have lower priority.
085: int numSourceNames = sourceNames.length;
086: for (int i = 0; i < numSourceNames; i++) {
087: nameSet.add(new CaselessStringKey(sourceNames[i]));
088: }
089:
090: // Add local names which will "bump" duplicate source names.
091: int numLocalNames = localNames.length;
092: for (int i = 0; i < numLocalNames; i++) {
093: nameSet.add(new CaselessStringKey(localNames[i]));
094: }
095:
096: // Convert result to an array of Strings.
097: int numNames = nameSet.size();
098: CaselessStringKey[] caselessNames = new CaselessStringKey[numNames];
099: nameSet.toArray(caselessNames);
100: names = new String[numNames];
101: for (int i = 0; i < numNames; i++) {
102: names[i] = caselessNames[i].getName();
103: }
104: }
105:
106: // Set return value to null if zero-length.
107: if (names != null && names.length == 0) {
108: names = null;
109: }
110:
111: return names;
112: }
113:
114: /**
115: * Constructs a RenderedImageAdapter.
116: *
117: * @param im a RenderedImage to be `wrapped' as a PlanarImage.
118: * @throws IllegalArgumentException if <code>im</code> is
119: * <code>null</code>.
120: */
121: public RenderedImageAdapter(RenderedImage im) {
122: super (im != null ? new ImageLayout(im) : null, null, null);
123: if (im == null)
124: throw new IllegalArgumentException(JaiI18N
125: .getString("Generic0"));
126:
127: theImage = im;
128:
129: tileIndexBounds = new Rectangle(theImage.getMinTileX(),
130: theImage.getMinTileY(), theImage.getNumXTiles(),
131: theImage.getNumYTiles());
132: }
133:
134: /**
135: * Returns the reference to the external <code>RenderedImage</code>
136: * originally supplied to the constructor.
137: *
138: * @since JAI 1.1.2
139: */
140: public final RenderedImage getWrappedImage() {
141: return theImage;
142: }
143:
144: /**
145: * Forwards call to the true source unless the specified tile indices
146: * refer to a tile which does not overlap the image bounds in which
147: * case <code>null</code> is returned.
148: */
149: public final Raster getTile(int x, int y) {
150: return tileIndexBounds.contains(x, y) ? theImage.getTile(x, y)
151: : null;
152: }
153:
154: /** Forwards call to the true source. */
155: public final Raster getData() {
156: return theImage.getData();
157: }
158:
159: /** Forwards call to the true source. */
160: public final Raster getData(Rectangle rect) {
161: return theImage.getData(rect);
162: }
163:
164: /** Forwards call to the true source. */
165: public final WritableRaster copyData(WritableRaster raster) {
166: return theImage.copyData(raster);
167: }
168:
169: /**
170: * Retrieves a list of property names recognized by this image.
171: * The locally defined property names are combined with those derived
172: * from the true source.
173: */
174: public final String[] getPropertyNames() {
175: return mergePropertyNames(super .getPropertyNames(), theImage
176: .getPropertyNames());
177: }
178:
179: /**
180: * Retrieves the property from those set locally on the image or,
181: * if the property is not available locally, the call is forwarded to
182: * the true source.
183: * @exception IllegalArgumentException if <code>name</code>
184: * is <code>null</code>.
185: */
186: public final Object getProperty(String name) {
187: // Retrieve the property from the local cache.
188: Object property = super .getProperty(name);
189:
190: // If it is still undefined, forward the call.
191: if (property == java.awt.Image.UndefinedProperty) {
192: property = theImage.getProperty(name);
193: }
194:
195: return property;
196: }
197:
198: /**
199: * Returns the class expected to be returned by a request for
200: * the property with the specified name. If this information
201: * is unavailable, <code>null</code> will be returned.
202: *
203: * @exception IllegalArgumentException if <code>name</code>
204: * is <code>null</code>.
205: *
206: * @return The <code>Class</code> expected to be return by a
207: * request for the value of this property or <code>null</code>.
208: *
209: * @since JAI 1.1
210: */
211: public final Class getPropertyClass(String name) {
212: // Get the class if the property is local.
213: Class propClass = super .getPropertyClass(name);
214:
215: // If not local ...
216: if (propClass == null) {
217: // Get the property value.
218: Object propValue = getProperty(name);
219:
220: if (propValue != java.awt.Image.UndefinedProperty) {
221: // If the property is defined, get the class.
222: propClass = propValue.getClass();
223: }
224: }
225:
226: return propClass;
227: }
228: }
|