/* * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.imageio; import java.awt.Point; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Set; import javax.imageio.spi.ImageReaderSpi; import javax.imageio.event.IIOReadWarningListener; import javax.imageio.event.IIOReadProgressListener; import javax.imageio.event.IIOReadUpdateListener; import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataFormatImpl; import javax.imageio.stream.ImageInputStream; /** * An abstract superclass for parsing and decoding of images. This * class must be subclassed by classes that read in images in the * context of the Java Image I/O framework. * *

ImageReader objects are normally instantiated by * the service provider interface (SPI) class for the specific format. * Service provider classes (e.g., instances of * ImageReaderSpi) are registered with the * IIORegistry, which uses them for format recognition * and presentation of available format readers and writers. * *

When an input source is set (using the setInput * method), it may be marked as "seek forward only". This setting * means that images contained within the input source will only be * read in order, possibly allowing the reader to avoid caching * portions of the input containing data associated with images that * have been read previously. * * @see ImageWriter * @see javax.imageio.spi.IIORegistry * @see javax.imageio.spi.ImageReaderSpi * */ public abstract class ImageReader { /** * The ImageReaderSpi that instantiated this object, * or null if its identity is not known or none * exists. By default it is initialized to null. */ protected ImageReaderSpi originatingProvider; /** * The ImageInputStream or other * Object by setInput and retrieved * by getInput. By default it is initialized to * null. */ protected Object input = null; /** * true if the current input source has been marked * as allowing only forward seeking by setInput. By * default, the value is false. * * @see #minIndex * @see #setInput */ protected boolean seekForwardOnly = false; /** * true if the current input source has been marked * as allowing metadata to be ignored by setInput. * By default, the value is false. * * @see #setInput */ protected boolean ignoreMetadata = false; /** * The smallest valid index for reading, initially 0. When * seekForwardOnly is true, various methods * may throw an IndexOutOfBoundsException on an * attempt to access data associate with an image having a lower * index. * * @see #seekForwardOnly * @see #setInput */ protected int minIndex = 0; /** * An array of Locales which may be used to localize * warning messages, or null if localization is not * supported. */ protected Locale[] availableLocales = null; /** * The current Locale to be used for localization, or * null if none has been set. */ protected Locale locale = null; /** * A List of currently registered * IIOReadWarningListeners, initialized by default to * null, which is synonymous with an empty * List. */ protected List warningListeners = null; /** * A List of the Locales associated with * each currently registered IIOReadWarningListener, * initialized by default to null, which is * synonymous with an empty List. */ protected List warningLocales = null; /** * A List of currently registered * IIOReadProgressListeners, initialized by default * to null, which is synonymous with an empty * List. */ protected List progressListeners = null; /** * A List of currently registered * IIOReadUpdateListeners, initialized by default to * null, which is synonymous with an empty * List. */ protected List updateListeners = null; /** * If true, the current read operation should be * aborted. */ private boolean abortFlag = false; /** * Constructs an ImageReader and sets its * originatingProvider field to the supplied value. * *

Subclasses that make use of extensions should provide a * constructor with signature (ImageReaderSpi, * Object) in order to retrieve the extension object. If * the extension object is unsuitable, an * IllegalArgumentException should be thrown. * * @param originatingProvider the ImageReaderSpi that is * invoking this constructor, or null. */ protected ImageReader(ImageReaderSpi originatingProvider) { this.originatingProvider = originatingProvider; } /** * Returns a String identifying the format of the * input source. * *

The default implementation returns * originatingProvider.getFormatNames()[0]. * Implementations that may not have an originating service * provider, or which desire a different naming policy should * override this method. * * @exception IOException if an error occurs reading the * information from the input source. * * @return the format name, as a String. */ public String getFormatName() throws IOException { return originatingProvider.getFormatNames()[0]; } /** * Returns the ImageReaderSpi that was passed in on * the constructor. Note that this value may be null. * * @return an ImageReaderSpi, or null. * * @see ImageReaderSpi */ public ImageReaderSpi getOriginatingProvider() { return originatingProvider; } /** * Sets the input source to use to the given * ImageInputStream or other Object. * The input source must be set before any of the query or read * methods are used. If input is null, * any currently set input source will be removed. In any case, * the value of minIndex will be initialized to 0. * *

The seekForwardOnly parameter controls whether * the value returned by getMinIndex will be * increased as each image (or thumbnail, or image metadata) is * read. If seekForwardOnly is true, then a call to * read(index) will throw an * IndexOutOfBoundsException if {@code index < this.minIndex}; * otherwise, the value of * minIndex will be set to index. If * seekForwardOnly is false, the value of * minIndex will remain 0 regardless of any read * operations. * *

The ignoreMetadata parameter, if set to * true, allows the reader to disregard any metadata * encountered during the read. Subsequent calls to the * getStreamMetadata and * getImageMetadata methods may return * null, and an IIOImage returned from * readAll may return null from their * getMetadata method. Setting this parameter may * allow the reader to work more efficiently. The reader may * choose to disregard this setting and return metadata normally. * *

Subclasses should take care to remove any cached * information based on the previous stream, such as header * information or partially decoded image data. * *

Use of a general Object other than an * ImageInputStream is intended for readers that * interact directly with a capture device or imaging protocol. * The set of legal classes is advertised by the reader's service * provider's getInputTypes method; most readers * will return a single-element array containing only * ImageInputStream.class to indicate that they * accept only an ImageInputStream. * *

The default implementation checks the input * argument against the list returned by * originatingProvider.getInputTypes() and fails * if the argument is not an instance of one of the classes * in the list. If the originating provider is set to * null, the input is accepted only if it is an * ImageInputStream. * * @param input the ImageInputStream or other * Object to use for future decoding. * @param seekForwardOnly if true, images and metadata * may only be read in ascending order from this input source. * @param ignoreMetadata if true, metadata * may be ignored during reads. * * @exception IllegalArgumentException if input is * not an instance of one of the classes returned by the * originating service provider's getInputTypes * method, or is not an ImageInputStream. * * @see ImageInputStream * @see #getInput * @see javax.imageio.spi.ImageReaderSpi#getInputTypes */ public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) { if (input != null) { boolean found = false; if (originatingProvider != null) { Class[] classes = originatingProvider.getInputTypes(); for (int i = 0; i < classes.length; i++) { if (classes[i].isInstance(input)) { found = true; break; } } } else { if (input instanceof ImageInputStream) { found = true; } } if (!found) { throw new IllegalArgumentException("Incorrect input type!"); } this.seekForwardOnly = seekForwardOnly; this.ignoreMetadata = ignoreMetadata; this.minIndex = 0; } this.input = input; } /** * Sets the input source to use to the given * ImageInputStream or other Object. * The input source must be set before any of the query or read * methods are used. If input is null, * any currently set input source will be removed. In any case, * the value of minIndex will be initialized to 0. * *

The seekForwardOnly parameter controls whether * the value returned by getMinIndex will be * increased as each image (or thumbnail, or image metadata) is * read. If seekForwardOnly is true, then a call to * read(index) will throw an * IndexOutOfBoundsException if {@code index < this.minIndex}; * otherwise, the value of * minIndex will be set to index. If * seekForwardOnly is false, the value of * minIndex will remain 0 regardless of any read * operations. * *

This method is equivalent to setInput(input, * seekForwardOnly, false). * * @param input the ImageInputStream or other * Object to use for future decoding. * @param seekForwardOnly if true, images and metadata * may only be read in ascending order from this input source. * * @exception IllegalArgumentException if input is * not an instance of one of the classes returned by the * originating service provider's getInputTypes * method, or is not an ImageInputStream. * * @see #getInput */ public void setInput(Object input, boolean seekForwardOnly) { setInput(input, seekForwardOnly, false); } /** * Sets the input source to use to the given * ImageInputStream or other Object. * The input source must be set before any of the query or read * methods are used. If input is null, * any currently set input source will be removed. In any case, * the value of minIndex will be initialized to 0. * *

This method is equivalent to setInput(input, false, * false). * * @param input the ImageInputStream or other * Object to use for future decoding. * * @exception IllegalArgumentException if input is * not an instance of one of the classes returned by the * originating service provider's getInputTypes * method, or is not an ImageInputStream. * * @see #getInput */ public void setInput(Object input) { setInput(input, false, false); } /** * Returns the ImageInputStream or other * Object previously set as the input source. If the * input source has not been set, null is returned. * * @return the Object that will be used for future * decoding, or null. * * @see ImageInputStream * @see #setInput */ public Object getInput() { return input; } /** * Returns true if the current input source has been * marked as seek forward only by passing true as the * seekForwardOnly argument to the * setInput method. * * @return true if the input source is seek forward * only. * * @see #setInput */ public boolean isSeekForwardOnly() { return seekForwardOnly; } /** * Returns true if the current input source has been * marked as allowing metadata to be ignored by passing * true as the ignoreMetadata argument * to the setInput method. * * @return true if the metadata may be ignored. * * @see #setInput */ public boolean isIgnoringMetadata() { return ignoreMetadata; } /** * Returns the lowest valid index for reading an image, thumbnail, * or image metadata. If seekForwardOnly() is * false, this value will typically remain 0, * indicating that random access is possible. Otherwise, it will * contain the value of the most recently accessed index, and * increase in a monotonic fashion. * * @return the minimum legal index for reading. */ public int getMinIndex() { return minIndex; } // Localization /** * Returns an array of Locales that may be used to * localize warning listeners and compression settings. A return * value of null indicates that localization is not * supported. * *

