001: /*
002: * $RCSfile: RenderedImageList.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.ColorModel;
016: import java.awt.image.Raster;
017: import java.awt.image.RenderedImage;
018: import java.awt.image.SampleModel;
019: import java.awt.image.WritableRaster;
020: import java.io.Serializable;
021: import java.util.Collection;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.ListIterator;
025: import java.util.Vector;
026:
027: /**
028: * A <code>CollectionImage</code> which is also a
029: * <code>RenderedImage</code>. The underlying <code>Collection</code>
030: * in this case is required to be a <code>List</code> containing only
031: * <code>RenderedImage</code>s.
032: *
033: * <p> Instances of this class may be returned from either a
034: * <code>RenderedImageFactory</code> or from a
035: * <code>CollectionImageFactory</code>. This class would be
036: * particularly useful for implementing operations the result of which
037: * includes a single primary image and one or more secondary or
038: * dependant images the data of which are less likely to be requested.
039: *
040: * <p> Invocations of <code>RenderedImage</code> methods on an instance
041: * of this class will be forwarded to the first <code>RenderedImage</code>
042: * in the underlying <code>List</code>, i.e., the image at index zero.
043: * This should be the index assigned to the primary image in the case
044: * alluded to above. If there are no images in the <code>List</code>
045: * when a <code>RenderedImage</code> method is invoked an
046: * <code>IllegalStateException</code> will be thrown.
047: *
048: * <p> One example of the use of this class is in generating a classmap
049: * image using a classification algorithm. A by-product image of such an
050: * operation is often an error image wherein the value of each pixel is
051: * some measure of the classification error at that pixel. In this case
052: * the classmap image would be stored at index zero in the internal list
053: * and the error image at the unity index. The error image would be
054: * an <code>OpImage</code> that has the classmap image as its source.
055: * The result is that a reference to the error image is always available
056: * with the classmap image but the computation of the error image pixel
057: * values may be deferred until such time as the data are needed, if ever.
058: *
059: * <p> Methods defined in the <code>RenderedImage</code> and <code>List</code>
060: * interfaces are not all commented in detail. The <code>List</code> methods
061: * merely forward the call in most cases directly to the underlying
062: * <code>List</code>; as previously stated, <code>RenderedImage</code> method
063: * invocations are forwarded to the <code>RenderedImage</code> at position
064: * zero in the <code>List</code>.
065: *
066: * @since JAI 1.1
067: * @see CollectionImage
068: * @see java.awt.image.RenderedImage
069: * @see java.util.List
070: */
071: public class RenderedImageList extends CollectionImage implements List,
072: RenderedImage, Serializable {
073:
074: /**
075: * Creates an empty <code>RenderedImageList</code>.
076: */
077: protected RenderedImageList() {
078: super ();
079: }
080:
081: /**
082: * Creates a <code>RenderedImageList</code> from the supplied
083: * <code>List</code>.
084: *
085: * @throws <code>IllegalArgumentException</code> if any objects in the
086: * <code>List</code> are not <code>RenderedImage</code>s.
087: * @throws <code>IllegalArgumentException</code> if the <code>List</code>
088: * is empty.
089: * @throws <code>IllegalArgumentException</code> if the <code>List</code>
090: * parameter is <code>null</code>.
091: */
092: public RenderedImageList(List renderedImageList) {
093: super ();
094:
095: // separate throws, for better error reporting
096: if (renderedImageList == null) {
097: throw new IllegalArgumentException(JaiI18N
098: .getString("RenderedImageList0"));
099: }
100:
101: if (renderedImageList.isEmpty()) {
102: throw new IllegalArgumentException(JaiI18N
103: .getString("RenderedImageList1"));
104: }
105:
106: Iterator iter = renderedImageList.iterator();
107: imageCollection = new Vector();
108:
109: while (iter.hasNext()) {
110: Object item = iter.next();
111:
112: if (item instanceof RenderedImage) {
113: imageCollection.add(item);
114: } else {
115: throw new IllegalArgumentException(JaiI18N
116: .getString("RenderedImageList2"));
117: }
118: }
119: }
120:
121: /// --- RenderedImage methods. ---
122:
123: /**
124: * Returns the image <code>Collection</code> as a <code>List</code>.
125: */
126: private List getList() {
127: return (List) imageCollection;
128: }
129:
130: /**
131: * Returns the first image in the underlying list of
132: * <code>RenderedImage</code>s.
133: * The call is forwarded to the first image in the <code>List</code>.
134: */
135: public RenderedImage getPrimaryImage() {
136: return (RenderedImage) getList().get(0);
137: }
138:
139: /**
140: * Returns the X coordinate of the leftmost column of the
141: * primary image.
142: * The call is forwarded to the first image in the <code>List</code>.
143: */
144: public int getMinX() {
145: return ((RenderedImage) getList().get(0)).getMinX();
146: }
147:
148: /**
149: * Returns the X coordinate of the uppermost row of the primary image.
150: * The call is forwarded to the first image in the <code>List</code>.
151: */
152: public int getMinY() {
153: return ((RenderedImage) getList().get(0)).getMinY();
154: }
155:
156: /**
157: * Returns the width of the primary image.
158: * The call is forwarded to the first image in the <code>List</code>.
159: */
160: public int getWidth() {
161: return ((RenderedImage) getList().get(0)).getWidth();
162: }
163:
164: /**
165: * Returns the height of the primary image.
166: * The call is forwarded to the first image in the <code>List</code>.
167: */
168: public int getHeight() {
169: return ((RenderedImage) getList().get(0)).getHeight();
170: }
171:
172: /**
173: * Returns the width of a tile of the primary image.
174: * The call is forwarded to the first image in the <code>List</code>.
175: */
176: public int getTileWidth() {
177: return ((RenderedImage) getList().get(0)).getTileWidth();
178: }
179:
180: /**
181: * Returns the height of a tile of the primary image.
182: * The call is forwarded to the first image in the <code>List</code>.
183: */
184: public int getTileHeight() {
185: return ((RenderedImage) getList().get(0)).getTileHeight();
186: }
187:
188: /**
189: * Returns the X coordinate of the upper-left pixel of tile (0, 0)
190: * of the primary image.
191: * The call is forwarded to the first image in the <code>List</code>.
192: */
193: public int getTileGridXOffset() {
194: return ((RenderedImage) getList().get(0)).getTileGridXOffset();
195: }
196:
197: /**
198: * Returns the Y coordinate of the upper-left pixel of tile (0, 0)
199: * of the primary image.
200: * The call is forwarded to the first image in the <code>List</code>.
201: */
202: public int getTileGridYOffset() {
203: return ((RenderedImage) getList().get(0)).getTileGridYOffset();
204: }
205:
206: /**
207: * Returns the horizontal index of the leftmost column of tiles
208: * of the primary image.
209: * The call is forwarded to the first image in the <code>List</code>.
210: */
211: public int getMinTileX() {
212: return ((RenderedImage) getList().get(0)).getMinTileX();
213: }
214:
215: /**
216: * Returns the number of tiles of the primary image along the
217: * tile grid in the horizontal direction.
218: * The call is forwarded to the first image in the <code>List</code>.
219: */
220: public int getNumXTiles() {
221: return ((RenderedImage) getList().get(0)).getNumXTiles();
222: }
223:
224: /**
225: * Returns the vertical index of the uppermost row of tiles
226: * of the primary image.
227: * The call is forwarded to the first image in the <code>List</code>.
228: */
229: public int getMinTileY() {
230: return ((RenderedImage) getList().get(0)).getMinTileY();
231: }
232:
233: /**
234: * Returns the number of tiles of the primary image along the
235: * tile grid in the vertical direction.
236: * The call is forwarded to the first image in the <code>List</code>.
237: */
238: public int getNumYTiles() {
239: return ((RenderedImage) getList().get(0)).getNumYTiles();
240: }
241:
242: /**
243: * Returns the SampleModel of the primary image.
244: * The call is forwarded to the first image in the <code>List</code>.
245: */
246: public SampleModel getSampleModel() {
247: return ((RenderedImage) getList().get(0)).getSampleModel();
248: }
249:
250: /**
251: * Returns the ColorModel of the primary image.
252: * The call is forwarded to the first image in the <code>List</code>.
253: */
254: public ColorModel getColorModel() {
255: return ((RenderedImage) getList().get(0)).getColorModel();
256: }
257:
258: /**
259: * Gets a property from the property set of this image. If the
260: * property name is not recognized,
261: * <code>java.awt.Image.UndefinedProperty</code> will be returned.
262: * The call is forwarded to the first image in the <code>List</code>.
263: *
264: * @param name the name of the property to get, as a
265: * <code>String</code>.
266: * @return a reference to the property
267: * <code>Object</code>, or the value
268: * <code>java.awt.Image.UndefinedProperty.</code>
269: * @throws IllegalArgumentException if <code>name</code> is
270: * <code>null</code>.
271: */
272: public Object getProperty(String name) {
273: if (name == null) {
274: throw new IllegalArgumentException(JaiI18N
275: .getString("RenderedImageList0"));
276: }
277:
278: return ((RenderedImage) getList().get(0)).getProperty(name);
279: }
280:
281: /**
282: * Returns a list of the properties recognized by this image. If
283: * no properties are available, <code>null</code> will be
284: * returned.
285: * The call is forwarded to the first image in the <code>List</code>.
286: *
287: * @return an array of <code>String</code>s representing valid
288: * property names.
289: */
290: public String[] getPropertyNames() {
291: return ((RenderedImage) getList().get(0)).getPropertyNames();
292: }
293:
294: /**
295: * Returns a <code>Vector</code> containing the image sources.
296: * The call is forwarded to the first image in the <code>List</code>.
297: */
298: public Vector getSources() {
299: return ((RenderedImage) getList().get(0)).getSources();
300: }
301:
302: /**
303: * Returns tile (<code>tileX</code>, <code>tileY</code>) of the
304: * primary image as a <code>Raster</code>. Note that <code>tileX</code>
305: * and <code>tileY</code> are indices into the tile array, not pixel
306: * locations.
307: * The call is forwarded to the first image in the <code>List</code>.
308: *
309: * @param tileX The X index of the requested tile in the tile array.
310: * @param tileY The Y index of the requested tile in the tile array.
311: */
312: public Raster getTile(int tileX, int tileY) {
313: return ((RenderedImage) getList().get(0)).getTile(tileX, tileY);
314: }
315:
316: /**
317: * Returns the entire primary image in a single <code>Raster</code>.
318: * For images with multiple tiles this will require making a copy.
319: * The returned <code>Raster</code> is semantically a copy.
320: * The call is forwarded to the first image in the <code>List</code>.
321: *
322: * @return a <code>Raster</code> containing a copy of this image's data.
323: */
324: public Raster getData() {
325: return ((RenderedImage) getList().get(0)).getData();
326: }
327:
328: /**
329: * Returns an arbitrary rectangular region of the primary image
330: * in a <code>Raster</code>. The returned <code>Raster</code> is
331: * semantically a copy.
332: * The call is forwarded to the first image in the <code>List</code>.
333: *
334: * @param bounds the region of the <code>RenderedImage</code> to be
335: * returned.
336: */
337: public Raster getData(Rectangle bounds) {
338: return ((RenderedImage) getList().get(0)).getData(bounds);
339: }
340:
341: /**
342: * Copies an arbitrary rectangular region of the primary image
343: * into a caller-supplied WritableRaster. The region to be
344: * computed is determined by clipping the bounds of the supplied
345: * WritableRaster against the bounds of the image. The supplied
346: * WritableRaster must have a SampleModel that is compatible with
347: * that of the image.
348: *
349: * <p> If the raster argument is null, the entire image will
350: * be copied into a newly-created WritableRaster with a SampleModel
351: * that is compatible with that of the image.
352: * The call is forwarded to the first image in the <code>List</code>.
353: *
354: * @param dest a WritableRaster to hold the returned portion of
355: * the image.
356: * @return a reference to the supplied WritableRaster, or to a
357: * new WritableRaster if the supplied one was null.
358: */
359: public WritableRaster copyData(WritableRaster dest) {
360: return ((RenderedImage) getList().get(0)).copyData(dest);
361: }
362:
363: /// --- List methods. ---
364:
365: /**
366: * Inserts the specified element at the specified position in this list.
367: *
368: * @throws IllegalArgumentException if the specified element
369: * is not a <code>RenderedImage</code>.
370: * @throws IndexOutOfBoundsException if the index is out of range
371: * (index < 0 || index > size()).
372: */
373: public void add(int index, Object element) {
374: if (element instanceof RenderedImage) {
375: if (index >= 0 && index <= imageCollection.size()) {
376: ((List) imageCollection).add(index, element);
377: } else {
378: throw new IndexOutOfBoundsException(JaiI18N
379: .getString("RenderedImageList3"));
380: }
381: } else {
382: throw new IllegalArgumentException(JaiI18N
383: .getString("RenderedImageList2"));
384: }
385: }
386:
387: /**
388: * Inserts into this <code>List</code> at the indicated position
389: * all elements in the specified <code>Collection</code> which are
390: * <code>RenderedImage</code>s.
391: *
392: * @return <code>true</code> if this <code>List</code> changed
393: * as a result of the call.
394: * @throws IndexOutOfBoundsException if the index is out of range
395: * (index < 0 || index > size()).
396: */
397: public boolean addAll(int index, Collection c) {
398: // Add only elements of c which are RenderedImages.
399: if (index < 0 || index > imageCollection.size()) {
400: throw new IndexOutOfBoundsException(JaiI18N
401: .getString("RenderedImageList3"));
402: }
403:
404: // Only allow RenderedImages
405: Vector temp = null;
406: Iterator iter = c.iterator();
407:
408: while (iter.hasNext()) {
409: Object o = iter.next();
410:
411: if (o instanceof RenderedImage) {
412: if (temp == null) {
413: temp = new Vector();
414: }
415:
416: temp.add(o);
417: }
418: }
419:
420: return ((List) imageCollection).addAll(index, temp);
421: }
422:
423: /**
424: * @return the <code>RenderedImage</code> object at the
425: * specified index.
426: *
427: * @param index index of element to return.
428: * @return the element at the specified position in this list.
429: *
430: * @throws IndexOutOfBoundsException if the index is out of range (index
431: * < 0 || index >= size()).
432: */
433: public Object get(int index) {
434: if (index < 0 || index >= imageCollection.size()) {
435: throw new IndexOutOfBoundsException(JaiI18N
436: .getString("RenderedImageList3"));
437: }
438:
439: return ((List) imageCollection).get(index);
440: }
441:
442: public int indexOf(Object o) {
443: // Do not throw an <code>IllegalArgumentException</code> even
444: // if o is not a RenderedImage.
445: return ((List) imageCollection).indexOf(o);
446: }
447:
448: public int lastIndexOf(Object o) {
449: // Do not throw an <code>IllegalArgumentException</code> even
450: // if o is not a RenderedImage.
451: return ((List) imageCollection).lastIndexOf(o);
452: }
453:
454: public ListIterator listIterator() {
455: return ((List) imageCollection).listIterator();
456: }
457:
458: public ListIterator listIterator(int index) {
459: return ((List) imageCollection).listIterator(index);
460: }
461:
462: public Object remove(int index) {
463: return ((List) imageCollection).remove(index);
464: }
465:
466: public Object set(int index, Object element) {
467: if (element instanceof RenderedImage) {
468: return ((List) imageCollection).set(index, element);
469: }
470:
471: throw new IllegalArgumentException(JaiI18N
472: .getString("RenderedImageList2"));
473: }
474:
475: public List subList(int fromIndex, int toIndex) {
476: return ((List) imageCollection).subList(fromIndex, toIndex);
477: }
478:
479: // --- Collection methods: overridden to require RenderedImages. ---
480:
481: /**
482: * Adds the specified object to this <code>List</code>.
483: *
484: * @throws IllegalArgumentException if <code>o</code> is <code>null</code>
485: * or is not an <code>RenderedImage</code>.
486: *
487: * @return <code>true</code> if and only if the parameter is added to the
488: * <code>List</code>.
489: */
490: public boolean add(Object o) {
491: if (o == null) {
492: throw new IllegalArgumentException(JaiI18N
493: .getString("RenderedImageList0"));
494: }
495:
496: if (o instanceof RenderedImage) {
497: imageCollection.add(o);
498: return true;
499: } else {
500: throw new IllegalArgumentException(JaiI18N
501: .getString("RenderedImageList2"));
502: }
503: }
504:
505: /**
506: * Adds to this <code>List</code> all elements in the specified
507: * <code>Collection</code> which are <code>RenderedImage</code>s.
508: *
509: * @return <code>true</code> if this <code>List</code> changed
510: * as a result of the call.
511: */
512: public boolean addAll(Collection c) {
513: Iterator iter = c.iterator();
514: boolean status = false;
515:
516: while (iter.hasNext()) {
517: Object o = iter.next();
518:
519: if (o instanceof RenderedImage) {
520: imageCollection.add(o);
521: status = true;
522: }
523: }
524:
525: return status;
526: }
527: }
|