OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / javax / imageio / ImageReader.java
1 /* ImageReader.java -- Decodes raster images.
2    Copyright (C) 2004, 2005  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package javax.imageio;
40
41 import java.awt.Point;
42 import java.awt.Rectangle;
43 import java.awt.image.BufferedImage;
44 import java.awt.image.Raster;
45 import java.awt.image.RenderedImage;
46 import java.io.IOException;
47 import java.util.ArrayList;
48 import java.util.Iterator;
49 import java.util.List;
50 import java.util.Locale;
51 import java.util.ResourceBundle;
52 import java.util.MissingResourceException;
53 import java.util.Set;
54
55 import javax.imageio.event.IIOReadProgressListener;
56 import javax.imageio.event.IIOReadUpdateListener;
57 import javax.imageio.event.IIOReadWarningListener;
58 import javax.imageio.metadata.IIOMetadata;
59 import javax.imageio.spi.ImageReaderSpi;
60 import javax.imageio.stream.ImageInputStream;
61
62 /**
63  * A class for decoding images within the ImageIO framework.
64  *
65  * An ImageReader for a given format is instantiated by an
66  * ImageReaderSpi for that format.  ImageReaderSpis are registered
67  * with the IIORegistry.
68  *
69  * The ImageReader API supports reading animated images that may have
70  * multiple frames; to support such images many methods take an index
71  * parameter.
72  *
73  * Images may also be read in multiple passes, where each successive
74  * pass increases the level of detail in the destination image.
75  */
76 public abstract class ImageReader
77 {
78   private boolean aborted;
79
80   /**
81    * All locales available for localization of warning messages, or
82    * null if localization is not supported.
83    */
84   protected Locale[] availableLocales = null;
85
86   /**
87    * true if the input source does not require metadata to be read,
88    * false otherwise.
89    */
90   protected boolean ignoreMetadata = false;
91
92   /**
93    * An ImageInputStream from which image data is read.
94    */
95   protected Object input = null;
96
97   /**
98    * The current locale used to localize warning messages, or null if
99    * no locale has been set.
100    */
101   protected Locale locale = null;
102
103   /**
104    * The minimum index at which data can be read.  Constantly 0 if
105    * seekForwardOnly is false, always increasing if seekForwardOnly is
106    * true.
107    */
108   protected int minIndex = 0;
109
110   /**
111    * The image reader SPI that instantiated this reader.
112    */
113   protected ImageReaderSpi originatingProvider = null;
114
115   /**
116    * A list of installed progress listeners.  Initially null, meaning
117    * no installed listeners.
118    */
119   protected List<IIOReadProgressListener> progressListeners = null;
120
121   /**
122    * true if this reader should only read data further ahead in the
123    * stream than its current location.  false if it can read backwards
124    * in the stream.  If this is true then caching can be avoided.
125    */
126   protected boolean seekForwardOnly = false;
127
128   /**
129    * A list of installed update listeners.  Initially null, meaning no
130    * installed listeners.
131    */
132   protected List<IIOReadUpdateListener> updateListeners = null;
133
134   /**
135    * A list of installed warning listeners.  Initially null, meaning
136    * no installed listeners.
137    */
138   protected List<IIOReadWarningListener> warningListeners = null;
139
140   /**
141    * A list of warning locales corresponding with the list of
142    * installed warning listeners.  Initially null, meaning no locales.
143    */
144   protected List<Locale> warningLocales = null;
145
146   /**
147    * Construct an image reader.
148    *
149    * @param originatingProvider the provider that is constructing this
150    * image reader, or null
151    */
152   protected ImageReader(ImageReaderSpi originatingProvider)
153   {
154     this.originatingProvider = originatingProvider;
155   }
156
157   /**
158    * Request that reading be aborted.  The unread contents of the
159    * image will be undefined.
160    *
161    * Readers should clear the abort flag before starting a read
162    * operation, then poll it periodically during the read operation.
163    */
164   public void abort()
165   {
166     aborted = true;
167   }
168
169   /**
170    * Check if the abort flag is set.
171    *
172    * @return true if the current read operation should be aborted,
173    * false otherwise
174    */
175   protected boolean abortRequested()
176   {
177     return aborted;
178   }
179
180   /**
181    * Install a read progress listener.  This method will return
182    * immediately if listener is null.
183    *
184    * @param listener a read progress listener or null
185    */
186   public void addIIOReadProgressListener(IIOReadProgressListener listener)
187   {
188     if (listener == null)
189       return;
190     if (progressListeners == null)
191       progressListeners = new ArrayList ();
192     progressListeners.add(listener);
193   }
194
195   /**
196    * Install a read update listener.  This method will return
197    * immediately if listener is null.
198    *
199    * @param listener a read update listener
200    */
201   public void addIIOReadUpdateListener(IIOReadUpdateListener listener)
202   {
203     if (listener == null)
204       return;
205     if (updateListeners == null)
206       updateListeners = new ArrayList ();
207     updateListeners.add(listener);
208   }
209
210   /**
211    * Install a read warning listener.  This method will return
212    * immediately if listener is null.  Warning messages sent to this
213    * listener will be localized using the current locale.  If the
214    * current locale is null then this reader will select a sensible
215    * default.
216    *
217    * @param listener a read warning listener
218    */
219   public void addIIOReadWarningListener(IIOReadWarningListener listener)
220   {
221     if (listener == null)
222       return;
223     if (warningListeners == null)
224       warningListeners = new ArrayList ();
225     warningListeners.add(listener);
226   }
227
228   /**
229    * Check if this reader can handle raster data.  Determines whether
230    * or not readRaster and readTileRaster throw
231    * UnsupportedOperationException.
232    *
233    * @return true if this reader supports raster data, false if not
234    */
235   public boolean canReadRaster()
236   {
237     return false;
238   }
239
240   /**
241    * Clear the abort flag.
242    */
243   protected void clearAbortRequest()
244   {
245     aborted = false;
246   }
247
248   /**
249    * Releases any resources allocated to this object.  Subsequent
250    * calls to methods on this object will produce undefined results.
251    *
252    * The default implementation does nothing; subclasses should use
253    * this method ensure that native resources are released.
254    */
255   public void dispose()
256   {
257     // The default implementation does nothing.
258   }
259
260   /**
261    * Returns the aspect ratio of this image, the ration of its width
262    * to its height.  The aspect ratio is useful when resizing an image
263    * while keeping its proportions constant.
264    *
265    * @param imageIndex the frame index
266    *
267    * @return the image's aspect ratio
268    *
269    * @exception IllegalStateException if input is null
270    * @exception IndexOutOfBoundsException if the frame index is
271    * out-of-bounds
272    * @exception IOException if a read error occurs
273    */
274   public float getAspectRatio(int imageIndex)
275     throws IOException
276   {
277     if (input == null)
278       throw new IllegalStateException("input is null");
279
280     return (float) (getWidth(imageIndex) / getHeight(imageIndex));
281   }
282
283   /**
284    * Retrieve the available locales.  Return null if no locales are
285    * available or a clone of availableLocales.
286    *
287    * @return an array of locales or null
288    */
289   public Locale[] getAvailableLocales()
290   {
291     if (availableLocales == null)
292       return null;
293     
294     return (Locale[]) availableLocales.clone();
295   }
296
297   /**
298    * Retrieve the default read parameters for this reader's image
299    * format.
300    *
301    * The default implementation returns new ImageReadParam().
302    *
303    * @return image reading parameters
304    */
305   public ImageReadParam getDefaultReadParam()
306   {
307     return new ImageReadParam();
308   }
309
310   /**
311    * Retrieve the format of the input source.
312    *
313    * @return the input source format name
314    *
315    * @exception IOException if a read error occurs
316    */
317   public String getFormatName()
318     throws IOException
319   {
320     return originatingProvider.getFormatNames()[0];
321   }
322
323   /**
324    * Get the height of the input image in pixels.  If the input image
325    * is resizable then a default height is returned.
326    *
327    * @param imageIndex the frame index
328    *
329    * @return the height of the input image
330    *
331    * @exception IllegalStateException if input has not been set
332    * @exception IndexOutOfBoundsException if the frame index is
333    * out-of-bounds
334    * @exception IOException if a read error occurs
335    */
336   public abstract int getHeight(int imageIndex)
337     throws IOException;
338
339   /**
340    * Get the metadata associated with this image.  If the reader is
341    * set to ignore metadata or does not support reading metadata, or
342    * if no metadata is available then null is returned.
343    *
344    * @param imageIndex the frame index
345    *
346    * @return a metadata object, or null
347    *
348    * @exception IllegalStateException if input has not been set
349    * @exception IndexOutOfBoundsException if the frame index is
350    * out-of-bounds
351    * @exception IOException if a read error occurs
352    */
353   public abstract IIOMetadata getImageMetadata(int imageIndex)
354     throws IOException;
355
356   /**
357    * Get an iterator over the collection of image types into which
358    * this reader can decode image data.  This method is guaranteed to
359    * return at least one valid image type specifier.
360    *
361    * The elements of the iterator should be ordered; the first element
362    * should be the most appropriate image type for this decoder,
363    * followed by the second-most appropriate, and so on.
364    *
365    * @param imageIndex the frame index
366    *
367    * @return an iterator over a collection of image type specifiers
368    *
369    * @exception IllegalStateException if input has not been set
370    * @exception IndexOutOfBoundsException if the frame index is
371    * out-of-bounds
372    * @exception IOException if a read error occurs
373    */
374   public abstract Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex)
375     throws IOException;
376
377   /**
378    * Set the input source to the given object, specify whether this
379    * reader should be allowed to read input from the data stream more
380    * than once, and specify whether this reader should ignore metadata
381    * in the input stream.  The input source must be set before many
382    * methods can be called on this reader. (see all ImageReader
383    * methods that throw IllegalStateException).  If input is null then
384    * the current input source will be removed.
385    *
386    * Unless this reader has direct access with imaging hardware, input
387    * should be an ImageInputStream.
388    *
389    * @param input the input source object
390    * @param seekForwardOnly true if this reader should be allowed to
391    * read input from the data stream more than once, false otherwise
392    * @param ignoreMetadata true if this reader should ignore metadata
393    * associated with the input source, false otherwise
394    *
395    * @exception IllegalArgumentException if input is not a valid input
396    * source for this reader and is not an ImageInputStream
397    */
398   public void setInput(Object input,
399                        boolean seekForwardOnly,
400                        boolean ignoreMetadata)
401   {
402     Class[] okClasses = originatingProvider.getInputTypes();
403     if (okClasses == null)
404       {
405         if (!(input instanceof ImageInputStream))
406           throw new IllegalArgumentException();
407       }
408     else
409       {
410         boolean classOk = false;
411         for (int i = 0; i < okClasses.length; ++i)
412           if (okClasses[i].isInstance(input))
413             classOk = true;
414         if (!classOk)
415           throw new IllegalArgumentException();
416       }
417
418     this.input = input;
419     this.seekForwardOnly = seekForwardOnly;
420     this.ignoreMetadata = ignoreMetadata;
421     this.minIndex = 0;
422   }
423
424   /**
425    * Set the input source to the given object and specify whether this
426    * reader should be allowed to read input from the data stream more
427    * than once.  The input source must be set before many methods can
428    * be called on this reader. (see all ImageReader methods that throw
429    * IllegalStateException).  If input is null then the current input
430    * source will be removed.
431    *
432    * @param input the input source object
433    * @param seekForwardOnly true if this reader should be allowed to
434    * read input from the data stream more than once, false otherwise
435    *
436    * @exception IllegalArgumentException if input is not a valid input
437    * source for this reader and is not an ImageInputStream
438    */
439   public void setInput(Object in, boolean seekForwardOnly)
440   {
441     setInput(in, seekForwardOnly, false);
442   }
443
444   /**
445    * Set the input source to the given object.  The input source must
446    * be set before many methods can be called on this reader. (see all
447    * ImageReader methods that throw IllegalStateException).  If input
448    * is null then the current input source will be removed.
449    *
450    * @param input the input source object
451    *
452    * @exception IllegalArgumentException if input is not a valid input
453    * source for this reader and is not an ImageInputStream
454    */
455   public void setInput(Object input)
456   {
457     setInput(input, false, false);
458   }
459
460   /**
461    * Get this reader's image input source.  null is returned if the
462    * image source has not been set.
463    *
464    * @return an image input source object, or null
465    */
466   public Object getInput()
467   {
468     return input;
469   }
470
471   /**
472    * Get this reader's locale.  null is returned if the locale has not
473    * been set.
474    *
475    * @return this reader's locale, or null
476    */
477   public Locale getLocale()
478   {
479     return locale;
480   }
481
482   /**
483    * Return the number of images available from the image input
484    * source, not including thumbnails.  This method will return 1
485    * unless this reader is reading an animated image.
486    *
487    * Certain multi-image formats do not encode the total number of
488    * images.  When reading images in those formats it may be necessary
489    * to repeatedly call read, incrementing the image index at each
490    * call, until an IndexOutOfBoundsException is thrown.
491    *
492    * The allowSearch parameter determines whether all images must be
493    * available at all times.  When allowSearch is false, getNumImages
494    * will return -1 if the total number of images is unknown.
495    * Otherwise this method returns the number of images.
496    *
497    * @param allowSearch true if all images should be available at
498    * once, false otherwise
499    *
500    * @return -1 if allowSearch is false and the total number of images
501    * is currently unknown, or the number of images
502    *
503    * @exception IllegalStateException if input has not been set, or if
504    * seekForwardOnly is true
505    * @exception IOException if a read error occurs
506    */
507   public abstract int getNumImages(boolean allowSearch)
508     throws IOException;
509
510   /**
511    * Get the number of thumbnails associated with an image.
512    *
513    * @param imageIndex the frame index
514    *
515    * @return the number of thumbnails associated with this image
516    */
517   public int getNumThumbnails(int imageIndex)
518     throws IOException
519   {
520     return 0;
521   }
522
523   /**
524    * Get the ImageReaderSpi that created this reader or null.
525    *
526    * @return an ImageReaderSpi, or null
527    */
528   public ImageReaderSpi getOriginatingProvider()
529   {
530     return originatingProvider;
531   }
532
533   /**
534    * Get the metadata associated with the image being read.  If the
535    * reader is set to ignore metadata or does not support reading
536    * metadata, or if no metadata is available then null is returned.
537    * This method returns metadata associated with the entirety of the
538    * image data, whereas getImageMetadata(int) returns metadata
539    * associated with a frame within a multi-image data stream.
540    *
541    * @return metadata associated with the image being read, or null
542    *
543    * @exception IOException if a read error occurs
544    */
545   public abstract IIOMetadata getStreamMetadata()
546     throws IOException;
547
548   /**
549    * Get the height of a thumbnail image.
550    *
551    * @param imageIndex the frame index
552    * @param thumbnailIndex the thumbnail index
553    *
554    * @return the height of the thumbnail image
555    *
556    * @exception UnsupportedOperationException if this reader does not
557    * support thumbnails
558    * @exception IllegalStateException if input is null
559    * @exception IndexOutOfBoundsException if either index is
560    * out-of-bounds
561    * @exception IOException if a read error occurs
562    */
563   public int getThumbnailHeight(int imageIndex, int thumbnailIndex)
564     throws IOException
565   {
566     return readThumbnail(imageIndex, thumbnailIndex).getHeight();
567   }
568
569   /**
570    * Get the width of a thumbnail image.
571    *
572    * @param imageIndex the frame index
573    * @param thumbnailIndex the thumbnail index
574    *
575    * @return the width of the thumbnail image
576    *
577    * @exception UnsupportedOperationException if this reader does not
578    * support thumbnails
579    * @exception IllegalStateException if input is null
580    * @exception IndexOutOfBoundsException if either index is
581    * out-of-bounds
582    * @exception IOException if a read error occurs
583    */
584   public int getThumbnailWidth(int imageIndex, int thumbnailIndex)
585     throws IOException
586   {
587     return readThumbnail(imageIndex, thumbnailIndex).getWidth();
588   }
589
590   /**
591    * Get the X coordinate in pixels of the top-left corner of the
592    * first tile in this image.
593    *
594    * @param imageIndex the frame index
595    *
596    * @return the X coordinate of this image's first tile
597    *
598    * @exception IllegalStateException if input is needed but the input
599    * source is not set
600    * @exception IndexOutOfBoundsException if the frame index is
601    * out-of-bounds
602    * @exception IOException if a read error occurs
603    */
604   public int getTileGridXOffset(int imageIndex)
605     throws IOException
606   {
607     return 0;
608   }
609
610   /**
611    * Get the Y coordinate in pixels of the top-left corner of the
612    * first tile in this image.
613    *
614    * @param imageIndex the frame index
615    *
616    * @return the Y coordinate of this image's first tile
617    *
618    * @exception IllegalStateException if input is needed but the input
619    * source is not set
620    * @exception IndexOutOfBoundsException if the frame index is
621    * out-of-bounds
622    * @exception IOException if a read error occurs
623    */
624   public int getTileGridYOffset(int imageIndex)
625     throws IOException
626   {
627     return 0;
628   }
629
630   /**
631    * Get the height of an image tile.
632    *
633    * @param imageIndex the frame index
634    *
635    * @return the tile height for the given image
636    *
637    * @exception IllegalStateException if input is null
638    * @exception IndexOutOfBoundsException if the frame index is
639    * out-of-bounds
640    * @exception IOException if a read error occurs
641    */
642   public int getTileHeight(int imageIndex)
643     throws IOException
644   {
645     return getHeight(imageIndex);
646   }
647
648   /**
649    * Get the width of an image tile.
650    *
651    * @param imageIndex the frame index
652    *
653    * @return the tile width for the given image
654    *
655    * @exception IllegalStateException if input is null
656    * @exception IndexOutOfBoundsException if the frame index is
657    * out-of-bounds
658    * @exception IOException if a read error occurs
659    */
660   public int getTileWidth(int imageIndex)
661     throws IOException
662   {
663     return getWidth(imageIndex);
664   }
665
666   /**
667    * Get the width of the input image in pixels.  If the input image
668    * is resizable then a default width is returned.
669    *
670    * @param imageIndex the image's index
671    *
672    * @return the width of the input image
673    *
674    * @exception IllegalStateException if input has not been set
675    * @exception IndexOutOfBoundsException if the frame index is
676    * out-of-bounds
677    * @exception IOException if a read error occurs
678    */
679   public abstract int getWidth(int imageIndex)
680     throws IOException;
681
682   /**
683    * Check whether or not the given image has thumbnails associated
684    * with it.
685    *
686    * @return true if the given image has thumbnails, false otherwise
687    *
688    * @exception IllegalStateException if input is null
689    * @exception IndexOutOfBoundsException if the frame index is
690    * out-of-bounds
691    * @exception IOException if a read error occurs
692    */
693   public boolean hasThumbnails(int imageIndex)
694     throws IOException
695   {
696     return getNumThumbnails(imageIndex) > 0;
697   }
698
699   /**
700    * Check if this image reader ignores metadata.  This method simply
701    * returns the value of ignoreMetadata.
702    *
703    * @return true if metadata is being ignored, false otherwise
704    */
705   public boolean isIgnoringMetadata()
706   {
707     return ignoreMetadata;
708   }
709
710   /**
711    * Check if the given image is sub-divided into equal-sized
712    * non-overlapping pixel rectangles.
713    *
714    * A reader may expose tiling in the underlying format, hide it, or
715    * simulate tiling even if the underlying format is not tiled.
716    *
717    * @return true if the given image is tiled, false otherwise
718    *
719    * @exception IllegalStateException if input is null
720    * @exception IndexOutOfBoundsException if the frame index is
721    * out-of-bounds
722    * @exception IOException if a read error occurs
723    */
724   public boolean isImageTiled(int imageIndex)
725     throws IOException
726   {
727     return false;
728   }
729
730   /**
731    * Check if all pixels in this image are readily accessible.  This
732    * method should return false for compressed formats.  The return
733    * value is a hint as to the efficiency of certain image reader
734    * operations.
735    *
736    * @param imageIndex the frame index
737    *
738    * @return true if random pixel access is fast, false otherwise
739    *
740    * @exception IllegalStateException if input is null and it is
741    * needed to determine the return value
742    * @exception IndexOutOfBoundsException if the frame index is
743    * out-of-bounds but the frame data must be accessed to determine
744    * the return value
745    * @exception IOException if a read error occurs
746    */
747   public boolean isRandomAccessEasy(int imageIndex)
748     throws IOException
749   {
750     return false;
751   }
752
753   /**
754    * Check if this image reader may only seek forward within the input
755    * stream.
756    *
757    * @return true if this reader may only seek forward, false
758    * otherwise
759    */
760   public boolean isSeekForwardOnly()
761   {
762     return seekForwardOnly;
763   }
764
765   /**
766    * Notifies all installed read progress listeners that image loading
767    * has completed by calling their imageComplete methods.
768    */
769   protected void processImageComplete()
770   {
771     if (progressListeners != null)
772       {
773         Iterator it = progressListeners.iterator();
774
775         while (it.hasNext())
776           {
777             IIOReadProgressListener listener =
778               (IIOReadProgressListener) it.next();
779             listener.imageComplete (this);
780           }
781       }
782   }
783
784   /**
785    * Notifies all installed read progress listeners that a certain
786    * percentage of the image has been loaded, by calling their
787    * imageProgress methods.
788    *
789    * @param percentageDone the percentage of image data that has been
790    * loaded
791    */
792   protected void processImageProgress(float percentageDone)
793   {
794      if (progressListeners != null)
795       {
796         Iterator it = progressListeners.iterator();
797
798         while (it.hasNext())
799           {
800             IIOReadProgressListener listener =
801               (IIOReadProgressListener) it.next();
802             listener.imageProgress(this, percentageDone);
803           }
804       }
805   }
806   /**
807    * Notifies all installed read progress listeners, by calling their
808    * imageStarted methods, that image loading has started on the given
809    * image.
810    *
811    * @param imageIndex the frame index of the image that has started
812    * loading
813    */
814   protected void processImageStarted(int imageIndex)
815   {
816      if (progressListeners != null)
817       {
818         Iterator it = progressListeners.iterator();
819
820         while (it.hasNext())
821           {
822             IIOReadProgressListener listener =
823               (IIOReadProgressListener) it.next();
824             listener.imageStarted(this, imageIndex);
825           }
826       }
827   }
828
829   /**
830    * Notifies all installed read update listeners, by calling their
831    * imageUpdate methods, that the set of samples has changed.
832    *
833    * @param image the buffered image that is being updated
834    * @param minX the X coordinate of the top-left pixel in this pass
835    * @param minY the Y coordinate of the top-left pixel in this pass
836    * @param width the total width of the rectangle covered by this
837    * pass, including skipped pixels
838    * @param height the total height of the rectangle covered by this
839    * pass, including skipped pixels
840    * @param periodX the horizontal sample interval
841    * @param periodY the vertical sample interval
842    * @param bands the affected bands in the destination
843    */
844   protected void processImageUpdate(BufferedImage image, int minX, int minY,
845                                     int width, int height, int periodX,
846                                     int periodY, int[] bands)
847   {
848     if (updateListeners != null)
849       {
850         Iterator it = updateListeners.iterator();
851
852         while (it.hasNext())
853           {
854             IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next();
855             listener.imageUpdate(this, image, minX, minY, width, height,
856                                  periodX, periodY, bands);
857           }
858       }
859   }
860
861   /**
862    * Notifies all installed update progress listeners, by calling
863    * their passComplete methods, that a progressive pass has
864    * completed.
865    *
866    * @param image the image that has being updated
867    */
868   protected void processPassComplete(BufferedImage image)
869   {
870     if (updateListeners != null)
871       {
872         Iterator it = updateListeners.iterator();
873
874         while (it.hasNext())
875           {
876             IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next();
877             listener.passComplete(this, image);
878           }
879       }
880   }
881
882   /**
883    * Notifies all installed read update listeners, by calling their
884    * passStarted methods, that a new pass has begun.
885    *
886    * @param image the buffered image that is being updated
887    * @param pass the current pass number
888    * @param minPass the pass at which decoding will begin
889    * @param maxPass the pass at which decoding will end
890    * @param minX the X coordinate of the top-left pixel in this pass
891    * @param minY the Y coordinate of the top-left pixel in this pass
892    * @param width the total width of the rectangle covered by this
893    * pass, including skipped pixels
894    * @param height the total height of the rectangle covered by this
895    * pass, including skipped pixels
896    * @param periodX the horizontal sample interval
897    * @param periodY the vertical sample interval
898    * @param bands the affected bands in the destination
899    */
900   protected void processPassStarted(BufferedImage image, int pass, int minPass,
901                                     int maxPass, int minX, int minY,
902                                     int periodX, int periodY, int[] bands)
903   {
904     if (updateListeners != null)
905       {
906         Iterator it = updateListeners.iterator();
907
908         while (it.hasNext())
909           {
910             IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next();
911             listener.passStarted(this, image, pass, minPass, maxPass, minX,
912                                  minY, periodX, periodY, bands);
913           }
914       }
915   }
916
917   /**
918    * Notifies all installed read progress listeners that image loading
919    * has been aborted by calling their readAborted methods.
920    */
921   protected void processReadAborted()
922   {
923      if (progressListeners != null)
924       {
925         Iterator it = progressListeners.iterator();
926
927         while (it.hasNext())
928           {
929             IIOReadProgressListener listener =
930               (IIOReadProgressListener) it.next();
931             listener.readAborted(this);
932           }
933       }
934   }
935   /**
936    * Notifies all installed read progress listeners, by calling their
937    * sequenceComplete methods, that a sequence of images has completed
938    * loading.
939    */
940   protected void processSequenceComplete()
941   {
942      if (progressListeners != null)
943       {
944         Iterator it = progressListeners.iterator();
945
946         while (it.hasNext())
947           {
948             IIOReadProgressListener listener =
949               (IIOReadProgressListener) it.next();
950             listener.sequenceComplete(this);
951           }
952       }
953   }
954
955   /**
956    * Notifies all installed read progress listeners, by calling their
957    * sequenceStarted methods, a sequence of images has started
958    * loading.
959    *
960    * @param minIndex the index of the first image in the sequence
961    */
962   protected void processSequenceStarted(int minIndex)
963   {
964
965     if (progressListeners != null)
966       {
967         Iterator it = progressListeners.iterator();
968
969         while (it.hasNext())
970           {
971             IIOReadProgressListener listener =
972               (IIOReadProgressListener) it.next();
973             listener.sequenceStarted(this, minIndex);
974           }
975       }
976   }
977
978   /**
979    * Notifies all installed read progress listeners, by calling their
980    * thumbnailComplete methods, that a thumbnail has completed
981    * loading.
982    */
983   protected void processThumbnailComplete()
984   {
985     if (progressListeners != null)
986       {
987         Iterator it = progressListeners.iterator();
988
989         while (it.hasNext())
990           {
991             IIOReadProgressListener listener =
992               (IIOReadProgressListener) it.next();
993             listener.thumbnailComplete(this);
994           }
995       }
996   }
997
998   /**
999    * Notifies all installed update progress listeners, by calling
1000    * their thumbnailPassComplete methods, that a progressive pass has
1001    * completed on a thumbnail.
1002    *
1003    * @param thumbnail the thumbnail that has being updated
1004    */
1005   protected void processThumbnailPassComplete(BufferedImage thumbnail)
1006   {
1007     if (updateListeners != null)
1008       {
1009         Iterator it = updateListeners.iterator();
1010
1011         while (it.hasNext())
1012           {
1013             IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next();
1014             listener.thumbnailPassComplete(this, thumbnail);
1015           }
1016       }
1017   }
1018
1019   /**
1020    * Notifies all installed read update listeners, by calling their
1021    * thumbnailPassStarted methods, that a new pass has begun.
1022    *
1023    * @param thumbnail the thumbnail that is being updated
1024    * @param pass the current pass number
1025    * @param minPass the pass at which decoding will begin
1026    * @param maxPass the pass at which decoding will end
1027    * @param minX the X coordinate of the top-left pixel in this pass
1028    * @param minY the Y coordinate of the top-left pixel in this pass
1029    * @param width the total width of the rectangle covered by this
1030    * pass, including skipped pixels
1031    * @param height the total height of the rectangle covered by this
1032    * pass, including skipped pixels
1033    * @param periodX the horizontal sample interval
1034    * @param periodY the vertical sample interval
1035    * @param bands the affected bands in the destination
1036    */
1037   protected void processThumbnailPassStarted(BufferedImage thumbnail, int pass,
1038                                              int minPass, int maxPass, int minX,
1039                                              int minY, int periodX, int periodY,
1040                                              int[] bands)
1041   {
1042     if (updateListeners != null)
1043       {
1044         Iterator it = updateListeners.iterator();
1045
1046         while (it.hasNext())
1047           {
1048             IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next();
1049             listener.thumbnailPassStarted(this, thumbnail, pass, minPass,
1050                                           maxPass, minX, minY, periodX,
1051                                           periodY, bands);
1052           }
1053       }
1054   }
1055
1056   /**
1057    * Notifies all installed read progress listeners that a certain
1058    * percentage of a thumbnail has been loaded, by calling their
1059    * thumbnailProgress methods.
1060    *
1061    * @param percentageDone the percentage of thumbnail data that has
1062    * been loaded
1063    */
1064   protected void processThumbnailProgress(float percentageDone)
1065   {
1066     if (progressListeners != null)
1067       {
1068         Iterator it = progressListeners.iterator();
1069
1070         while (it.hasNext())
1071           {
1072             IIOReadProgressListener listener =
1073               (IIOReadProgressListener) it.next();
1074             listener.thumbnailProgress(this, percentageDone);
1075           }
1076       }
1077   }
1078
1079   /**
1080    * Notifies all installed read progress listeners, by calling their
1081    * imageStarted methods, that thumbnail loading has started on the
1082    * given thumbnail of the given image.
1083    *
1084    * @param imageIndex the frame index of the image one of who's
1085    * thumbnails has started loading
1086    * @param thumbnailIndex the index of the thumbnail that has started
1087    * loading
1088    */
1089   protected void processThumbnailStarted(int imageIndex, int thumbnailIndex)
1090   {
1091     if (progressListeners != null)
1092       {
1093         Iterator it = progressListeners.iterator();
1094
1095         while (it.hasNext())
1096           {
1097             IIOReadProgressListener listener =
1098               (IIOReadProgressListener) it.next();
1099             listener.thumbnailStarted(this, imageIndex, thumbnailIndex);
1100           }
1101       }
1102   }
1103
1104   /**
1105    * Notifies all installed read update listeners, by calling their
1106    * thumbnailUpdate methods, that the set of samples has changed.
1107    *
1108    * @param image the buffered image that is being updated
1109    * @param minX the X coordinate of the top-left pixel in this pass
1110    * @param minY the Y coordinate of the top-left pixel in this pass
1111    * @param width the total width of the rectangle covered by this
1112    * pass, including skipped pixels
1113    * @param height the total height of the rectangle covered by this
1114    * pass, including skipped pixels
1115    * @param periodX the horizontal sample interval
1116    * @param periodY the vertical sample interval
1117    * @param bands the affected bands in the destination
1118    */
1119   protected void processThumbnailUpdate(BufferedImage image, int minX, int minY,
1120                                         int width, int height, int periodX,
1121                                         int periodY, int[] bands)
1122   {
1123     if (updateListeners != null)
1124       {
1125         Iterator it = updateListeners.iterator();
1126
1127         while (it.hasNext())
1128           {
1129             IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next();
1130             listener.thumbnailUpdate(this, image, minX, minY, width, height,
1131                                      periodX, periodY, bands);
1132           }
1133       }
1134   }
1135
1136   /**
1137    * Notifies all installed warning listeners, by calling their
1138    * warningOccurred methods, that a warning message has been raised.
1139    *
1140    * @param warning the warning message
1141    *
1142    * @exception IllegalArgumentException if warning is null
1143    */
1144   protected void processWarningOccurred(String warning)
1145   {
1146     if (warning == null)
1147       throw new IllegalArgumentException ("null argument");
1148     if (warningListeners != null)
1149       {
1150         Iterator it = warningListeners.iterator();
1151
1152         while (it.hasNext())
1153           {
1154             IIOReadWarningListener listener =
1155               (IIOReadWarningListener) it.next();
1156             listener.warningOccurred(this, warning);
1157           }
1158       }
1159   }
1160
1161   /**
1162    * Notify all installed warning listeners, by calling their
1163    * warningOccurred methods, that a warning message has been raised.
1164    * The warning message is retrieved from a resource bundle, using
1165    * the given basename and keyword.
1166    *
1167    * @param baseName the basename of the resource from which to
1168    * retrieve the warning message
1169    * @param keyword the keyword used to retrieve the warning from the
1170    * resource bundle
1171    *
1172    * @exception IllegalArgumentException if either baseName or keyword
1173    * is null
1174    * @exception IllegalArgumentException if no resource bundle is
1175    * found using baseName
1176    * @exception IllegalArgumentException if the given keyword produces
1177    * no results from the resource bundle
1178    * @exception IllegalArgumentException if the retrieved object is
1179    * not a String
1180    */
1181   protected void processWarningOccurred(String baseName,
1182                                         String keyword)
1183   {
1184     if (baseName == null || keyword == null)
1185       throw new IllegalArgumentException ("null argument");
1186
1187     ResourceBundle b = null;
1188
1189     try
1190       {
1191         b = ResourceBundle.getBundle(baseName, getLocale());
1192       }
1193     catch (MissingResourceException e)
1194       {
1195         throw new IllegalArgumentException ("no resource bundle found");
1196       }
1197
1198     Object str = null;
1199
1200     try
1201       {
1202         str = b.getObject(keyword);
1203       }
1204     catch (MissingResourceException e)
1205       {
1206         throw new IllegalArgumentException ("no results found for keyword");
1207       }
1208
1209     if (! (str instanceof String))
1210       throw new IllegalArgumentException ("retrieved object not a String");
1211
1212     String warning = (String) str;
1213
1214     if (warningListeners != null)
1215       {
1216         Iterator it = warningListeners.iterator();
1217
1218         while (it.hasNext())
1219           {
1220             IIOReadWarningListener listener =
1221               (IIOReadWarningListener) it.next();
1222             listener.warningOccurred(this, warning);
1223           }
1224       }
1225   }
1226
1227   /**
1228    * Read the given frame into a buffered image using the given read
1229    * parameters.  Listeners will be notified of image loading progress
1230    * and warnings.
1231    *
1232    * @param imageIndex the index of the frame to read
1233    * @param param the image read parameters to use when reading
1234    *
1235    * @return a buffered image
1236    *
1237    * @exception IllegalStateException if input is null
1238    * @exception IndexOutOfBoundsException if the frame index is
1239    * out-of-bounds
1240    * @exception IOException if a read error occurs
1241    */
1242   public abstract BufferedImage read(int imageIndex, ImageReadParam param)
1243     throws IOException;
1244
1245   /**
1246    * Check if this reader supports reading thumbnails.
1247    *
1248    * @return true if this reader supports reading thumbnails, false
1249    * otherwise
1250    */
1251   public boolean readerSupportsThumbnails()
1252   {
1253     return false;
1254   }
1255
1256   /**
1257    * Read raw raster data.  The image type specifier in param is
1258    * ignored but all other parameters are used.  Offset parameters are
1259    * translated into the raster's coordinate space.  This method may
1260    * be implemented by image readers that want to provide direct
1261    * access to raw image data.
1262    *
1263    * @param imageIndex the frame index
1264    * @param param the image read parameters
1265    *
1266    * @return a raster containing the read image data
1267    *
1268    * @exception UnsupportedOperationException if this reader doesn't
1269    * support rasters
1270    * @exception IllegalStateException if input is null
1271    * @exception IndexOutOfBoundsException if the frame index is
1272    * out-of-bounds
1273    * @exception IOException if a read error occurs
1274    */
1275   public Raster readRaster(int imageIndex, ImageReadParam param)
1276     throws IOException
1277   {
1278     throw new UnsupportedOperationException();
1279   }
1280
1281   /**
1282    * Read a thumbnail.
1283    *
1284    * @param imageIndex the frame index
1285    * @param thumbnailIndex the thumbnail index
1286    *
1287    * @return a buffered image of the thumbnail
1288    *
1289    * @exception UnsupportedOperationException if this reader doesn't
1290    * support thumbnails
1291    * @exception IllegalStateException if input is null
1292    * @exception IndexOutOfBoundsException if either the frame index or
1293    * the thumbnail index is out-of-bounds
1294    * @exception IOException if a read error occurs
1295    * 
1296    */
1297   public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex)
1298     throws IOException
1299   {
1300     throw new UnsupportedOperationException();
1301   }
1302
1303   /**
1304    * Uninstall all read progress listeners.
1305    */
1306   public void removeAllIIOReadProgressListeners()
1307   {
1308     progressListeners = null;
1309   }
1310
1311   /**
1312    * Uninstall all read update listeners.
1313    */
1314   public void removeAllIIOReadUpdateListeners()
1315   {
1316     updateListeners = null;
1317   }
1318
1319   /**
1320    * Uninstall all read warning listeners.
1321    */
1322   public void removeAllIIOReadWarningListeners()
1323   {
1324     warningListeners = null;
1325   }
1326
1327   /**
1328    * Uninstall the given read progress listener.
1329    *
1330    * @param listener the listener to remove
1331    */
1332   public void removeIIOReadProgressListener(IIOReadProgressListener listener) 
1333   {
1334     if (listener == null)
1335       return;
1336     if (progressListeners != null)
1337       {
1338         progressListeners.remove(listener);
1339       }
1340   }
1341
1342   /**
1343    * Uninstall the given read update listener.
1344    *
1345    * @param listener the listener to remove
1346    */
1347   public void removeIIOReadUpdateListener(IIOReadUpdateListener listener) 
1348   {
1349     if (listener == null)
1350       return;
1351
1352     if (updateListeners != null)
1353       {
1354         updateListeners.remove(listener);
1355       }
1356   }
1357
1358   /**
1359    * Uninstall the given read warning listener.
1360    *
1361    * @param listener the listener to remove
1362    */
1363   public void removeIIOReadWarningListener(IIOReadWarningListener listener)
1364   {
1365     if (listener == null)
1366       return;
1367     if (warningListeners != null)
1368       {
1369         warningListeners.remove(listener);
1370       }
1371   }
1372
1373   /**
1374    * Set the current locale or use the default locale.
1375    *
1376    * @param locale the locale to set, or null
1377    */
1378   public void setLocale(Locale locale)
1379   {
1380     if (locale != null)
1381       {
1382         // Check if its a valid locale.
1383         boolean found = false;
1384
1385         if (availableLocales != null)
1386           for (int i = availableLocales.length - 1; i >= 0; --i)
1387             if (availableLocales[i].equals(locale))
1388               found = true;
1389
1390         if (! found)
1391           throw new IllegalArgumentException("looale not available");
1392       }
1393
1394     this.locale = locale;
1395   }
1396
1397   /**
1398    * Check that the given read parameters have valid source and
1399    * destination band settings.  If the param.getSourceBands() returns
1400    * null, the array is assumed to include all band indices, 0 to
1401    * numSrcBands - 1; likewise if param.getDestinationBands() returns
1402    * null, it is assumed to be an array containing indices 0 to
1403    * numDstBands - 1.  A failure will cause this method to throw
1404    * IllegalArgumentException.
1405    *
1406    * @param param the image parameters to check
1407    * @param numSrcBands the number of input source bands
1408    * @param numDstBands the number of ouput destination bands
1409    *
1410    * @exception IllegalArgumentException if either the given source or
1411    * destination band indices are invalid
1412    */
1413   protected static void checkReadParamBandSettings(ImageReadParam param,
1414                                                    int numSrcBands,
1415                                                    int numDstBands)
1416   {
1417     int[] srcBands = param.getSourceBands();
1418     int[] dstBands = param.getDestinationBands();
1419     boolean lengthsDiffer = false;
1420     boolean srcOOB = false;
1421     boolean dstOOB = false;
1422
1423     if (srcBands == null)
1424       {
1425         if (dstBands == null)
1426           {
1427             if (numSrcBands != numDstBands)
1428               lengthsDiffer = true;
1429           }
1430         else
1431           {
1432             if (numSrcBands != dstBands.length)
1433               lengthsDiffer = true;
1434
1435             for (int i = 0; i < dstBands.length; i++)
1436               if (dstBands[i] > numSrcBands - 1)
1437                 {
1438                   dstOOB = true;
1439                   break;
1440                 }
1441           }
1442       }
1443     else
1444       {
1445         if (dstBands == null)
1446           {
1447             if (srcBands.length != numDstBands)
1448               lengthsDiffer = true;
1449
1450             for (int i = 0; i < srcBands.length; i++)
1451               if (srcBands[i] > numDstBands - 1)
1452                 {
1453                   srcOOB = true;
1454                   break;
1455                 }
1456           }
1457         else
1458           {
1459             if (srcBands.length != dstBands.length)
1460               lengthsDiffer = true;
1461
1462             for (int i = 0; i < srcBands.length; i++)
1463               if (srcBands[i] > numDstBands - 1)
1464                 {
1465                   srcOOB = true;
1466                   break;
1467                 }
1468
1469             for (int i = 0; i < dstBands.length; i++)
1470               if (dstBands[i] > numSrcBands - 1)
1471                 {
1472                   dstOOB = true;
1473                   break;
1474                 }
1475           }
1476       }
1477
1478     if (lengthsDiffer)
1479       throw new IllegalArgumentException ("array lengths differ");
1480
1481     if (srcOOB)
1482       throw new IllegalArgumentException ("source band index"
1483                                           + " out-of-bounds");
1484
1485     if (dstOOB)
1486       throw new IllegalArgumentException ("destination band index"
1487                                           + " out-of-bounds");
1488   }
1489
1490   /**
1491    * Calcluate the source and destination regions that will be read
1492    * from and written to, given image parameters and/or a destination
1493    * buffered image.  The source region will be clipped if any of its
1494    * bounds are outside the destination region.  Clipping will account
1495    * for subsampling and destination offsets.  Likewise, the
1496    * destination region is clipped to the given destination image, if
1497    * it is not null, using the given image parameters, if they are not
1498    * null.  IllegalArgumentException is thrown if either region will
1499    * contain 0 pixels after clipping.
1500    *
1501    * @param image read parameters, or null
1502    * @param srcWidth the width of the source image
1503    * @param srcHeight the height of the source image
1504    * @param image the destination image, or null
1505    * @param srcRegion a rectangle whose values will be set to the
1506    * clipped source region
1507    * @param destRegion a rectangle whose values will be set to the
1508    * clipped destination region
1509    *
1510    * @exception IllegalArgumentException if either srcRegion or
1511    * destRegion is null
1512    * @exception IllegalArgumentException if either of the calculated
1513    * regions is empty
1514    */
1515   protected static void computeRegions (ImageReadParam param,
1516                                         int srcWidth,
1517                                         int srcHeight,
1518                                         BufferedImage image,
1519                                         Rectangle srcRegion,
1520                                         Rectangle destRegion)
1521   {
1522     if (srcRegion == null || destRegion == null)
1523       throw new IllegalArgumentException ("null region");
1524
1525     if (srcWidth == 0 || srcHeight == 0)
1526       throw new IllegalArgumentException ("zero-sized region");
1527
1528     srcRegion = getSourceRegion(param, srcWidth, srcHeight);
1529     if (image != null)
1530       destRegion = new Rectangle (0, 0, image.getWidth(), image.getHeight());
1531     else
1532       destRegion = new Rectangle (0, 0, srcWidth, srcHeight);
1533
1534     if (param != null)
1535       {
1536         Point offset = param.getDestinationOffset();
1537
1538         if (offset.x < 0)
1539           {
1540             srcRegion.x -= offset.x;
1541             srcRegion.width += offset.x;
1542           }
1543         if (offset.y < 0)
1544           {
1545             srcRegion.y -= offset.y;
1546             srcRegion.height += offset.y;
1547           }
1548
1549         srcRegion.width = srcRegion.width > destRegion.width
1550           ? destRegion.width : srcRegion.width;
1551         srcRegion.height = srcRegion.height > destRegion.height
1552           ? destRegion.height : srcRegion.height;
1553
1554         if (offset.x >= 0)
1555           {
1556             destRegion.x += offset.x;
1557             destRegion.width -= offset.x;
1558           }
1559         if (offset.y >= 0)
1560           {
1561             destRegion.y += offset.y;
1562             destRegion.height -= offset.y;
1563           }
1564       }
1565
1566     if (srcRegion.isEmpty() || destRegion.isEmpty())
1567       throw new IllegalArgumentException ("zero-sized region");
1568   }
1569
1570   /**
1571    * Return a suitable destination buffered image.  If
1572    * param.getDestination() is non-null, then it is returned,
1573    * otherwise a buffered image is created using
1574    * param.getDestinationType() if it is non-null and also in the
1575    * given imageTypes collection, or the first element of imageTypes
1576    * otherwise.
1577    *
1578    * @param param image read parameters from which a destination image
1579    * or image type is retrieved, or null
1580    * @param imageTypes a collection of legal image types
1581    * @param width the width of the source image
1582    * @param height the height of the source image
1583    *
1584    * @return a suitable destination buffered image
1585    *
1586    * @exception IIOException if param.getDestinationType() does not
1587    * return an image type in imageTypes
1588    * @exception IllegalArgumentException if imageTypes is null or
1589    * empty, or if a non-ImageTypeSpecifier object is retrieved from
1590    * imageTypes
1591    * @exception IllegalArgumentException if the resulting destination
1592    * region is empty
1593    * @exception IllegalArgumentException if the product of width and
1594    * height is greater than Integer.MAX_VALUE
1595    */
1596   protected static BufferedImage getDestination (ImageReadParam param,
1597                                                  Iterator<ImageTypeSpecifier> imageTypes,
1598                                                  int width,
1599                                                  int height)
1600     throws IIOException
1601   {
1602     if (imageTypes == null || !imageTypes.hasNext())
1603       throw new IllegalArgumentException ("imageTypes null or empty");
1604
1605     if (width < 0 || height < 0)
1606       throw new IllegalArgumentException ("negative dimension");
1607
1608     // test for overflow
1609     if (width * height < Math.min (width, height))
1610       throw new IllegalArgumentException ("width * height > Integer.MAX_VALUE");
1611
1612     BufferedImage dest = null;
1613     ImageTypeSpecifier destType = null;
1614
1615     if (param != null)
1616       {
1617         dest = param.getDestination ();
1618         if (dest == null)
1619           {
1620             ImageTypeSpecifier type = param.getDestinationType();
1621             if (type != null)
1622               {
1623                 Iterator it = imageTypes;
1624
1625                 while (it.hasNext())
1626                   {
1627                     Object o = it.next ();
1628                     if (! (o instanceof ImageTypeSpecifier))
1629                       throw new IllegalArgumentException ("non-ImageTypeSpecifier object");
1630
1631                     ImageTypeSpecifier t = (ImageTypeSpecifier) o;
1632                     if (t.equals (type))
1633                       {
1634                         dest = t.createBufferedImage (width, height);
1635                         break;
1636                       }
1637                     if (destType == null)
1638                       throw new IIOException ("invalid destination type");
1639
1640                   }
1641               }
1642           }
1643       }
1644     if (dest == null)
1645       {
1646         Rectangle srcRegion = new Rectangle ();
1647         Rectangle destRegion = new Rectangle ();
1648
1649         computeRegions (param, width, height, null, srcRegion, destRegion);
1650
1651         if (destRegion.isEmpty())
1652           throw new IllegalArgumentException ("destination region empty");
1653
1654         if (destType == null)
1655           {
1656             Object o = imageTypes.next();
1657             if (! (o instanceof ImageTypeSpecifier))
1658               throw new IllegalArgumentException ("non-ImageTypeSpecifier"
1659                                                   + " object");
1660
1661             dest = ((ImageTypeSpecifier) o).createBufferedImage
1662               (destRegion.width, destRegion.height);
1663           }
1664         else
1665           dest = destType.createBufferedImage
1666             (destRegion.width, destRegion.height);
1667       }
1668     return dest;
1669   }
1670
1671   /**
1672    * Get the metadata associated with this image.  If the reader is
1673    * set to ignore metadata or does not support reading metadata, or
1674    * if no metadata is available then null is returned.
1675    *
1676    * This more specific version of getImageMetadata(int) can be used
1677    * to restrict metadata retrieval to specific formats and node
1678    * names, which can limit the amount of data that needs to be
1679    * processed.
1680    *
1681    * @param imageIndex the frame index
1682    * @param formatName the format of metadata requested
1683    * @param nodeNames a set of Strings specifiying node names to be
1684    * retrieved
1685    *
1686    * @return a metadata object, or null
1687    *
1688    * @exception IllegalStateException if input has not been set
1689    * @exception IndexOutOfBoundsException if the frame index is
1690    * out-of-bounds
1691    * @exception IllegalArgumentException if formatName is null
1692    * @exception IllegalArgumentException if nodeNames is null
1693    * @exception IOException if a read error occurs
1694    */
1695   public IIOMetadata getImageMetadata (int imageIndex,
1696                                        String formatName,
1697                                        Set<String> nodeNames)
1698     throws IOException
1699   {
1700     if (formatName == null || nodeNames == null)
1701       throw new IllegalArgumentException ("null argument");
1702
1703     return getImageMetadata (imageIndex);
1704   }
1705
1706   /**
1707    * Get the index at which the next image will be read.  If
1708    * seekForwardOnly is true then the returned value will increase
1709    * monotonically each time an image frame is read.  If
1710    * seekForwardOnly is false then the returned value will always be
1711    * 0.
1712    *
1713    * @return the current frame index
1714    */
1715   public int getMinIndex()
1716   {
1717     return minIndex;
1718   }
1719
1720   /**
1721    * Get the image type specifier that most closely represents the
1722    * internal data representation used by this reader.  This value
1723    * should be included in the return value of getImageTypes.
1724    *
1725    * @param imageIndex the frame index
1726    *
1727    * @return an image type specifier
1728    *
1729    * @exception IllegalStateException if input has not been set
1730    * @exception IndexOutOfBoundsException if the frame index is
1731    * out-of-bounds
1732    * @exception IOException if a read error occurs
1733    */
1734   public ImageTypeSpecifier getRawImageType (int imageIndex)
1735     throws IOException
1736   {
1737     return (ImageTypeSpecifier) getImageTypes(imageIndex).next();
1738   }
1739
1740   /**
1741    * Calculate a source region based on the given source image
1742    * dimensions and parameters.  Subsampling offsets and a source
1743    * region are taken from the given image read parameters and used to
1744    * clip the given image dimensions, returning a new rectangular
1745    * region as a result.
1746    *
1747    * @param param image parameters, or null
1748    * @param srcWidth the width of the source image
1749    * @param srcHeight the height of the source image
1750    *
1751    * @return a clipped rectangle
1752    */
1753   protected static Rectangle getSourceRegion (ImageReadParam param,
1754                                               int srcWidth,
1755                                               int srcHeight)
1756   {
1757     Rectangle clippedRegion = new Rectangle (0, 0, srcWidth, srcHeight);
1758
1759     if (param != null)
1760       {
1761         Rectangle srcRegion = param.getSourceRegion();
1762
1763         if (srcRegion != null)
1764           {
1765             clippedRegion.x = srcRegion.x > clippedRegion.x
1766               ? srcRegion.x : clippedRegion.x;
1767             clippedRegion.y = srcRegion.y > clippedRegion.y
1768               ? srcRegion.y : clippedRegion.y;
1769             clippedRegion.width = srcRegion.width > clippedRegion.width
1770               ? srcRegion.width : clippedRegion.width;
1771             clippedRegion.height = srcRegion.height > clippedRegion.height
1772               ? srcRegion.height : clippedRegion.height;
1773           }
1774
1775         int xOffset = param.getSubsamplingXOffset();
1776
1777         clippedRegion.x += xOffset;
1778         clippedRegion.width -= xOffset;
1779
1780         int yOffset = param.getSubsamplingYOffset();
1781
1782         clippedRegion.y += yOffset;
1783         clippedRegion.height -= yOffset;
1784       }
1785     return clippedRegion;
1786   }
1787
1788   /**
1789    * Get the metadata associated with the image being read.  If the
1790    * reader is set to ignore metadata or does not support reading
1791    * metadata, or if no metadata is available then null is returned.
1792    * This method returns metadata associated with the entirety of the
1793    * image data, whereas getStreamMetadata() returns metadata
1794    * associated with a frame within a multi-image data stream.
1795    *
1796    * This more specific version of getStreamMetadata() can be used to
1797    * restrict metadata retrieval to specific formats and node names,
1798    * which can limit the amount of data that needs to be processed.
1799    *
1800    * @param formatName the format of metadata requested
1801    * @param nodeNames a set of Strings specifiying node names to be
1802    * retrieved
1803    *
1804    * @return metadata associated with the image being read, or null
1805    *
1806    * @exception IllegalArgumentException if formatName is null
1807    * @exception IllegalArgumentException if nodeNames is null
1808    * @exception IOException if a read error occurs
1809    */
1810   public IIOMetadata getStreamMetadata (String formatName,
1811                                         Set<String> nodeNames)
1812     throws IOException
1813   {
1814     if (formatName == null || nodeNames == null)
1815       throw new IllegalArgumentException ("null argument");
1816
1817     return getStreamMetadata();
1818   }
1819
1820   /**
1821    * Read the given frame all at once, using default image read
1822    * parameters, and return a buffered image.
1823    *
1824    * The returned image will be formatted according to the
1825    * currently-preferred image type specifier.
1826    *
1827    * Installed read progress listeners, update progress listeners and
1828    * warning listeners will be notified of read progress, changes in
1829    * sample sets and warnings respectively.
1830    *
1831    * @param the index of the image frame to read
1832    *
1833    * @return a buffered image
1834    *
1835    * @exception IllegalStateException if input has not been set
1836    * @exception IndexOutOfBoundsException if the frame index is
1837    * out-of-bounds
1838    * @exception IOException if a read error occurs
1839    */
1840   public BufferedImage read (int imageIndex)
1841     throws IOException
1842   {
1843     return read (imageIndex, null);
1844   }
1845
1846   /**
1847    * Read the given frame all at once, using the given image read
1848    * parameters, and return an IIOImage.  The IIOImage will contain a
1849    * buffered image as returned by getDestination.
1850    *
1851    * Installed read progress listeners, update progress listeners and
1852    * warning listeners will be notified of read progress, changes in
1853    * sample sets and warnings respectively.
1854    *
1855    * The source and destination band settings are checked with a call
1856    * to checkReadParamBandSettings.
1857    *
1858    * @param the index of the image frame to read
1859    * @param the image read parameters
1860    *
1861    * @return an IIOImage
1862    *
1863    * @exception IllegalStateException if input has not been set
1864    * @exception IndexOutOfBoundsException if the frame index is
1865    * out-of-bounds
1866    * @exception IllegalArgumentException if param.getSourceBands() and
1867    * param.getDestinationBands() are incompatible
1868    * @exception IllegalArgumentException if either the source or
1869    * destination image regions are empty
1870    * @exception IOException if a read error occurs
1871    */
1872   public IIOImage readAll (int imageIndex,
1873                            ImageReadParam param)
1874     throws IOException
1875   {
1876     checkReadParamBandSettings (param,
1877                                 param.getSourceBands().length,
1878                                 param.getDestinationBands().length);
1879
1880     List l = new ArrayList ();
1881
1882     for (int i = 0; i < getNumThumbnails (imageIndex); i++)
1883       l.add (readThumbnail(imageIndex, i));
1884
1885     return new IIOImage (getDestination(param, getImageTypes(imageIndex),
1886                                         getWidth(imageIndex),
1887                                         getHeight(imageIndex)),
1888                          l,
1889                          getImageMetadata (imageIndex));
1890   }
1891
1892   /**
1893    * Read all image frames all at once, using the given image read
1894    * parameters iterator, and return an iterator over a collection of
1895    * IIOImages.  Each IIOImage in the collection will contain a
1896    * buffered image as returned by getDestination.
1897    *
1898    * Installed read progress listeners, update progress listeners and
1899    * warning listeners will be notified of read progress, changes in
1900    * sample sets and warnings respectively.
1901    *
1902    * Each set of source and destination band settings are checked with
1903    * a call to checkReadParamBandSettings.
1904    *
1905    * @param an iterator over the image read parameters
1906    *
1907    * @return an IIOImage
1908    *
1909    * @exception IllegalStateException if input has not been set
1910    * @exception IllegalArgumentException if a non-ImageReadParam is
1911    * found in params
1912    * @exception IllegalArgumentException if param.getSourceBands() and
1913    * param.getDestinationBands() are incompatible
1914    * @exception IllegalArgumentException if either the source or
1915    * destination image regions are empty
1916    * @exception IOException if a read error occurs
1917    */
1918   public Iterator<IIOImage> readAll (Iterator<? extends ImageReadParam> params)
1919     throws IOException
1920   {
1921     List l = new ArrayList ();
1922     int index = 0;
1923
1924     while (params.hasNext())
1925       {
1926         if (params != null && ! (params instanceof ImageReadParam))
1927           throw new IllegalArgumentException ("non-ImageReadParam found");
1928
1929         l.add (readAll(index++, (ImageReadParam) params.next ()));
1930       }
1931
1932     return l.iterator();
1933   }
1934
1935   /**
1936    * Read a rendered image.  This is a more general counterpart to
1937    * read (int, ImageReadParam).  All image data may not be read
1938    * before this method returns and so listeners will not necessarily
1939    * be notified.
1940    *
1941    * @param the index of the image frame to read
1942    * @param the image read parameters
1943    *
1944    * @return a rendered image
1945    *
1946    * @exception IllegalStateException if input is null
1947    * @exception IndexOutOfBoundsException if the frame index is
1948    * out-of-bounds
1949    * @exception IllegalArgumentException if param.getSourceBands() and
1950    * param.getDestinationBands() are incompatible
1951    * @exception IllegalArgumentException if either the source or
1952    * destination image regions are empty
1953    * @exception IOException if a read error occurs
1954    */
1955   public RenderedImage readAsRenderedImage (int imageIndex,
1956                                             ImageReadParam param)
1957     throws IOException
1958   {
1959     return read (imageIndex, param);
1960   }
1961
1962   /**
1963    * Read the given tile into a buffered image.  If the tile
1964    * coordinates are out-of-bounds an exception is thrown.  If the
1965    * image is not tiled then the coordinates 0, 0 are expected and the
1966    * entire image will be read.
1967    *
1968    * @param imageIndex the frame index
1969    * @param tileX the horizontal tile coordinate
1970    * @param tileY the vertical tile coordinate
1971    *
1972    * @return the contents of the tile as a buffered image
1973    *
1974    * @exception IllegalStateException if input is null
1975    * @exception IndexOutOfBoundsException if the frame index is
1976    * out-of-bounds
1977    * @exception IllegalArgumentException if the tile coordinates are
1978    * out-of-bounds
1979    * @exception IOException if a read error occurs
1980    */
1981   public BufferedImage readTile (int imageIndex, int tileX, int tileY)
1982     throws IOException
1983   {
1984     if (tileX != 0 || tileY != 0)
1985       throw new IllegalArgumentException ("tileX not 0 or tileY not 0");
1986
1987     return read (imageIndex);
1988   }
1989
1990   /**
1991    * Read the given tile into a raster containing the raw image data.
1992    * If the tile coordinates are out-of-bounds an exception is thrown.
1993    * If the image is not tiled then the coordinates 0, 0 are expected
1994    * and the entire image will be read.
1995    *
1996    * @param imageIndex the frame index
1997    * @param tileX the horizontal tile coordinate
1998    * @param tileY the vertical tile coordinate
1999    *
2000    * @return the contents of the tile as a raster
2001    *
2002    * @exception UnsupportedOperationException if rasters are not
2003    * supported
2004    * @exception IllegalStateException if input is null
2005    * @exception IndexOutOfBoundsException if the frame index is
2006    * out-of-bounds
2007    * @exception IllegalArgumentException if the tile coordinates are
2008    * out-of-bounds
2009    * @exception IOException if a read error occurs
2010    */
2011   public Raster readTileRaster (int imageIndex, int tileX, int tileY)
2012     throws IOException
2013   {
2014     if (!canReadRaster())
2015       throw new UnsupportedOperationException ("cannot read rasters");
2016
2017     if (tileX != 0 || tileY != 0)
2018       throw new IllegalArgumentException ("tileX not 0 or tileY not 0");
2019
2020     return readRaster (imageIndex, null);
2021   }
2022
2023   /**
2024    * Reset this reader's internal state.
2025    */
2026   public void reset ()
2027   {
2028     setInput (null, false);
2029     setLocale (null);
2030     removeAllIIOReadUpdateListeners ();
2031     removeAllIIOReadWarningListeners ();
2032     removeAllIIOReadProgressListeners ();
2033     clearAbortRequest ();
2034   }
2035 }
2036