The default implementation returns a clone of the * availableLocales instance variable if it is * non-null, or else returns null. * * @return an array of Locales that may be used as * arguments to setLocale, or null. */ public Locale[] getAvailableLocales() { if (availableLocales == null) { return null; } else { return availableLocales.clone(); } } /** * Sets the current Locale of this * ImageReader to the given value. A value of * null removes any previous setting, and indicates * that the reader should localize as it sees fit. * * @param locale the desired Locale, or * null. * * @exception IllegalArgumentException if locale is * non-null but is not one of the values returned by * getAvailableLocales. * * @see #getLocale */ public void setLocale(Locale locale) { if (locale != null) { Locale[] locales = getAvailableLocales(); boolean found = false; if (locales != null) { for (int i = 0; i < locales.length; i++) { if (locale.equals(locales[i])) { found = true; break; } } } if (!found) { throw new IllegalArgumentException("Invalid locale!"); } } this.locale = locale; } /** * Returns the currently set Locale, or * null if none has been set. * * @return the current Locale, or null. * * @see #setLocale */ public Locale getLocale() { return locale; } // Image queries /** * Returns the number of images, not including thumbnails, available * from the current input source. * *

Note that some image formats (such as animated GIF) do not * specify how many images are present in the stream. Thus * determining the number of images will require the entire stream * to be scanned and may require memory for buffering. If images * are to be processed in order, it may be more efficient to * simply call read with increasing indices until an * IndexOutOfBoundsException is thrown to indicate * that no more images are available. The * allowSearch parameter may be set to * false to indicate that an exhaustive search is not * desired; the return value will be -1 to indicate * that a search is necessary. If the input has been specified * with seekForwardOnly set to true, * this method throws an IllegalStateException if * allowSearch is set to true. * * @param allowSearch if true, the true number of * images will be returned even if a search is required. If * false, the reader may return -1 * without performing the search. * * @return the number of images, as an int, or * -1 if allowSearch is * false and a search would be required. * * @exception IllegalStateException if the input source has not been set, * or if the input has been specified with seekForwardOnly * set to true. * @exception IOException if an error occurs reading the * information from the input source. * * @see #setInput */ public abstract int getNumImages(boolean allowSearch) throws IOException; /** * Returns the width in pixels of the given image within the input * source. * *

