CONTENTS | PREV | NEXT |
ImageReader
ImageIO
class to perform the entire decoding
operation, an application may use the ImageIO
class to
obtain an ImageReader
object that may be used to
perform the read:
Iterator readers = ImageIO.getImageReadersByFormatName("gif"); ImageReader reader = (ImageReader)readers.next();Readers may also be retrieved based on file contents, file suffix, or MIME type. The mechanism for locating and instantiating the reader makes use of the
javax.imageio.spi.ImageReaderSpi
class, which allows
information about a reader plug-in to be retrieved without actually
instantiating the plug-in. The notion of "service provider
interfaces" (SPIs) is described in detail in the following
chapter.
Once a reader has been obtained,
it must be supplied with an input source. Most readers are able to
read from an ImageInputStream
, which is a special
input source that is defined by the Image I/O API. A special input
source is used in order to make it simple for reader and writers to
work with both file and streaming I/O.
Obtaining an
ImageInputStream
is straightforward. Given an input
source in the form of a File
or
InputStream
, an ImageInputStream
is
produced by the call:
Object source; // File or InputStream ImageInputStream iis = ImageIO.createImageInputStream(source);Once a source has been obtained, it may be attached to the reader by calling
reader.setInput(iis, true);The second parameter should be set to false if the source file contains multiple images and the application is not guaranteed to read them in order. For file formats that allow only a single image to be stored in a file, it is always legal to pass in a value of true.
Once the reader has its input
source set, we can use it to obtain information about the image
without necessarily causing image data to be read into memory. For
example, calling reader.getImageWidth(0)
allows us to
obtain the width of the first image stored in the file. A
well-written plug-in will attempt to decode only as much of the
file as is necessary to determine the image width, without reading
any pixels.
To read the image, the application
may call reader.read(imageIndex)
, where
imageIndex
is the index of the image within the file.
This produces the same result as if it had called
ImageIO.read
, as shown above.
ImageReadParam
read
method with an additional parameter
of type ImageReadParam
. An ImageReadParam
allows the application to specify a destination image in which the
decoded image data should be stored, allowing better control over
memory use. It also allows a region of interest to be specified, as
well as subsampling factors that may be used to obtain a
scaled-down version of the image.
When a source region is set, the reader plug-in will attempt to decode only the desired region, to the extent that the file format allows partial decoding. In any case, no pixels outside the region will appear in the output. This capability makes it possible to work with extremely large images in a limited amount of memory.
For example, to decode only the
upper-left quadrant of the image, the application first obtains an
ImageReadParam
that is suitable for use with the
reader:
ImageReadParam param = reader.getDefaultReadParam();Next, the source region of interest is set on the
ImageReadParam
:
import java.awt.Rectangle; int imageIndex = 0; int half_width = reader.getImageWidth(imageIndex)/2; int half_height = reader.getImageHeight(imageIndex)/2; Rectangle rect = new Rectangle(0, 0, half_width, half_height); param.setSourceRegion(rect);Finally, the image is read using the
ImageReadParam
:
BufferedImage bi = reader.read(imageIndex, param);The result is a new
BufferedImage
whose width and height are equal to half
those of the original image (rounding down if the image had an odd
width or height).
The lower-right quadrant of the
image may then be read into the same BufferedImage
that was created to hold the upper-left quadrant, overwriting the
previous pixel data:
param.setDestination(bi); rect = new Rectangle(half_width, half_height, half_width, half_height); param.setSourceRegion(rect); BufferedImage bi2 = reader.read(0, param); if (bi == bi2) { System.out.println("The same BufferedImage was used!"); } else { System.out.println("This can't happen!"); }In practice, the application could simply call
reader.read(0, param)
without assigning
the result anywhere, knowing that the pixels will be written into
the existing BufferedImage
bi
.
As another example, to read every
third pixel of the image, resulting in an image one-ninth the size
of the original, subsampling factors may be set in the
ImageReadParam
:
param = reader.getDefaultImageParam(); param.setSourceSubsampling(3, 3, 0, 0); BufferedImage bi3 = reader.read(0, param);
IIOParamController
IIOParamController
object that may be used to set up
an IIOReadParam
(or IIOWriteParam
) using
a graphical user interface (GUI), or any other interface. A reader
plug-in may attach an IIOParamController
to any
ImageReadParam
objects that it creates:
ImageReadParam param = reader.getDefaultImageParam(); IIOParamController controller = param.getController(); if (controller != null) { controller.activate(param); }When the controller's
activate
method is called, it displays the GUI and
handles user events such as slider movements and button presses.
Typically the interface will contain an "OK" or
"Apply" button, which when pressed will cause the activate
method to return. The controller is responsible for calling methods
on its associated ImageReadParam
to update its state,
either in response to each GUI event, or all at once prior to
returning from activate
.ImageReader
class that deal with images take an
imageIndex
parameter. This parameter allows access to
any of the images in a multi-image file.
The
ImageReader.getNumImages
method returns the number of
images that are stored in the input file. This method takes a
boolean parameter, allowSearch
. Some image formats,
notably GIF, do not provide any way to determine the number of
images without reading the entire file. Since this may be costly,
setting allowSearch
to false
will allow
the reader to return a value of -1
instead of the
actual number of images. If the parameter is true
, the
reader will always return the actual number of images.
Even if the number of images is
not known by the application, it is still possible to call
read(imageIndex)
; if the index is too large, the
method will throw an IndexOutOfBoundsException
. Thus,
the application can request images with increasing indices until it
receives an exception.
Applications can determine how many thumbnail images associated with a particular image are available by calling:
reader.getNumThumbnails(imageIndex);If a thumbnail image is present, it can be retrieved by calling:
int thumbailIndex = 0; BufferedImage bi; bi = reader.readThumbnail(imageIndex, thumbnailIndex);