diff options
Diffstat (limited to 'libjava/classpath/javax/imageio')
19 files changed, 5494 insertions, 833 deletions
diff --git a/libjava/classpath/javax/imageio/IIOException.java b/libjava/classpath/javax/imageio/IIOException.java index 8f8dd03441c..b281db1b050 100644 --- a/libjava/classpath/javax/imageio/IIOException.java +++ b/libjava/classpath/javax/imageio/IIOException.java @@ -39,8 +39,9 @@ package javax.imageio; import java.io.IOException; - /** + * A runtime exception to indicate image reading and writing failures. + * * @author Michael Koch (konqueror@gmx.de) */ public class IIOException extends IOException diff --git a/libjava/classpath/javax/imageio/IIOImage.java b/libjava/classpath/javax/imageio/IIOImage.java index 651c9baaa21..0d987476239 100644 --- a/libjava/classpath/javax/imageio/IIOImage.java +++ b/libjava/classpath/javax/imageio/IIOImage.java @@ -45,13 +45,53 @@ import java.util.List; import javax.imageio.metadata.IIOMetadata; +/** + * IIOImage is a container class for components of an image file that + * stores image data, image metadata and thumbnails. + * + * The image data can be either a RenderedImage or a Raster but not + * both. Image readers that produce IIOImages will always produce + * BufferedImages from the RenderedImage field. Image writers that + * accept IIOImages will always accept RenderedImages and may + * optionally accept Rasters. + * + * @author Thomas Fitzsimmons (fitzsim@redhat.com) + */ public class IIOImage { + /** + * Image data as a RenderedImage. null if this IIOImage uses the + * Raster representation. + */ protected RenderedImage image; + + /** + * Image metadata. + */ protected IIOMetadata metadata; + + /** + * Image data as a Raster. null if this IIOImage uses the + * RenderedImage representation. + */ protected Raster raster; + + /** + * A list of BufferedImage thumbnails of this image. + */ + // for 1.5 these lists are List<? extends BufferedImage> protected List thumbnails; - + + /** + * Construct an IIOImage containing raster image data, thumbnails + * and metadata. + * + * @param raster image data + * @param thumbnails a list of BufferedImage thumbnails or null + * @param metadata image metadata or null + * + * @exception IllegalArgumentException if raster is null + */ public IIOImage (Raster raster, List thumbnails, IIOMetadata metadata) { if (raster == null) @@ -62,6 +102,16 @@ public class IIOImage this.metadata = metadata; } + /** + * Construct an IIOImage containing rendered image data, thumbnails + * and metadata. + * + * @param image rendered image data + * @param thumbnails a list of BufferedImage thumbnails or null + * @param metadata image metadata or null + * + * @exception IllegalArgumentException if image is null + */ public IIOImage (RenderedImage image, List thumbnails, IIOMetadata metadata) { if (image == null) @@ -72,46 +122,111 @@ public class IIOImage this.metadata = metadata; } + /** + * Retrieve the image metadata or null if there is no metadata + * associated with this IIOImage. + * + * @return image metadata or null + */ public IIOMetadata getMetadata() { return metadata; } + /** + * Retrieve the number of thumbnails in this IIOImage. + * + * @return the number of thumbnails + */ public int getNumThumbnails() { - return thumbnails.size(); + return thumbnails == null ? 0 : thumbnails.size(); } + /** + * Retrieve the raster image data stored in this IIOImage or null if + * this image stores data using the RenderedImage representation. + * + * @return the raster image data or null + */ public Raster getRaster() { return raster; } + /** + * Retrieve the rendered image data stored in this IIOImage or null + * if this image stores data using the Raster representation. + * + * @return the rendered image data or null + */ public RenderedImage getRenderedImage() { return image; } + /** + * Retrieve the thumbnail stored at the specified index in the + * thumbnails list. + * + * @param index the index of the thumbnail to retrieve + * + * @return the buffered image thumbnail + * + * @exception IndexOutOfBoundsException if index is out-of-bounds + * @exception ClassCastException if the object returned from the + * thumbnails list is not a BufferedImage + */ public BufferedImage getThumbnail (int index) { + // This throws a ClassCastException if the returned object is not + // a BufferedImage or an IndexOutOfBoundsException if index is + // out-of-bounds. return (BufferedImage) thumbnails.get (index); } + /** + * Retrieve the list of thumbnails or null if there are no + * thumbnails associated with this IIOImage. The returned reference + * can be used to update the thumbnails list. + * + * @return a list of thumbnails or null + */ public List getThumbnails() { return thumbnails; } + /** + * Check whether this IIOImage stores its image data as a Raster or + * as a RenderedImage. + * + * @return true if this IIOImage uses the Raster representation, + * false if it uses the RenderedImage representation. + */ public boolean hasRaster() { return raster != null; } + /** + * Set this IIOImage's metadata. + * + * @param metadata the image metadata + */ public void setMetadata (IIOMetadata metadata) { this.metadata = metadata; } + /** + * Set the raster data for this image. This disposes of any + * existing rendered image data stored in this IIOImage. + * + * @param raster the image raster data + * + * @exception IllegalArgumentException if raster is null + */ public void setRaster (Raster raster) { if (raster == null) @@ -121,6 +236,14 @@ public class IIOImage this.raster = raster; } + /** + * Set the rendered image data for this image. This disposes of any + * existing raster data stored in this IIOImage. + * + * @param image the rendered image data + * + * @exception IllegalArgumentException if image is null + */ public void setRenderedImage (RenderedImage image) { if (image == null) @@ -130,9 +253,15 @@ public class IIOImage this.raster = null; } + /** + * Set the list of thumbnails for this IIOImage to a new list of + * BufferedImages or to null. Any existing thumbnails list is + * disposed. + * + * @param thumbnails a new list of thumbnails or null + */ public void setThumbnails (List thumbnails) { this.thumbnails = thumbnails; } - -} // class IIOParam +} diff --git a/libjava/classpath/javax/imageio/IIOParam.java b/libjava/classpath/javax/imageio/IIOParam.java index 01f6166059d..f6460b4e7ed 100644 --- a/libjava/classpath/javax/imageio/IIOParam.java +++ b/libjava/classpath/javax/imageio/IIOParam.java @@ -42,97 +42,317 @@ import java.awt.Point; import java.awt.Rectangle; /** + * An IIOParam stores parameters used when encoding or decoding image + * streams. ImageReadParam and ImageWriteParam extend this abstract + * base class. + * + * IIOParams allow control over how source pixels converted into + * destination pixels. This conversion can take place between a + * stream and in-memory image data, when an image reader is doing the + * conversion, or a writer can be doing the conversion from an + * in-memory source to a stream destination. + * + * An image reader can be restricted to only read from a given region; + * likewise a writer can be restricted to only write output to a given + * region. + * + * For image readers and writers, IIOParam supports image pixelation + * -- where the input image is approximated by the output image using + * larger-sized pixel blocks. For example: FIXME + * + * IIOParams can control how pixels are combined into larger blocks + * using sub-sampling matrices. For example: FIXME + * + * They can also control which source bands are read and written; this + * example reads the RGBA (red, green, blue, transparency) data from a + * PNG image and outputs just the red and transparency bands: FIXME + * + * @author Thomas Fitzsimmons (fitzsim@redhat.com) * @author Michael Koch (konqueror@gmx.de) */ public abstract class IIOParam { - protected IIOParamController controller; - protected IIOParamController defaultController; + /** + * The controller called by this IIOParam to retrieve parameters. + */ + protected IIOParamController controller = null; + + /** + * The default controller called by this IIOParam to retrieve + * parameters. + */ + protected IIOParamController defaultController = null; + + /** + * The offset in the destination where the upper-left + * decoded/encoded pixel should be located. + */ protected Point destinationOffset = new Point(0, 0); - protected ImageTypeSpecifier destinationType; - protected int[] sourceBands; - protected Rectangle sourceRegion; - protected int sourceXSubsampling; - protected int sourceYSubsampling; - protected int subsamplingXOffset; - protected int subsamplingYOffset; /** - * Initializes an <code>IIOParam</code> object. + * Sets the output colour type when writing or the destination image + * type when reading. + */ + protected ImageTypeSpecifier destinationType = null; + + /** + * An array indicating which source bands will be used or null. + */ + protected int[] sourceBands = null; + + /** + * The source pixel region or null. + */ + protected Rectangle sourceRegion = null; + + /** + * Sample every sourceXSubsampling'th pixel in the source image when + * pixelating the destination image in the horizontal direction. + */ + protected int sourceXSubsampling = 1; + + /** + * Sample every sourceYSubsampling'th pixel in the source image when + * pixelating the destination image in the vertical direction. + */ + protected int sourceYSubsampling = 1; + + /** + * Start sampling at this horizontal offset within the source region + * when pixelating the destination image in the horizontal + * direction. + */ + protected int subsamplingXOffset = 0; + + /** + * Start sampling at this vertical offset within the source region + * when pixelating the destination image in the vertical direction. + */ + protected int subsamplingYOffset = 0; + + /** + * Indicates whether or not the controller has been explicitly set + * to null. + */ + private boolean no_controller = false; + + /** + * Constructs an IIOParam object. */ protected IIOParam() { - // Do nothing here. } + /** + * Activates the parameter controller by calling its activate method + * and passing it this IIOParam. A true return value indicates that + * this IIOParam's values are ready for the next read or write + * operation. A return value of false means that this IIOParam's + * values have not been affected because the controller operations + * were cancelled. + * + * @return true if parameters were successfully set, false if + * parameters were not changed + */ public boolean activateController() { if (controller == null) - return false; - - return controller.activate(this); + { + if (defaultController == null || no_controller) + return false; + else + return defaultController.activate (this); + } + else + return controller.activate(this); } - + + /** + * Retrieve the currently set controller if one has been set, or the + * default controller, or null if the controller has been explicitly + * set to null. + * + * @return the currently used controller or null + */ public IIOParamController getController() { - return controller; + return controller == null ? + (no_controller ? null : defaultController) : controller; } + /** + * Retrieve the default controller regardless of whether or not a + * non-default controller has been set. The default controller may + * be null. + * + * @return the default controller or null + */ public IIOParamController getDefaultController() { return defaultController; } + /** + * Retrieve the offset in the destination where the upper-left + * decoded/encoded pixel should be located. (0, 0) by default. + * + * @return the destination offset + */ public Point getDestinationOffset() { return destinationOffset; } + /** + * Retrieve the currently set image-type specifier or null if none + * has been set. + * + * @return the current image-type specifier or null + */ public ImageTypeSpecifier getDestinationType() { return destinationType; } + /** + * Retrieve the current source band values or null if source band + * values have not been set. + * + * The returned array is a copy of this IIOParam's source band + * array. + * + * @return the current set of source band values or null + */ public int[] getSourceBands() { - return sourceBands; + if (sourceBands == null) + return null; + + int[] sourceBandsCopy = new int[sourceBands.length]; + System.arraycopy (sourceBands, 0, sourceBandsCopy, 0, sourceBands.length); + return sourceBandsCopy; } + /** + * Retrieve the source rectangle from which pixels should be read or + * null if no source region has been set. + * + * @return the current source region or null + */ public Rectangle getSourceRegion() { return sourceRegion; } + /** + * Retrieve the number of pixel columns to advance before taking a + * pixel sample. + * + * @return the horizontal sub-sampling interval + */ public int getSourceXSubsampling() { return sourceXSubsampling; } + /** + * Retrieve the number of pixel rows to advance before taking a + * pixel sample. + * + * @return the vertical sub-sampling interval + */ public int getSourceYSubsampling() { return sourceYSubsampling; } + /** + * Retrieve the number of pixel columns to advance before taking any + * pixel samples. + * + * @return the horizontal sub-sampling offset + */ public int getSubsamplingXOffset() { return subsamplingXOffset; } - + + /** + * Retrieve the number of pixel rows to advance before taking any + * pixel samples. + * + * @return the vertical sub-sampling offset + */ public int getSubsamplingYOffset() { return subsamplingYOffset; } + /** + * Check if a non-null controller is currently available. + * + * @return true if getController returns a non-null value, false if + * getController returns null + */ public boolean hasController() { return getController() != null; } + /** + * Sets the controller for this IIOParam. This is the controller + * that will be activated when activateController is called. The + * argument controller overrides this IIOParam's default controller. + * If the argument is null then no controller will be set, not even + * the default one. To reset the default controller call + * setController(getDefaultController()). + * + * @param controller the controller to set or null + */ public void setController(IIOParamController controller) { - this.controller = controller; + if (controller == defaultController) + { + this.controller = null; + no_controller = false; + } + else + { + no_controller = (controller == null); + this.controller = controller; + } } + /** + * Set the destination image type. + * + * If this value is set on an image reader then its read method will + * return a new BufferedImage of the specified destination type. In + * this case any destination image set using setDestination() is + * ignored. + * + * If this is set on an image writer then the destination type + * affects only the colour model of the destination image. The + * destination type's SampleModel is ignored. The destination + * type's ColorModel will override the source image's colour model. + * + * @param destinationType the sample and colour models of the + * destination image + */ + public void setDestinationType (ImageTypeSpecifier destinationType) + { + this.destinationType = destinationType; + } + + /** + * Specify the destination pixel offset. Image writers are only + * affected by this setting when ImageWriter.replacePixels is called + * in which case the offset is into the region of pixels being + * changed. + * + * @param destinationOffset the offset where pixel writing should + * begin + */ public void setDestinationOffset(Point destinationOffset) { if (destinationOffset == null) @@ -141,11 +361,43 @@ public abstract class IIOParam this.destinationOffset = destinationOffset; } + /** + * Set the indices of the source bands to be used. Duplicate + * indices are not allowed. A value of null means use all source + * bands. The argument array is copied and stored, so subsequent + * updates to it will not be reflected in this IIOParam. + * + * @param sourceBands the array of source bands to use + */ public void setSourceBands(int[] sourceBands) { - this.sourceBands = sourceBands; + int[] sourceBandsCopy = new int[sourceBands.length]; + System.arraycopy (sourceBands, 0, sourceBandsCopy, 0, sourceBands.length); + this.sourceBands = sourceBandsCopy; } + /** + * Set the source region from which to read. The number of pixels + * sampled from the source region depends on the source sub-sampling + * settings. If the combination of this sourceRegion and the + * current sub-sampling settings would result in no pixels being + * sampled then an IllegalStateException will be thrown. + * + * The source region is specified in the source image coordinate + * system which has point (0, 0) at the top-left and increases down + * and to the right. The argument source region is clipped to the + * image boundaries at read-time. + * + * A null argument sets the source region to null meaning that the + * whole image should be read. + * + * @param sourceRegion the rectangular source region + * + * @exception IllegalArgumentException if sourceRegion has width or + * height <= 0 or x or y < 0 + * @exception IllegalStateException if the given sourceRegion and + * the current sampling settings would produce zero samples + */ public void setSourceRegion(Rectangle sourceRegion) { if (sourceRegion != null @@ -154,15 +406,83 @@ public abstract class IIOParam || sourceRegion.width <= 0 || sourceRegion.height <= 0)) throw new IllegalArgumentException("illegal source region"); - - // FIXME: Throw IllegalStateException. + + if (sourceRegion != null) + { + int num_rows = + (sourceRegion.height - subsamplingYOffset + sourceYSubsampling - 1) + / sourceYSubsampling; + + int num_columns = + (sourceRegion.width - subsamplingXOffset + sourceXSubsampling - 1) + / sourceXSubsampling; + + if (num_rows <= 0 || num_columns <= 0) + throw new IllegalStateException("zero pixels in source region"); + } this.sourceRegion = sourceRegion; } + /** + * Set the source sampling intervals and offsets. Every + * sourceXSubsampling'th pixel horizontally and + * sourceYSubsampling'th pixel vertically will be sampled. Sampling + * will being a the subsamplingXOffset'th column and the + * subsamplingYOffset'th row. + * + * Horizontally, the number of sampled pixels will be: + * + * floor((width - subsamplingXOffset + sourceXSubsampling - 1) / sourceXSubsampling) + * + * Vertically: + * + * floor((height - subsamplingYOffset + sourceYSubsampling - 1) / sourceYSubsampling) + * + * If the current source region setting is such that the given + * sub-sampling arguments would produce zero pixel samples, an + * IllegalStateException is thrown. + * + * The offset parameters can be used to make source regions overlap + * when tiling across an image. This can eliminate seams and + * better-tile images whose width or height is not a multiple of the + * sampling interval. + * + * @param sourceXSubsampling the horizontal sampling interval + * @param sourceYSubsampling the vertical sampling interval + * @param subsamplingXOffset the horizontal offset of the initial + * sample + * @param subsamplingYOffset the vertical offset of the initial + * sample + * + * @exception IllegalArgumentException if either subsamplingXOffset + * or subsamplingYOffset is < 0 + * @exception IllegalStateException if the current source region + * combined with the given sub-sampling parameters would produce + * zero pixel samples + */ public void setSourceSubsampling(int sourceXSubsampling, int sourceYSubsampling, int subsamplingXOffset, int subsamplingYOffset) { + if (subsamplingXOffset < 0 || subsamplingYOffset < 0) + throw new IllegalArgumentException("subsampling offset < 0"); + + if (sourceRegion != null) + { + int num_rows = + (sourceRegion.height - subsamplingYOffset + sourceYSubsampling - 1) + / sourceYSubsampling; + + int num_columns = + (sourceRegion.width - subsamplingXOffset + sourceXSubsampling - 1) + / sourceXSubsampling; + + if (num_rows <= 0 || num_columns <= 0) + throw new IllegalStateException("subsampling parameters would" + + " produce zero pixel samples" + + " in source region"); + } + this.sourceXSubsampling = sourceXSubsampling; this.sourceYSubsampling = sourceYSubsampling; this.subsamplingXOffset = subsamplingXOffset; diff --git a/libjava/classpath/javax/imageio/IIOParamController.java b/libjava/classpath/javax/imageio/IIOParamController.java index 125520e735b..0ee54df4071 100644 --- a/libjava/classpath/javax/imageio/IIOParamController.java +++ b/libjava/classpath/javax/imageio/IIOParamController.java @@ -39,12 +39,23 @@ exception statement from your version. */ package javax.imageio; /** + * An interface to set image parameters. An IIOParamController may be + * a GUI component, a database reader, command-line parser or any + * other means of getting parameter settings. For exampe, a dialog + * box could implement IIOParamController to allow a user to adjust + * JPEG compression levels. + * + * The activate method should always behave modally; it should only + * return when the action has been either cancelled or completed. + * * @author Michael Koch (konqueror@gmx.de) */ public interface IIOParamController { /** - * Activates the controller. + * Activates the controller. A return value of false should mean + * that no changes were made to param. A return value of true + * should mean that the image is ready to be read or written. * * @param param the <code>IIOParam</code> to be modified * diff --git a/libjava/classpath/javax/imageio/ImageIO.java b/libjava/classpath/javax/imageio/ImageIO.java index 95c7c325121..3ea7e858544 100644 --- a/libjava/classpath/javax/imageio/ImageIO.java +++ b/libjava/classpath/javax/imageio/ImageIO.java @@ -52,7 +52,10 @@ import java.util.Collections; import java.util.Iterator; import javax.imageio.spi.IIORegistry; +import javax.imageio.spi.ImageInputStreamSpi; +import javax.imageio.spi.ImageOutputStreamSpi; import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.spi.ImageTranscoderSpi; import javax.imageio.spi.ImageWriterSpi; import javax.imageio.spi.ServiceRegistry; import javax.imageio.stream.ImageInputStream; @@ -60,12 +63,18 @@ import javax.imageio.stream.ImageOutputStream; import javax.imageio.stream.MemoryCacheImageInputStream; import javax.imageio.stream.MemoryCacheImageOutputStream; +/** + * An uninstantiable class that provides static methods for locating + * and using image readers and writers. + */ public final class ImageIO { /** - * This class isn't intended to be instantiated. + * Construct an ImageIO. Private since ImageIO is not instantiable. */ - private ImageIO() {} + private ImageIO() + { + } private static final class ReaderFormatFilter implements ServiceRegistry.Filter { @@ -117,6 +126,35 @@ public final class ImageIO } } + private static final class ReaderObjectFilter implements ServiceRegistry.Filter + { + private Object object; + + public ReaderObjectFilter(Object object) + { + this.object = object; + } + + public boolean filter(Object provider) + { + if (provider instanceof ImageReaderSpi) + { + ImageReaderSpi spi = (ImageReaderSpi) provider; + + try + { + if (spi.canDecodeInput(object)) + return true; + } + catch (IOException e) + { + // Return false in this case + } + } + return false; + } + } + private static final class ReaderSuffixFilter implements ServiceRegistry.Filter { private String fileSuffix; @@ -217,6 +255,66 @@ public final class ImageIO } } + private static final class WriterObjectFilter implements ServiceRegistry.Filter + { + private ImageTypeSpecifier type; + private String formatName; + + public WriterObjectFilter(ImageTypeSpecifier type, + String formatName) + { + this.type = type; + this.formatName = formatName; + } + + public boolean filter(Object provider) + { + if (provider instanceof ImageWriterSpi) + { + ImageWriterSpi spi = (ImageWriterSpi) provider; + + if (spi.canEncodeImage(type)) + { + String[] formatNames = spi.getFormatNames(); + for (int i = formatNames.length - 1; i >= 0; --i) + if (formatName.equals(formatNames[i])) + return true; + } + } + + return false; + } + } + + private static final class TranscoderFilter implements ServiceRegistry.Filter + { + private ImageReader reader; + private ImageWriter writer; + + public TranscoderFilter(ImageReader reader, + ImageWriter writer) + { + this.reader = reader; + this.writer = writer; + } + + public boolean filter(Object provider) + { + if (provider instanceof ImageTranscoderSpi) + { + ImageTranscoderSpi spi = (ImageTranscoderSpi) provider; + + if (spi.getReaderServiceProviderName().equals + (reader.getOriginatingProvider().getClass().getName()) + && spi.getWriterServiceProviderName().equals + (writer.getOriginatingProvider().getClass().getName())) + return true; + } + + return false; + } + } + private static final class ImageReaderIterator implements Iterator { Iterator it; @@ -318,11 +416,26 @@ public final class ImageIO } } + /** + * Retrieve the current cache directory. + * + * @return the current cache directory or null if none is set. + */ public static File getCacheDirectory() { return cacheDirectory; } + /** + * Retrieve an iterator over all registered readers for the given + * format. + * + * @param formatName an infomal format name (e.g. "jpeg" or "bmp") + * + * @return an iterator over a collection of image readers + * + * @exception IllegalArgumentException if formatName is null + */ public static Iterator getImageReadersByFormatName(String formatName) { if (formatName == null) @@ -333,6 +446,17 @@ public final class ImageIO formatName); } + /** + * Retrieve an iterator over all registered readers for the given + * MIME type. + * + * @param MIMEType a MIME specification for an image type + * (e.g. "image/jpeg" or "image/x-bmp") + * + * @return an iterator over a collection of image readers + * + * @exception IllegalArgumentException if MIMEType is null + */ public static Iterator getImageReadersByMIMEType(String MIMEType) { if (MIMEType == null) @@ -343,6 +467,16 @@ public final class ImageIO MIMEType); } + /** + * Retrieve an iterator over all registered readers for the given + * file suffix. + * + * @param fileSuffix an image file suffix (e.g. "jpg" or "bmp") + * + * @return an iterator over a collection of image readers + * + * @exception IllegalArgumentException if fileSuffix is null + */ public static Iterator getImageReadersBySuffix(String fileSuffix) { if (fileSuffix == null) @@ -353,6 +487,16 @@ public final class ImageIO fileSuffix); } + /** + * Retrieve an iterator over all registered writers for the given + * format. + * + * @param formatName an infomal format name (e.g. "jpeg" or "bmp") + * + * @return an iterator over a collection of image writers + * + * @exception IllegalArgumentException if formatName is null + */ public static Iterator getImageWritersByFormatName(String formatName) { if (formatName == null) @@ -363,6 +507,17 @@ public final class ImageIO formatName); } + /** + * Retrieve an iterator over all registered writers for the given + * MIME type. + * + * @param MIMEType a MIME specification for an image type + * (e.g. "image/jpeg" or "image/x-bmp") + * + * @return an iterator over a collection of image writers + * + * @exception IllegalArgumentException if MIMEType is null + */ public static Iterator getImageWritersByMIMEType(String MIMEType) { if (MIMEType == null) @@ -373,6 +528,16 @@ public final class ImageIO MIMEType); } + /** + * Retrieve an iterator over all registered writers for the given + * file suffix. + * + * @param fileSuffix an image file suffix (e.g. "jpg" or "bmp") + * + * @return an iterator over a collection of image writers + * + * @exception IllegalArgumentException if fileSuffix is null + */ public static Iterator getImageWritersBySuffix(String fileSuffix) { if (fileSuffix == null) @@ -383,6 +548,12 @@ public final class ImageIO fileSuffix); } + /** + * Retrieve all the informal format names supported by the + * collection of registered image readers. + * + * @return an array of format names + */ public static String[] getReaderFormatNames() { try @@ -408,6 +579,12 @@ public final class ImageIO } } + /** + * Retrieve all the MIME types supported by the collection of + * registered image readers. + * + * @return an array of MIME types + */ public static String[] getReaderMIMETypes() { try @@ -438,11 +615,23 @@ public final class ImageIO return IIORegistry.getDefaultInstance(); } + /** + * Check whether or not an on-disk cache is used for image input and + * output streams. + * + * @return true if an on-disk cache is available, false otherwise + */ public static boolean getUseCache() { return useCache; } + /** + * Retrieve all the informal format names supported by the + * collection of registered image writers. + * + * @return an array of format names + */ public static String[] getWriterFormatNames() { try @@ -468,6 +657,12 @@ public final class ImageIO } } + /** + * Retrieve all the MIME types supported by the collection of + * registered image writers. + * + * @return an array of MIME types + */ public static String[] getWriterMIMETypes() { try @@ -502,8 +697,20 @@ public final class ImageIO IIORegistry.getDefaultInstance().registerApplicationClasspathSpis(); } + /** + * Set the directory to be used for caching image data. A null + * argument means to use the default system temporary directory. + * This cache directory is only used if getUseCache returns true. + * + * @param cacheDirectory the directory where image data should be + * cached + * + * @exception IllegalArgumentException if cacheDirectory is not a + * directory + */ public static void setCacheDirectory(File cacheDirectory) { + // FIXME: add SecurityManager call if (cacheDirectory != null) { if (!cacheDirectory.isDirectory()) @@ -515,37 +722,98 @@ public final class ImageIO ImageIO.cacheDirectory = cacheDirectory; } + /** + * Control whether or not an on-disk cache is used. This cache is + * used to store input or output data from an image data stream when + * data in the stream needs to be re-processed. + * + * If useCache is false the cache will be stored in memory. Doing + * so eliminates file creation and deletion overhead. The default + * is to use an on-disk cache. + * + * @param useCache true to use an on-disk cache, false otherwise + */ public static void setUseCache(boolean useCache) { ImageIO.useCache = useCache; } - /* - * "Standard" simplified entry points. + /** + * Write an image to a file using a registered writer that supports + * the given format, overwriting the file if it already exists. + * + * @param im the image data to write + * @param formatName an informal description of the output format + * @param output the file to which the image will be written + * + * @return false if no registered writer supports the given format, + * true otherwise + * + * @exception IllegalArgumentException if any argument is null + * @exception IOException if a writing error occurs */ - public static boolean write(RenderedImage im, String formatName, File output) throws IOException { + if (im == null || formatName == null || output == null) + throw new IllegalArgumentException ("null argument"); + return write(im, formatName, new FileOutputStream(output)); } + /** + * Write an image to an output stream using a registered writer that + * supports the given format. + * + * @param im the image data to write + * @param formatName an informal description of the output format + * @param output the output stream to which the image will be + * written + * + * @return false if no registered writer supports the given format, + * true otherwise + * + * @exception IllegalArgumentException if any argument is null + * @exception IOException if a writing error occurs + */ public static boolean write(RenderedImage im, String formatName, OutputStream output) throws IOException { + if (im == null || formatName == null || output == null) + throw new IllegalArgumentException ("null argument"); + return write(im, formatName, new MemoryCacheImageOutputStream(output)); } - - + + /** + * Write an image to an ImageOutputStream using a registered writer + * that supports the given format. Image data is written starting + * at the ImageOutputStream's current stream pointer, overwriting + * any existing data. + * + * @param im the image data to write + * @param formatName an informal description of the output format + * @param output the image output stream to which the image will be + * written + * + * @return false if no registered writer supports the given format, + * true otherwise + * + * @exception IllegalArgumentException if any argument is null + * @exception IOException if a writing error occurs + */ public static boolean write(RenderedImage im, String formatName, ImageOutputStream output) throws IOException { + if (im == null || formatName == null || output == null) + throw new IllegalArgumentException ("null argument"); + Iterator writers = getImageWritersByFormatName(formatName); IIOImage img = new IIOImage(im, null, null); while (writers.hasNext()) @@ -567,9 +835,27 @@ public final class ImageIO return false; } + /** + * Create a buffered image from an image input stream. An image + * reader that supports the given image data is automatically + * selected from the collection of registered readers. If no + * registered reader can handle the input format, null is returned. + * + * @param stream the image input stream from which to read image + * data + * + * @return a new buffered image created from the given image data, + * or null + * + * @exception IllegalArgumentException if stream is null + * @exception IOException if a reading error occurs + */ public static BufferedImage read(ImageInputStream stream) throws IOException { + if (stream == null) + throw new IllegalArgumentException("null argument"); + Iterator providers = getRegistry().getServiceProviders(ImageReaderSpi.class, true); while (providers.hasNext()) { @@ -583,23 +869,330 @@ public final class ImageIO } return null; } - + + /** + * Create a buffered image from a URL. An image reader that + * supports the given image data is automatically selected from the + * collection of registered readers. If no registered reader can + * handle the input format, null is returned. + * + * The image data will be cached in the current cache directory if + * caching is enabled. + * + * This method does not locate readers that read data directly from + * a URL. To locate such readers manually, use IIORegistry and + * ImageReaderSpi. + * + * @param input the URL from which to retrieve the image file + * + * @return a new buffered image created from the given image URL, or + * null + * + * @exception IllegalArgumentException if input is null + * @exception IOException if a reading error occurs + */ public static BufferedImage read(URL input) throws IOException { + if (input == null) + throw new IllegalArgumentException("null argument"); + return read(input.openStream()); } + /** + * Create a buffered image from an input stream. An image reader + * that supports the given image data is automatically selected from + * the collection of registered readers. If no registered reader + * can handle the input format, null is returned. + * + * The image data will be cached in the current cache directory if + * caching is enabled. + * + * This method does not locate readers that read data directly from + * an input stream. To locate such readers manually, use + * IIORegistry and ImageReaderSpi. + * + * @param input the input stream from which to read the image data + * + * @return a new buffered image created from the given input stream, + * or null + * + * @exception IllegalArgumentException if input is null + * @exception IOException if a reading error occurs + */ public static BufferedImage read(InputStream input) throws IOException { + if (input == null) + throw new IllegalArgumentException("null argument"); + return read(new MemoryCacheImageInputStream(input)); } + /** + * Create a buffered image from a file. An image reader that + * supports the given image data is automatically selected from the + * collection of registered readers. If no registered reader can + * handle the input format, null is returned. + * + * The image data will be cached in the current cache directory if + * caching is enabled. + * + * This method does not locate readers that read data directly from + * a file. To locate such readers manually, use IIORegistry and + * ImageReaderSpi. + * + * @param input the file from which to read image data + * + * @return a new buffered image created from the given image file, + * or null + * + * @exception IllegalArgumentException if input is null + * @exception IOException if a reading error occurs + */ public static BufferedImage read(File input) throws IOException { + if (input == null) + throw new IllegalArgumentException("null argument"); + return read(new FileInputStream(input)); } + /** + * Create an image input stream from the given object. The + * collection of ImageInputStreamSpis registered with the + * IIORegistry is searched for an image input stream that can take + * input from the given object. null is returned if no such SPI is + * registered. + * + * The image data will be cached in the current cache directory if + * caching is enabled. + * + * @param input an object from which to read image data + * + * @return an ImageInputStream that can read data from input, or + * null + * + * @exception IllegalArgumentException if input is null + * @exception IOException if caching is required but not enabled + */ + public static ImageInputStream createImageInputStream (Object input) + throws IOException + { + if (input == null) + throw new IllegalArgumentException ("null argument"); + + Iterator spis = getRegistry().getServiceProviders + (ImageInputStreamSpi.class, true); + + ImageInputStreamSpi foundSpi = null; + + while(spis.hasNext()) + { + ImageInputStreamSpi spi = (ImageInputStreamSpi) spis.next(); + + if (input.getClass().equals(spi.getInputClass())) + { + foundSpi = spi; + break; + } + } + + return foundSpi == null ? null : + foundSpi.createInputStreamInstance (input, + getUseCache(), + getCacheDirectory()); + } + + /** + * Create an image output stream from the given object. The + * collection of ImageOutputStreamSpis registered with the + * IIORegistry is searched for an image output stream that can send + * output to the given object. null is returned if no such SPI is + * registered. + * + * The image data will be cached in the current cache directory if + * caching is enabled. + * + * @param input an object to which to write image data + * + * @return an ImageOutputStream that can send data to output, or + * null + * + * @exception IllegalArgumentException if output is null + * @exception IOException if caching is required but not enabled + */ + public static ImageOutputStream createImageOutputStream (Object output) + throws IOException + { + if (output == null) + throw new IllegalArgumentException ("null argument"); + + Iterator spis = getRegistry().getServiceProviders + (ImageOutputStreamSpi.class, true); + + ImageOutputStreamSpi foundSpi = null; + + while(spis.hasNext()) + { + ImageOutputStreamSpi spi = (ImageOutputStreamSpi) spis.next(); + + if (output.getClass().equals(spi.getOutputClass())) + { + foundSpi = spi; + break; + } + } + + return foundSpi == null ? null : + foundSpi.createOutputStreamInstance (output, + getUseCache(), + getCacheDirectory()); + } + + /** + * Retrieve an image reader corresponding to an image writer, or + * null if writer is not registered or if no corresponding reader is + * registered. + * + * @param writer a registered image writer + * + * @return an image reader corresponding to writer, or null + * + * @exception IllegalArgumentException if writer is null + */ + public static ImageReader getImageReader (ImageWriter writer) + { + if (writer == null) + throw new IllegalArgumentException ("null argument"); + + ImageWriterSpi spi = (ImageWriterSpi) getRegistry() + .getServiceProviderByClass(writer.getClass()); + + String[] readerSpiNames = spi.getImageReaderSpiNames(); + + ImageReader r = null; + + if (readerSpiNames != null) + { + try + { + Class readerClass = Class.forName (readerSpiNames[0]); + r = (ImageReader) readerClass.newInstance (); + } + catch (Exception e) + { + return null; + } + } + return r; + } + + /** + * Retrieve an iterator over the collection of registered image + * readers that support reading data from the given object. + * + * @param input the object for which to retrieve image readers + * + * @return an iterator over a collection of image readers + */ + public static Iterator getImageReaders (Object input) + { + if (input == null) + throw new IllegalArgumentException ("null argument"); + + return getRegistry().getServiceProviders (ImageReaderSpi.class, + new ReaderObjectFilter(input), + true); + } + + /** + * Retrieve an iterator over the collection of registered image + * writers that support writing images of the given type and in the + * given format. + * + * @param type the output image's colour and sample models + * @param formatName the output image format + * + * @return an iterator over a collection of image writers + */ + public static Iterator getImageWriters (ImageTypeSpecifier type, + String formatName) + { + if (type == null || formatName == null) + throw new IllegalArgumentException ("null argument"); + + return getRegistry().getServiceProviders (ImageWriterSpi.class, + new WriterObjectFilter(type, + formatName), + true); + } + + /** + * Retrieve an image writer corresponding to an image reader, or + * null if reader is not registered or if no corresponding writer is + * registered. This method is useful for preserving metadata + * without needing to understand its format, since the returned + * writer will be able to write, unchanged, the metadata passed to + * it by the reader. + * + * @param reader a registered image reader + * + * @return an image writer corresponding to reader, or null + * + * @exception IllegalArgumentException if reader is null + */ + public static ImageWriter getImageWriter (ImageReader reader) + { + if (reader == null) + throw new IllegalArgumentException ("null argument"); + + ImageReaderSpi spi = (ImageReaderSpi) getRegistry() + .getServiceProviderByClass(reader.getClass()); + + String[] writerSpiNames = spi.getImageWriterSpiNames(); + + ImageWriter w = null; + + if (writerSpiNames != null) + { + try + { + Class writerClass = Class.forName (writerSpiNames[0]); + w = (ImageWriter) writerClass.newInstance (); + } + catch (Exception e) + { + return null; + } + } + return w; + } + + /** + * Retrieve an iterator over a collection of image transcoders that + * support transcoding from the given image reader's metadata format + * to the given writer's metadata format. + * + * @param reader an image reader + * @param writer an image writer + * + * @return an iterator over a collection of image transcoders + * + * @exception IllegalArgumentException if either reader or writer is + * null + */ + public static Iterator getImageTranscoders (ImageReader reader, + ImageWriter writer) + { + if (reader == null || writer == null) + throw new IllegalArgumentException ("null argument"); + + return getRegistry().getServiceProviders (ImageTranscoderSpi.class, + new TranscoderFilter (reader, + writer), + true); + } } diff --git a/libjava/classpath/javax/imageio/ImageReadParam.java b/libjava/classpath/javax/imageio/ImageReadParam.java index 889fe6cc97d..b2680f6b14e 100644 --- a/libjava/classpath/javax/imageio/ImageReadParam.java +++ b/libjava/classpath/javax/imageio/ImageReadParam.java @@ -42,6 +42,8 @@ import java.awt.Dimension; import java.awt.image.BufferedImage; /** + * DOCUMENT ME + * * @author Michel Koch (konqueror@gmx.de) */ public class ImageReadParam extends IIOParam diff --git a/libjava/classpath/javax/imageio/ImageReader.java b/libjava/classpath/javax/imageio/ImageReader.java index fdf692bd2aa..cdd77d52bad 100644 --- a/libjava/classpath/javax/imageio/ImageReader.java +++ b/libjava/classpath/javax/imageio/ImageReader.java @@ -1,5 +1,5 @@ /* ImageReader.java -- Decodes raster images. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,13 +38,19 @@ exception statement from your version. */ 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.ResourceBundle; +import java.util.MissingResourceException; +import java.util.Set; import javax.imageio.event.IIOReadProgressListener; import javax.imageio.event.IIOReadUpdateListener; @@ -53,82 +59,233 @@ import javax.imageio.metadata.IIOMetadata; import javax.imageio.spi.ImageReaderSpi; import javax.imageio.stream.ImageInputStream; +/** + * A class for decoding images within the ImageIO framework. + * + * An ImageReader for a given format is instantiated by an + * ImageReaderSpi for that format. ImageReaderSpis are registered + * with the IIORegistry. + * + * The ImageReader API supports reading animated images that may have + * multiple frames; to support such images many methods take an index + * parameter. + * + * Images may also be read in multiple passes, where each successive + * pass increases the level of detail in the destination image. + */ public abstract class ImageReader { private boolean aborted; - - protected Locale[] availableLocales; - protected boolean ignoreMetadata; - protected Object input; - protected Locale locale; - protected int minIndex; - protected ImageReaderSpi originatingProvider; - protected List progressListeners = new ArrayList(); - protected boolean seekForwardOnly; - protected List updateListeners = new ArrayList(); - protected List warningListeners = new ArrayList(); - protected List warningLocales = new ArrayList(); + /** + * All locales available for localization of warning messages, or + * null if localization is not supported. + */ + protected Locale[] availableLocales = null; + + /** + * true if the input source does not require metadata to be read, + * false otherwise. + */ + protected boolean ignoreMetadata = false; + + /** + * An ImageInputStream from which image data is read. + */ + protected Object input = null; + + /** + * The current locale used to localize warning messages, or null if + * no locale has been set. + */ + protected Locale locale = null; + + /** + * The minimum index at which data can be read. Constantly 0 if + * seekForwardOnly is false, always increasing if seekForwardOnly is + * true. + */ + protected int minIndex = 0; + + /** + * The image reader SPI that instantiated this reader. + */ + protected ImageReaderSpi originatingProvider = null; + + /** + * A list of installed progress listeners. Initially null, meaning + * no installed listeners. + */ + protected List progressListeners = null; + + /** + * true if this reader should only read data further ahead in the + * stream than its current location. false if it can read backwards + * in the stream. If this is true then caching can be avoided. + */ + protected boolean seekForwardOnly = false; + + /** + * A list of installed update listeners. Initially null, meaning no + * installed listeners. + */ + protected List updateListeners = null; + + /** + * A list of installed warning listeners. Initially null, meaning + * no installed listeners. + */ + protected List warningListeners = null; + + /** + * A list of warning locales corresponding with the list of + * installed warning listeners. Initially null, meaning no locales. + */ + protected List warningLocales = null; + + /** + * Construct an image reader. + * + * @param originatingProvider the provider that is constructing this + * image reader, or null + */ protected ImageReader(ImageReaderSpi originatingProvider) { this.originatingProvider = originatingProvider; } + /** + * Request that reading be aborted. The unread contents of the + * image will be undefined. + * + * Readers should clear the abort flag before starting a read + * operation, then poll it periodically during the read operation. + */ public void abort() { aborted = true; } + /** + * Check if the abort flag is set. + * + * @return true if the current read operation should be aborted, + * false otherwise + */ protected boolean abortRequested() { return aborted; } + /** + * Install a read progress listener. This method will return + * immediately if listener is null. + * + * @param listener a read progress listener or null + */ public void addIIOReadProgressListener(IIOReadProgressListener listener) { if (listener == null) return; - - progressListeners.add(listener); + if (progressListeners == null) + progressListeners = new ArrayList (); + progressListeners.add(listener); } + /** + * Install a read update listener. This method will return + * immediately if listener is null. + * + * @param listener a read update listener + */ public void addIIOReadUpdateListener(IIOReadUpdateListener listener) { if (listener == null) return; - - updateListeners.add(listener); + if (updateListeners == null) + updateListeners = new ArrayList (); + updateListeners.add(listener); } - + + /** + * Install a read warning listener. This method will return + * immediately if listener is null. Warning messages sent to this + * listener will be localized using the current locale. If the + * current locale is null then this reader will select a sensible + * default. + * + * @param listener a read warning listener + */ public void addIIOReadWarningListener(IIOReadWarningListener listener) { if (listener == null) return; - - warningListeners.add(listener); + if (warningListeners == null) + warningListeners = new ArrayList (); + warningListeners.add(listener); } + /** + * Check if this reader can handle raster data. Determines whether + * or not readRaster and readTileRaster throw + * UnsupportedOperationException. + * + * @return true if this reader supports raster data, false if not + */ public boolean canReadRaster() { return false; } + /** + * Clear the abort flag. + */ protected void clearAbortRequest() { aborted = false; } - + + /** + * Releases any resources allocated to this object. Subsequent + * calls to methods on this object will produce undefined results. + * + * The default implementation does nothing; subclasses should use + * this method ensure that native resources are released. + */ public void dispose() { // The default implementation does nothing. } - + + /** + * Returns the aspect ratio of this image, the ration of its width + * to its height. The aspect ratio is useful when resizing an image + * while keeping its proportions constant. + * + * @param imageIndex the frame index + * + * @return the image's aspect ratio + * + * @exception IllegalStateException if input is null + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public float getAspectRatio(int imageIndex) throws IOException { + if (input == null) + throw new IllegalStateException("input is null"); + return (float) (getWidth(imageIndex) / getHeight(imageIndex)); } + /** + * Retrieve the available locales. Return null if no locales are + * available or a clone of availableLocales. + * + * @return an array of locales or null + */ public Locale[] getAvailableLocales() { if (availableLocales == null) @@ -137,26 +294,107 @@ public abstract class ImageReader return (Locale[]) availableLocales.clone(); } + /** + * Retrieve the default read parameters for this reader's image + * format. + * + * The default implementation returns new ImageReadParam(). + * + * @return image reading parameters + */ public ImageReadParam getDefaultReadParam() { return new ImageReadParam(); } + /** + * Retrieve the format of the input source. + * + * @return the input source format name + * + * @exception IOException if a read error occurs + */ public String getFormatName() throws IOException { return originatingProvider.getFormatNames()[0]; } + /** + * Get the height of the input image in pixels. If the input image + * is resizable then a default height is returned. + * + * @param imageIndex the frame index + * + * @return the height of the input image + * + * @exception IllegalStateException if input has not been set + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public abstract int getHeight(int imageIndex) throws IOException; + /** + * Get the metadata associated with this image. If the reader is + * set to ignore metadata or does not support reading metadata, or + * if no metadata is available then null is returned. + * + * @param imageIndex the frame index + * + * @return a metadata object, or null + * + * @exception IllegalStateException if input has not been set + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public abstract IIOMetadata getImageMetadata(int imageIndex) throws IOException; + /** + * Get an iterator over the collection of image types into which + * this reader can decode image data. This method is guaranteed to + * return at least one valid image type specifier. + * + * The elements of the iterator should be ordered; the first element + * should be the most appropriate image type for this decoder, + * followed by the second-most appropriate, and so on. + * + * @param imageIndex the frame index + * + * @return an iterator over a collection of image type specifiers + * + * @exception IllegalStateException if input has not been set + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public abstract Iterator getImageTypes(int imageIndex) throws IOException; + /** + * Set the input source to the given object, specify whether this + * reader should be allowed to read input from the data stream more + * than once, and specify whether this reader should ignore metadata + * in the input stream. The input source must be set before many + * methods can be called on this reader. (see all ImageReader + * methods that throw IllegalStateException). If input is null then + * the current input source will be removed. + * + * Unless this reader has direct access with imaging hardware, input + * should be an ImageInputStream. + * + * @param input the input source object + * @param seekForwardOnly true if this reader should be allowed to + * read input from the data stream more than once, false otherwise + * @param ignoreMetadata true if this reader should ignore metadata + * associated with the input source, false otherwise + * + * @exception IllegalArgumentException if input is not a valid input + * source for this reader and is not an ImageInputStream + */ public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) @@ -183,358 +421,960 @@ public abstract class ImageReader this.minIndex = 0; } + /** + * Set the input source to the given object and specify whether this + * reader should be allowed to read input from the data stream more + * than once. The input source must be set before many methods can + * be called on this reader. (see all ImageReader methods that throw + * IllegalStateException). If input is null then the current input + * source will be removed. + * + * @param input the input source object + * @param seekForwardOnly true if this reader should be allowed to + * read input from the data stream more than once, false otherwise + * + * @exception IllegalArgumentException if input is not a valid input + * source for this reader and is not an ImageInputStream + */ public void setInput(Object in, boolean seekForwardOnly) { setInput(in, seekForwardOnly, false); } - public void setInput(Object in) + /** + * Set the input source to the given object. The input source must + * be set before many methods can be called on this reader. (see all + * ImageReader methods that throw IllegalStateException). If input + * is null then the current input source will be removed. + * + * @param input the input source object + * + * @exception IllegalArgumentException if input is not a valid input + * source for this reader and is not an ImageInputStream + */ + public void setInput(Object input) { - setInput(in, false, false); + setInput(input, false, false); } + /** + * Get this reader's image input source. null is returned if the + * image source has not been set. + * + * @return an image input source object, or null + */ public Object getInput() { return input; } + /** + * Get this reader's locale. null is returned if the locale has not + * been set. + * + * @return this reader's locale, or null + */ public Locale getLocale() { return locale; } + /** + * Return the number of images available from the image input + * source, not including thumbnails. This method will return 1 + * unless this reader is reading an animated image. + * + * Certain multi-image formats do not encode the total number of + * images. When reading images in those formats it may be necessary + * to repeatedly call read, incrementing the image index at each + * call, until an IndexOutOfBoundsException is thrown. + * + * The allowSearch parameter determines whether all images must be + * available at all times. When allowSearch is false, getNumImages + * will return -1 if the total number of images is unknown. + * Otherwise this method returns the number of images. + * + * @param allowSearch true if all images should be available at + * once, false otherwise + * + * @return -1 if allowSearch is false and the total number of images + * is currently unknown, or the number of images + * + * @exception IllegalStateException if input has not been set, or if + * seekForwardOnly is true + * @exception IOException if a read error occurs + */ public abstract int getNumImages(boolean allowSearch) throws IOException; + /** + * Get the number of thumbnails associated with an image. + * + * @param imageIndex the frame index + * + * @return the number of thumbnails associated with this image + */ public int getNumThumbnails(int imageIndex) throws IOException { return 0; } + /** + * Get the ImageReaderSpi that created this reader or null. + * + * @return an ImageReaderSpi, or null + */ public ImageReaderSpi getOriginatingProvider() { return originatingProvider; } + /** + * Get the metadata associated with the image being read. If the + * reader is set to ignore metadata or does not support reading + * metadata, or if no metadata is available then null is returned. + * This method returns metadata associated with the entirety of the + * image data, whereas getImageMetadata(int) returns metadata + * associated with a frame within a multi-image data stream. + * + * @return metadata associated with the image being read, or null + * + * @exception IOException if a read error occurs + */ public abstract IIOMetadata getStreamMetadata() throws IOException; + /** + * Get the height of a thumbnail image. + * + * @param imageIndex the frame index + * @param thumbnailIndex the thumbnail index + * + * @return the height of the thumbnail image + * + * @exception UnsupportedOperationException if this reader does not + * support thumbnails + * @exception IllegalStateException if input is null + * @exception IndexOutOfBoundsException if either index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public int getThumbnailHeight(int imageIndex, int thumbnailIndex) throws IOException { return readThumbnail(imageIndex, thumbnailIndex).getHeight(); } + /** + * Get the width of a thumbnail image. + * + * @param imageIndex the frame index + * @param thumbnailIndex the thumbnail index + * + * @return the width of the thumbnail image + * + * @exception UnsupportedOperationException if this reader does not + * support thumbnails + * @exception IllegalStateException if input is null + * @exception IndexOutOfBoundsException if either index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public int getThumbnailWidth(int imageIndex, int thumbnailIndex) throws IOException { return readThumbnail(imageIndex, thumbnailIndex).getWidth(); } + /** + * Get the X coordinate in pixels of the top-left corner of the + * first tile in this image. + * + * @param imageIndex the frame index + * + * @return the X coordinate of this image's first tile + * + * @exception IllegalStateException if input is needed but the input + * source is not set + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public int getTileGridXOffset(int imageIndex) throws IOException { return 0; } + /** + * Get the Y coordinate in pixels of the top-left corner of the + * first tile in this image. + * + * @param imageIndex the frame index + * + * @return the Y coordinate of this image's first tile + * + * @exception IllegalStateException if input is needed but the input + * source is not set + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public int getTileGridYOffset(int imageIndex) throws IOException { return 0; } + /** + * Get the height of an image tile. + * + * @param imageIndex the frame index + * + * @return the tile height for the given image + * + * @exception IllegalStateException if input is null + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public int getTileHeight(int imageIndex) throws IOException { return getHeight(imageIndex); } + /** + * Get the width of an image tile. + * + * @param imageIndex the frame index + * + * @return the tile width for the given image + * + * @exception IllegalStateException if input is null + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public int getTileWidth(int imageIndex) throws IOException { return getWidth(imageIndex); } + /** + * Get the width of the input image in pixels. If the input image + * is resizable then a default width is returned. + * + * @param imageIndex the image's index + * + * @return the width of the input image + * + * @exception IllegalStateException if input has not been set + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public abstract int getWidth(int imageIndex) throws IOException; + /** + * Check whether or not the given image has thumbnails associated + * with it. + * + * @return true if the given image has thumbnails, false otherwise + * + * @exception IllegalStateException if input is null + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public boolean hasThumbnails(int imageIndex) throws IOException { return getNumThumbnails(imageIndex) > 0; } + /** + * Check if this image reader ignores metadata. This method simply + * returns the value of ignoreMetadata. + * + * @return true if metadata is being ignored, false otherwise + */ public boolean isIgnoringMetadata() { return ignoreMetadata; } + /** + * Check if the given image is sub-divided into equal-sized + * non-overlapping pixel rectangles. + * + * A reader may expose tiling in the underlying format, hide it, or + * simulate tiling even if the underlying format is not tiled. + * + * @return true if the given image is tiled, false otherwise + * + * @exception IllegalStateException if input is null + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public boolean isImageTiled(int imageIndex) throws IOException { return false; } + /** + * Check if all pixels in this image are readily accessible. This + * method should return false for compressed formats. The return + * value is a hint as to the efficiency of certain image reader + * operations. + * + * @param imageIndex the frame index + * + * @return true if random pixel access is fast, false otherwise + * + * @exception IllegalStateException if input is null and it is + * needed to determine the return value + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds but the frame data must be accessed to determine + * the return value + * @exception IOException if a read error occurs + */ public boolean isRandomAccessEasy(int imageIndex) throws IOException { return false; } + /** + * Check if this image reader may only seek forward within the input + * stream. + * + * @return true if this reader may only seek forward, false + * otherwise + */ public boolean isSeekForwardOnly() { return seekForwardOnly; } + /** + * Notifies all installed read progress listeners that image loading + * has completed by calling their imageComplete methods. + */ protected void processImageComplete() { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOReadProgressListener listener = (IIOReadProgressListener) it.next(); - listener.imageComplete (this); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOReadProgressListener listener = + (IIOReadProgressListener) it.next(); + listener.imageComplete (this); + } } } + /** + * Notifies all installed read progress listeners that a certain + * percentage of the image has been loaded, by calling their + * imageProgress methods. + * + * @param percentageDone the percentage of image data that has been + * loaded + */ protected void processImageProgress(float percentageDone) { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOReadProgressListener listener = (IIOReadProgressListener) it.next(); - listener.imageProgress(this, percentageDone); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOReadProgressListener listener = + (IIOReadProgressListener) it.next(); + listener.imageProgress(this, percentageDone); + } } } - + /** + * Notifies all installed read progress listeners, by calling their + * imageStarted methods, that image loading has started on the given + * image. + * + * @param imageIndex the frame index of the image that has started + * loading + */ protected void processImageStarted(int imageIndex) { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOReadProgressListener listener = (IIOReadProgressListener) it.next(); - listener.imageStarted(this, imageIndex); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOReadProgressListener listener = + (IIOReadProgressListener) it.next(); + listener.imageStarted(this, imageIndex); + } } } + /** + * Notifies all installed read update listeners, by calling their + * imageUpdate methods, that the set of samples has changed. + * + * @param image the buffered image that is being updated + * @param minX the X coordinate of the top-left pixel in this pass + * @param minY the Y coordinate of the top-left pixel in this pass + * @param width the total width of the rectangle covered by this + * pass, including skipped pixels + * @param height the total height of the rectangle covered by this + * pass, including skipped pixels + * @param periodX the horizontal sample interval + * @param periodY the vertical sample interval + * @param bands the affected bands in the destination + */ protected void processImageUpdate(BufferedImage image, int minX, int minY, int width, int height, int periodX, int periodY, int[] bands) { - Iterator it = updateListeners.iterator(); - - while (it.hasNext()) + if (updateListeners != null) { - IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); - listener.imageUpdate(this, image, minX, minY, width, height, periodX, - periodY, bands); + Iterator it = updateListeners.iterator(); + + while (it.hasNext()) + { + IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); + listener.imageUpdate(this, image, minX, minY, width, height, + periodX, periodY, bands); + } } } + /** + * Notifies all installed update progress listeners, by calling + * their passComplete methods, that a progressive pass has + * completed. + * + * @param image the image that has being updated + */ protected void processPassComplete(BufferedImage image) { - Iterator it = updateListeners.iterator(); - - while (it.hasNext()) + if (updateListeners != null) { - IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); - listener.passComplete(this, image); + Iterator it = updateListeners.iterator(); + + while (it.hasNext()) + { + IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); + listener.passComplete(this, image); + } } } + /** + * Notifies all installed read update listeners, by calling their + * passStarted methods, that a new pass has begun. + * + * @param image the buffered image that is being updated + * @param pass the current pass number + * @param minPass the pass at which decoding will begin + * @param maxPass the pass at which decoding will end + * @param minX the X coordinate of the top-left pixel in this pass + * @param minY the Y coordinate of the top-left pixel in this pass + * @param width the total width of the rectangle covered by this + * pass, including skipped pixels + * @param height the total height of the rectangle covered by this + * pass, including skipped pixels + * @param periodX the horizontal sample interval + * @param periodY the vertical sample interval + * @param bands the affected bands in the destination + */ protected void processPassStarted(BufferedImage image, int pass, int minPass, int maxPass, int minX, int minY, int periodX, int periodY, int[] bands) { - Iterator it = updateListeners.iterator(); - - while (it.hasNext()) + if (updateListeners != null) { - IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); - listener.passStarted(this, image, pass, minPass, maxPass, minX, minY, - periodX, periodY, bands); + Iterator it = updateListeners.iterator(); + + while (it.hasNext()) + { + IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); + listener.passStarted(this, image, pass, minPass, maxPass, minX, + minY, periodX, periodY, bands); + } } } + /** + * Notifies all installed read progress listeners that image loading + * has been aborted by calling their readAborted methods. + */ protected void processReadAborted() { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOReadProgressListener listener = (IIOReadProgressListener) it.next(); - listener.readAborted(this); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOReadProgressListener listener = + (IIOReadProgressListener) it.next(); + listener.readAborted(this); + } } } - + /** + * Notifies all installed read progress listeners, by calling their + * sequenceComplete methods, that a sequence of images has completed + * loading. + */ protected void processSequenceComplete() { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOReadProgressListener listener = (IIOReadProgressListener) it.next(); - listener.sequenceComplete(this); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOReadProgressListener listener = + (IIOReadProgressListener) it.next(); + listener.sequenceComplete(this); + } } } + /** + * Notifies all installed read progress listeners, by calling their + * sequenceStarted methods, a sequence of images has started + * loading. + * + * @param minIndex the index of the first image in the sequence + */ protected void processSequenceStarted(int minIndex) { - Iterator it = progressListeners.iterator(); - while (it.hasNext()) + if (progressListeners != null) { - IIOReadProgressListener listener = (IIOReadProgressListener) it.next(); - listener.sequenceStarted(this, minIndex); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOReadProgressListener listener = + (IIOReadProgressListener) it.next(); + listener.sequenceStarted(this, minIndex); + } } } + /** + * Notifies all installed read progress listeners, by calling their + * thumbnailComplete methods, that a thumbnail has completed + * loading. + */ protected void processThumbnailComplete() { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOReadProgressListener listener = (IIOReadProgressListener) it.next(); - listener.thumbnailComplete(this); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOReadProgressListener listener = + (IIOReadProgressListener) it.next(); + listener.thumbnailComplete(this); + } } } + /** + * Notifies all installed update progress listeners, by calling + * their thumbnailPassComplete methods, that a progressive pass has + * completed on a thumbnail. + * + * @param thumbnail the thumbnail that has being updated + */ protected void processThumbnailPassComplete(BufferedImage thumbnail) { - Iterator it = updateListeners.iterator(); - - while (it.hasNext()) + if (updateListeners != null) { - IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); - listener.thumbnailPassComplete(this, thumbnail); + Iterator it = updateListeners.iterator(); + + while (it.hasNext()) + { + IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); + listener.thumbnailPassComplete(this, thumbnail); + } } } + /** + * Notifies all installed read update listeners, by calling their + * thumbnailPassStarted methods, that a new pass has begun. + * + * @param thumbnail the thumbnail that is being updated + * @param pass the current pass number + * @param minPass the pass at which decoding will begin + * @param maxPass the pass at which decoding will end + * @param minX the X coordinate of the top-left pixel in this pass + * @param minY the Y coordinate of the top-left pixel in this pass + * @param width the total width of the rectangle covered by this + * pass, including skipped pixels + * @param height the total height of the rectangle covered by this + * pass, including skipped pixels + * @param periodX the horizontal sample interval + * @param periodY the vertical sample interval + * @param bands the affected bands in the destination + */ protected void processThumbnailPassStarted(BufferedImage thumbnail, int pass, int minPass, int maxPass, int minX, int minY, int periodX, int periodY, int[] bands) { - Iterator it = updateListeners.iterator(); - - while (it.hasNext()) + if (updateListeners != null) { - IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); - listener.thumbnailPassStarted(this, thumbnail, pass, minPass, maxPass, - minX, minY, periodX, periodY, bands); + Iterator it = updateListeners.iterator(); + + while (it.hasNext()) + { + IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); + listener.thumbnailPassStarted(this, thumbnail, pass, minPass, + maxPass, minX, minY, periodX, + periodY, bands); + } } } - + + /** + * Notifies all installed read progress listeners that a certain + * percentage of a thumbnail has been loaded, by calling their + * thumbnailProgress methods. + * + * @param percentageDone the percentage of thumbnail data that has + * been loaded + */ protected void processThumbnailProgress(float percentageDone) { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOReadProgressListener listener = (IIOReadProgressListener) it.next(); - listener.thumbnailProgress(this, percentageDone); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOReadProgressListener listener = + (IIOReadProgressListener) it.next(); + listener.thumbnailProgress(this, percentageDone); + } } } + /** + * Notifies all installed read progress listeners, by calling their + * imageStarted methods, that thumbnail loading has started on the + * given thumbnail of the given image. + * + * @param imageIndex the frame index of the image one of who's + * thumbnails has started loading + * @param thumbnailIndex the index of the thumbnail that has started + * loading + */ protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOReadProgressListener listener = (IIOReadProgressListener) it.next(); - listener.thumbnailStarted(this, imageIndex, thumbnailIndex); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOReadProgressListener listener = + (IIOReadProgressListener) it.next(); + listener.thumbnailStarted(this, imageIndex, thumbnailIndex); + } } } + /** + * Notifies all installed read update listeners, by calling their + * thumbnailUpdate methods, that the set of samples has changed. + * + * @param image the buffered image that is being updated + * @param minX the X coordinate of the top-left pixel in this pass + * @param minY the Y coordinate of the top-left pixel in this pass + * @param width the total width of the rectangle covered by this + * pass, including skipped pixels + * @param height the total height of the rectangle covered by this + * pass, including skipped pixels + * @param periodX the horizontal sample interval + * @param periodY the vertical sample interval + * @param bands the affected bands in the destination + */ protected void processThumbnailUpdate(BufferedImage image, int minX, int minY, int width, int height, int periodX, int periodY, int[] bands) { - Iterator it = updateListeners.iterator(); - - while (it.hasNext()) + if (updateListeners != null) { - IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); - listener.thumbnailUpdate(this, image, minX, minY, width, height, - periodX, periodY, bands); + Iterator it = updateListeners.iterator(); + + while (it.hasNext()) + { + IIOReadUpdateListener listener = (IIOReadUpdateListener) it.next(); + listener.thumbnailUpdate(this, image, minX, minY, width, height, + periodX, periodY, bands); + } } } + /** + * Notifies all installed warning listeners, by calling their + * warningOccurred methods, that a warning message has been raised. + * + * @param warning the warning message + * + * @exception IllegalArgumentException if warning is null + */ protected void processWarningOccurred(String warning) { - Iterator it = warningListeners.iterator(); + if (warning == null) + throw new IllegalArgumentException ("null argument"); + if (warningListeners != null) + { + Iterator it = warningListeners.iterator(); + + while (it.hasNext()) + { + IIOReadWarningListener listener = + (IIOReadWarningListener) it.next(); + listener.warningOccurred(this, warning); + } + } + } + + /** + * Notify all installed warning listeners, by calling their + * warningOccurred methods, that a warning message has been raised. + * The warning message is retrieved from a resource bundle, using + * the given basename and keyword. + * + * @param baseName the basename of the resource from which to + * retrieve the warning message + * @param keyword the keyword used to retrieve the warning from the + * resource bundle + * + * @exception IllegalArgumentException if either baseName or keyword + * is null + * @exception IllegalArgumentException if no resource bundle is + * found using baseName + * @exception IllegalArgumentException if the given keyword produces + * no results from the resource bundle + * @exception IllegalArgumentException if the retrieved object is + * not a String + */ + protected void processWarningOccurred(String baseName, + String keyword) + { + if (baseName == null || keyword == null) + throw new IllegalArgumentException ("null argument"); + + ResourceBundle b = null; + + try + { + b = ResourceBundle.getBundle(baseName, getLocale()); + } + catch (MissingResourceException e) + { + throw new IllegalArgumentException ("no resource bundle found"); + } + + Object str = null; - while (it.hasNext()) + try { - IIOReadWarningListener listener = (IIOReadWarningListener) it.next(); - listener.warningOccurred(this, warning); + str = b.getObject(keyword); + } + catch (MissingResourceException e) + { + throw new IllegalArgumentException ("no results found for keyword"); + } + + if (! (str instanceof String)) + throw new IllegalArgumentException ("retrieved object not a String"); + + String warning = (String) str; + + if (warningListeners != null) + { + Iterator it = warningListeners.iterator(); + + while (it.hasNext()) + { + IIOReadWarningListener listener = + (IIOReadWarningListener) it.next(); + listener.warningOccurred(this, warning); + } } } + /** + * Read the given frame into a buffered image using the given read + * parameters. Listeners will be notified of image loading progress + * and warnings. + * + * @param imageIndex the index of the frame to read + * @param param the image read parameters to use when reading + * + * @return a buffered image + * + * @exception IllegalStateException if input is null + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public abstract BufferedImage read(int imageIndex, ImageReadParam param) throws IOException; + /** + * Check if this reader supports reading thumbnails. + * + * @return true if this reader supports reading thumbnails, false + * otherwise + */ public boolean readerSupportsThumbnails() { return false; } + /** + * Read raw raster data. The image type specifier in param is + * ignored but all other parameters are used. Offset parameters are + * translated into the raster's coordinate space. This method may + * be implemented by image readers that want to provide direct + * access to raw image data. + * + * @param imageIndex the frame index + * @param param the image read parameters + * + * @return a raster containing the read image data + * + * @exception UnsupportedOperationException if this reader doesn't + * support rasters + * @exception IllegalStateException if input is null + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ public Raster readRaster(int imageIndex, ImageReadParam param) throws IOException { throw new UnsupportedOperationException(); } + /** + * Read a thumbnail. + * + * @param imageIndex the frame index + * @param thumbnailIndex the thumbnail index + * + * @return a buffered image of the thumbnail + * + * @exception UnsupportedOperationException if this reader doesn't + * support thumbnails + * @exception IllegalStateException if input is null + * @exception IndexOutOfBoundsException if either the frame index or + * the thumbnail index is out-of-bounds + * @exception IOException if a read error occurs + * + */ public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException { throw new UnsupportedOperationException(); } + /** + * Uninstall all read progress listeners. + */ public void removeAllIIOReadProgressListeners() { - progressListeners.clear(); + progressListeners = null; } + /** + * Uninstall all read update listeners. + */ public void removeAllIIOReadUpdateListeners() { - updateListeners.clear(); + updateListeners = null; } + /** + * Uninstall all read warning listeners. + */ public void removeAllIIOReadWarningListeners() { - warningListeners.clear(); + warningListeners = null; } - + + /** + * Uninstall the given read progress listener. + * + * @param listener the listener to remove + */ public void removeIIOReadProgressListener(IIOReadProgressListener listener) { if (listener == null) return; - - progressListeners.remove(listener); + if (progressListeners != null) + { + progressListeners.remove(listener); + } } - + + /** + * Uninstall the given read update listener. + * + * @param listener the listener to remove + */ public void removeIIOReadUpdateListener(IIOReadUpdateListener listener) { if (listener == null) return; - - updateListeners.remove(listener); + + if (updateListeners != null) + { + updateListeners.remove(listener); + } } - + + /** + * Uninstall the given read warning listener. + * + * @param listener the listener to remove + */ public void removeIIOReadWarningListener(IIOReadWarningListener listener) { if (listener == null) return; - - warningListeners.remove(listener); + if (warningListeners != null) + { + warningListeners.remove(listener); + } } - + + /** + * Set the current locale or use the default locale. + * + * @param locale the locale to set, or null + */ public void setLocale(Locale locale) { if (locale != null) @@ -553,4 +1393,644 @@ public abstract class ImageReader this.locale = locale; } + + /** + * Check that the given read parameters have valid source and + * destination band settings. If the param.getSourceBands() returns + * null, the array is assumed to include all band indices, 0 to + * numSrcBands - 1; likewise if param.getDestinationBands() returns + * null, it is assumed to be an array containing indices 0 to + * numDstBands - 1. A failure will cause this method to throw + * IllegalArgumentException. + * + * @param param the image parameters to check + * @param numSrcBands the number of input source bands + * @param numDstBands the number of ouput destination bands + * + * @exception IllegalArgumentException if either the given source or + * destination band indices are invalid + */ + protected static void checkReadParamBandSettings(ImageReadParam param, + int numSrcBands, + int numDstBands) + { + int[] srcBands = param.getSourceBands(); + int[] dstBands = param.getDestinationBands(); + boolean lengthsDiffer = false; + boolean srcOOB = false; + boolean dstOOB = false; + + if (srcBands == null) + { + if (dstBands == null) + { + if (numSrcBands != numDstBands) + lengthsDiffer = true; + } + else + { + if (numSrcBands != dstBands.length) + lengthsDiffer = true; + + for (int i = 0; i < dstBands.length; i++) + if (dstBands[i] > numSrcBands - 1) + { + dstOOB = true; + break; + } + } + } + else + { + if (dstBands == null) + { + if (srcBands.length != numDstBands) + lengthsDiffer = true; + + for (int i = 0; i < srcBands.length; i++) + if (srcBands[i] > numDstBands - 1) + { + srcOOB = true; + break; + } + } + else + { + if (srcBands.length != dstBands.length) + lengthsDiffer = true; + + for (int i = 0; i < srcBands.length; i++) + if (srcBands[i] > numDstBands - 1) + { + srcOOB = true; + break; + } + + for (int i = 0; i < dstBands.length; i++) + if (dstBands[i] > numSrcBands - 1) + { + dstOOB = true; + break; + } + } + } + + if (lengthsDiffer) + throw new IllegalArgumentException ("array lengths differ"); + + if (srcOOB) + throw new IllegalArgumentException ("source band index" + + " out-of-bounds"); + + if (dstOOB) + throw new IllegalArgumentException ("destination band index" + + " out-of-bounds"); + } + + /** + * Calcluate the source and destination regions that will be read + * from and written to, given image parameters and/or a destination + * buffered image. The source region will be clipped if any of its + * bounds are outside the destination region. Clipping will account + * for subsampling and destination offsets. Likewise, the + * destination region is clipped to the given destination image, if + * it is not null, using the given image parameters, if they are not + * null. IllegalArgumentException is thrown if either region will + * contain 0 pixels after clipping. + * + * @param image read parameters, or null + * @param srcWidth the width of the source image + * @param srcHeight the height of the source image + * @param image the destination image, or null + * @param srcRegion a rectangle whose values will be set to the + * clipped source region + * @param destRegion a rectangle whose values will be set to the + * clipped destination region + * + * @exception IllegalArgumentException if either srcRegion or + * destRegion is null + * @exception IllegalArgumentException if either of the calculated + * regions is empty + */ + protected static void computeRegions (ImageReadParam param, + int srcWidth, + int srcHeight, + BufferedImage image, + Rectangle srcRegion, + Rectangle destRegion) + { + if (srcRegion == null || destRegion == null) + throw new IllegalArgumentException ("null region"); + + if (srcWidth == 0 || srcHeight == 0) + throw new IllegalArgumentException ("zero-sized region"); + + srcRegion = getSourceRegion(param, srcWidth, srcHeight); + if (image != null) + destRegion = new Rectangle (0, 0, image.getWidth(), image.getHeight()); + else + destRegion = new Rectangle (0, 0, srcWidth, srcHeight); + + if (param != null) + { + Point offset = param.getDestinationOffset(); + + if (offset.x < 0) + { + srcRegion.x -= offset.x; + srcRegion.width += offset.x; + } + if (offset.y < 0) + { + srcRegion.y -= offset.y; + srcRegion.height += offset.y; + } + + srcRegion.width = srcRegion.width > destRegion.width + ? destRegion.width : srcRegion.width; + srcRegion.height = srcRegion.height > destRegion.height + ? destRegion.height : srcRegion.height; + + if (offset.x >= 0) + { + destRegion.x += offset.x; + destRegion.width -= offset.x; + } + if (offset.y >= 0) + { + destRegion.y += offset.y; + destRegion.height -= offset.y; + } + } + + if (srcRegion.isEmpty() || destRegion.isEmpty()) + throw new IllegalArgumentException ("zero-sized region"); + } + + /** + * Return a suitable destination buffered image. If + * param.getDestination() is non-null, then it is returned, + * otherwise a buffered image is created using + * param.getDestinationType() if it is non-null and also in the + * given imageTypes collection, or the first element of imageTypes + * otherwise. + * + * @param param image read parameters from which a destination image + * or image type is retrieved, or null + * @param imageTypes a collection of legal image types + * @param width the width of the source image + * @param height the height of the source image + * + * @return a suitable destination buffered image + * + * @exception IIOException if param.getDestinationType() does not + * return an image type in imageTypes + * @exception IllegalArgumentException if imageTypes is null or + * empty, or if a non-ImageTypeSpecifier object is retrieved from + * imageTypes + * @exception IllegalArgumentException if the resulting destination + * region is empty + * @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 (width < 0 || height < 0) + throw new IllegalArgumentException ("negative dimension"); + + // test for overflow + if (width * height < Math.min (width, height)) + throw new IllegalArgumentException ("width * height > Integer.MAX_VALUE"); + + BufferedImage dest = null; + ImageTypeSpecifier destType = null; + + if (param != null) + { + dest = param.getDestination (); + if (dest == null) + { + ImageTypeSpecifier type = param.getDestinationType(); + if (type != null) + { + Iterator it = imageTypes; + + while (it.hasNext()) + { + Object o = it.next (); + if (! (o instanceof ImageTypeSpecifier)) + throw new IllegalArgumentException ("non-ImageTypeSpecifier object"); + + ImageTypeSpecifier t = (ImageTypeSpecifier) o; + if (t.equals (type)) + { + dest = t.createBufferedImage (width, height); + break; + } + if (destType == null) + throw new IIOException ("invalid destination type"); + + } + } + } + } + if (dest == null) + { + Rectangle srcRegion = new Rectangle (); + Rectangle destRegion = new Rectangle (); + + computeRegions (param, width, height, null, srcRegion, destRegion); + + if (destRegion.isEmpty()) + throw new IllegalArgumentException ("destination region empty"); + + if (destType == null) + { + Object o = imageTypes.next(); + if (! (o instanceof ImageTypeSpecifier)) + throw new IllegalArgumentException ("non-ImageTypeSpecifier" + + " object"); + + dest = ((ImageTypeSpecifier) o).createBufferedImage + (destRegion.width, destRegion.height); + } + else + dest = destType.createBufferedImage + (destRegion.width, destRegion.height); + } + return dest; + } + + /** + * Get the metadata associated with this image. If the reader is + * set to ignore metadata or does not support reading metadata, or + * if no metadata is available then null is returned. + * + * This more specific version of getImageMetadata(int) can be used + * to restrict metadata retrieval to specific formats and node + * names, which can limit the amount of data that needs to be + * processed. + * + * @param imageIndex the frame index + * @param formatName the format of metadata requested + * @param nodeNames a set of Strings specifiying node names to be + * retrieved + * + * @return a metadata object, or null + * + * @exception IllegalStateException if input has not been set + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IllegalArgumentException if formatName is null + * @exception IllegalArgumentException if nodeNames is null + * @exception IOException if a read error occurs + */ + public IIOMetadata getImageMetadata (int imageIndex, + String formatName, + Set nodeNames) + throws IOException + { + if (formatName == null || nodeNames == null) + throw new IllegalArgumentException ("null argument"); + + return getImageMetadata (imageIndex); + } + + /** + * Get the index at which the next image will be read. If + * seekForwardOnly is true then the returned value will increase + * monotonically each time an image frame is read. If + * seekForwardOnly is false then the returned value will always be + * 0. + * + * @return the current frame index + */ + public int getMinIndex() + { + return minIndex; + } + + /** + * Get the image type specifier that most closely represents the + * internal data representation used by this reader. This value + * should be included in the return value of getImageTypes. + * + * @param imageIndex the frame index + * + * @return an image type specifier + * + * @exception IllegalStateException if input has not been set + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ + public ImageTypeSpecifier getRawImageType (int imageIndex) + throws IOException + { + return (ImageTypeSpecifier) getImageTypes(imageIndex).next(); + } + + /** + * Calculate a source region based on the given source image + * dimensions and parameters. Subsampling offsets and a source + * region are taken from the given image read parameters and used to + * clip the given image dimensions, returning a new rectangular + * region as a result. + * + * @param param image parameters, or null + * @param srcWidth the width of the source image + * @param srcHeight the height of the source image + * + * @return a clipped rectangle + */ + protected static Rectangle getSourceRegion (ImageReadParam param, + int srcWidth, + int srcHeight) + { + Rectangle clippedRegion = new Rectangle (0, 0, srcWidth, srcHeight); + + if (param != null) + { + Rectangle srcRegion = param.getSourceRegion(); + + if (srcRegion != null) + { + clippedRegion.x = srcRegion.x > clippedRegion.x + ? srcRegion.x : clippedRegion.x; + clippedRegion.y = srcRegion.y > clippedRegion.y + ? srcRegion.y : clippedRegion.y; + clippedRegion.width = srcRegion.width > clippedRegion.width + ? srcRegion.width : clippedRegion.width; + clippedRegion.height = srcRegion.height > clippedRegion.height + ? srcRegion.height : clippedRegion.height; + } + + int xOffset = param.getSubsamplingXOffset(); + + clippedRegion.x += xOffset; + clippedRegion.width -= xOffset; + + int yOffset = param.getSubsamplingYOffset(); + + clippedRegion.y += yOffset; + clippedRegion.height -= yOffset; + } + return clippedRegion; + } + + /** + * Get the metadata associated with the image being read. If the + * reader is set to ignore metadata or does not support reading + * metadata, or if no metadata is available then null is returned. + * This method returns metadata associated with the entirety of the + * image data, whereas getStreamMetadata() returns metadata + * associated with a frame within a multi-image data stream. + * + * This more specific version of getStreamMetadata() can be used to + * restrict metadata retrieval to specific formats and node names, + * which can limit the amount of data that needs to be processed. + * + * @param formatName the format of metadata requested + * @param nodeNames a set of Strings specifiying node names to be + * retrieved + * + * @return metadata associated with the image being read, or null + * + * @exception IllegalArgumentException if formatName is null + * @exception IllegalArgumentException if nodeNames is null + * @exception IOException if a read error occurs + */ + public IIOMetadata getStreamMetadata (String formatName, + Set nodeNames) + throws IOException + { + if (formatName == null || nodeNames == null) + throw new IllegalArgumentException ("null argument"); + + return getStreamMetadata(); + } + + /** + * Read the given frame all at once, using default image read + * parameters, and return a buffered image. + * + * The returned image will be formatted according to the + * currently-preferred image type specifier. + * + * Installed read progress listeners, update progress listeners and + * warning listeners will be notified of read progress, changes in + * sample sets and warnings respectively. + * + * @param the index of the image frame to read + * + * @return a buffered image + * + * @exception IllegalStateException if input has not been set + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IOException if a read error occurs + */ + public BufferedImage read (int imageIndex) + throws IOException + { + return read (imageIndex, null); + } + + /** + * Read the given frame all at once, using the given image read + * parameters, and return an IIOImage. The IIOImage will contain a + * buffered image as returned by getDestination. + * + * Installed read progress listeners, update progress listeners and + * warning listeners will be notified of read progress, changes in + * sample sets and warnings respectively. + * + * The source and destination band settings are checked with a call + * to checkReadParamBandSettings. + * + * @param the index of the image frame to read + * @param the image read parameters + * + * @return an IIOImage + * + * @exception IllegalStateException if input has not been set + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IllegalArgumentException if param.getSourceBands() and + * param.getDestinationBands() are incompatible + * @exception IllegalArgumentException if either the source or + * destination image regions are empty + * @exception IOException if a read error occurs + */ + public IIOImage readAll (int imageIndex, + ImageReadParam param) + throws IOException + { + checkReadParamBandSettings (param, + param.getSourceBands().length, + param.getDestinationBands().length); + + List l = new ArrayList (); + + for (int i = 0; i < getNumThumbnails (imageIndex); i++) + l.add (readThumbnail(imageIndex, i)); + + return new IIOImage (getDestination(param, getImageTypes(imageIndex), + getWidth(imageIndex), + getHeight(imageIndex)), + l, + getImageMetadata (imageIndex)); + } + + /** + * Read all image frames all at once, using the given image read + * parameters iterator, and return an iterator over a collection of + * IIOImages. Each IIOImage in the collection will contain a + * buffered image as returned by getDestination. + * + * Installed read progress listeners, update progress listeners and + * warning listeners will be notified of read progress, changes in + * sample sets and warnings respectively. + * + * Each set of source and destination band settings are checked with + * a call to checkReadParamBandSettings. + * + * @param an iterator over the image read parameters + * + * @return an IIOImage + * + * @exception IllegalStateException if input has not been set + * @exception IllegalArgumentException if a non-ImageReadParam is + * found in params + * @exception IllegalArgumentException if param.getSourceBands() and + * param.getDestinationBands() are incompatible + * @exception IllegalArgumentException if either the source or + * destination image regions are empty + * @exception IOException if a read error occurs + */ + public Iterator readAll (Iterator params) + throws IOException + { + List l = new ArrayList (); + int index = 0; + + while (params.hasNext()) + { + if (params != null && ! (params instanceof ImageReadParam)) + throw new IllegalArgumentException ("non-ImageReadParam found"); + + l.add (readAll(index++, (ImageReadParam) params.next ())); + } + + return l.iterator(); + } + + /** + * Read a rendered image. This is a more general counterpart to + * read (int, ImageReadParam). All image data may not be read + * before this method returns and so listeners will not necessarily + * be notified. + * + * @param the index of the image frame to read + * @param the image read parameters + * + * @return a rendered image + * + * @exception IllegalStateException if input is null + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IllegalArgumentException if param.getSourceBands() and + * param.getDestinationBands() are incompatible + * @exception IllegalArgumentException if either the source or + * destination image regions are empty + * @exception IOException if a read error occurs + */ + public RenderedImage readAsRenderedImage (int imageIndex, + ImageReadParam param) + throws IOException + { + return read (imageIndex, param); + } + + /** + * Read the given tile into a buffered image. If the tile + * coordinates are out-of-bounds an exception is thrown. If the + * image is not tiled then the coordinates 0, 0 are expected and the + * entire image will be read. + * + * @param imageIndex the frame index + * @param tileX the horizontal tile coordinate + * @param tileY the vertical tile coordinate + * + * @return the contents of the tile as a buffered image + * + * @exception IllegalStateException if input is null + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IllegalArgumentException if the tile coordinates are + * out-of-bounds + * @exception IOException if a read error occurs + */ + public BufferedImage readTile (int imageIndex, int tileX, int tileY) + throws IOException + { + if (tileX != 0 || tileY != 0) + throw new IllegalArgumentException ("tileX not 0 or tileY not 0"); + + return read (imageIndex); + } + + /** + * Read the given tile into a raster containing the raw image data. + * If the tile coordinates are out-of-bounds an exception is thrown. + * If the image is not tiled then the coordinates 0, 0 are expected + * and the entire image will be read. + * + * @param imageIndex the frame index + * @param tileX the horizontal tile coordinate + * @param tileY the vertical tile coordinate + * + * @return the contents of the tile as a raster + * + * @exception UnsupportedOperationException if rasters are not + * supported + * @exception IllegalStateException if input is null + * @exception IndexOutOfBoundsException if the frame index is + * out-of-bounds + * @exception IllegalArgumentException if the tile coordinates are + * out-of-bounds + * @exception IOException if a read error occurs + */ + public Raster readTileRaster (int imageIndex, int tileX, int tileY) + throws IOException + { + if (!canReadRaster()) + throw new UnsupportedOperationException ("cannot read rasters"); + + if (tileX != 0 || tileY != 0) + throw new IllegalArgumentException ("tileX not 0 or tileY not 0"); + + return readRaster (imageIndex, null); + } + + /** + * Reset this reader's internal state. + */ + public void reset () + { + setInput (null, false); + setLocale (null); + removeAllIIOReadUpdateListeners (); + removeAllIIOReadWarningListeners (); + removeAllIIOReadProgressListeners (); + clearAbortRequest (); + } } + diff --git a/libjava/classpath/javax/imageio/ImageTranscoder.java b/libjava/classpath/javax/imageio/ImageTranscoder.java index ccc99316269..1f9195f5816 100644 --- a/libjava/classpath/javax/imageio/ImageTranscoder.java +++ b/libjava/classpath/javax/imageio/ImageTranscoder.java @@ -41,14 +41,62 @@ package javax.imageio; import javax.imageio.metadata.IIOMetadata; /** + * An ImageTranscoder translates IIOMetadata objects provided by an + * ImageReader into corresponding IIOMetadata objects that can be + * understood by a given ImageWriter. + * + * Usually an ImageWriter will implement ImageTranscoder directly in + * which case the conversion methods will return IIOMetadata objects + * appropriate for this ImageWriter. + * + * Independent transcoders are also allowed; they must have knowledge + * of both the source IIOMetadata provided by the reader and the + * returned IIOMetadata expected by the writer. + * * @author Michael Koch (konqueror@gmx.de) */ public interface ImageTranscoder { + /** + * Converts IIOMetadata from an input reader format, returning an + * IIOMetadata suitable for use by an image writer. + * + * The ImageTypeSpecifier specifies the destination image type. + * + * An optional ImageWriteParam argument is available in case the + * image writing parameters affect the metadata conversion. + * + * @param inData the metadata coming from an image reader + * @param imageType the output image type of the writer + * @param param the image writing parameters or null + * + * @return the converted metadata that should be used by the image + * writer, or null if this ImageTranscoder has no knowledge of the + * input metadata + * + * @exception IllegalArgumentException if either inData or imageType + * is null + */ IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param); + /** + * Converts IIOMetadata from an input stream format, returning an + * IIOMetadata suitable for use by an image writer. + * + * An optional ImageWriteParam argument is available in case the + * image writing parameters affect the metadata conversion. + * + * @param inData the metadata coming from an input image stream + * @param param the image writing parameters or null + * + * @return the converted metadata that should be used by the image + * writer, or null if this ImageTranscoder has no knowledge of the + * input metadata + * + * @exception IllegalArgumentException if inData is null + */ IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param); } diff --git a/libjava/classpath/javax/imageio/ImageTypeSpecifier.java b/libjava/classpath/javax/imageio/ImageTypeSpecifier.java index 0751e376757..05b3a26d493 100644 --- a/libjava/classpath/javax/imageio/ImageTypeSpecifier.java +++ b/libjava/classpath/javax/imageio/ImageTypeSpecifier.java @@ -38,15 +38,47 @@ exception statement from your version. */ package javax.imageio; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.DataBuffer; +import java.awt.image.BandedSampleModel; +import java.awt.image.BufferedImage; import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.IndexColorModel; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.PixelInterleavedSampleModel; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; +/** + * ImageTypeSpecifier store the color and sample models associated + * with an IIOImage. + */ public class ImageTypeSpecifier { + /** + * The image's color model. + */ protected ColorModel colorModel; + + /** + * The image's sample model. + */ protected SampleModel sampleModel; + /** + * Construct an image type specifier with the given models. + * + * @param colorModel the color model + * @param sampleModel the sample model + * + * @exception IllegalArgumentException if either model argument is + * null + * @exception IllegalArgumentException if the models are + * incompatible with one another + */ public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel) { if (colorModel == null) @@ -63,6 +95,14 @@ public class ImageTypeSpecifier this.sampleModel = sampleModel; } + /** + * Construct an image type specifier that describes the given + * rendered image. + * + * @param image a rendered image + * + * @exception IllegalArgumentException if image is null + */ public ImageTypeSpecifier(RenderedImage image) { if (image == null) @@ -72,21 +112,448 @@ public class ImageTypeSpecifier this.sampleModel = image.getSampleModel(); } + /** + * Create an image type specifier for a banded image using a + * component color model and a banded sample model. + * + * @param colorSpace the color space + * @param bankIndices the bank indices at which each band will be + * stored + * @param bandOffsets the starting band offset for each band within + * its bank + * @param dataType the data type, a DataBuffer constant + * @param hasAlpha true if this image type specifier should have an + * alpha component, false otherwise + * @param isAlphaPremultiplied true if other color components should + * be premultiplied by the alpha component, false otherwise + * + * @return a banded image type specifier + * + * @exception IllegalArgumentException if any of colorSpace, + * bankIndices or bankOffsets is null + * @exception IllegalArgumentException if bankIndices and + * bankOffsets differ in length + * @excpetion IllegalArgumentException if the number of color space + * components, including the alpha component if requested, is + * different from bandOffsets.length + * @exception if dataType is not a valid DataBuffer constant + */ + public static ImageTypeSpecifier createBanded (ColorSpace colorSpace, + int[] bankIndices, + int[] bankOffsets, + int dataType, + boolean hasAlpha, + boolean isAlphaPremultiplied) + { + if (colorSpace == null || bankIndices == null || bankOffsets == null) + throw new IllegalArgumentException ("null argument"); + + if (bankIndices.length != bankOffsets.length) + throw new IllegalArgumentException ("array lengths differ"); + + if (bankOffsets.length != (colorSpace.getNumComponents() + (hasAlpha ? 1 : 0))) + throw new IllegalArgumentException ("invalid bankOffsets length"); + + return new ImageTypeSpecifier (new ComponentColorModel (colorSpace, + hasAlpha, + isAlphaPremultiplied, + hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE, + dataType), + new BandedSampleModel (dataType, 1, 1, 1, + bankIndices, + bankOffsets)); + } + + /** + * Create a buffered image with the given dimensions using that has + * the characteristics specified by this image type specifier. + * + * @param the width of the buffered image, in pixels + * @param the height of the buffered image, in pixels + * + * @return a buffered image + * + * @exception IllegalArgumentException if either width or height is + * less than or equal to zero + * @exception IllegalArgumentException if width * height is greater + * than Integer.MAX_VALUE or if the storage required is greater than + * Integer.MAX_VALUE + */ + public BufferedImage createBufferedImage (int width, int height) + { + if (width <= 0 || height <= 0) + throw new IllegalArgumentException ("dimension <= 0"); + + // test for overflow + if (width * height < Math.min (width, height)) + throw new IllegalArgumentException ("width * height > Integer.MAX_VALUE"); + + if (width * height * sampleModel.getNumBands() < Math.min (width, height)) + throw new IllegalArgumentException ("storage required >" + + " Integer.MAX_VALUE"); + + // FIXME: this is probably wrong: + return new BufferedImage (width, height, BufferedImage.TYPE_INT_RGB); + } + + /** + * Create an image type specifier that describes the given buffered + * image type. + * + * @param bufferedImageType the buffered image type to represent + * with the returned image type specifier + * + * @return a new image type specifier + * + * @exception IllegalArgumentException if bufferedImageType is not a + * BufferedImage constant or is BufferedImage.TYPE_CUSTOM + */ + public static ImageTypeSpecifier createFromBufferedImageType (int bufferedImageType) + { + if (bufferedImageType <= BufferedImage.TYPE_CUSTOM + || bufferedImageType > BufferedImage.TYPE_BYTE_INDEXED) + throw new IllegalArgumentException ("invalid buffered image type"); + + return new ImageTypeSpecifier (new BufferedImage (1, 1, bufferedImageType)); + } + + /** + * Create an image type specifier that describes the given rendered + * image's type. + * + * @param image the rendered image + * + * @return a new image type specifier + * + * @exception IllegalArgumentException if image is null + */ + public static ImageTypeSpecifier createFromRenderedImage (RenderedImage image) + { + if (image == null) + throw new IllegalArgumentException ("image null"); + + return new ImageTypeSpecifier (image); + } + + /** + * Create a grayscale image type specifier, given the number of + * bits, data type and whether or not the data is signed. + * + * @param bits the number of bits used to specify a greyscale value + * @param dataType a DataBuffer type constant + * @param isSigned true if this type specifier should support + * negative values, false otherwise + * + * @return a greyscal image type specifier + * + * @exception IllegalArgumentException if bits is not 1, 2, 4, 8 or 16 + * @exception IllegalArgumentException if dataType is not + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or + * DataBuffer.TYPE_USHORT + * @exception if bits is larger than the number of bits in the given + * data type + */ + public static ImageTypeSpecifier createGrayscale (int bits, int dataType, boolean isSigned) + { + return createGrayscale (bits, dataType, isSigned, false); + } + + /** + * Create a grayscale image type specifier, given the number of + * bits, data type and whether or not the data is signed. + * + * @param bits the number of bits used to specify a greyscale value + * @param dataType a DataBuffer type constant + * @param isSigned true if this type specifier should support + * negative values, false otherwise + * + * @return a greyscal image type specifier + * + * @exception IllegalArgumentException if bits is not 1, 2, 4, 8 or + * 16 + * @exception IllegalArgumentException if dataType is not + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or + * DataBuffer.TYPE_USHORT + * @exception if bits is larger than the number of bits in the given + * data type + */ + public static ImageTypeSpecifier createGrayscale (int bits, int dataType, + boolean isSigned, + boolean isAlphaPremultiplied) + { + if (bits != 1 && bits != 2 && bits != 4 && bits != 8 && bits != 16) + throw new IllegalArgumentException ("invalid bit size"); + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_SHORT + && dataType != DataBuffer.TYPE_USHORT) + throw new IllegalArgumentException ("invalid data type"); + + if (dataType == DataBuffer.TYPE_BYTE && bits > 8) + throw new IllegalArgumentException ("number of bits too large for data type"); + + // FIXME: this is probably wrong: + return new ImageTypeSpecifier (new DirectColorModel (bits, 0xff, 0x0, + 0x0, 0xff), + new MultiPixelPackedSampleModel (dataType, + 1, 1, + bits)); + } + + /** + * Return an image type specifier for an image that uses an indexed + * colour model where each colour value has the specified number of + * bits and type and where the colour tables are those given. + * + * @param redLUT the red index values + * @param greenLUT the green index values + * @param blueLUT the blue index values + * @param alphaLUT the alpha index values + * @param bits the number of bits per index value + * @param dataType the type of each index value + * + * @return an indexed image type specifier + * + * @exception IllegalArgumentException if any of the colour arrays, + * not including alphaLUT, is null + * @exception IllegalArgumentException if bits is not 1, 2, 4, 8 or + * 16 + * @exception IllegalArgumentException if dataType is not + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or + * DataBuffer.TYPE_USHORT + * @exception if bits is larger than the number of bits in the given + * data type + */ + public static ImageTypeSpecifier createIndexed (byte[] redLUT, + byte[] greenLUT, + byte[] blueLUT, + byte[] alphaLUT, + int bits, + int dataType) + { + if (redLUT == null || greenLUT == null || blueLUT == null) + throw new IllegalArgumentException ("null colour table"); + + if (bits != 1 && bits != 2 && bits != 4 && bits != 8 && bits != 16) + throw new IllegalArgumentException ("invalid bit size"); + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_SHORT + && dataType != DataBuffer.TYPE_USHORT) + throw new IllegalArgumentException ("invalid data type"); + + if (dataType == DataBuffer.TYPE_BYTE && bits > 8) + throw new IllegalArgumentException ("number of bits too large for data type"); + + // FIXME: this is probably wrong: + return new ImageTypeSpecifier (new IndexColorModel (bits, redLUT.length, + redLUT, greenLUT, blueLUT, + alphaLUT), + new MultiPixelPackedSampleModel (dataType, + 1, 1, + bits)); + } + + /** + * Create an image type specifier that uses a component colour model + * and a pixel interleaved sample model. Each pixel component will + * be stored in a separate value of the given data type. + * + * @param colorSpace the colour space used by the colour model + * @param bandOffsets the starting band offset for each band within + * its bank + * @param dataType the type of each pixel value + * @param hasAlpha true if an alpha channel should be specified, + * false otherwise + * @param isAlphaPremultiplied true if other colour channels should + * be premultiplied by the alpha value, false otherwise + * + * @return an interleaved image type specifier + * + * @exception IllegalArgumentException if either colorSpace or + * bandOffsets is null + * @excpetion IllegalArgumentException if the number of color space + * components, including the alpha component if requested, is + * different from bandOffsets.length + * @exception if dataType is not a valid DataBuffer constant + */ + public static ImageTypeSpecifier createInterleaved (ColorSpace colorSpace, + int[] bandOffsets, + int dataType, + boolean hasAlpha, + boolean isAlphaPremultiplied) + { + if (colorSpace == null || bandOffsets == null) + throw new IllegalArgumentException ("null argument"); + + if (bandOffsets.length != (colorSpace.getNumComponents() + (hasAlpha ? 1 : 0))) + throw new IllegalArgumentException ("invalid bankOffsets length"); + + return new ImageTypeSpecifier (new ComponentColorModel (colorSpace, + hasAlpha, + isAlphaPremultiplied, + hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE, + dataType), + new PixelInterleavedSampleModel (dataType, 1, 1, 1, 1, + bandOffsets)); + } + + /** + * Create an image type specifier using a direct color model and a + * packed sample model. All pixel components will be packed into + * one value of the given data type. + * + * @param colorSpace the color space to use in the color model + * @param redMask the bitmask for the red bits + * @param greenMask the bitmask for the green bits + * @param blueMask the bitmask for the blue bits + * @param alphaMask the bitmask for the alpha bits + * @param transferType the data type used to store pixel values + * @param isAlphaPremultiplied true if other colour channels should + * be premultiplied by the alpha value, false otherwise + * + * @return a packed image type specifier + * + * @exception IllegalArgumentException if colorSpace is null + * @exception IllegalArgumentException if colorSpace does not have + * type ColorSpace.TYPE_RGB + * @exception IllegalArgumentException if all masks are 0 + * @exception IllegalArgumentException if dataType is not + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_SHORT or + * DataBuffer.TYPE_INT + */ + public static ImageTypeSpecifier createPacked (ColorSpace colorSpace, + int redMask, + int greenMask, + int blueMask, + int alphaMask, + int transferType, + boolean isAlphaPremultiplied) + { + if (colorSpace == null) + throw new IllegalArgumentException ("null color space"); + + if (colorSpace.getType() != ColorSpace.TYPE_RGB) + throw new IllegalArgumentException ("invalid color space type"); + + if (redMask == 0 && greenMask == 0 && blueMask == 0 && alphaMask == 0) + throw new IllegalArgumentException ("no non-zero mask"); + + if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT + && transferType != DataBuffer.TYPE_INT) + throw new IllegalArgumentException ("invalid data type"); + + // Assume DataBuffer.TYPE_BYTE. + int numBits = 8; + + if (transferType == DataBuffer.TYPE_SHORT) + numBits = 16; + else if (transferType == DataBuffer.TYPE_INT) + numBits = 32; + + return new ImageTypeSpecifier (new DirectColorModel (colorSpace, + numBits, + redMask, + greenMask, + blueMask, + alphaMask, + isAlphaPremultiplied, + transferType), + new MultiPixelPackedSampleModel (transferType, + 1, 1, numBits)); + } + + /** + * Get the number of bits per sample in the given band. + * + * @param band the band from which to get the number of bits + * + * @return the number of bits in the given band + * + * @exception IllegalArgumentException if band is out-of-bounds + */ + public int getBitsPerBand (int band) + { + if (band < 0 || band > sampleModel.getNumBands()) + throw new IllegalArgumentException ("band out-of-bounds"); + + return sampleModel.getSampleSize (band); + } + + /** + * Get the buffered image constant specified by this image type + * specifier. + * + * @return a buffered image constant + */ + public int getBufferedImageType () + { + // FIXME: + return BufferedImage.TYPE_INT_RGB; + } + + /** + * Create a sample model that is compatible with the one specified + * by this image type specifier, with the given dimensions. + * + * @param width the width of the returned sample model + * @param height the height of the returned sample model + * + * @return a sample model compatible with the one in this image type + * specifier, with the given dimensions + * + * @exception IllegalArgumentException if either width or height is + * less than or equal to 0 + * @exception IllegalArgumentException if width * height is greater + * than Intere.MAX_VALUE + */ + public SampleModel getSampleModel (int width, int height) + { + if (width <= 0 || height <= 0) + throw new IllegalArgumentException ("invalid dimension"); + + // test for overflow + if (width * height < Math.min (width, height)) + throw new IllegalArgumentException ("width * height > Integer.MAX_VALUE"); + + return sampleModel.createCompatibleSampleModel (width, height); + } + + /** + * Get the color model specified by this image type specifier. + * + * @return the color model + */ public ColorModel getColorModel() { return colorModel; } + /** + * Get the number of bands specified by this image type specifier's + * sample model. + * + * @return the number of bands in the sample model + */ public int getNumBands() { return sampleModel.getNumBands(); } + /** + * Get the number of components specified by this image type + * specifier's color model. + * + * @return the number of color components per pixel + */ public int getNumComponents() { return colorModel.getNumComponents(); } + /** + * Get the sample model specified by this image type specifier. + * + * @return the sample model + */ public SampleModel getSampleModel() { return sampleModel; diff --git a/libjava/classpath/javax/imageio/ImageWriteParam.java b/libjava/classpath/javax/imageio/ImageWriteParam.java index 08f4885a8d1..84b257e04eb 100644 --- a/libjava/classpath/javax/imageio/ImageWriteParam.java +++ b/libjava/classpath/javax/imageio/ImageWriteParam.java @@ -41,6 +41,9 @@ package javax.imageio; import java.awt.Dimension; import java.util.Locale; +/** + * DOCUMENT ME + */ public class ImageWriteParam extends IIOParam { public static final int MODE_DISABLED = 0; diff --git a/libjava/classpath/javax/imageio/ImageWriter.java b/libjava/classpath/javax/imageio/ImageWriter.java index 7479c3074f7..ef352154164 100644 --- a/libjava/classpath/javax/imageio/ImageWriter.java +++ b/libjava/classpath/javax/imageio/ImageWriter.java @@ -1,5 +1,5 @@ /* ImageWriter.java -- Encodes raster images. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,11 +39,16 @@ exception statement from your version. */ package javax.imageio; import java.awt.Dimension; +import java.awt.Rectangle; +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.ResourceBundle; +import java.util.MissingResourceException; import javax.imageio.event.IIOWriteProgressListener; import javax.imageio.event.IIOWriteWarningListener; @@ -51,56 +56,161 @@ import javax.imageio.metadata.IIOMetadata; import javax.imageio.spi.ImageWriterSpi; +/** + * A class for encoding images within the ImageIO framework. + * + * An ImageWriter for a given format is instantiated by an + * ImageWriterSpi for that format. ImageWriterSpis are registered + * with the IIORegistry. + * + * The ImageWriter API supports writing animated images that may have + * multiple frames; to support such images many methods take an index + * parameter. + * + * Images may also be written in multiple passes, where each + * successive pass increases the level of detail in the destination + * image. + */ public abstract class ImageWriter implements ImageTranscoder { private boolean aborted; - protected Locale[] availableLocales; - protected Locale locale; - protected ImageWriterSpi originatingProvider; - protected Object output; - protected List progressListeners = new ArrayList(); - protected List warningListeners = new ArrayList(); - protected List warningLocales = new ArrayList(); + /** + * All locales available for localization of warning messages, or + * null if localization is not supported. + */ + protected Locale[] availableLocales = null; + /** + * The current locale used to localize warning messages, or null if + * no locale has been set. + */ + protected Locale locale = null; + + /** + * The image writer SPI that instantiated this writer. + */ + protected ImageWriterSpi originatingProvider = null; + + /** + * An ImageInputStream to which image data is written. + */ + protected Object output = null; + + /** + * A list of installed progress listeners. Initially null, meaning + * no installed listeners. + */ + protected List progressListeners = null; + + /** + * A list of installed warning listeners. Initially null, meaning + * no installed listeners. + */ + protected List warningListeners = null; + + /** + * A list of warning locales corresponding with the list of + * installed warning listeners. Initially null, meaning no locales. + */ + protected List warningLocales = null; + + /** + * Construct an image writer. + * + * @param originatingProvider the provider that is constructing this + * image writer, or null + */ protected ImageWriter(ImageWriterSpi originatingProvider) { this.originatingProvider = originatingProvider; } + /** + * Throw an IllegalStateException if output is null. + * + * @exception IllegalStateException if output is null + */ private void checkOutputSet() { if (output == null) throw new IllegalStateException("no output set"); } + /** + * Request that writing be aborted. The unwritten portions of the + * destination image will be undefined. + * + * Writers should clear the abort flag before starting a write + * operation, then poll it periodically during the write operation. + */ public void abort() { aborted = true; } + /** + * Check if the abort flag is set. + * + * @return true if the current write operation should be aborted, + * false otherwise + */ protected boolean abortRequested() { return aborted; } + /** + * Install a write progress listener. This method will return + * immediately if listener is null. + * + * @param listener a write progress listener or null + */ public void addIIOWriteProgressListener(IIOWriteProgressListener listener) { if (listener == null) return; - + if (progressListeners == null) + progressListeners = new ArrayList (); progressListeners.add(listener); } - + + /** + * Install a write warning listener. This method will return + * immediately if listener is null. Warning messages sent to this + * listener will be localized using the current locale. If the + * current locale is null then this writer will select a sensible + * default. + * + * @param listener a write warning listener + */ public void addIIOWriteWarningListener (IIOWriteWarningListener listener) { if (listener == null) return; - + if (warningListeners == null) + warningListeners = new ArrayList (); warningListeners.add(listener); } + /** + * Check whether a new empty image can be inserted at the given + * frame index. Pixel values may be filled in later using the + * replacePixels methods. Indices greater than the insertion index + * will be incremented. If imageIndex is -1, the image will be + * appended at the end of the current image list. + * + * @param imageIndex the frame index + * + * @return true if an empty image can be inserted at imageIndex, + * false otherwise + * + * @exception IllegalStateException if output is null + * @exception IndexOutOfBoundsException if imageIndex is less than + * -1 or greater than the last index in the current image list + * @exception IOException if a write error occurs + */ public boolean canInsertEmpty(int imageIndex) throws IOException { @@ -108,6 +218,22 @@ public abstract class ImageWriter return false; } + /** + * Check whether an image can be inserted at the given frame index. + * Indices greater than the insertion index will be incremented. If + * imageIndex is -1, the image will be appended at the end of the + * current image list. + * + * @param imageIndex the frame index + * + * @return true if an image can be inserted at imageIndex, false + * otherwise + * + * @exception IllegalStateException if output is null + * @exception IndexOutOfBoundsException if imageIndex is less than + * -1 or greater than the last index in the current image list + * @exception IOException if a write error occurs + */ public boolean canInsertImage(int imageIndex) throws IOException { @@ -115,6 +241,20 @@ public abstract class ImageWriter return false; } + /** + * Check whether an image can be removed from the given frame index. + * Indices greater than the removal index will be decremented. + * + * @param imageIndex the frame index + * + * @return true if an image can be removed from imageIndex, false + * otherwise + * + * @exception IllegalStateException if output is null + * @exception IndexOutOfBoundsException if imageIndex is less than 0 + * or greater than the last index in the current image list + * @exception IOException if a write error occurs + */ public boolean canRemoveImage(int imageIndex) throws IOException { @@ -122,6 +262,20 @@ public abstract class ImageWriter return false; } + /** + * Check whether the metadata associated the image at the given + * frame index can be replaced. + * + * @param imageIndex the frame index + * + * @return true if the metadata associated with the image at + * imageIndex can be replaced, false otherwise + * + * @exception IllegalStateException if output is null + * @exception IndexOutOfBoundsException if imageIndex is less than 0 + * or greater than the last index in the current image list + * @exception IOException if a write error occurs + */ public boolean canReplaceImageMetadata(int imageIndex) throws IOException { @@ -129,6 +283,20 @@ public abstract class ImageWriter return false; } + /** + * Check whether the pixels within the image at the given index can + * be replaced. + * + * @param imageIndex the frame index + * + * @return true if the pixels in the image at imageIndex can be + * replaced, false otherwise + * + * @exception IllegalStateException if output is null + * @exception IndexOutOfBoundsException if imageIndex is less than 0 + * or greater than the last index in the current image list + * @exception IOException if a write error occurs + */ public boolean canReplacePixels(int imageIndex) throws IOException { @@ -136,6 +304,16 @@ public abstract class ImageWriter return false; } + /** + * Check whether the metadata associated the entire image stream can + * be replaced. + * + * @return true if the stream metadata can be replaced, false + * otherwise + * + * @exception IllegalStateException if output is null + * @exception IOException if a write error occurs + */ public boolean canReplaceStreamMetadata() throws IOException { @@ -143,6 +321,18 @@ public abstract class ImageWriter return false; } + /** + * Check whether an entire empty image, including empty metadata and + * empty thumbnails, can be written to the output stream, leaving + * pixel values to be filled in later using the replacePixels + * methods. + * + * @return true if an entire empty image can be written before its + * contents are filled in, false otherwise + * + * @exception IllegalStateException if output is null + * @exception IOException if a write error occurs + */ public boolean canWriteEmpty() throws IOException { @@ -150,68 +340,217 @@ public abstract class ImageWriter return false; } + /** + * Check if IIOImages containing raster data are supported. + * + * @return true if raster IIOImages are supported, false otherwise + */ public boolean canWriteRasters() { return false; } + /** + * Check if an image can be appended at the end of the current list + * of images even if prior images have already been written. + * + * @return true if sequences of images can be written, false + * otherwise + */ public boolean canWriteSequence() { return false; } + /** + * Clear the abort flag. + */ protected void clearAbortRequest() { aborted = false; } - + + /** + * Convert IIOMetadata from an input reader format, returning an + * IIOMetadata suitable for use by an image writer. + * + * The ImageTypeSpecifier specifies the destination image type. + * + * An optional ImageWriteParam argument is available in case the + * image writing parameters affect the metadata conversion. + * + * @param inData the metadata coming from an image reader + * @param imageType the output image type of the writer + * @param param the image writing parameters or null + * + * @return the converted metadata that should be used by the image + * writer, or null if this ImageTranscoder has no knowledge of the + * input metadata + * + * @exception IllegalArgumentException if either inData or imageType + * is null + */ public abstract IIOMetadata convertImageMetadata (IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param); + /** + * Convert IIOMetadata from an input stream format, returning an + * IIOMetadata suitable for use by an image writer. + * + * An optional ImageWriteParam argument is available in case the + * image writing parameters affect the metadata conversion. + * + * @param inData the metadata coming from an input image stream + * @param param the image writing parameters or null + * + * @return the converted metadata that should be used by the image + * writer, or null if this ImageTranscoder has no knowledge of the + * input metadata + * + * @exception IllegalArgumentException if inData is null + */ public abstract IIOMetadata convertStreamMetadata (IIOMetadata inData, ImageWriteParam param); + /** + * Releases any resources allocated to this object. Subsequent + * calls to methods on this object will produce undefined results. + * + * The default implementation does nothing; subclasses should use + * this method ensure that native resources are released. + */ public void dispose() { // The default implementation is empty. Subclasses have to overwrite it. } + /** + * Retrieve the available locales. Return null if no locales are + * available or a clone of availableLocales. + * + * @return an array of locales or null + */ public Locale[] getAvailableLocales() { return availableLocales; } + /** + * Get a metadata object appropriate for encoding an image specified + * by the given image type specifier and optional image write + * parameters. + * + * @param imageType an image type specifier + * @param param image writing parameters, or null + * + * @return a metadata object appropriate for encoding an image of + * the given type with the given parameters + */ public abstract IIOMetadata getDefaultImageMetadata (ImageTypeSpecifier imageType, ImageWriteParam param); + /** + * Get a metadata object appropriate for encoding the default image + * type handled by this writer, optionally considering image write + * parameters. + * + * @param param image writing parameters, or null + * + * @return a metadata object appropriate for encoding an image of + * the default type with the given parameters + */ public abstract IIOMetadata getDefaultStreamMetadata (ImageWriteParam param); + /** + * Retrieve the default write parameters for this writer's image + * format. + * + * The default implementation returns new ImageWriteParam(). + * + * @return image writing parameters + */ public ImageWriteParam getDefaultWriteParam() { return new ImageWriteParam(getLocale()); } + /** + * Get this writer's locale. null is returned if the locale has not + * been set. + * + * @return this writer's locale, or null + */ public Locale getLocale() { return locale; } - public int getNumThumbnailsSupported (ImageTypeSpecifier imageType, ImageWriteParam param, - IIOMetadata streamMetadata, IIOMetadata imageMetadata) + /** + * Get the number of thumbnails supported by this image writer, + * based on the given image type, image writing parameters, and + * stream and image metadata. The image writing parameters are + * optional, in case they affect the number of thumbnails supported. + * + * @param imageType an image type specifier, or null + * @param param image writing parameters, or null + * @param streamMetadata the metadata associated with this stream, + * or null + * @param imageMetadata the metadata associated with this image, or + * null + * + * @return the number of thumbnails that this writer supports + * writing or -1 if the given information is insufficient + */ + public int getNumThumbnailsSupported (ImageTypeSpecifier imageType, + ImageWriteParam param, + IIOMetadata streamMetadata, + IIOMetadata imageMetadata) { return 0; } + /** + * Get the ImageWriterSpi that created this writer or null. + * + * @return an ImageWriterSpi, or null + */ public ImageWriterSpi getOriginatingProvider() { return originatingProvider; } + /** + * Get this reader's image output destination. null is returned if + * the image destination has not been set. + * + * @return an image output destination object, or null + */ public Object getOutput() { return output; } + /** + * Get the preferred sizes for thumbnails based on the given image + * type, image writing parameters, and stream and image metadata. + * The preferred sizes are returned in pairs of dimension values; + * the first value in the array is a dimension object representing + * the minimum thumbnail size, the second value is a dimension + * object representing a maximum thumbnail size. The writer can + * select a size within the range given by each pair, or it can + * ignore these size hints. + * + * @param imageType an image type specifier, or null + * @param param image writing parameters, or null + * @param streamMetadata the metadata associated with this stream, + * or null + * @param imageMetadata the metadata associated with this image, or + * null + * + * @return an array of dimension pairs whose length is a multiple of + * 2, or null if there is no preferred size (any size is allowed) or + * if the size is unknown (insufficient information was provided) + */ public Dimension[] getPreferredThumbnailSizes (ImageTypeSpecifier imageType, ImageWriteParam param, IIOMetadata streamMetadata, @@ -220,120 +559,305 @@ public abstract class ImageWriter return null; } + /** + * Notifies all installed write progress listeners that image + * loading has completed by calling their imageComplete methods. + */ protected void processImageComplete() { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOWriteProgressListener listener = (IIOWriteProgressListener) it.next(); - listener.imageComplete(this); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOWriteProgressListener listener = + (IIOWriteProgressListener) it.next(); + listener.imageComplete(this); + } } } + /** + * Notifies all installed write progress listeners that a certain + * percentage of the image has been loaded, by calling their + * imageProgress methods. + * + * @param percentageDone the percentage of image data that has been + * loaded + */ protected void processImageProgress(float percentageDone) { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOWriteProgressListener listener = (IIOWriteProgressListener) it.next(); - listener.imageProgress(this, percentageDone); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOWriteProgressListener listener = + (IIOWriteProgressListener) it.next(); + listener.imageProgress(this, percentageDone); + } } } + /** + * Notifies all installed write progress listeners, by calling their + * imageStarted methods, that image loading has started on the given + * image. + * + * @param imageIndex the frame index of the image that has started + * loading + */ protected void processImageStarted(int imageIndex) { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOWriteProgressListener listener = (IIOWriteProgressListener) it.next(); - listener.imageStarted(this, imageIndex); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOWriteProgressListener listener = + (IIOWriteProgressListener) it.next(); + listener.imageStarted(this, imageIndex); + } } } + /** + * Notifies all installed write progress listeners, by calling their + * thumbnailComplete methods, that a thumbnail has completed + * loading. + */ protected void processThumbnailComplete() { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOWriteProgressListener listener = (IIOWriteProgressListener) it.next(); - listener.thumbnailComplete(this); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOWriteProgressListener listener = + (IIOWriteProgressListener) it.next(); + listener.thumbnailComplete(this); + } } } + /** + * Notifies all installed write progress listeners that a certain + * percentage of a thumbnail has been loaded, by calling their + * thumbnailProgress methods. + * + * @param percentageDone the percentage of thumbnail data that has + * been loaded + */ protected void processThumbnailProgress(float percentageDone) { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOWriteProgressListener listener = (IIOWriteProgressListener) it.next(); - listener.thumbnailProgress(this, percentageDone); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOWriteProgressListener listener = + (IIOWriteProgressListener) it.next(); + listener.thumbnailProgress(this, percentageDone); + } } } + /** + * Notifies all installed write progress listeners, by calling their + * imageStarted methods, that thumbnail loading has started on the + * given thumbnail of the given image. + * + * @param imageIndex the frame index of the image one of who's + * thumbnails has started loading + * @param thumbnailIndex the index of the thumbnail that has started + * loading + */ protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOWriteProgressListener listener = (IIOWriteProgressListener) it.next(); - listener.thumbnailStarted(this, imageIndex, thumbnailIndex); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOWriteProgressListener listener = + (IIOWriteProgressListener) it.next(); + listener.thumbnailStarted(this, imageIndex, thumbnailIndex); + } } } + /** + * Notifies all installed warning listeners, by calling their + * warningOccurred methods, that a warning message has been raised. + * + * @param imageIndex the index of the image that was being written + * when the warning was raised + * @param warning the warning message + * + * @exception IllegalArgumentException if warning is null + */ protected void processWarningOccurred(int imageIndex, String warning) { - Iterator it = warningListeners.iterator(); + if (warningListeners != null) + { + Iterator it = warningListeners.iterator(); + + while (it.hasNext()) + { + IIOWriteWarningListener listener = + (IIOWriteWarningListener) it.next(); + listener.warningOccurred(this, imageIndex, warning); + } + } + } + + /** + * Notify all installed warning listeners, by calling their + * warningOccurred methods, that a warning message has been raised. + * The warning message is retrieved from a resource bundle, using + * the given basename and keyword. + * + * @param imageIndex the index of the image that was being written + * when the warning was raised + * @param baseName the basename of the resource from which to + * retrieve the warning message + * @param keyword the keyword used to retrieve the warning from the + * resource bundle + * + * @exception IllegalArgumentException if either baseName or keyword + * is null + * @exception IllegalArgumentException if no resource bundle is + * found using baseName + * @exception IllegalArgumentException if the given keyword produces + * no results from the resource bundle + * @exception IllegalArgumentException if the retrieved object is + * not a String + */ + protected void processWarningOccurred(int imageIndex, + String baseName, + String keyword) + { + if (baseName == null || keyword == null) + throw new IllegalArgumentException ("null argument"); + + ResourceBundle b = null; - while (it.hasNext()) + try { - IIOWriteWarningListener listener = (IIOWriteWarningListener) it.next(); - listener.warningOccurred(this, imageIndex, warning); + b = ResourceBundle.getBundle(baseName, getLocale()); + } + catch (MissingResourceException e) + { + throw new IllegalArgumentException ("no resource bundle found"); + } + + Object str = null; + + try + { + str = b.getObject(keyword); + } + catch (MissingResourceException e) + { + throw new IllegalArgumentException ("no results found for keyword"); + } + + if (! (str instanceof String)) + throw new IllegalArgumentException ("retrieved object not a String"); + + String warning = (String) str; + + if (warningListeners != null) + { + Iterator it = warningListeners.iterator(); + + while (it.hasNext()) + { + IIOWriteWarningListener listener = + (IIOWriteWarningListener) it.next(); + listener.warningOccurred(this, imageIndex, warning); + } } } + /** + * Notifies all installed write progress listeners that image + * loading has been aborted by calling their writeAborted methods. + */ protected void processWriteAborted() { - Iterator it = progressListeners.iterator(); - - while (it.hasNext()) + if (progressListeners != null) { - IIOWriteProgressListener listener = (IIOWriteProgressListener) it.next(); - listener.writeAborted(this); + Iterator it = progressListeners.iterator(); + + while (it.hasNext()) + { + IIOWriteProgressListener listener = + (IIOWriteProgressListener) it.next(); + listener.writeAborted(this); + } } } + /** + * Uninstall all write progress listeners. + */ public void removeAllIIOWriteProgressListeners() { - progressListeners.clear(); + if (progressListeners != null) + { + progressListeners.clear(); + } } + /** + * Uninstall all write warning listeners. + */ public void removeAllIIOWriteWarningListeners() { - progressListeners.clear(); + if (progressListeners != null) + { + progressListeners.clear(); + } } - - public void removeIIOWriteProgressListener (IIOWriteProgressListener listener) + + /** + * Uninstall the given write progress listener. + * + * @param listener the listener to remove + */ + public void removeIIOWriteProgressListener (IIOWriteProgressListener listener) { if (listener == null) return; - - progressListeners.remove(listener); + if (progressListeners != null) + { + progressListeners.remove(listener); + } } - + /** + * Uninstall the given write warning listener. + * + * @param listener the listener to remove + */ public void removeIIOWriteWarningListener (IIOWriteWarningListener listener) { if (listener == null) return; - - warningListeners.remove(listener); + if (warningListeners != null) + { + warningListeners.remove(listener); + } } - + /** + * Reset this writer's internal state. + */ public void reset() { setOutput(null); @@ -343,6 +867,11 @@ public abstract class ImageWriter clearAbortRequest(); } + /** + * Set the current locale or use the default locale. + * + * @param locale the locale to set, or null + */ public void setLocale(Locale locale) { if (locale != null) @@ -362,6 +891,18 @@ public abstract class ImageWriter this.locale = locale; } + /** + * Set the output destination of the given object. The output + * destination must be set before many methods can be called on this + * writer. (see all ImageWriter methods that throw + * IllegalStateException). If input is null then the current input + * source will be removed. + * + * @param input the output destination object + * + * @exception IllegalArgumentException if input is not a valid input + * source for this writer and is not an ImageInputStream + */ public void setOutput(Object output) { if (output != null) @@ -385,6 +926,464 @@ public abstract class ImageWriter this.output = output; } + /** + * Write an image stream, including thumbnails and metadata to the + * output stream. The output must have been set prior to this + * method being called. Metadata associated with the stream may be + * supplied, or it can be left null. IIOImage may contain raster + * data if this writer supports rasters, or it will contain a + * rendered image. Thumbnails are resized if need be. Image + * writing parameters may be specified to affect writing, or may be + * left null. + * + * @param streamMetadata metadata associated with this stream, or + * null + * @param image an IIOImage containing image data, metadata and + * thumbnails to be written + * @param param image writing parameters, or null + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if image contains raster + * data but this writer does not support rasters + * @exception IllegalArgumentException if image is null + * @exception IOException if a write error occurs + */ public abstract void write (IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException; + + /** + * Complete inserting an empty image in the output stream. + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if inserting empty + * images is not supported + * @exception IllegalArgumentException if a call to + * prepareInsertEmpty was not called previous to this method being + * called (a sequence of prepareInsertEmpty calls must be terminated + * by a call to endInsertEmpty) + * @exception IllegalArgumentException if prepareWriteEmpty was + * called before this method being called (without a terminating + * call to endWriteEmpty) + * @exception IllegalArgumentException if prepareReplacePixels was + * called before this method being called (without a terminating + * call to endReplacePixels) + * @exception IOException if a write error occurs + */ + public void endInsertEmpty () + throws IOException + { + if (!canInsertEmpty(0)) + throw new UnsupportedOperationException(); + } + + /** + * Complete replacing pixels in an image in the output stream. + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if replacing pixels is + * not supported by this writer + * @exception IllegalArgumentException if prepareReplacePixels was + * not called before this method being called + * @exception IOException if a write error occurs + */ + public void endReplacePixels () + throws IOException + { + if (!canReplacePixels(0)) + throw new UnsupportedOperationException(); + } + + /** + * Complete writing an empty image to the image output stream. + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if writing empty images + * is not supported + * @exception IllegalArgumentException if a call to + * prepareWriteEmpty was not called previous to this method being + * called (a sequence of prepareWriteEmpty calls must be terminated + * by a call to endWriteEmpty) + * @exception IllegalArgumentException if prepareInsertEmpty was + * called before this method being called (without a terminating + * call to endInsertEmpty) + * @exception IllegalArgumentException if prepareReplacePixels was + * called before this method being called (without a terminating + * call to endReplacePixels) + * @exception IOException if a write error occurs + */ + public void endWriteEmpty () + throws IOException + { + if (!canWriteEmpty()) + throw new UnsupportedOperationException(); + } + + /** + * Complete writing a sequence of images to the output stream. This + * method may patch header data and write out footer data. + * + * @exception IllegalStateException if output is null + * @exception IllegalStateException if prepareWriteSequence has not + * been called + * @exception UnsupportedOperationException if writing a sequence of + * images is not supported + * @exception IOException if a write error occurs + */ + public void endWriteSequence () + throws IOException + { + checkOutputSet(); + if (!canWriteSequence()) + throw new UnsupportedOperationException(); + } + + /** + * Start inserting an empty image in the image output stream. All + * indices after the specified index are incremented. An index of + * -1 implies that the empty image should be appended to the end of + * the current image list. + * + * The insertion that this method call starts is not complete until + * endInsertEmpty is called. prepareInsertEmpty cannot be called + * again until endInsertEmpty is called and calls to + * prepareWriteEmpty and prepareInsertEmpty may not be intersperced. + * + * @param imageIndex the image index + * @param imageType the image type specifier + * @param width the image width + * @param height the image height + * @param imageMetadata the image metadata, or null + * @param thumbnails a list of thumbnails, or null + * @param param image write parameters, or null + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if inserting empty + * images is not supported + * @exception IndexOutOfBoundsException if imageIndex is less than + * -1 or greater than the last index in the current image list + * @exception IllegalStateException if a previous call to + * prepareInsertEmpty was made (without a terminating call to + * endInsertEmpty) + * @exception IllegalStateException if a previous call to + * prepareWriteEmpty was made (without a terminating call to + * endWriteEmpty) + * @exception IllegalArgumentException if imageType is null or + * thumbnails contain non-BufferedImage objects + * @exception IllegalArgumentException if either width or height is + * less than 1 + * @exception IOException if a write error occurs + */ + public void prepareInsertEmpty (int imageIndex, ImageTypeSpecifier imageType, + int width, int height, + IIOMetadata imageMetadata, + List thumbnails, + ImageWriteParam param) + throws IOException + { + if (!canInsertEmpty(imageIndex)) + throw new UnsupportedOperationException(); + } + + /** + * Start the replacement of pixels within an image in the output + * stream. Output pixels will be clipped to lie within region. + * + * @param imageIndex the index of the image in which pixels are + * being replaced + * @param region the rectangle to which to limit pixel replacement + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if replacing pixels is + * not supported + * @exception IndexOutOfBoundsException if imageIndex is less than 0 + * or greater than the last index in the current image list + * @exception IllegalStateException if a previous call to + * prepareReplacePixels was made (without a terminating call to + * endReplacePixels) + * @exception IllegalArgumentException if either region.width or + * region.height is less than 1, or if region is null + * @exception IOException if a write error occurs + */ + public void prepareReplacePixels (int imageIndex, Rectangle region) + throws IOException + { + if (canReplacePixels(imageIndex)) + throw new UnsupportedOperationException(); + } + + /** + * Start writing an empty image to the end of the image output + * stream. + * + * The writing that this method call starts is not complete until + * endWriteEmpty is called. prepareWritetEmpty cannot be called + * again until endWriteEmpty is called and calls to + * prepareWriteEmpty and prepareInsertEmpty may not be intersperced. + * + * @param streamMetadata metadata associated with the stream, or null + * @param imageType the image type specifier + * @param width the image width + * @param height the image height + * @param imageMetadata the image metadata, or null + * @param thumbnails a list of thumbnails, or null + * @param param image write parameters, or null + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if writing empty images + * is not supported + * @exception IndexOutOfBoundsException if imageIndex is less than + * -1 or greater than the last index in the current image list + * @exception IllegalStateException if a previous call to + * prepareInsertEmpty was made (without a terminating call to + * endInsertEmpty) + * @exception IllegalStateException if a previous call to + * prepareWriteEmpty was made (without a terminating call to + * endWriteEmpty) + * @exception IllegalArgumentException if imageType is null or + * thumbnails contain non-BufferedImage objects + * @exception IllegalArgumentException if either width or height is + * less than 1 + * @exception IOException if a write error occurs + */ + public void prepareWriteEmpty (IIOMetadata streamMetadata, + ImageTypeSpecifier imageType, + int width, int height, + IIOMetadata imageMetadata, + List thumbnails, + ImageWriteParam param) + throws IOException + { + if (!canWriteEmpty()) + throw new UnsupportedOperationException(); + } + + /** + * Start the writing of a sequence of images. + * + * @param streamMetadata the stream metadata, or null + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if writing sequences of + * images is not supported + * @exception IOException if a write error occurs + */ + public void prepareWriteSequence (IIOMetadata streamMetadata) + throws IOException + { + checkOutputSet(); + if (!canWriteSequence()) + throw new UnsupportedOperationException(); + } + + /** + * Remove the image at the specified index from the output stream. + * + * @param imageIndex the frame index from which to remove the image + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if removing this image + * is not supported + * @exception IndexOutOfBoundsException if imageIndex is less than 0 + * or greater than the last index in the current image list + * @exception IOException if a write error occurs + */ + public void removeImage (int imageIndex) + throws IOException + { + if (!canRemoveImage(imageIndex)) + throw new UnsupportedOperationException(); + } + + /** + * Replace the metadata associated with the image at the given + * index. + * + * @param imageIndex the index of the image whose metadata should be + * replaced + * @param imageMetadata the metadata, or null + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if replacing this + * image's metadata is not supported + * @exception IndexOutOfBoundsException if imageIndex is less than 0 + * or greater than the last index in the current image list + * @exception IOException if a write error occurs + */ + public void replaceImageMetadata (int imageIndex, IIOMetadata imageMetadata) + throws IOException + { + if (!canReplaceImageMetadata(imageIndex)) + throw new UnsupportedOperationException(); + } + + /** + * Replace a region of an image in the output stream with a portion + * of the given rendered image. The image data must be of the same + * type as that in the output stream. The destination region is + * given by the image writing parameters and the source region is + * the one given to prepareReplacePixels. + * + * @param image the rendered image with which to overwrite the image + * region in the stream + * @param param the image writing parameters + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if replacing pixels is + * not supported + * @exception IllegalStateException if prepareReplacePixels was not + * called before this method was called + * @exception IllegalArgumentException if image is null or if param + * is null or if the overlap of the source and destination regions + * contains no pixels or if the image types differ and no conversion + * is possible + * @exception IOException if a write error occurs + */ + public void replacePixels (RenderedImage image, + ImageWriteParam param) + throws IOException + { + if (!canReplacePixels(0)) + throw new UnsupportedOperationException(); + } + + /** + * Replace a region of an image in the output stream with a portion + * of the given raster data. The image data must be of the same + * type as that in the output stream. The destination region is + * given by the image writing parameters and the source region is + * the one given to prepareReplacePixels. + * + * @param raster the raster data with which to overwrite the image + * region in the stream + * @param param the image writing parameters + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if replacing pixels is + * not supported + * @exception IllegalStateException if prepareReplacePixels was not + * called before this method was called + * @exception UnsupportedOperationException if raster data is not + * supported + * @exception IllegalArgumentException if raster is null or if param + * is null or if the overlap of the source and destination regions + * contains no pixels or if the image types differ and no conversion + * is possible + * @exception IOException if a write error occurs + */ + public void replacePixels (Raster raster, ImageWriteParam param) + throws IOException + { + if (!canReplacePixels(0)) + throw new UnsupportedOperationException(); + } + + /** + * Replace the metadata associated with this image stream. + * + * @param streamMetadata the stream metadata, or null + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if replacing the stream + * metadata is not supported + * @exception IOException if a write error occurs + */ + public void replaceStreamMetadata (IIOMetadata streamMetadata) + throws IOException + { + if (!canReplaceStreamMetadata()) + throw new UnsupportedOperationException(); + } + + /** + * Write a rendered image to the output stream. + * + * @param image a rendered image containing image data to be written + * + * @exception IllegalStateException if output is null + * @exception IllegalArgumentException if image is null + * @exception IOException if a write error occurs + */ + public void write (RenderedImage image) + throws IOException + { + checkOutputSet(); + write (null, new IIOImage(image, null, null), null); + } + + /** + * Write a image data, metadata and thumbnails to the output stream. + * + * @param image image data, metadata and thumbnails to be written + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if image contains raster + * data but this writer does not support rasters + * @exception IllegalArgumentException if image is null + * @exception IOException if a write error occurs + */ + public void write (IIOImage image) + throws IOException + { + checkOutputSet(); + write (null, image, null); + } + + /** + * Insert an image into the output stream. Indices greater than the + * specified index are incremented accordingly. Specifying an index + * of -1 causes the image to be appended at the end of the current + * image list. + * + * @param imageIndex the frame index at which to insert the image + * @param image the image data, metadata and thumbnails to be + * inserted + * @param the image write parameters, or null + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if image insertion is + * not supported + * @exception IllegalArgumentException if image is null + * @exception IndexOutOfBoundsException if imageIndex is less than + * -1 or greater than the last index in the current image list + * @exception UnsupportedOperationException if image contains raster + * data but this writer does not support rasters + * @exception IOException if a write error occurs + */ + public void writeInsert (int imageIndex, IIOImage image, ImageWriteParam param) + throws IOException + { + if (!canInsertImage(imageIndex)) + throw new UnsupportedOperationException(); + } + + /** + * Write a sequence of images, including thumbnails and metadata, to + * the output stream. The output must have been set prior to this + * method being called. Metadata associated with the stream may be + * supplied, or it can be left null. IIOImage may contain raster + * data if this writer supports rasters, or it will contain a + * rendered image. Thumbnails are resized if need be. Image + * writing parameters may be specified to affect writing, or may be + * left null. + * + * @param streamMetadata metadata associated with this stream, or + * null + * @param image an IIOImage containing image data, metadata and + * thumbnails to be written + * @param param image writing parameters, or null + * + * @exception IllegalStateException if output is null + * @exception UnsupportedOperationException if writing sequences of + * images is not supported + * @exception IllegalArgumentException if image is null + * @exception UnsupportedOperationException if image contains raster + * data but this writer does not support rasters + * @exception IOException if a write error occurs + */ + public void writeToSequence (IIOImage image, ImageWriteParam param) + throws IOException + { + if (!canWriteSequence()) + throw new UnsupportedOperationException(); + } } diff --git a/libjava/classpath/javax/imageio/metadata/IIOAttr.java b/libjava/classpath/javax/imageio/metadata/IIOAttr.java deleted file mode 100644 index 0c1d3d2ef3f..00000000000 --- a/libjava/classpath/javax/imageio/metadata/IIOAttr.java +++ /dev/null @@ -1,378 +0,0 @@ -/* IIOAttr.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package javax.imageio.metadata; - -import org.w3c.dom.Attr; -import org.w3c.dom.DOMException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.TypeInfo; -import org.w3c.dom.UserDataHandler; - -/** - * Simple Attr node for metadata trees - * - * @author jlquinn - */ -class IIOAttr implements Attr -{ - String name; - String value; - IIOMetadataNode owner; - - public IIOAttr(String name, String value, IIOMetadataNode owner) - { - this.name = name; - this.value = value; - this.owner = owner; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Attr#getName() - */ - public String getName() - { - return name; - } - - public TypeInfo getSchemaTypeInfo() - { - throw new Error("not implemented"); - } - - /* (non-Javadoc) - * @see org.w3c.dom.Attr#getSpecified() - */ - public boolean getSpecified() - { - // I don't think there can be default attrs in metadata - return true; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Attr#getValue() - */ - public String getValue() - { - return value; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Attr#setValue(java.lang.String) - */ - public void setValue(String value) throws DOMException - { - this.value = value; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Attr#getOwnerElement() - */ - public Element getOwnerElement() - { - return owner; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#getNodeName() - */ - public String getNodeName() - { - return name; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#getNodeValue() - */ - public String getNodeValue() throws DOMException - { - return value; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#setNodeValue(java.lang.String) - */ - public void setNodeValue(String nodeValue) throws DOMException - { - this.value = nodeValue; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#getNodeType() - */ - public short getNodeType() - { - return ATTRIBUTE_NODE; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#getParentNode() - */ - public Node getParentNode() - { - return null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#getChildNodes() - */ - public NodeList getChildNodes() - { - return null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#getFirstChild() - */ - public Node getFirstChild() - { - return null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#getLastChild() - */ - public Node getLastChild() - { - return null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#getPreviousSibling() - */ - public Node getPreviousSibling() - { - return null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#getNextSibling() - */ - public Node getNextSibling() - { - return null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#getAttributes() - */ - public NamedNodeMap getAttributes() - { - return null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#getOwnerDocument() - */ - public Document getOwnerDocument() - { - return null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#insertBefore(org.w3c.dom.Node, org.w3c.dom.Node) - */ - public Node insertBefore(Node newChild, Node refChild) throws DOMException - { - return null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#replaceChild(org.w3c.dom.Node, org.w3c.dom.Node) - */ - public Node replaceChild(Node newChild, Node oldChild) throws DOMException - { - return null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#removeChild(org.w3c.dom.Node) - */ - public Node removeChild(Node oldChild) throws DOMException - { - return null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#appendChild(org.w3c.dom.Node) - */ - public Node appendChild(Node newChild) throws DOMException - { - return null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#hasChildNodes() - */ - public boolean hasChildNodes() - { - return false; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#cloneNode(boolean) - */ - public Node cloneNode(boolean deep) - { - return new IIOAttr(name, value, owner); - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#normalize() - */ - public void normalize() - { - } - - public boolean isDefaultNamespace(String namespaceURI) - { - throw new Error("not implemented"); - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#isSupported(java.lang.String, java.lang.String) - */ - public boolean isSupported(String feature, String version) - { - return false; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#getNamespaceURI() - */ - public String getNamespaceURI() - { - return null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#getPrefix() - */ - public String getPrefix() - { - return null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#setPrefix(java.lang.String) - */ - public void setPrefix(String prefix) throws DOMException - { - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#getLocalName() - */ - public String getLocalName() - { - return name; - } - - public Object getUserData(String key) - { - throw new Error("not implemented"); - } - - /* (non-Javadoc) - * @see org.w3c.dom.Node#hasAttributes() - */ - public boolean hasAttributes() - { - return false; - } - - public boolean isId() - { - throw new Error("not implemented"); - } - - public String lookupNamespaceURI(String prefix) - { - throw new Error("not implemented"); - } - - public String lookupPrefix(String namespaceURI) - { - throw new Error("not implemented"); - } - - public Object setUserData(String key, Object data, UserDataHandler handler) - { - throw new Error("not implemented"); - } - - public String getBaseURI() - { - throw new Error("not implemented"); - } - - public String getTextContent() - { - throw new Error("not implemented"); - } - - public void setTextContent(String textContent) - { - throw new Error("not implemented"); - } - - public short compareDocumentPosition(Node other) - throws DOMException - { - throw new Error("not implemented"); - } - - public Object getFeature(String feature, String version) - { - throw new Error("not implemented"); - } - - public boolean isEqualNode(Node other) - { - throw new Error("not implemented"); - } - - public boolean isSameNode(Node other) - { - throw new Error("not implemented"); - } -} diff --git a/libjava/classpath/javax/imageio/metadata/IIOMetadata.java b/libjava/classpath/javax/imageio/metadata/IIOMetadata.java index d727e1d1e51..e5105de2caf 100644 --- a/libjava/classpath/javax/imageio/metadata/IIOMetadata.java +++ b/libjava/classpath/javax/imageio/metadata/IIOMetadata.java @@ -38,8 +38,41 @@ exception statement from your version. */ package javax.imageio.metadata; +import org.w3c.dom.Node; + /** + * Represents metadata that describe an image or an image stream. + * Each ImageIO plugin will represent image data using an opaque + * object but all such objects should expose their internal + * information as a tree of IIOMetadataNodes. + * + * There are three formats of metadata that a plugin can support: + * + * <ul> + * <li>a "native" format</li> + * <li>a custom format</li> + * <li>a standard plugin-neutral format</li> + * </ul> + * + * If a plugin supports more than one format of metadata, the other + * formats can be retrieved by calling getMetadataFormatNames. + * + * The native format is used to transfer metadata from one image to + * another image of the same type, losslessly. + * + * The custom format describes the image metadata and exposes a tree + * of IIOMetadataNodes but its internal representation is specific to + * this plugin. + * + * The plugin-neutral format uses a generic tree structure as its + * internal representation. + * + * ImageTranscoders may be used to convert metadata understood by one + * plugin to metadata understood by another, however the conversion + * may be lossy. + * * @author Michael Koch (konqueror@gmx.de) + * @author Thomas Fitzsimmons (fitzsim@redhat.com) */ public abstract class IIOMetadata { @@ -52,7 +85,7 @@ public abstract class IIOMetadata protected boolean standardFormatSupported; /** - * Creates a <code>IIOMetaData</code> object. + * Construct an IIOMetadata object. */ protected IIOMetadata() { @@ -60,7 +93,7 @@ public abstract class IIOMetadata } /** - * Creates a <code>IIOMetaData</code> object with the given arguments. + * Construct an IIOMetadata object. * * @param standardMetadataFormatSupported * @param nativeMetadataFormatName @@ -210,4 +243,81 @@ public abstract class IIOMetadata { this.controller = controller; } + + public abstract Node getAsTree (String formatName); + + protected IIOMetadataNode getStandardChromaNode () + { + return null; + } + + protected IIOMetadataNode getStandardCompressionNode () + { + return null; + } + + protected IIOMetadataNode getStandardDataNode () + { + return null; + } + + protected IIOMetadataNode getStandardDimensionNode () + { + return null; + } + + protected IIOMetadataNode getStandardDocumentNode () + { + return null; + } + + protected IIOMetadataNode getStandardTextNode () + { + return null; + } + + protected IIOMetadataNode getStandardTileNode () + { + return null; + } + + protected IIOMetadataNode getStandardTransparencyNode () + { + return null; + } + + private void appendChild (IIOMetadataNode node, + IIOMetadataNode child) + { + if (child != null) + node.appendChild(child); + } + + protected final IIOMetadataNode getStandardTree () + { + IIOMetadataNode node = new IIOMetadataNode(); + + appendChild (node, getStandardChromaNode()); + appendChild (node, getStandardCompressionNode()); + appendChild (node, getStandardDataNode()); + appendChild (node, getStandardDimensionNode()); + appendChild (node, getStandardDocumentNode()); + appendChild (node, getStandardTextNode()); + appendChild (node, getStandardTileNode()); + appendChild (node, getStandardTransparencyNode()); + + return node; + } + + public abstract void mergeTree (String formatName, + Node root) + throws IIOInvalidTreeException; + + public void setFromTree (String formatName, Node root) + throws IIOInvalidTreeException + { + reset(); + + mergeTree (formatName, root); + } } diff --git a/libjava/classpath/javax/imageio/metadata/IIOMetadataFormatImpl.java b/libjava/classpath/javax/imageio/metadata/IIOMetadataFormatImpl.java index 2ce8f9c3d4b..aad30447c2f 100644 --- a/libjava/classpath/javax/imageio/metadata/IIOMetadataFormatImpl.java +++ b/libjava/classpath/javax/imageio/metadata/IIOMetadataFormatImpl.java @@ -38,6 +38,848 @@ exception statement from your version. */ package javax.imageio.metadata; +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.TypeInfo; +import org.w3c.dom.UserDataHandler; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.MissingResourceException; +import javax.imageio.ImageTypeSpecifier; + public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { + /** + * The standard metadata format name constant set to + * "javax_imageio_1.0". + */ + public static final String standardMetadataFormatName = "javax_imageio_1.0"; + + private String rootName; + + // These maps assume that each element name is unique. + + private Map nodes = new HashMap(); + + // A mapping from element name to child policy. + private Map childPolicies = new HashMap(); + + // A mapping from element name to the permissible number of + // children. Values in this map are length-two integer arrays; the + // first index is the minimum bound, the second index is the maximum + // bound. + private Map childRanges = new HashMap(); + + private String resourceBaseName; + + // Package-private so that it may be used in IIOMetadataNode. + static class IIOMetadataNodeAttr extends IIOMetadataNode + implements Attr + { + protected Element owner; + protected String name; + protected int dataType; + protected boolean required; + protected String defaultValue; + + public IIOMetadataNodeAttr (Element owner, + String name, + String defaultValue) + { + this (owner, name, IIOMetadataFormat.DATATYPE_STRING, + true, defaultValue); + } + + public IIOMetadataNodeAttr (Element owner, + String name, + int dataType, + boolean required, + String defaultValue) + { + this.owner = owner; + this.name = name; + this.dataType = dataType; + this.required = required; + this.defaultValue = defaultValue; + } + + public String getName () + { + return name; + } + + public Element getOwnerElement () + { + return owner; + } + + public int getDataType () + { + return dataType; + } + + public TypeInfo getSchemaTypeInfo () + { + return null; + } + + public boolean getSpecified () + { + return false; + } + + public String getValue () + { + return defaultValue; + } + + public boolean isId() + { + return false; + } + + public void setValue (String value) + { + } + + // new methods + + public boolean isRequired () + { + return required; + } + } + + private class IIOMetadataNodeAttrEnumerated extends IIOMetadataNodeAttr + { + protected List enumeratedValues; + + public IIOMetadataNodeAttrEnumerated (Element owner, + String name, + int dataType, + boolean required, + String defaultValue, + List enumeratedValues) + { + super (owner, name, dataType, required, defaultValue); + this.enumeratedValues = new ArrayList (enumeratedValues); + } + + public Object[] getEnumerations () + { + return enumeratedValues.toArray (); + } + } + + private class IIOMetadataNodeAttrBounded extends IIOMetadataNodeAttr + { + protected String minValue; + protected String maxValue; + protected boolean minInclusive; + protected boolean maxInclusive; + + public IIOMetadataNodeAttrBounded (Element owner, + String name, + int dataType, + boolean required, + String defaultValue, + String minValue, + String maxValue, + boolean minInclusive, + boolean maxInclusive) + { + super (owner, name, dataType, required, defaultValue); + this.minValue = minValue; + this.maxValue = maxValue; + this.minInclusive = minInclusive; + this.maxInclusive = maxInclusive; + } + + public String getMinValue () + { + return minValue; + } + + public String getMaxValue () + { + return maxValue; + } + } + + private class IIOMetadataNodeAttrList extends IIOMetadataNodeAttr + { + protected int listMinLength; + protected int listMaxLength; + + public IIOMetadataNodeAttrList (Element owner, + String name, + int dataType, + boolean required, + int listMinLength, + int listMaxLength) + { + super (owner, name, dataType, required, null); + this.listMinLength = listMinLength; + this.listMaxLength = listMaxLength; + } + + public int getListMinLength () + { + return listMinLength; + } + + public int getListMaxLength () + { + return listMaxLength; + } + } + + private class NodeObject + { + protected Element owner; + protected Class classType; + protected boolean required; + protected Object defaultValue; + protected int valueType; + + public NodeObject (Element owner, + Class classType, + boolean required, + Object defaultValue) + { + this.owner = owner; + this.classType = classType; + this.required = required; + this.defaultValue = defaultValue; + valueType = IIOMetadataFormat.VALUE_ARBITRARY; + } + + public int getValueType () + { + return valueType; + } + + public Class getClassType () + { + return classType; + } + + public Element getOwnerElement () + { + return owner; + } + + public Object getDefaultValue () + { + return defaultValue; + } + + public boolean isRequired () + { + return required; + } + } + + private class NodeObjectEnumerated extends NodeObject + { + protected List enumeratedValues; + + public NodeObjectEnumerated (Element owner, + Class classType, + boolean required, + Object defaultValue, + List enumeratedValues) + { + super (owner, classType, false, defaultValue); + this.enumeratedValues = enumeratedValues; + valueType = IIOMetadataFormat.VALUE_ENUMERATION; + } + + public Object[] getEnumerations () + { + return enumeratedValues.toArray(); + } + } + + private class NodeObjectBounded extends NodeObject + { + protected Comparable minValue; + protected Comparable maxValue; + protected boolean minInclusive; + protected boolean maxInclusive; + + public NodeObjectBounded (Element owner, + Class classType, + Object defaultValue, + Comparable minValue, + Comparable maxValue, + boolean minInclusive, + boolean maxInclusive) + { + super (owner, classType, false, defaultValue); + this.minValue = minValue; + this.maxValue = maxValue; + this.minInclusive = minInclusive; + this.maxInclusive = maxInclusive; + if (minInclusive) + { + if (maxInclusive) + valueType = IIOMetadataFormat.VALUE_RANGE_MIN_MAX_INCLUSIVE; + else + valueType = IIOMetadataFormat.VALUE_RANGE_MIN_INCLUSIVE; + } + else + { + if (maxInclusive) + valueType = IIOMetadataFormat.VALUE_RANGE_MAX_INCLUSIVE; + else + valueType = IIOMetadataFormat.VALUE_RANGE; + } + } + + public Comparable getMinValue () + { + return minValue; + } + + public Comparable getMaxValue () + { + return maxValue; + } + } + + private class NodeObjectArray extends NodeObject + { + protected Integer arrayMinLength; + protected Integer arrayMaxLength; + + public NodeObjectArray (Element owner, + Class classType, + int arrayMinLength, + int arrayMaxLength) + { + super (owner, classType, false, null); + this.arrayMinLength = new Integer (arrayMinLength); + this.arrayMaxLength = new Integer (arrayMaxLength); + valueType = IIOMetadataFormat.VALUE_LIST; + } + + public Comparable getArrayMinLength () + { + return arrayMinLength; + } + + public Comparable getArrayMaxLength () + { + return arrayMaxLength; + } + } + + /** + * Construct a blank IIOMetadataFormatImpl with the given root name + * and child policy. + * + * @param rootName the root element name + * @param childPolicy the child policy of the root element + * + * @exception IllegalArgumentException if rootName is null + * @exception IllegalArgumentException if childPolicy is + * CHILD_POLICY_REPEAT or if childPolicy is not a CHILD_POLICY + * constant + */ + public IIOMetadataFormatImpl (String rootName, int childPolicy) + { + if (rootName == null) + throw new IllegalArgumentException ("null argument"); + + if (childPolicy < IIOMetadataFormat.CHILD_POLICY_ALL + || childPolicy > IIOMetadataFormat.CHILD_POLICY_SOME + || childPolicy == IIOMetadataFormat.CHILD_POLICY_REPEAT) + throw new IllegalArgumentException ("wrong child policy"); + + nodes.put (rootName, new IIOMetadataNode (rootName)); + childPolicies.put (rootName, new Integer (childPolicy)); + this.rootName = rootName; + } + + /** + * Construct a blank IIOMetadataFormatImpl with the given root name, + * a child policy of CHILD_POLICY_REPEAT and the given minimum and + * maximum limits on the number of root element children. + * + * @param rootName the root element name + * @param minChildren the minimum number of children that this node + * can have + * @param maxChildren the maximum number of children that this node + * can have + * + * @exception IllegalArgumentException if rootName is null + * @exception IllegalArgumentException if minChildren is less than + * zero or greater than maxChildren + */ + public IIOMetadataFormatImpl (String rootName, + int minChildren, + int maxChildren) + { + if (rootName == null) + throw new IllegalArgumentException ("null argument"); + + if (minChildren < 0 || maxChildren < minChildren) + throw new IllegalArgumentException ("invalid min or max children argument"); + + nodes.put (rootName, new IIOMetadataNode (rootName)); + childPolicies.put (rootName, new Integer (IIOMetadataFormat.CHILD_POLICY_REPEAT)); + childRanges.put (rootName, new int [] { minChildren, maxChildren }); + this.rootName = rootName; + } + + protected void addAttribute (String elementName, + String attrName, + int dataType, + boolean required, + String defaultValue) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + node.setAttributeNode (new IIOMetadataNodeAttr (node, + attrName, + dataType, + required, + defaultValue)); + } + + protected void addAttribute (String elementName, + String attrName, + int dataType, + boolean required, + String defaultValue, + List enumeratedValues) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + node.setAttributeNode (new IIOMetadataNodeAttrEnumerated (node, + attrName, + dataType, + required, + defaultValue, + enumeratedValues)); + } + + protected void addAttribute (String elementName, + String attrName, + int dataType, + boolean required, + String defaultValue, + String minValue, + String maxValue, + boolean minInclusive, + boolean maxInclusive) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + node.setAttributeNode (new IIOMetadataNodeAttrBounded (node, + attrName, + dataType, + required, + defaultValue, + minValue, + maxValue, + minInclusive, + maxInclusive)); + } + + protected void addAttribute (String elementName, + String attrName, + int dataType, + boolean required, + int listMinLength, + int listMaxLength) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + node.setAttributeNode (new IIOMetadataNodeAttrList (node, + attrName, + dataType, + required, + listMinLength, + listMaxLength)); + } + + protected void addBooleanAttribute (String elementName, + String attrName, + boolean hasDefaultValue, + boolean defaultValue) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + + List enumeratedValues = new ArrayList(); + enumeratedValues.add ("TRUE"); + enumeratedValues.add ("FALSE"); + + node.setAttributeNode (new IIOMetadataNodeAttrEnumerated (node, + attrName, + IIOMetadataFormat.DATATYPE_BOOLEAN, + hasDefaultValue, + defaultValue ? "TRUE" : "FALSE", + enumeratedValues)); + } + + protected void addChildElement (String elementName, String parentName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (parentName); + + node.appendChild (new IIOMetadataNode (elementName)); + childPolicies.put (elementName, new Integer (IIOMetadataFormat.CHILD_POLICY_REPEAT)); + } + + protected void addElement (String elementName, String parentName, int childPolicy) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (parentName); + + node.appendChild (new IIOMetadataNode (elementName)); + childPolicies.put (elementName, new Integer (childPolicy)); + } + + protected void addElement (String elementName, String parentName, + int minChildren, int maxChildren) + { + addChildElement (elementName, parentName); + childRanges.put (elementName, new int [] { minChildren, maxChildren }); + } + + private void addNodeObject (IIOMetadataNode node, NodeObject o) + { + node.setUserObject (o); + } + + private NodeObject getNodeObject (IIOMetadataNode node) + { + return (NodeObject) node.getUserObject (); + } + + private void removeNodeObject (IIOMetadataNode node) + { + node.setUserObject (null); + } + + protected void addObjectValue (String elementName, Class classType, + boolean required, Object defaultValue) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + addNodeObject (node, new NodeObject (node, + classType, + required, + defaultValue)); + } + + protected void addObjectValue (String elementName, Class classType, + boolean required, Object defaultValue, + List enumeratedValues) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + addNodeObject (node, new NodeObjectEnumerated (node, + classType, + required, + defaultValue, + enumeratedValues)); + } + + protected void addObjectValue (String elementName, Class classType, + Object defaultValue, + Comparable minValue, + Comparable maxValue, + boolean minInclusive, + boolean maxInclusive) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + addNodeObject (node, new NodeObjectBounded (node, + classType, + defaultValue, + minValue, + maxValue, + minInclusive, + maxInclusive)); + } + + protected void addObjectValue (String elementName, Class classType, + int arrayMinLength, int arrayMaxLength) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + addNodeObject (node, new NodeObjectArray (node, + classType, + arrayMinLength, + arrayMaxLength)); + } + + public String getRootName () + { + return rootName; + } + + protected String getResourceBaseName () + { + return resourceBaseName; + } + + public static IIOMetadataFormat getStandardFormatInstance () + { + // FIXME: populate this with the standard metadata format + return new IIOMetadataFormatImpl (standardMetadataFormatName, + IIOMetadataFormat.CHILD_POLICY_ALL) + { + public boolean canNodeAppear (String elementName, + ImageTypeSpecifier specifier) + { + return true; + } + }; + } + + public abstract boolean canNodeAppear (String elementName, + ImageTypeSpecifier specifier); + + protected void removeAttribute (String elementName, + String attrName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + node.removeAttribute (attrName); + } + + protected void removeElement (String elementName) + { + nodes.remove (elementName); + } + + protected void removeObjectValue (String elementName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + removeNodeObject (node); + } + + protected void setResourceBaseName (String resourceBaseName) + { + this.resourceBaseName = resourceBaseName; + } + + public int getAttributeDataType (String elementName, String attrName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + IIOMetadataNodeAttr attr = (IIOMetadataNodeAttr) node.getAttributeNode (attrName); + return attr.getDataType (); + } + + public String getAttributeDefaultValue (String elementName, String attrName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + IIOMetadataNodeAttr attr = (IIOMetadataNodeAttr) node.getAttributeNode (attrName); + return attr.getValue(); + } + + public String getAttributeDescription (String elementName, String attrName, Locale locale) + { + return getDescription (elementName + "/" + attrName, locale); + } + + public String[] getAttributeEnumerations (String elementName, String attrName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + IIOMetadataNodeAttrEnumerated attr = + (IIOMetadataNodeAttrEnumerated) node.getAttributeNode (attrName); + + Object[] attrEnums = attr.getEnumerations(); + + String[] attrNames = new String[attrEnums.length]; + + for (int i = 0; i < attrEnums.length; i++) + { + attrNames[i] = (String) attrEnums[i]; + } + + return attrNames; + } + + public int getAttributeListMaxLength (String elementName, String attrName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + IIOMetadataNodeAttrList attr = + (IIOMetadataNodeAttrList) node.getAttributeNode (attrName); + return attr.getListMaxLength(); + } + + public int getAttributeListMinLength (String elementName, String attrName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + IIOMetadataNodeAttrList attr = + (IIOMetadataNodeAttrList) node.getAttributeNode (attrName); + return attr.getListMinLength(); + } + + public String getAttributeMaxValue (String elementName, String attrName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + IIOMetadataNodeAttrBounded attr = + (IIOMetadataNodeAttrBounded) node.getAttributeNode (attrName); + return attr.getMaxValue(); + } + + public String getAttributeMinValue (String elementName, String attrName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + IIOMetadataNodeAttrBounded attr = + (IIOMetadataNodeAttrBounded) node.getAttributeNode (attrName); + return attr.getMinValue(); + } + + public String[] getAttributeNames (String elementName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + + NamedNodeMap attrNodes = node.getAttributes(); + + String[] attrNames = new String[attrNodes.getLength()]; + + for (int i = 0; i < attrNodes.getLength(); i++) + { + attrNames[i] = attrNodes.item (i).getLocalName(); + } + + return attrNames; + } + + public int getAttributeValueType (String elementName, String attrName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + IIOMetadataNodeAttr attr = (IIOMetadataNodeAttr) node.getAttributeNode (attrName); + return attr.getDataType(); + } + + public String[] getChildNames (String elementName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + + NodeList childNodes = node.getChildNodes(); + + String[] childNames = new String[childNodes.getLength()]; + + for (int i = 0; i < childNodes.getLength(); i++) + { + childNames[i] = childNodes.item (i).getLocalName(); + } + + return childNames; + } + + public int getChildPolicy (String elementName) + { + return ((Integer) childPolicies.get (elementName)).intValue(); + } + + private String getDescription (String resourceName, Locale locale) + { + if (resourceBaseName == null) + return null; + + Locale l = locale; + + if (l == null) + l = Locale.getDefault(); + + ResourceBundle bundle = ResourceBundle.getBundle (resourceBaseName, locale); + + String desc = null; + + if (bundle == null) + { + try + { + desc = bundle.getString (resourceName); + } + catch (MissingResourceException e) + { + desc = null; + } + } + + return desc; + } + + public String getElementDescription (String elementName, Locale locale) + { + return getDescription (elementName, locale); + } + + public int getElementMaxChildren (String elementName) + { + return ((int[]) childRanges.get (elementName))[1]; + } + + public int getElementMinChildren (String elementName) + { + return ((int[]) childRanges.get (elementName))[0]; + } + + public int getObjectArrayMaxLength (String elementName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + return ((Integer) ((NodeObjectArray) getNodeObject (node)).getArrayMaxLength ()).intValue(); + } + + public int getObjectArrayMinLength (String elementName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + return ((Integer) ((NodeObjectArray) getNodeObject (node)).getArrayMinLength ()).intValue(); + } + + public Class getObjectClass (String elementName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + return getNodeObject (node).getClassType (); + } + + public Object getObjectDefaultValue (String elementName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + return getNodeObject (node).getDefaultValue (); + } + + public Object[] getObjectEnumerations (String elementName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + return ((NodeObjectEnumerated) getNodeObject (node)).getEnumerations (); + } + + public Comparable getObjectMaxValue (String elementName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + return ((NodeObjectBounded) getNodeObject (node)).getMaxValue (); + } + + public Comparable getObjectMinValue (String elementName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + return ((NodeObjectBounded) getNodeObject (node)).getMinValue (); + } + + public int getObjectValueType (String elementName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + NodeObject n = getNodeObject (node); + + if (n == null) + return IIOMetadataFormat.VALUE_NONE; + else + return n.getValueType (); + } + + public boolean isAttributeRequired (String elementName, String attrName) + { + IIOMetadataNode node = (IIOMetadataNode) nodes.get (elementName); + return ((IIOMetadataNodeAttr) node.getAttributeNode (attrName)).isRequired(); + } } diff --git a/libjava/classpath/javax/imageio/metadata/IIOMetadataNode.java b/libjava/classpath/javax/imageio/metadata/IIOMetadataNode.java index d9e0983e94a..2d52e467078 100644 --- a/libjava/classpath/javax/imageio/metadata/IIOMetadataNode.java +++ b/libjava/classpath/javax/imageio/metadata/IIOMetadataNode.java @@ -52,6 +52,7 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.TypeInfo; import org.w3c.dom.UserDataHandler; +import javax.imageio.metadata.IIOMetadataFormatImpl.IIOMetadataNodeAttr; public class IIOMetadataNode implements Element, NodeList @@ -61,7 +62,127 @@ public class IIOMetadataNode private List children = new ArrayList(); private IIOMetadataNode parent; private Object obj; + + /** + * Simple NamedNodeMap class for IIOMetadataNode. + * + * @author jlquinn + */ + private class IIONamedNodeMap implements NamedNodeMap + { + HashMap attrs; + + /** + * @param attrs + * @param node + */ + public IIONamedNodeMap(HashMap attrs) + { + this.attrs = attrs; + } + + /* (non-Javadoc) + * @see org.w3c.dom.NamedNodeMap#getNamedItem(java.lang.String) + */ + public Node getNamedItem(String name) + { + return (Node)attrs.get(name); + } + + /* (non-Javadoc) + * @see org.w3c.dom.NamedNodeMap#setNamedItem(org.w3c.dom.Node) + */ + public Node setNamedItem(Node arg) throws DOMException + { + if (arg instanceof IIOMetadataNodeAttr) + { + IIOMetadataNodeAttr attr = (IIOMetadataNodeAttr) arg; + // The only code that can successfully do this is in this package. + if (attr.owner != null) + throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, ""); + return (Node)attrs.put(attr.name, attr); + } + // Anything else gets treated as an invalid op. + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, ""); + } + + /* (non-Javadoc) + * @see org.w3c.dom.NamedNodeMap#removeNamedItem(java.lang.String) + */ + public Node removeNamedItem(String name) throws DOMException + { + return (Node)attrs.remove(name); + } + + /* (non-Javadoc) + * @see org.w3c.dom.NamedNodeMap#item(int) + */ + public Node item(int index) + { + return (Node)attrs.values().toArray()[index]; + } + + /* (non-Javadoc) + * @see org.w3c.dom.NamedNodeMap#getLength() + */ + public int getLength() + { + return attrs.size(); + } + + /* (non-Javadoc) + * @see org.w3c.dom.NamedNodeMap#getNamedItemNS(java.lang.String, java.lang.String) + */ + public Node getNamedItemNS(String namespaceURI, String localName) + { + return getNamedItem(localName); + } + + /* (non-Javadoc) + * @see org.w3c.dom.NamedNodeMap#setNamedItemNS(org.w3c.dom.Node) + */ + public Node setNamedItemNS(Node arg) throws DOMException + { + return setNamedItem(arg); + } + + /* (non-Javadoc) + * @see org.w3c.dom.NamedNodeMap#removeNamedItemNS(java.lang.String, java.lang.String) + */ + public Node removeNamedItemNS(String namespaceURI, String localName) + throws DOMException + { + return removeNamedItem(localName); + } + } + + /** + * Simple NodeList implementation for IIOMetadataNode. + * + * @author jlquinn + * + */ + private class IIONodeList implements NodeList + { + List children = new ArrayList(); + /* (non-Javadoc) + * @see org.w3c.dom.NodeList#item(int) + */ + public Node item(int index) + { + return (index < children.size()) ? (Node)children.get(index) : null; + } + + /* (non-Javadoc) + * @see org.w3c.dom.NodeList#getLength() + */ + public int getLength() + { + return children.size(); + } + } + public IIOMetadataNode() { // Do nothing here. @@ -71,12 +192,12 @@ public class IIOMetadataNode { name = nodename; } - + public Object getUserObject() { return obj; } - + public void setUserObject(Object o) { obj = o; @@ -85,7 +206,7 @@ public class IIOMetadataNode public short compareDocumentPosition(Node other) throws DOMException { - throw new Error("not implemented"); + return Element.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC; } /* (non-Javadoc) @@ -104,7 +225,7 @@ public class IIOMetadataNode { String val = getAttribute(name); if (val != null) - return new IIOAttr(name, val, this); + return new IIOMetadataNodeAttr(this, name, val); return null; } @@ -126,7 +247,7 @@ public class IIOMetadataNode public String getBaseURI() { - throw new Error("not implemented"); + return null; } // Recursive function for assembling a node list. @@ -217,7 +338,7 @@ public class IIOMetadataNode if (attr != null) attr.setValue(value); else - attrs.put(name, new IIOAttr(name, value, this)); + attrs.put(name, new IIOMetadataNodeAttr(this, name, value)); } /* (non-Javadoc) @@ -295,7 +416,7 @@ public class IIOMetadataNode // clone attrs for (Iterator it = attrs.values().iterator(); it.hasNext();) { - IIOAttr attr = (IIOAttr)it.next(); + IIOMetadataNodeAttr attr = (IIOMetadataNodeAttr)it.next(); newnode.attrs.put(attr.name, attr.cloneNode(deep)); attr.owner = newnode; } @@ -321,7 +442,7 @@ public class IIOMetadataNode public Object getFeature(String feature, String version) { - throw new Error("not implemented"); + return null; } /* (non-Javadoc) @@ -432,18 +553,18 @@ public class IIOMetadataNode public TypeInfo getSchemaTypeInfo() { - throw new Error("not implemented"); + return null; } public String getTextContent() throws DOMException { - throw new Error("not implemented"); + return null; } public Object getUserData(String key) { - throw new Error("not implemented"); + return null; } /* (non-Javadoc) @@ -482,12 +603,12 @@ public class IIOMetadataNode public boolean isDefaultNamespace(String namespaceURI) { - throw new Error("not implemented"); + return true; } public boolean isEqualNode(Node arg) { - throw new Error("not implemented"); + return true; } public boolean isSameNode(Node other) @@ -506,12 +627,12 @@ public class IIOMetadataNode public String lookupNamespaceURI(String prefix) { - throw new Error("not implemented"); + return null; } public String lookupPrefix(String namespaceURI) { - throw new Error("not implemented"); + return null; } /* (non-Javadoc) @@ -550,19 +671,16 @@ public class IIOMetadataNode public void setIdAttribute(String name, boolean isId) throws DOMException { - throw new Error("not implemented"); } public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException { - throw new Error("not implemented"); } public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) throws DOMException { - throw new Error("not implemented"); } /* (non-Javadoc) @@ -582,11 +700,10 @@ public class IIOMetadataNode public void setTextContent(String textContent) throws DOMException { - throw new Error("not implemented"); } public Object setUserData(String key, Object data, UserDataHandler handler) { - throw new Error("not implemented"); + return null; } } diff --git a/libjava/classpath/javax/imageio/metadata/IIONamedNodeMap.java b/libjava/classpath/javax/imageio/metadata/IIONamedNodeMap.java deleted file mode 100644 index 92da28d5bb2..00000000000 --- a/libjava/classpath/javax/imageio/metadata/IIONamedNodeMap.java +++ /dev/null @@ -1,138 +0,0 @@ -/* IIONamedNodeMap.java -- - Copyright (C) 2004 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package javax.imageio.metadata; - -import java.util.HashMap; - -import org.w3c.dom.DOMException; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - -/** - * Simple NamedNodeMap class for IIOMetadataNode. - * - * @author jlquinn - */ -class IIONamedNodeMap implements NamedNodeMap -{ - HashMap attrs; - - /** - * @param attrs - * @param node - */ - public IIONamedNodeMap(HashMap attrs) - { - this.attrs = attrs; - } - - /* (non-Javadoc) - * @see org.w3c.dom.NamedNodeMap#getNamedItem(java.lang.String) - */ - public Node getNamedItem(String name) - { - return (Node)attrs.get(name); - } - - /* (non-Javadoc) - * @see org.w3c.dom.NamedNodeMap#setNamedItem(org.w3c.dom.Node) - */ - public Node setNamedItem(Node arg) throws DOMException - { - if (arg instanceof IIOAttr) - { - IIOAttr attr = (IIOAttr) arg; - // The only code that can successfully do this is in this package. - if (attr.owner != null) - throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, ""); - return (Node)attrs.put(attr.name, attr); - } - // Anything else gets treated as an invalid op. - throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, ""); - } - - /* (non-Javadoc) - * @see org.w3c.dom.NamedNodeMap#removeNamedItem(java.lang.String) - */ - public Node removeNamedItem(String name) throws DOMException - { - return (Node)attrs.remove(name); - } - - /* (non-Javadoc) - * @see org.w3c.dom.NamedNodeMap#item(int) - */ - public Node item(int index) - { - return (Node)attrs.values().toArray()[index]; - } - - /* (non-Javadoc) - * @see org.w3c.dom.NamedNodeMap#getLength() - */ - public int getLength() - { - return attrs.size(); - } - - /* (non-Javadoc) - * @see org.w3c.dom.NamedNodeMap#getNamedItemNS(java.lang.String, java.lang.String) - */ - public Node getNamedItemNS(String namespaceURI, String localName) - { - return getNamedItem(localName); - } - - /* (non-Javadoc) - * @see org.w3c.dom.NamedNodeMap#setNamedItemNS(org.w3c.dom.Node) - */ - public Node setNamedItemNS(Node arg) throws DOMException - { - return setNamedItem(arg); - } - - /* (non-Javadoc) - * @see org.w3c.dom.NamedNodeMap#removeNamedItemNS(java.lang.String, java.lang.String) - */ - public Node removeNamedItemNS(String namespaceURI, String localName) - throws DOMException - { - return removeNamedItem(localName); - } - -} diff --git a/libjava/classpath/javax/imageio/metadata/IIONodeList.java b/libjava/classpath/javax/imageio/metadata/IIONodeList.java deleted file mode 100644 index 395d261b6c6..00000000000 --- a/libjava/classpath/javax/imageio/metadata/IIONodeList.java +++ /dev/null @@ -1,72 +0,0 @@ -/* IIOAttr.java -- - Copyright (C) 2004 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package javax.imageio.metadata; - -import java.util.ArrayList; -import java.util.List; - -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -/** - * Simple NodeList implementation for IIOMetadataNode. - * - * @author jlquinn - * - */ -class IIONodeList implements NodeList -{ - List children = new ArrayList(); - - /* (non-Javadoc) - * @see org.w3c.dom.NodeList#item(int) - */ - public Node item(int index) - { - return (index < children.size()) ? (Node)children.get(index) : null; - } - - /* (non-Javadoc) - * @see org.w3c.dom.NodeList#getLength() - */ - public int getLength() - { - return children.size(); - } - -} diff --git a/libjava/classpath/javax/imageio/package.html b/libjava/classpath/javax/imageio/package.html index ce36a7b44bd..f6a604de8fc 100644 --- a/libjava/classpath/javax/imageio/package.html +++ b/libjava/classpath/javax/imageio/package.html @@ -40,7 +40,48 @@ exception statement from your version. --> <head><title>GNU Classpath - javax.imageio</title></head> <body> -<p></p> - +<p> +This package provides image input/output APIs. +</p> +<p> +The standard class library provides other ways of loading images (@see +java.awt.Toolkit, @see java.awt.Component)) but the ImageIO package is +more powerful. +</p> +<p> +The static ImageIO class supports reading and writing images in many +different formats along with most other basic image I/O operations. +</p> +<p> +Other classes provide finer control of image-related operations; +reading is controlled by ImageReader, ImageReadParam and +ImageTypeSpecifyer, writing by ImageWriter and ImageWriteParam. +ImageTranscoder allows fine-grained control over how images are +converted between formats and IIOException reports errors. IIOImage +describes an image file in detail including metadata and thumbnails. +</p> +<h2>Supported Formats</h2> +<p> +The default GNU Classpath ImageIO backend uses ImageMagick and so +supports the following formats: +<table> +<tr> +<th></th> <th>Read</th> <th>Write</th> +</tr> +<tr><td>JPEG</td><td>yes</td><td>yes</td></tr> +<tr><td>PNG</td><td>yes</td><td>yes</td></tr> +<tr><td>BMP</td><td>yes</td><td>yes</td></tr> +<tr><td>WBMP</td><td>yes</td><td>yes</td></tr> +<tr><td>GIF</td><td>yes</td><td>yes</td></tr> +<tr><td>TIFF</td><td>yes</td><td>yes</td></tr> +<tr><td>XPM</td><td>yes</td><td>yes</td></tr> +<tr><td>TGA</td><td>yes</td><td>yes</td></tr> +<tr><td>PDF</td><td>yes</td><td>no</td></tr> +<tr><td>SVG</td><td>yes</td><td>no</td></tr> +<table> +</p> +<p> +@since 1.4 +</p> </body> </html> diff --git a/libjava/classpath/javax/imageio/spi/ImageReaderWriterSpi.java b/libjava/classpath/javax/imageio/spi/ImageReaderWriterSpi.java index 4aa7fd41272..40d44e3d0e2 100644 --- a/libjava/classpath/javax/imageio/spi/ImageReaderWriterSpi.java +++ b/libjava/classpath/javax/imageio/spi/ImageReaderWriterSpi.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.imageio.spi; +import javax.imageio.metadata.IIOMetadataFormat; +import javax.imageio.metadata.IIOMetadataFormatImpl; /** * An abstract superclass that contains the common parts of {@link @@ -422,4 +424,88 @@ public abstract class ImageReaderWriterSpi { return extraImageMetadataFormatNames; } + + /** + * Returns an IIOMetadataFormat object that represents the requested + * stream metadata format or null if the given format is supported + * but no IIOMetadataFormat can be created for it. + * + * @param formatName the requested stream metadata format name + * + * @return an IIOMetadataFormat object or null + * + * @throws IllegalArgumentException if formatName is null or is not + * one of the standard metadata format or this provider's native or + * extra stream metadata formats + */ + public IIOMetadataFormat getStreamMetadataFormat (String formatName) + { + if (formatName == null) + throw new IllegalArgumentException ("null stream metadata format name"); + + if (!formatName.equals (getNativeStreamMetadataFormatName()) + && !formatName.equals (IIOMetadataFormatImpl.standardMetadataFormatName)) + { + String[] extraNames = getExtraStreamMetadataFormatNames (); + boolean foundName = false; + for (int i = 0; i < extraNames.length; i++) + { + if (formatName.equals(extraNames[i])) + { + foundName = true; + break; + } + } + if (!foundName) + throw new IllegalArgumentException ("unsupported stream metadata format name"); + } + + if (formatName.equals (IIOMetadataFormatImpl.standardMetadataFormatName)) + return IIOMetadataFormatImpl.getStandardFormatInstance (); + else + // Default implementation returns null. + return null; + } + + /** + * Returns an IIOMetadataFormat object that represents the requested + * image metadata format or null if the given format is supported + * but no IIOMetadataFormat can be created for it. + * + * @param formatName the requested image metadata format name + * + * @return an IIOMetadataFormat object or null + * + * @throws IllegalArgumentException if formatName is null or is not + * one of the standard metadata format or this provider's native or + * extra image metadata formats + */ + public IIOMetadataFormat getImageMetadataFormat (String formatName) + { + if (formatName == null) + throw new IllegalArgumentException ("null image metadata format name"); + + if (!formatName.equals (getNativeImageMetadataFormatName()) + && !formatName.equals (IIOMetadataFormatImpl.standardMetadataFormatName)) + { + String[] extraNames = getExtraImageMetadataFormatNames (); + boolean foundName = false; + for (int i = 0; i < extraNames.length; i++) + { + if (formatName.equals(extraNames[i])) + { + foundName = true; + break; + } + } + if (!foundName) + throw new IllegalArgumentException ("unsupported image metadata format name"); + } + + if (formatName.equals (IIOMetadataFormatImpl.standardMetadataFormatName)) + return IIOMetadataFormatImpl.getStandardFormatInstance (); + else + // Default implementation returns null. + return null; + } } |