If the image can be rendered to a user-specified size, then * this method returns the default width. * * @param imageIndex the index of the image to be queried. * * @return the width of the image, as an int. * * @exception IllegalStateException if the input source has not been set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * @exception IOException if an error occurs reading the width * information from the input source. */ public abstract int getWidth(int imageIndex) throws IOException; /** * Returns the height in pixels of the given image within the * input source. * *

If the image can be rendered to a user-specified size, then * this method returns the default height. * * @param imageIndex the index of the image to be queried. * * @return the height of the image, as an int. * * @exception IllegalStateException if the input source has not been set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * @exception IOException if an error occurs reading the height * information from the input source. */ public abstract int getHeight(int imageIndex) throws IOException; /** * Returns true if the storage format of the given * image places no inherent impediment on random access to pixels. * For most compressed formats, such as JPEG, this method should * return false, as a large section of the image in * addition to the region of interest may need to be decoded. * *

This is merely a hint for programs that wish to be * efficient; all readers must be able to read arbitrary regions * as specified in an ImageReadParam. * *

Note that formats that return false from * this method may nonetheless allow tiling (e.g. Restart * Markers in JPEG), and random access will likely be reasonably * efficient on tiles. See {@link #isImageTiled isImageTiled}. * *

A reader for which all images are guaranteed to support * easy random access, or are guaranteed not to support easy * random access, may return true or * false respectively without accessing any image * data. In such cases, it is not necessary to throw an exception * even if no input source has been set or the image index is out * of bounds. * *

The default implementation returns false. * * @param imageIndex the index of the image to be queried. * * @return true if reading a region of interest of * the given image is likely to be efficient. * * @exception IllegalStateException if an input source is required * to determine the return value, but none has been set. * @exception IndexOutOfBoundsException if an image must be * accessed to determine the return value, but the supplied index * is out of bounds. * @exception IOException if an error occurs during reading. */ public boolean isRandomAccessEasy(int imageIndex) throws IOException { return false; } /** * Returns the aspect ratio of the given image (that is, its width * divided by its height) as a float. For images * that are inherently resizable, this method provides a way to * determine the appropriate width given a desired height, or vice * versa. For non-resizable images, the true width and height * are used. * *

The default implementation simply returns * (float)getWidth(imageIndex)/getHeight(imageIndex). * * @param imageIndex the index of the image to be queried. * * @return a float indicating the aspect ratio of the * given image. * * @exception IllegalStateException if the input source has not been set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * @exception IOException if an error occurs during reading. */ public float getAspectRatio(int imageIndex) throws IOException { return (float)getWidth(imageIndex)/getHeight(imageIndex); } /** * Returns an ImageTypeSpecifier indicating the * SampleModel and ColorModel which most * closely represents the "raw" internal format of the image. For * example, for a JPEG image the raw type might have a YCbCr color * space even though the image would conventionally be transformed * into an RGB color space prior to display. The returned value * should also be included in the list of values returned by * getImageTypes. * *

The default implementation simply returns the first entry * from the list provided by getImageType. * * @param imageIndex the index of the image to be queried. * * @return an ImageTypeSpecifier. * * @exception IllegalStateException if the input source has not been set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * @exception IOException if an error occurs reading the format * information from the input source. */ public ImageTypeSpecifier getRawImageType(int imageIndex) throws IOException { return getImageTypes(imageIndex).next(); } /** * Returns an Iterator containing possible image * types to which the given image may be decoded, in the form of * ImageTypeSpecifierss. At least one legal image * type will be returned. * *

The first element of the iterator should be the most * "natural" type for decoding the image with as little loss as * possible. For example, for a JPEG image the first entry should * be an RGB image, even though the image data is stored * internally in a YCbCr color space. * * @param imageIndex the index of the image to be * retrieved. * * @return an Iterator containing at least one * ImageTypeSpecifier representing suggested image * types for decoding the current given image. * * @exception IllegalStateException if the input source has not been set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * @exception IOException if an error occurs reading the format * information from the input source. * * @see ImageReadParam#setDestination(BufferedImage) * @see ImageReadParam#setDestinationType(ImageTypeSpecifier) */ public abstract Iterator getImageTypes(int imageIndex) throws IOException; /** * Returns a default ImageReadParam object * appropriate for this format. All subclasses should define a * set of default values for all parameters and return them with * this call. This method may be called before the input source * is set. * *

The default implementation constructs and returns a new * ImageReadParam object that does not allow source * scaling (i.e., it returns new * ImageReadParam(). * * @return an ImageReadParam object which may be used * to control the decoding process using a set of default settings. */ public ImageReadParam getDefaultReadParam() { return new ImageReadParam(); } /** * Returns an IIOMetadata object representing the * metadata associated with the input source as a whole (i.e., not * associated with any particular image), or null if * the reader does not support reading metadata, is set to ignore * metadata, or if no metadata is available. * * @return an IIOMetadata object, or null. * * @exception IOException if an error occurs during reading. */ public abstract IIOMetadata getStreamMetadata() throws IOException; /** * Returns an IIOMetadata object representing the * metadata associated with the input source as a whole (i.e., * not associated with any particular image). If no such data * exists, null is returned. * *

The resulting metadata object is only responsible for * returning documents in the format named by * formatName. Within any documents that are * returned, only nodes whose names are members of * nodeNames are required to be returned. In this * way, the amount of metadata processing done by the reader may * be kept to a minimum, based on what information is actually * needed. * *

If formatName is not the name of a supported * metadata format, null is returned. * *

In all cases, it is legal to return a more capable metadata * object than strictly necessary. The format name and node names * are merely hints that may be used to reduce the reader's * workload. * *

The default implementation simply returns the result of * calling getStreamMetadata(), after checking that * the format name is supported. If it is not, * null is returned. * * @param formatName a metadata format name that may be used to retrieve * a document from the returned IIOMetadata object. * @param nodeNames a Set containing the names of * nodes that may be contained in a retrieved document. * * @return an IIOMetadata object, or null. * * @exception IllegalArgumentException if formatName * is null. * @exception IllegalArgumentException if nodeNames * is null. * @exception IOException if an error occurs during reading. */ public IIOMetadata getStreamMetadata(String formatName, Set nodeNames) throws IOException { return getMetadata(formatName, nodeNames, true, 0); } private IIOMetadata getMetadata(String formatName, Set nodeNames, boolean wantStream, int imageIndex) throws IOException { if (formatName == null) { throw new IllegalArgumentException("formatName == null!"); } if (nodeNames == null) { throw new IllegalArgumentException("nodeNames == null!"); } IIOMetadata metadata = wantStream ? getStreamMetadata() : getImageMetadata(imageIndex); if (metadata != null) { if (metadata.isStandardMetadataFormatSupported() && formatName.equals (IIOMetadataFormatImpl.standardMetadataFormatName)) { return metadata; } String nativeName = metadata.getNativeMetadataFormatName(); if (nativeName != null && formatName.equals(nativeName)) { return metadata; } String[] extraNames = metadata.getExtraMetadataFormatNames(); if (extraNames != null) { for (int i = 0; i < extraNames.length; i++) { if (formatName.equals(extraNames[i])) { return metadata; } } } } return null; } /** * Returns an IIOMetadata object containing metadata * associated with the given image, or null if the * reader does not support reading metadata, is set to ignore * metadata, or if no metadata is available. * * @param imageIndex the index of the image whose metadata is to * be retrieved. * * @return an IIOMetadata object, or * null. * * @exception IllegalStateException if the input source has not been * set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * @exception IOException if an error occurs during reading. */ public abstract IIOMetadata getImageMetadata(int imageIndex) throws IOException; /** * Returns an IIOMetadata object representing the * metadata associated with the given image, or null * if the reader does not support reading metadata or none * is available. * *

The resulting metadata object is only responsible for * returning documents in the format named by * formatName. Within any documents that are * returned, only nodes whose names are members of * nodeNames are required to be returned. In this * way, the amount of metadata processing done by the reader may * be kept to a minimum, based on what information is actually * needed. * *

If formatName is not the name of a supported * metadata format, null may be returned. * *

In all cases, it is legal to return a more capable metadata * object than strictly necessary. The format name and node names * are merely hints that may be used to reduce the reader's * workload. * *

The default implementation simply returns the result of * calling getImageMetadata(imageIndex), after * checking that the format name is supported. If it is not, * null is returned. * * @param imageIndex the index of the image whose metadata is to * be retrieved. * @param formatName a metadata format name that may be used to retrieve * a document from the returned IIOMetadata object. * @param nodeNames a Set containing the names of * nodes that may be contained in a retrieved document. * * @return an IIOMetadata object, or null. * * @exception IllegalStateException if the input source has not been * set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * @exception IllegalArgumentException if formatName * is null. * @exception IllegalArgumentException if nodeNames * is null. * @exception IOException if an error occurs during reading. */ public IIOMetadata getImageMetadata(int imageIndex, String formatName, Set nodeNames) throws IOException { return getMetadata(formatName, nodeNames, false, imageIndex); } /** * Reads the image indexed by imageIndex and returns * it as a complete BufferedImage, using a default * ImageReadParam. This is a convenience method * that calls read(imageIndex, null). * *

The image returned will be formatted according to the first * ImageTypeSpecifier returned from * getImageTypes. * *

Any registered IIOReadProgressListener objects * will be notified by calling their imageStarted * method, followed by calls to their imageProgress * method as the read progresses. Finally their * imageComplete method will be called. * IIOReadUpdateListener objects may be updated at * other times during the read as pixels are decoded. Finally, * IIOReadWarningListener objects will receive * notification of any non-fatal warnings that occur during * decoding. * * @param imageIndex the index of the image to be retrieved. * * @return the desired portion of the image as a * BufferedImage. * * @exception IllegalStateException if the input source has not been * set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * @exception IOException if an error occurs during reading. */ public BufferedImage read(int imageIndex) throws IOException { return read(imageIndex, null); } /** * Reads the image indexed by imageIndex and returns * it as a complete BufferedImage, using a supplied * ImageReadParam. * *

The actual BufferedImage returned will be * chosen using the algorithm defined by the * getDestination method. * *

Any registered IIOReadProgressListener objects * will be notified by calling their imageStarted * method, followed by calls to their imageProgress * method as the read progresses. Finally their * imageComplete method will be called. * IIOReadUpdateListener objects may be updated at * other times during the read as pixels are decoded. Finally, * IIOReadWarningListener objects will receive * notification of any non-fatal warnings that occur during * decoding. * *

The set of source bands to be read and destination bands to * be written is determined by calling getSourceBands * and getDestinationBands on the supplied * ImageReadParam. If the lengths of the arrays * returned by these methods differ, the set of source bands * contains an index larger that the largest available source * index, or the set of destination bands contains an index larger * than the largest legal destination index, an * IllegalArgumentException is thrown. * *

If the supplied ImageReadParam contains * optional setting values not supported by this reader (e.g. * source render size or any format-specific settings), they will * be ignored. * * @param imageIndex the index of the image to be retrieved. * @param param an ImageReadParam used to control * the reading process, or null. * * @return the desired portion of the image as a * BufferedImage. * * @exception IllegalStateException if the input source has not been * set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * @exception IllegalArgumentException if the set of source and * destination bands specified by * param.getSourceBands and * param.getDestinationBands differ in length or * include indices that are out of bounds. * @exception IllegalArgumentException if the resulting image would * have a width or height less than 1. * @exception IOException if an error occurs during reading. */ public abstract BufferedImage read(int imageIndex, ImageReadParam param) throws IOException; /** * Reads the image indexed by imageIndex and returns * an IIOImage containing the image, thumbnails, and * associated image metadata, using a supplied * ImageReadParam. * *

The actual BufferedImage referenced by the * returned IIOImage will be chosen using the * algorithm defined by the getDestination method. * *

Any registered IIOReadProgressListener objects * will be notified by calling their imageStarted * method, followed by calls to their imageProgress * method as the read progresses. Finally their * imageComplete method will be called. * IIOReadUpdateListener objects may be updated at * other times during the read as pixels are decoded. Finally, * IIOReadWarningListener objects will receive * notification of any non-fatal warnings that occur during * decoding. * *

The set of source bands to be read and destination bands to * be written is determined by calling getSourceBands * and getDestinationBands on the supplied * ImageReadParam. If the lengths of the arrays * returned by these methods differ, the set of source bands * contains an index larger that the largest available source * index, or the set of destination bands contains an index larger * than the largest legal destination index, an * IllegalArgumentException is thrown. * *

Thumbnails will be returned in their entirety regardless of * the region settings. * *

If the supplied ImageReadParam contains * optional setting values not supported by this reader (e.g. * source render size or any format-specific settings), those * values will be ignored. * * @param imageIndex the index of the image to be retrieved. * @param param an ImageReadParam used to control * the reading process, or null. * * @return an IIOImage containing the desired portion * of the image, a set of thumbnails, and associated image * metadata. * * @exception IllegalStateException if the input source has not been * set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * @exception IllegalArgumentException if the set of source and * destination bands specified by * param.getSourceBands and * param.getDestinationBands differ in length or * include indices that are out of bounds. * @exception IllegalArgumentException if the resulting image * would have a width or height less than 1. * @exception IOException if an error occurs during reading. */ public IIOImage readAll(int imageIndex, ImageReadParam param) throws IOException { if (imageIndex < getMinIndex()) { throw new IndexOutOfBoundsException("imageIndex < getMinIndex()!"); } BufferedImage im = read(imageIndex, param); ArrayList thumbnails = null; int numThumbnails = getNumThumbnails(imageIndex); if (numThumbnails > 0) { thumbnails = new ArrayList<>(); for (int j = 0; j < numThumbnails; j++) { thumbnails.add(readThumbnail(imageIndex, j)); } } IIOMetadata metadata = getImageMetadata(imageIndex); return new IIOImage(im, thumbnails, metadata); } /** * Returns an Iterator containing all the images, * thumbnails, and metadata, starting at the index given by * getMinIndex, from the input source in the form of * IIOImage objects. An Iterator * containing ImageReadParam objects is supplied; one * element is consumed for each image read from the input source * until no more images are available. If the read param * Iterator runs out of elements, but there are still * more images available from the input source, default read * params are used for the remaining images. * *

If params is null, a default read * param will be used for all images. * *

The actual BufferedImage referenced by the * returned IIOImage will be chosen using the * algorithm defined by the getDestination method. * *

Any registered IIOReadProgressListener objects * will be notified by calling their sequenceStarted * method once. Then, for each image decoded, there will be a * call to imageStarted, followed by calls to * imageProgress as the read progresses, and finally * to imageComplete. The * sequenceComplete method will be called after the * last image has been decoded. * IIOReadUpdateListener objects may be updated at * other times during the read as pixels are decoded. Finally, * IIOReadWarningListener objects will receive * notification of any non-fatal warnings that occur during * decoding. * *

The set of source bands to be read and destination bands to * be written is determined by calling getSourceBands * and getDestinationBands on the supplied * ImageReadParam. If the lengths of the arrays * returned by these methods differ, the set of source bands * contains an index larger that the largest available source * index, or the set of destination bands contains an index larger * than the largest legal destination index, an * IllegalArgumentException is thrown. * *

Thumbnails will be returned in their entirety regardless of the * region settings. * *

If any of the supplied ImageReadParams contain * optional setting values not supported by this reader (e.g. * source render size or any format-specific settings), they will * be ignored. * * @param params an Iterator containing * ImageReadParam objects. * * @return an Iterator representing the * contents of the input source as IIOImages. * * @exception IllegalStateException if the input source has not been * set. * @exception IllegalArgumentException if any * non-null element of params is not an * ImageReadParam. * @exception IllegalArgumentException if the set of source and * destination bands specified by * param.getSourceBands and * param.getDestinationBands differ in length or * include indices that are out of bounds. * @exception IllegalArgumentException if a resulting image would * have a width or height less than 1. * @exception IOException if an error occurs during reading. * * @see ImageReadParam * @see IIOImage */ public Iterator readAll(Iterator params) throws IOException { List output = new ArrayList<>(); int imageIndex = getMinIndex(); // Inform IIOReadProgressListeners we're starting a sequence processSequenceStarted(imageIndex); while (true) { // Inform IIOReadProgressListeners and IIOReadUpdateListeners // that we're starting a new image ImageReadParam param = null; if (params != null && params.hasNext()) { Object o = params.next(); if (o != null) { if (o instanceof ImageReadParam) { param = (ImageReadParam)o; } else { throw new IllegalArgumentException ("Non-ImageReadParam supplied as part of params!"); } } } BufferedImage bi = null; try { bi = read(imageIndex, param); } catch (IndexOutOfBoundsException e) { break; } ArrayList thumbnails = null; int numThumbnails = getNumThumbnails(imageIndex); if (numThumbnails > 0) { thumbnails = new ArrayList<>(); for (int j = 0; j < numThumbnails; j++) { thumbnails.add(readThumbnail(imageIndex, j)); } } IIOMetadata metadata = getImageMetadata(imageIndex); IIOImage im = new IIOImage(bi, thumbnails, metadata); output.add(im); ++imageIndex; } // Inform IIOReadProgressListeners we're ending a sequence processSequenceComplete(); return output.iterator(); } /** * Returns true if this plug-in supports reading * just a {@link java.awt.image.Raster Raster} of pixel data. * If this method returns false, calls to * {@link #readRaster readRaster} or {@link #readTileRaster readTileRaster} * will throw an UnsupportedOperationException. * *

The default implementation returns false. * * @return true if this plug-in supports reading raw * Rasters. * * @see #readRaster * @see #readTileRaster */ public boolean canReadRaster() { return false; } /** * Returns a new Raster object containing the raw pixel data * from the image stream, without any color conversion applied. The * application must determine how to interpret the pixel data by other * means. Any destination or image-type parameters in the supplied * ImageReadParam object are ignored, but all other * parameters are used exactly as in the {@link #read read} * method, except that any destination offset is used as a logical rather * than a physical offset. The size of the returned Raster * will always be that of the source region clipped to the actual image. * Logical offsets in the stream itself are ignored. * *

This method allows formats that normally apply a color * conversion, such as JPEG, and formats that do not normally have an * associated colorspace, such as remote sensing or medical imaging data, * to provide access to raw pixel data. * *

Any registered readUpdateListeners are ignored, as * there is no BufferedImage, but all other listeners are * called exactly as they are for the {@link #read read} method. * *

If {@link #canReadRaster canReadRaster()} returns * false, this method throws an * UnsupportedOperationException. * *

If the supplied ImageReadParam contains * optional setting values not supported by this reader (e.g. * source render size or any format-specific settings), they will * be ignored. * *

The default implementation throws an * UnsupportedOperationException. * * @param imageIndex the index of the image to be read. * @param param an ImageReadParam used to control * the reading process, or null. * * @return the desired portion of the image as a * Raster. * * @exception UnsupportedOperationException if this plug-in does not * support reading raw Rasters. * @exception IllegalStateException if the input source has not been * set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * @exception IOException if an error occurs during reading. * * @see #canReadRaster * @see #read * @see java.awt.image.Raster */ public Raster readRaster(int imageIndex, ImageReadParam param) throws IOException { throw new UnsupportedOperationException("readRaster not supported!"); } /** * Returns true if the image is organized into * tiles, that is, equal-sized non-overlapping rectangles. * *

A reader plug-in may choose whether or not to expose tiling * that is present in the image as it is stored. It may even * choose to advertise tiling when none is explicitly present. In * general, tiling should only be advertised if there is some * advantage (in speed or space) to accessing individual tiles. * Regardless of whether the reader advertises tiling, it must be * capable of reading an arbitrary rectangular region specified in * an ImageReadParam. * *

A reader for which all images are guaranteed to be tiled, * or are guaranteed not to be tiled, may return true * or false respectively without accessing any image * data. In such cases, it is not necessary to throw an exception * even if no input source has been set or the image index is out * of bounds. * *

The default implementation just returns false. * * @param imageIndex the index of the image to be queried. * * @return true if the image is tiled. * * @exception IllegalStateException if an input source is required * to determine the return value, but none has been set. * @exception IndexOutOfBoundsException if an image must be * accessed to determine the return value, but the supplied index * is out of bounds. * @exception IOException if an error occurs during reading. */ public boolean isImageTiled(int imageIndex) throws IOException { return false; } /** * Returns the width of a tile in the given image. * *

The default implementation simply returns * getWidth(imageIndex), which is correct for * non-tiled images. Readers that support tiling should override * this method. * * @return the width of a tile. * * @param imageIndex the index of the image to be queried. * * @exception IllegalStateException if the input source has not been set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * @exception IOException if an error occurs during reading. */ public int getTileWidth(int imageIndex) throws IOException { return getWidth(imageIndex); } /** * Returns the height of a tile in the given image. * *

The default implementation simply returns * getHeight(imageIndex), which is correct for * non-tiled images. Readers that support tiling should override * this method. * * @return the height of a tile. * * @param imageIndex the index of the image to be queried. * * @exception IllegalStateException if the input source has not been set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * @exception IOException if an error occurs during reading. */ public int getTileHeight(int imageIndex) throws IOException { return getHeight(imageIndex); } /** * Returns the X coordinate of the upper-left corner of tile (0, * 0) in the given image. * *

A reader for which the tile grid X offset always has the * same value (usually 0), may return the value without accessing * any image data. In such cases, it is not necessary to throw an * exception even if no input source has been set or the image * index is out of bounds. * *

The default implementation simply returns 0, which is * correct for non-tiled images and tiled images in most formats. * Readers that support tiling with non-(0, 0) offsets should * override this method. * * @return the X offset of the tile grid. * * @param imageIndex the index of the image to be queried. * * @exception IllegalStateException if an input source is required * to determine the return value, but none has been set. * @exception IndexOutOfBoundsException if an image must be * accessed to determine the return value, but the supplied index * is out of bounds. * @exception IOException if an error occurs during reading. */ public int getTileGridXOffset(int imageIndex) throws IOException { return 0; } /** * Returns the Y coordinate of the upper-left corner of tile (0, * 0) in the given image. * *

A reader for which the tile grid Y offset always has the * same value (usually 0), may return the value without accessing * any image data. In such cases, it is not necessary to throw an * exception even if no input source has been set or the image * index is out of bounds. * *

The default implementation simply returns 0, which is * correct for non-tiled images and tiled images in most formats. * Readers that support tiling with non-(0, 0) offsets should * override this method. * * @return the Y offset of the tile grid. * * @param imageIndex the index of the image to be queried. * * @exception IllegalStateException if an input source is required * to determine the return value, but none has been set. * @exception IndexOutOfBoundsException if an image must be * accessed to determine the return value, but the supplied index * is out of bounds. * @exception IOException if an error occurs during reading. */ public int getTileGridYOffset(int imageIndex) throws IOException { return 0; } /** * Reads the tile indicated by the tileX and * tileY arguments, returning it as a * BufferedImage. If the arguments are out of range, * an IllegalArgumentException is thrown. If the * image is not tiled, the values 0, 0 will return the entire * image; any other values will cause an * IllegalArgumentException to be thrown. * *

This method is merely a convenience equivalent to calling * read(int, ImageReadParam) with a read param * specifying a source region having offsets of * tileX*getTileWidth(imageIndex), * tileY*getTileHeight(imageIndex) and width and * height of getTileWidth(imageIndex), * getTileHeight(imageIndex); and subsampling * factors of 1 and offsets of 0. To subsample a tile, call * read with a read param specifying this region * and different subsampling parameters. * *

The default implementation returns the entire image if * tileX and tileY are 0, or throws * an IllegalArgumentException otherwise. * * @param imageIndex the index of the image to be retrieved. * @param tileX the column index (starting with 0) of the tile * to be retrieved. * @param tileY the row index (starting with 0) of the tile * to be retrieved. * * @return the tile as a BufferedImage. * * @exception IllegalStateException if the input source has not been * set. * @exception IndexOutOfBoundsException if imageIndex * is out of bounds. * @exception IllegalArgumentException if the tile indices are * out of bounds. * @exception IOException if an error occurs during reading. */ public BufferedImage readTile(int imageIndex, int tileX, int tileY) throws IOException { if ((tileX != 0) || (tileY != 0)) { throw new IllegalArgumentException("Invalid tile indices"); } return read(imageIndex); } /** * Returns a new Raster object containing the raw * pixel data from the tile, without any color conversion applied. * The application must determine how to interpret the pixel data by other * means. * *

If {@link #canReadRaster canReadRaster()} returns * false, this method throws an * UnsupportedOperationException. * *

The default implementation checks if reading * Rasters is supported, and if so calls {@link * #readRaster readRaster(imageIndex, null)} if * tileX and tileY are 0, or throws an * IllegalArgumentException otherwise. * * @param imageIndex the index of the image to be retrieved. * @param tileX the column index (starting with 0) of the tile * to be retrieved. * @param tileY the row index (starting with 0) of the tile * to be retrieved. * * @return the tile as a Raster. * * @exception UnsupportedOperationException if this plug-in does not * support reading raw Rasters. * @exception IllegalArgumentException if the tile indices are * out of bounds. * @exception IllegalStateException if the input source has not been * set. * @exception IndexOutOfBoundsException if imageIndex * is out of bounds. * @exception IOException if an error occurs during reading. * * @see #readTile * @see #readRaster * @see java.awt.image.Raster */ public Raster readTileRaster(int imageIndex, int tileX, int tileY) throws IOException { if (!canReadRaster()) { throw new UnsupportedOperationException ("readTileRaster not supported!"); } if ((tileX != 0) || (tileY != 0)) { throw new IllegalArgumentException("Invalid tile indices"); } return readRaster(imageIndex, null); } // RenderedImages /** * Returns a RenderedImage object that contains the * contents of the image indexed by imageIndex. By * default, the returned image is simply the * BufferedImage returned by read(imageIndex, * param). * *

The semantics of this method may differ from those of the * other read methods in several ways. First, any * destination image and/or image type set in the * ImageReadParam may be ignored. Second, the usual * listener calls are not guaranteed to be made, or to be * meaningful if they are. This is because the returned image may * not be fully populated with pixel data at the time it is * returned, or indeed at any time. * *

If the supplied ImageReadParam contains * optional setting values not supported by this reader (e.g. * source render size or any format-specific settings), they will * be ignored. * *

The default implementation just calls * {@link #read read(imageIndex, param)}. * * @param imageIndex the index of the image to be retrieved. * @param param an ImageReadParam used to control * the reading process, or null. * * @return a RenderedImage object providing a view of * the image. * * @exception IllegalStateException if the input source has not been * set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * @exception IllegalArgumentException if the set of source and * destination bands specified by * param.getSourceBands and * param.getDestinationBands differ in length or * include indices that are out of bounds. * @exception IllegalArgumentException if the resulting image * would have a width or height less than 1. * @exception IOException if an error occurs during reading. */ public RenderedImage readAsRenderedImage(int imageIndex, ImageReadParam param) throws IOException { return read(imageIndex, param); } // Thumbnails /** * Returns true if the image format understood by * this reader supports thumbnail preview images associated with * it. The default implementation returns false. * *

If this method returns false, * hasThumbnails and getNumThumbnails * will return false and 0, * respectively, and readThumbnail will throw an * UnsupportedOperationException, regardless of their * arguments. * *

A reader that does not support thumbnails need not * implement any of the thumbnail-related methods. * * @return true if thumbnails are supported. */ public boolean readerSupportsThumbnails() { return false; } /** * Returns true if the given image has thumbnail * preview images associated with it. If the format does not * support thumbnails (readerSupportsThumbnails * returns false), false will be * returned regardless of whether an input source has been set or * whether imageIndex is in bounds. * *

The default implementation returns true if * getNumThumbnails returns a value greater than 0. * * @param imageIndex the index of the image being queried. * * @return true if the given image has thumbnails. * * @exception IllegalStateException if the reader supports * thumbnails but the input source has not been set. * @exception IndexOutOfBoundsException if the reader supports * thumbnails but imageIndex is out of bounds. * @exception IOException if an error occurs during reading. */ public boolean hasThumbnails(int imageIndex) throws IOException { return getNumThumbnails(imageIndex) > 0; } /** * Returns the number of thumbnail preview images associated with * the given image. If the format does not support thumbnails, * (readerSupportsThumbnails returns * false), 0 will be returned regardless * of whether an input source has been set or whether * imageIndex is in bounds. * *

The default implementation returns 0 without checking its * argument. * * @param imageIndex the index of the image being queried. * * @return the number of thumbnails associated with the given * image. * * @exception IllegalStateException if the reader supports * thumbnails but the input source has not been set. * @exception IndexOutOfBoundsException if the reader supports * thumbnails but imageIndex is out of bounds. * @exception IOException if an error occurs during reading. */ public int getNumThumbnails(int imageIndex) throws IOException { return 0; } /** * Returns the width of the thumbnail preview image indexed by * thumbnailIndex, associated with the image indexed * by ImageIndex. * *

If the reader does not support thumbnails, * (readerSupportsThumbnails returns * false), an UnsupportedOperationException * will be thrown. * *

The default implementation simply returns * readThumbnail(imageindex, * thumbnailIndex).getWidth(). Subclasses should therefore * override this method if possible in order to avoid forcing the * thumbnail to be read. * * @param imageIndex the index of the image to be retrieved. * @param thumbnailIndex the index of the thumbnail to be retrieved. * * @return the width of the desired thumbnail as an int. * * @exception UnsupportedOperationException if thumbnails are not * supported. * @exception IllegalStateException if the input source has not been set. * @exception IndexOutOfBoundsException if either of the supplied * indices are out of bounds. * @exception IOException if an error occurs during reading. */ public int getThumbnailWidth(int imageIndex, int thumbnailIndex) throws IOException { return readThumbnail(imageIndex, thumbnailIndex).getWidth(); } /** * Returns the height of the thumbnail preview image indexed by * thumbnailIndex, associated with the image indexed * by ImageIndex. * *

If the reader does not support thumbnails, * (readerSupportsThumbnails returns * false), an UnsupportedOperationException * will be thrown. * *

The default implementation simply returns * readThumbnail(imageindex, * thumbnailIndex).getHeight(). Subclasses should * therefore override this method if possible in order to avoid * forcing the thumbnail to be read. * * @param imageIndex the index of the image to be retrieved. * @param thumbnailIndex the index of the thumbnail to be retrieved. * * @return the height of the desired thumbnail as an int. * * @exception UnsupportedOperationException if thumbnails are not * supported. * @exception IllegalStateException if the input source has not been set. * @exception IndexOutOfBoundsException if either of the supplied * indices are out of bounds. * @exception IOException if an error occurs during reading. */ public int getThumbnailHeight(int imageIndex, int thumbnailIndex) throws IOException { return readThumbnail(imageIndex, thumbnailIndex).getHeight(); } /** * Returns the thumbnail preview image indexed by * thumbnailIndex, associated with the image indexed * by ImageIndex as a BufferedImage. * *

Any registered IIOReadProgressListener objects * will be notified by calling their * thumbnailStarted, thumbnailProgress, * and thumbnailComplete methods. * *

If the reader does not support thumbnails, * (readerSupportsThumbnails returns * false), an UnsupportedOperationException * will be thrown regardless of whether an input source has been * set or whether the indices are in bounds. * *

The default implementation throws an * UnsupportedOperationException. * * @param imageIndex the index of the image to be retrieved. * @param thumbnailIndex the index of the thumbnail to be retrieved. * * @return the desired thumbnail as a BufferedImage. * * @exception UnsupportedOperationException if thumbnails are not * supported. * @exception IllegalStateException if the input source has not been set. * @exception IndexOutOfBoundsException if either of the supplied * indices are out of bounds. * @exception IOException if an error occurs during reading. */ public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException { throw new UnsupportedOperationException("Thumbnails not supported!"); } // Abort /** * Requests that any current read operation be aborted. The * contents of the image following the abort will be undefined. * *

Readers should call clearAbortRequest at the * beginning of each read operation, and poll the value of * abortRequested regularly during the read. */ public synchronized void abort() { this.abortFlag = true; } /** * Returns true if a request to abort the current * read operation has been made since the reader was instantiated or * clearAbortRequest was called. * * @return true if the current read operation should * be aborted. * * @see #abort * @see #clearAbortRequest */ protected synchronized boolean abortRequested() { return this.abortFlag; } /** * Clears any previous abort request. After this method has been * called, abortRequested will return * false. * * @see #abort * @see #abortRequested */ protected synchronized void clearAbortRequest() { this.abortFlag = false; } // Listeners // Add an element to a list, creating a new list if the // existing list is null, and return the list. static List addToList(List l, T elt) { if (l == null) { l = new ArrayList<>(); } l.add(elt); return l; } // Remove an element from a list, discarding the list if the // resulting list is empty, and return the list or null. static List removeFromList(List l, T elt) { if (l == null) { return l; } l.remove(elt); if (l.size() == 0) { l = null; } return l; } /** * Adds an IIOReadWarningListener to the list of * registered warning listeners. If listener is * null, no exception will be thrown and no action * will be taken. Messages sent to the given listener will be * localized, if possible, to match the current * Locale. If no Locale has been set, * warning messages may be localized as the reader sees fit. * * @param listener an IIOReadWarningListener to be registered. * * @see #removeIIOReadWarningListener */ public void addIIOReadWarningListener(IIOReadWarningListener listener) { if (listener == null) { return; } warningListeners = addToList(warningListeners, listener); warningLocales = addToList(warningLocales, getLocale()); } /** * Removes an IIOReadWarningListener from the list of * registered error listeners. If the listener was not previously * registered, or if listener is null, * no exception will be thrown and no action will be taken. * * @param listener an IIOReadWarningListener to be unregistered. * * @see #addIIOReadWarningListener */ public void removeIIOReadWarningListener(IIOReadWarningListener listener) { if (listener == null || warningListeners == null) { return; } int index = warningListeners.indexOf(listener); if (index != -1) { warningListeners.remove(index); warningLocales.remove(index); if (warningListeners.size() == 0) { warningListeners = null; warningLocales = null; } } } /** * Removes all currently registered * IIOReadWarningListener objects. * *

The default implementation sets the * warningListeners and warningLocales * instance variables to null. */ public void removeAllIIOReadWarningListeners() { warningListeners = null; warningLocales = null; } /** * Adds an IIOReadProgressListener to the list of * registered progress listeners. If listener is * null, no exception will be thrown and no action * will be taken. * * @param listener an IIOReadProgressListener to be registered. * * @see #removeIIOReadProgressListener */ public void addIIOReadProgressListener(IIOReadProgressListener listener) { if (listener == null) { return; } progressListeners = addToList(progressListeners, listener); } /** * Removes an IIOReadProgressListener from the list * of registered progress listeners. If the listener was not * previously registered, or if listener is * null, no exception will be thrown and no action * will be taken. * * @param listener an IIOReadProgressListener to be unregistered. * * @see #addIIOReadProgressListener */ public void removeIIOReadProgressListener (IIOReadProgressListener listener) { if (listener == null || progressListeners == null) { return; } progressListeners = removeFromList(progressListeners, listener); } /** * Removes all currently registered * IIOReadProgressListener objects. * *

The default implementation sets the * progressListeners instance variable to * null. */ public void removeAllIIOReadProgressListeners() { progressListeners = null; } /** * Adds an IIOReadUpdateListener to the list of * registered update listeners. If listener is * null, no exception will be thrown and no action * will be taken. The listener will receive notification of pixel * updates as images and thumbnails are decoded, including the * starts and ends of progressive passes. * *

If no update listeners are present, the reader may choose * to perform fewer updates to the pixels of the destination * images and/or thumbnails, which may result in more efficient * decoding. * *

For example, in progressive JPEG decoding each pass * contains updates to a set of coefficients, which would have to * be transformed into pixel values and converted to an RGB color * space for each pass if listeners are present. If no listeners * are present, the coefficients may simply be accumulated and the * final results transformed and color converted one time only. * *

The final results of decoding will be the same whether or * not intermediate updates are performed. Thus if only the final * image is desired it may be preferable not to register any * IIOReadUpdateListeners. In general, progressive * updating is most effective when fetching images over a network * connection that is very slow compared to local CPU processing; * over a fast connection, progressive updates may actually slow * down the presentation of the image. * * @param listener an IIOReadUpdateListener to be registered. * * @see #removeIIOReadUpdateListener */ public void addIIOReadUpdateListener(IIOReadUpdateListener listener) { if (listener == null) { return; } updateListeners = addToList(updateListeners, listener); } /** * Removes an IIOReadUpdateListener from the list of * registered update listeners. If the listener was not * previously registered, or if listener is * null, no exception will be thrown and no action * will be taken. * * @param listener an IIOReadUpdateListener to be unregistered. * * @see #addIIOReadUpdateListener */ public void removeIIOReadUpdateListener(IIOReadUpdateListener listener) { if (listener == null || updateListeners == null) { return; } updateListeners = removeFromList(updateListeners, listener); } /** * Removes all currently registered * IIOReadUpdateListener objects. * *

The default implementation sets the * updateListeners instance variable to * null. */ public void removeAllIIOReadUpdateListeners() { updateListeners = null; } /** * Broadcasts the start of an sequence of image reads to all * registered IIOReadProgressListeners by calling * their sequenceStarted method. Subclasses may use * this method as a convenience. * * @param minIndex the lowest index being read. */ protected void processSequenceStarted(int minIndex) { if (progressListeners == null) { return; } int numListeners = progressListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadProgressListener listener = progressListeners.get(i); listener.sequenceStarted(this, minIndex); } } /** * Broadcasts the completion of an sequence of image reads to all * registered IIOReadProgressListeners by calling * their sequenceComplete method. Subclasses may use * this method as a convenience. */ protected void processSequenceComplete() { if (progressListeners == null) { return; } int numListeners = progressListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadProgressListener listener = progressListeners.get(i); listener.sequenceComplete(this); } } /** * Broadcasts the start of an image read to all registered * IIOReadProgressListeners by calling their * imageStarted method. Subclasses may use this * method as a convenience. * * @param imageIndex the index of the image about to be read. */ protected void processImageStarted(int imageIndex) { if (progressListeners == null) { return; } int numListeners = progressListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadProgressListener listener = progressListeners.get(i); listener.imageStarted(this, imageIndex); } } /** * Broadcasts the current percentage of image completion to all * registered IIOReadProgressListeners by calling * their imageProgress method. Subclasses may use * this method as a convenience. * * @param percentageDone the current percentage of completion, * as a float. */ protected void processImageProgress(float percentageDone) { if (progressListeners == null) { return; } int numListeners = progressListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadProgressListener listener = progressListeners.get(i); listener.imageProgress(this, percentageDone); } } /** * Broadcasts the completion of an image read to all registered * IIOReadProgressListeners by calling their * imageComplete method. Subclasses may use this * method as a convenience. */ protected void processImageComplete() { if (progressListeners == null) { return; } int numListeners = progressListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadProgressListener listener = progressListeners.get(i); listener.imageComplete(this); } } /** * Broadcasts the start of a thumbnail read to all registered * IIOReadProgressListeners by calling their * thumbnailStarted method. Subclasses may use this * method as a convenience. * * @param imageIndex the index of the image associated with the * thumbnail. * @param thumbnailIndex the index of the thumbnail. */ protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) { if (progressListeners == null) { return; } int numListeners = progressListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadProgressListener listener = progressListeners.get(i); listener.thumbnailStarted(this, imageIndex, thumbnailIndex); } } /** * Broadcasts the current percentage of thumbnail completion to * all registered IIOReadProgressListeners by calling * their thumbnailProgress method. Subclasses may * use this method as a convenience. * * @param percentageDone the current percentage of completion, * as a float. */ protected void processThumbnailProgress(float percentageDone) { if (progressListeners == null) { return; } int numListeners = progressListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadProgressListener listener = progressListeners.get(i); listener.thumbnailProgress(this, percentageDone); } } /** * Broadcasts the completion of a thumbnail read to all registered * IIOReadProgressListeners by calling their * thumbnailComplete method. Subclasses may use this * method as a convenience. */ protected void processThumbnailComplete() { if (progressListeners == null) { return; } int numListeners = progressListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadProgressListener listener = progressListeners.get(i); listener.thumbnailComplete(this); } } /** * Broadcasts that the read has been aborted to all registered * IIOReadProgressListeners by calling their * readAborted method. Subclasses may use this * method as a convenience. */ protected void processReadAborted() { if (progressListeners == null) { return; } int numListeners = progressListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadProgressListener listener = progressListeners.get(i); listener.readAborted(this); } } /** * Broadcasts the beginning of a progressive pass to all * registered IIOReadUpdateListeners by calling their * passStarted method. Subclasses may use this * method as a convenience. * * @param theImage the BufferedImage being updated. * @param pass the index of the current pass, starting with 0. * @param minPass the index of the first pass that will be decoded. * @param maxPass the index of the last pass that will be decoded. * @param minX the X coordinate of the upper-left pixel included * in the pass. * @param minY the X coordinate of the upper-left pixel included * in the pass. * @param periodX the horizontal separation between pixels. * @param periodY the vertical separation between pixels. * @param bands an array of ints indicating the * set of affected bands of the destination. */ protected void processPassStarted(BufferedImage theImage, int pass, int minPass, int maxPass, int minX, int minY, int periodX, int periodY, int[] bands) { if (updateListeners == null) { return; } int numListeners = updateListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadUpdateListener listener = updateListeners.get(i); listener.passStarted(this, theImage, pass, minPass, maxPass, minX, minY, periodX, periodY, bands); } } /** * Broadcasts the update of a set of samples to all registered * IIOReadUpdateListeners by calling their * imageUpdate method. Subclasses may use this * method as a convenience. * * @param theImage the BufferedImage being updated. * @param minX the X coordinate of the upper-left pixel included * in the pass. * @param minY the X coordinate of the upper-left pixel included * in the pass. * @param width the total width of the area being updated, including * pixels being skipped if periodX > 1. * @param height the total height of the area being updated, * including pixels being skipped if periodY > 1. * @param periodX the horizontal separation between pixels. * @param periodY the vertical separation between pixels. * @param bands an array of ints indicating the * set of affected bands of the destination. */ protected void processImageUpdate(BufferedImage theImage, int minX, int minY, int width, int height, int periodX, int periodY, int[] bands) { if (updateListeners == null) { return; } int numListeners = updateListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadUpdateListener listener = updateListeners.get(i); listener.imageUpdate(this, theImage, minX, minY, width, height, periodX, periodY, bands); } } /** * Broadcasts the end of a progressive pass to all * registered IIOReadUpdateListeners by calling their * passComplete method. Subclasses may use this * method as a convenience. * * @param theImage the BufferedImage being updated. */ protected void processPassComplete(BufferedImage theImage) { if (updateListeners == null) { return; } int numListeners = updateListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadUpdateListener listener = updateListeners.get(i); listener.passComplete(this, theImage); } } /** * Broadcasts the beginning of a thumbnail progressive pass to all * registered IIOReadUpdateListeners by calling their * thumbnailPassStarted method. Subclasses may use this * method as a convenience. * * @param theThumbnail the BufferedImage thumbnail * being updated. * @param pass the index of the current pass, starting with 0. * @param minPass the index of the first pass that will be decoded. * @param maxPass the index of the last pass that will be decoded. * @param minX the X coordinate of the upper-left pixel included * in the pass. * @param minY the X coordinate of the upper-left pixel included * in the pass. * @param periodX the horizontal separation between pixels. * @param periodY the vertical separation between pixels. * @param bands an array of ints indicating the * set of affected bands of the destination. */ protected void processThumbnailPassStarted(BufferedImage theThumbnail, int pass, int minPass, int maxPass, int minX, int minY, int periodX, int periodY, int[] bands) { if (updateListeners == null) { return; } int numListeners = updateListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadUpdateListener listener = updateListeners.get(i); listener.thumbnailPassStarted(this, theThumbnail, pass, minPass, maxPass, minX, minY, periodX, periodY, bands); } } /** * Broadcasts the update of a set of samples in a thumbnail image * to all registered IIOReadUpdateListeners by * calling their thumbnailUpdate method. Subclasses may * use this method as a convenience. * * @param theThumbnail the BufferedImage thumbnail * being updated. * @param minX the X coordinate of the upper-left pixel included * in the pass. * @param minY the X coordinate of the upper-left pixel included * in the pass. * @param width the total width of the area being updated, including * pixels being skipped if periodX > 1. * @param height the total height of the area being updated, * including pixels being skipped if periodY > 1. * @param periodX the horizontal separation between pixels. * @param periodY the vertical separation between pixels. * @param bands an array of ints indicating the * set of affected bands of the destination. */ protected void processThumbnailUpdate(BufferedImage theThumbnail, int minX, int minY, int width, int height, int periodX, int periodY, int[] bands) { if (updateListeners == null) { return; } int numListeners = updateListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadUpdateListener listener = updateListeners.get(i); listener.thumbnailUpdate(this, theThumbnail, minX, minY, width, height, periodX, periodY, bands); } } /** * Broadcasts the end of a thumbnail progressive pass to all * registered IIOReadUpdateListeners by calling their * thumbnailPassComplete method. Subclasses may use this * method as a convenience. * * @param theThumbnail the BufferedImage thumbnail * being updated. */ protected void processThumbnailPassComplete(BufferedImage theThumbnail) { if (updateListeners == null) { return; } int numListeners = updateListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadUpdateListener listener = updateListeners.get(i); listener.thumbnailPassComplete(this, theThumbnail); } } /** * Broadcasts a warning message to all registered * IIOReadWarningListeners by calling their * warningOccurred method. Subclasses may use this * method as a convenience. * * @param warning the warning message to send. * * @exception IllegalArgumentException if warning * is null. */ protected void processWarningOccurred(String warning) { if (warningListeners == null) { return; } if (warning == null) { throw new IllegalArgumentException("warning == null!"); } int numListeners = warningListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadWarningListener listener = warningListeners.get(i); listener.warningOccurred(this, warning); } } /** * Broadcasts a localized warning message to all registered * IIOReadWarningListeners by calling their * warningOccurred method with a string taken * from a ResourceBundle. Subclasses may use this * method as a convenience. * * @param baseName the base name of a set of * ResourceBundles containing localized warning * messages. * @param keyword the keyword used to index the warning message * within the set of ResourceBundles. * * @exception IllegalArgumentException if baseName * is null. * @exception IllegalArgumentException if keyword * is null. * @exception IllegalArgumentException if no appropriate * ResourceBundle may be located. * @exception IllegalArgumentException if the named resource is * not found in the located ResourceBundle. * @exception IllegalArgumentException if the object retrieved * from the ResourceBundle is not a * String. */ protected void processWarningOccurred(String baseName, String keyword) { if (warningListeners == null) { return; } if (baseName == null) { throw new IllegalArgumentException("baseName == null!"); } if (keyword == null) { throw new IllegalArgumentException("keyword == null!"); } int numListeners = warningListeners.size(); for (int i = 0; i < numListeners; i++) { IIOReadWarningListener listener = warningListeners.get(i); Locale locale = warningLocales.get(i); if (locale == null) { locale = Locale.getDefault(); } /** * If an applet supplies an implementation of ImageReader and * resource bundles, then the resource bundle will need to be * accessed via the applet class loader. So first try the context * class loader to locate the resource bundle. * If that throws MissingResourceException, then try the * system class loader. */ ClassLoader loader = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); } }); ResourceBundle bundle = null; try { bundle = ResourceBundle.getBundle(baseName, locale, loader); } catch (MissingResourceException mre) { try { bundle = ResourceBundle.getBundle(baseName, locale); } catch (MissingResourceException mre1) { throw new IllegalArgumentException("Bundle not found!"); } } String warning = null; try { warning = bundle.getString(keyword); } catch (ClassCastException cce) { throw new IllegalArgumentException("Resource is not a String!"); } catch (MissingResourceException mre) { throw new IllegalArgumentException("Resource is missing!"); } listener.warningOccurred(this, warning); } } // State management /** * Restores the ImageReader to its initial state. * *

The default implementation calls setInput(null, * false), setLocale(null), * removeAllIIOReadUpdateListeners(), * removeAllIIOReadWarningListeners(), * removeAllIIOReadProgressListeners(), and * clearAbortRequest. */ public void reset() { setInput(null, false, false); setLocale(null); removeAllIIOReadUpdateListeners(); removeAllIIOReadProgressListeners(); removeAllIIOReadWarningListeners(); clearAbortRequest(); } /** * Allows any resources held by this object to be released. The * result of calling any other method (other than * finalize) subsequent to a call to this method * is undefined. * *

It is important for applications to call this method when they * know they will no longer be using this ImageReader. * Otherwise, the reader may continue to hold on to resources * indefinitely. * *

The default implementation of this method in the superclass does * nothing. Subclass implementations should ensure that all resources, * especially native resources, are released. */ public void dispose() { } // Utility methods /** * A utility method that may be used by readers to compute the * region of the source image that should be read, taking into * account any source region and subsampling offset settings in * the supplied ImageReadParam. The actual * subsampling factors, destination size, and destination offset * are not taken into consideration, thus further * clipping must take place. The {@link #computeRegions computeRegions} * method performs all necessary clipping. * * @param param the ImageReadParam being used, or * null. * @param srcWidth the width of the source image. * @param srcHeight the height of the source image. * * @return the source region as a Rectangle. */ protected static Rectangle getSourceRegion(ImageReadParam param, int srcWidth, int srcHeight) { Rectangle sourceRegion = new Rectangle(0, 0, srcWidth, srcHeight); if (param != null) { Rectangle region = param.getSourceRegion(); if (region != null) { sourceRegion = sourceRegion.intersection(region); } int subsampleXOffset = param.getSubsamplingXOffset(); int subsampleYOffset = param.getSubsamplingYOffset(); sourceRegion.x += subsampleXOffset; sourceRegion.y += subsampleYOffset; sourceRegion.width -= subsampleXOffset; sourceRegion.height -= subsampleYOffset; } return sourceRegion; } /** * Computes the source region of interest and the destination * region of interest, taking the width and height of the source * image, an optional destination image, and an optional * ImageReadParam into account. The source region * begins with the entire source image. Then that is clipped to * the source region specified in the ImageReadParam, * if one is specified. * *

If either of the destination offsets are negative, the * source region is clipped so that its top left will coincide * with the top left of the destination image, taking subsampling * into account. Then the result is clipped to the destination * image on the right and bottom, if one is specified, taking * subsampling and destination offsets into account. * *

Similarly, the destination region begins with the source * image, is translated to the destination offset given in the * ImageReadParam if there is one, and finally is * clipped to the destination image, if there is one. * *

If either the source or destination regions end up having a * width or height of 0, an IllegalArgumentException * is thrown. * *

The {@link #getSourceRegion getSourceRegion>} * method may be used if only source clipping is desired. * * @param param an ImageReadParam, or null. * @param srcWidth the width of the source image. * @param srcHeight the height of the source image. * @param image a BufferedImage that will be the * destination image, or null. * @param srcRegion a Rectangle that will be filled with * the source region of interest. * @param destRegion a Rectangle that will be filled with * the destination region of interest. * @exception IllegalArgumentException if srcRegion * is null. * @exception IllegalArgumentException if dstRegion * is null. * @exception IllegalArgumentException if the resulting source or * destination region is empty. */ protected static void computeRegions(ImageReadParam param, int srcWidth, int srcHeight, BufferedImage image, Rectangle srcRegion, Rectangle destRegion) { if (srcRegion == null) { throw new IllegalArgumentException("srcRegion == null!"); } if (destRegion == null) { throw new IllegalArgumentException("destRegion == null!"); } // Start with the entire source image srcRegion.setBounds(0, 0, srcWidth, srcHeight); // Destination also starts with source image, as that is the // maximum extent if there is no subsampling destRegion.setBounds(0, 0, srcWidth, srcHeight); // Clip that to the param region, if there is one int periodX = 1; int periodY = 1; int gridX = 0; int gridY = 0; if (param != null) { Rectangle paramSrcRegion = param.getSourceRegion(); if (paramSrcRegion != null) { srcRegion.setBounds(srcRegion.intersection(paramSrcRegion)); } periodX = param.getSourceXSubsampling(); periodY = param.getSourceYSubsampling(); gridX = param.getSubsamplingXOffset(); gridY = param.getSubsamplingYOffset(); srcRegion.translate(gridX, gridY); srcRegion.width -= gridX; srcRegion.height -= gridY; destRegion.setLocation(param.getDestinationOffset()); } // Now clip any negative destination offsets, i.e. clip // to the top and left of the destination image if (destRegion.x < 0) { int delta = -destRegion.x*periodX; srcRegion.x += delta; srcRegion.width -= delta; destRegion.x = 0; } if (destRegion.y < 0) { int delta = -destRegion.y*periodY; srcRegion.y += delta; srcRegion.height -= delta; destRegion.y = 0; } // Now clip the destination Region to the subsampled width and height int subsampledWidth = (srcRegion.width + periodX - 1)/periodX; int subsampledHeight = (srcRegion.height + periodY - 1)/periodY; destRegion.width = subsampledWidth; destRegion.height = subsampledHeight; // Now clip that to right and bottom of the destination image, // if there is one, taking subsampling into account if (image != null) { Rectangle destImageRect = new Rectangle(0, 0, image.getWidth(), image.getHeight()); destRegion.setBounds(destRegion.intersection(destImageRect)); if (destRegion.isEmpty()) { throw new IllegalArgumentException ("Empty destination region!"); } int deltaX = destRegion.x + subsampledWidth - image.getWidth(); if (deltaX > 0) { srcRegion.width -= deltaX*periodX; } int deltaY = destRegion.y + subsampledHeight - image.getHeight(); if (deltaY > 0) { srcRegion.height -= deltaY*periodY; } } if (srcRegion.isEmpty() || destRegion.isEmpty()) { throw new IllegalArgumentException("Empty region!"); } } /** * A utility method that may be used by readers to test the * validity of the source and destination band settings of an * ImageReadParam. This method may be called as soon * as the reader knows both the number of bands of the source * image as it exists in the input stream, and the number of bands * of the destination image that being written. * *

The method retrieves the source and destination band * setting arrays from param using the getSourceBands * and getDestinationBandsmethods (or considers them * to be null if param is * null). If the source band setting array is * null, it is considered to be equal to the array * { 0, 1, ..., numSrcBands - 1 }, and similarly for * the destination band setting array. * *

The method then tests that both arrays are equal in length, * and that neither array contains a value larger than the largest * available band index. * *

Any failure results in an * IllegalArgumentException being thrown; success * results in the method returning silently. * * @param param the ImageReadParam being used to read * the image. * @param numSrcBands the number of bands of the image as it exists * int the input source. * @param numDstBands the number of bands in the destination image * being written. * * @exception IllegalArgumentException if param * contains an invalid specification of a source and/or * destination band subset. */ protected static void checkReadParamBandSettings(ImageReadParam param, int numSrcBands, int numDstBands) { // A null param is equivalent to srcBands == dstBands == null. int[] srcBands = null; int[] dstBands = null; if (param != null) { srcBands = param.getSourceBands(); dstBands = param.getDestinationBands(); } int paramSrcBandLength = (srcBands == null) ? numSrcBands : srcBands.length; int paramDstBandLength = (dstBands == null) ? numDstBands : dstBands.length; if (paramSrcBandLength != paramDstBandLength) { throw new IllegalArgumentException("ImageReadParam num source & dest bands differ!"); } if (srcBands != null) { for (int i = 0; i < srcBands.length; i++) { if (srcBands[i] >= numSrcBands) { throw new IllegalArgumentException("ImageReadParam source bands contains a value >= the number of source bands!"); } } } if (dstBands != null) { for (int i = 0; i < dstBands.length; i++) { if (dstBands[i] >= numDstBands) { throw new IllegalArgumentException("ImageReadParam dest bands contains a value >= the number of dest bands!"); } } } } /** * Returns the BufferedImage to which decoded pixel * data should be written. The image is determined by inspecting * the supplied ImageReadParam if it is * non-null; if its getDestination * method returns a non-null value, that image is * simply returned. Otherwise, * param.getDestinationType method is called to * determine if a particular image type has been specified. If * so, the returned ImageTypeSpecifier is used after * checking that it is equal to one of those included in * imageTypes. * *

If param is null or the above * steps have not yielded an image or an * ImageTypeSpecifier, the first value obtained from * the imageTypes parameter is used. Typically, the * caller will set imageTypes to the value of * getImageTypes(imageIndex). * *

Next, the dimensions of the image are determined by a call * to computeRegions. The actual width and height of * the image being decoded are passed in as the width * and height parameters. * * @param param an ImageReadParam to be used to get * the destination image or image type, or null. * @param imageTypes an Iterator of * ImageTypeSpecifiers indicating the legal image * types, with the default first. * @param width the true width of the image or tile begin decoded. * @param height the true width of the image or tile being decoded. * * @return the BufferedImage to which decoded pixel * data should be written. * * @exception IIOException if the ImageTypeSpecifier * specified by param does not match any of the legal * ones from imageTypes. * @exception IllegalArgumentException if imageTypes * is null or empty, or if an object not of type * ImageTypeSpecifier is retrieved from it. * @exception IllegalArgumentException if the resulting image would * have a width or height less than 1. * @exception IllegalArgumentException if the product of * width and height is greater than * Integer.MAX_VALUE. */ protected static BufferedImage getDestination(ImageReadParam param, Iterator imageTypes, int width, int height) throws IIOException { if (imageTypes == null || !imageTypes.hasNext()) { throw new IllegalArgumentException("imageTypes null or empty!"); } if ((long)width*height > Integer.MAX_VALUE) { throw new IllegalArgumentException ("width*height > Integer.MAX_VALUE!"); } BufferedImage dest = null; ImageTypeSpecifier imageType = null; // If param is non-null, use it if (param != null) { // Try to get the image itself dest = param.getDestination(); if (dest != null) { return dest; } // No image, get the image type imageType = param.getDestinationType(); } // No info from param, use fallback image type if (imageType == null) { Object o = imageTypes.next(); if (!(o instanceof ImageTypeSpecifier)) { throw new IllegalArgumentException ("Non-ImageTypeSpecifier retrieved from imageTypes!"); } imageType = (ImageTypeSpecifier)o; } else { boolean foundIt = false; while (imageTypes.hasNext()) { ImageTypeSpecifier type = imageTypes.next(); if (type.equals(imageType)) { foundIt = true; break; } } if (!foundIt) { throw new IIOException ("Destination type from ImageReadParam does not match!"); } } Rectangle srcRegion = new Rectangle(0,0,0,0); Rectangle destRegion = new Rectangle(0,0,0,0); computeRegions(param, width, height, null, srcRegion, destRegion); int destWidth = destRegion.x + destRegion.width; int destHeight = destRegion.y + destRegion.height; // Create a new image based on the type specifier return imageType.createBufferedImage(destWidth, destHeight); } }