feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio;
import java.io.IOException;
/**
* An exception class used for signaling run-time failure of reading
* and writing operations.
*
* <p> In addition to a message string, a reference to another
* <code>Throwable</code> (<code>Error</code> or
* <code>Exception</code>) is maintained. This reference, if
* non-<code>null</code>, refers to the event that caused this
* exception to occur. For example, an <code>IOException</code> while
* reading from a <code>File</code> would be stored there.
*
*/
public class IIOException extends IOException {
/**
* Constructs an <code>IIOException</code> with a given message
* <code>String</code>. No underlying cause is set;
* <code>getCause</code> will return <code>null</code>.
*
* @param message the error message.
*
* @see #getMessage
*/
public IIOException(String message) {
super(message);
}
/**
* Constructs an <code>IIOException</code> with a given message
* <code>String</code> and a <code>Throwable</code> that was its
* underlying cause.
*
* @param message the error message.
* @param cause the <code>Throwable</code> (<code>Error</code> or
* <code>Exception</code>) that caused this exception to occur.
*
* @see #getCause
* @see #getMessage
*/
public IIOException(String message, Throwable cause) {
super(message);
initCause(cause);
}
}

View File

@@ -0,0 +1,322 @@
/*
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.util.List;
import javax.imageio.metadata.IIOMetadata;
/**
* A simple container class to aggregate an image, a set of
* thumbnail (preview) images, and an object representing metadata
* associated with the image.
*
* <p> The image data may take the form of either a
* <code>RenderedImage</code>, or a <code>Raster</code>. Reader
* methods that return an <code>IIOImage</code> will always return a
* <code>BufferedImage</code> using the <code>RenderedImage</code>
* reference. Writer methods that accept an <code>IIOImage</code>
* will always accept a <code>RenderedImage</code>, and may optionally
* accept a <code>Raster</code>.
*
* <p> Exactly one of <code>getRenderedImage</code> and
* <code>getRaster</code> will return a non-<code>null</code> value.
* Subclasses are responsible for ensuring this behavior.
*
* @see ImageReader#readAll(int, ImageReadParam)
* @see ImageReader#readAll(java.util.Iterator)
* @see ImageWriter#write(javax.imageio.metadata.IIOMetadata,
* IIOImage, ImageWriteParam)
* @see ImageWriter#write(IIOImage)
* @see ImageWriter#writeToSequence(IIOImage, ImageWriteParam)
* @see ImageWriter#writeInsert(int, IIOImage, ImageWriteParam)
*
*/
public class IIOImage {
/**
* The <code>RenderedImage</code> being referenced.
*/
protected RenderedImage image;
/**
* The <code>Raster</code> being referenced.
*/
protected Raster raster;
/**
* A <code>List</code> of <code>BufferedImage</code> thumbnails,
* or <code>null</code>. Non-<code>BufferedImage</code> objects
* must not be stored in this <code>List</code>.
*/
protected List<? extends BufferedImage> thumbnails = null;
/**
* An <code>IIOMetadata</code> object containing metadata
* associated with the image.
*/
protected IIOMetadata metadata;
/**
* Constructs an <code>IIOImage</code> containing a
* <code>RenderedImage</code>, and thumbnails and metadata
* associated with it.
*
* <p> All parameters are stored by reference.
*
* <p> The <code>thumbnails</code> argument must either be
* <code>null</code> or contain only <code>BufferedImage</code>
* objects.
*
* @param image a <code>RenderedImage</code>.
* @param thumbnails a <code>List</code> of <code>BufferedImage</code>s,
* or <code>null</code>.
* @param metadata an <code>IIOMetadata</code> object, or
* <code>null</code>.
*
* @exception IllegalArgumentException if <code>image</code> is
* <code>null</code>.
*/
public IIOImage(RenderedImage image,
List<? extends BufferedImage> thumbnails,
IIOMetadata metadata) {
if (image == null) {
throw new IllegalArgumentException("image == null!");
}
this.image = image;
this.raster = null;
this.thumbnails = thumbnails;
this.metadata = metadata;
}
/**
* Constructs an <code>IIOImage</code> containing a
* <code>Raster</code>, and thumbnails and metadata
* associated with it.
*
* <p> All parameters are stored by reference.
*
* @param raster a <code>Raster</code>.
* @param thumbnails a <code>List</code> of <code>BufferedImage</code>s,
* or <code>null</code>.
* @param metadata an <code>IIOMetadata</code> object, or
* <code>null</code>.
*
* @exception IllegalArgumentException if <code>raster</code> is
* <code>null</code>.
*/
public IIOImage(Raster raster,
List<? extends BufferedImage> thumbnails,
IIOMetadata metadata) {
if (raster == null) {
throw new IllegalArgumentException("raster == null!");
}
this.raster = raster;
this.image = null;
this.thumbnails = thumbnails;
this.metadata = metadata;
}
/**
* Returns the currently set <code>RenderedImage</code>, or
* <code>null</code> if only a <code>Raster</code> is available.
*
* @return a <code>RenderedImage</code>, or <code>null</code>.
*
* @see #setRenderedImage
*/
public RenderedImage getRenderedImage() {
synchronized(this) {
return image;
}
}
/**
* Sets the current <code>RenderedImage</code>. The value is
* stored by reference. Any existing <code>Raster</code> is
* discarded.
*
* @param image a <code>RenderedImage</code>.
*
* @exception IllegalArgumentException if <code>image</code> is
* <code>null</code>.
*
* @see #getRenderedImage
*/
public void setRenderedImage(RenderedImage image) {
synchronized(this) {
if (image == null) {
throw new IllegalArgumentException("image == null!");
}
this.image = image;
this.raster = null;
}
}
/**
* Returns <code>true</code> if this <code>IIOImage</code> stores
* a <code>Raster</code> rather than a <code>RenderedImage</code>.
*
* @return <code>true</code> if a <code>Raster</code> is
* available.
*/
public boolean hasRaster() {
synchronized(this) {
return (raster != null);
}
}
/**
* Returns the currently set <code>Raster</code>, or
* <code>null</code> if only a <code>RenderedImage</code> is
* available.
*
* @return a <code>Raster</code>, or <code>null</code>.
*
* @see #setRaster
*/
public Raster getRaster() {
synchronized(this) {
return raster;
}
}
/**
* Sets the current <code>Raster</code>. The value is
* stored by reference. Any existing <code>RenderedImage</code> is
* discarded.
*
* @param raster a <code>Raster</code>.
*
* @exception IllegalArgumentException if <code>raster</code> is
* <code>null</code>.
*
* @see #getRaster
*/
public void setRaster(Raster raster) {
synchronized(this) {
if (raster == null) {
throw new IllegalArgumentException("raster == null!");
}
this.raster = raster;
this.image = null;
}
}
/**
* Returns the number of thumbnails stored in this
* <code>IIOImage</code>.
*
* @return the number of thumbnails, as an <code>int</code>.
*/
public int getNumThumbnails() {
return thumbnails == null ? 0 : thumbnails.size();
}
/**
* Returns a thumbnail associated with the main image.
*
* @param index the index of the desired thumbnail image.
*
* @return a thumbnail image, as a <code>BufferedImage</code>.
*
* @exception IndexOutOfBoundsException if the supplied index is
* negative or larger than the largest valid index.
* @exception ClassCastException if a
* non-<code>BufferedImage</code> object is encountered in the
* list of thumbnails at the given index.
*
* @see #getThumbnails
* @see #setThumbnails
*/
public BufferedImage getThumbnail(int index) {
if (thumbnails == null) {
throw new IndexOutOfBoundsException("No thumbnails available!");
}
return (BufferedImage)thumbnails.get(index);
}
/**
* Returns the current <code>List</code> of thumbnail
* <code>BufferedImage</code>s, or <code>null</code> if none is
* set. A live reference is returned.
*
* @return the current <code>List</code> of
* <code>BufferedImage</code> thumbnails, or <code>null</code>.
*
* @see #getThumbnail(int)
* @see #setThumbnails
*/
public List<? extends BufferedImage> getThumbnails() {
return thumbnails;
}
/**
* Sets the list of thumbnails to a new <code>List</code> of
* <code>BufferedImage</code>s, or to <code>null</code>. The
* reference to the previous <code>List</code> is discarded.
*
* <p> The <code>thumbnails</code> argument must either be
* <code>null</code> or contain only <code>BufferedImage</code>
* objects.
*
* @param thumbnails a <code>List</code> of
* <code>BufferedImage</code> thumbnails, or <code>null</code>.
*
* @see #getThumbnail(int)
* @see #getThumbnails
*/
public void setThumbnails(List<? extends BufferedImage> thumbnails) {
this.thumbnails = thumbnails;
}
/**
* Returns a reference to the current <code>IIOMetadata</code>
* object, or <code>null</code> is none is set.
*
* @return an <code>IIOMetadata</code> object, or <code>null</code>.
*
* @see #setMetadata
*/
public IIOMetadata getMetadata() {
return metadata;
}
/**
* Sets the <code>IIOMetadata</code> to a new object, or
* <code>null</code>.
*
* @param metadata an <code>IIOMetadata</code> object, or
* <code>null</code>.
*
* @see #getMetadata
*/
public void setMetadata(IIOMetadata metadata) {
this.metadata = metadata;
}
}

View File

@@ -0,0 +1,676 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio;
import java.awt.Point;
import java.awt.Rectangle;
/**
* A superclass of all classes describing how streams should be
* decoded or encoded. This class contains all the variables and
* methods that are shared by <code>ImageReadParam</code> and
* <code>ImageWriteParam</code>.
*
* <p> This class provides mechanisms to specify a source region and a
* destination region. When reading, the source is the stream and
* the in-memory image is the destination. When writing, these are
* reversed. In the case of writing, destination regions may be used
* only with a writer that supports pixel replacement.
* <p>
* Decimation subsampling may be specified for both readers
* and writers, using a movable subsampling grid.
* <p>
* Subsets of the source and destination bands may be selected.
*
*/
public abstract class IIOParam {
/**
* The source region, on <code>null</code> if none is set.
*/
protected Rectangle sourceRegion = null;
/**
* The decimation subsampling to be applied in the horizontal
* direction. By default, the value is <code>1</code>.
* The value must not be negative or 0.
*/
protected int sourceXSubsampling = 1;
/**
* The decimation subsampling to be applied in the vertical
* direction. By default, the value is <code>1</code>.
* The value must not be negative or 0.
*/
protected int sourceYSubsampling = 1;
/**
* A horizontal offset to be applied to the subsampling grid before
* subsampling. The first pixel to be used will be offset this
* amount from the origin of the region, or of the image if no
* region is specified.
*/
protected int subsamplingXOffset = 0;
/**
* A vertical offset to be applied to the subsampling grid before
* subsampling. The first pixel to be used will be offset this
* amount from the origin of the region, or of the image if no
* region is specified.
*/
protected int subsamplingYOffset = 0;
/**
* An array of <code>int</code>s indicating which source bands
* will be used, or <code>null</code>. If <code>null</code>, the
* set of source bands to be used is as described in the comment
* for the <code>setSourceBands</code> method. No value should
* be allowed to be negative.
*/
protected int[] sourceBands = null;
/**
* An <code>ImageTypeSpecifier</code> to be used to generate a
* destination image when reading, or to set the output color type
* when writing. If non has been set the value will be
* <code>null</code>. By default, the value is <code>null</code>.
*/
protected ImageTypeSpecifier destinationType = null;
/**
* The offset in the destination where the upper-left decoded
* pixel should be placed. By default, the value is (0, 0).
*/
protected Point destinationOffset = new Point(0, 0);
/**
* The default <code>IIOParamController</code> that will be
* used to provide settings for this <code>IIOParam</code>
* object when the <code>activateController</code> method
* is called. This default should be set by subclasses
* that choose to provide their own default controller,
* usually a GUI, for setting parameters.
*
* @see IIOParamController
* @see #getDefaultController
* @see #activateController
*/
protected IIOParamController defaultController = null;
/**
* The <code>IIOParamController</code> that will be
* used to provide settings for this <code>IIOParam</code>
* object when the <code>activateController</code> method
* is called. This value overrides any default controller,
* even when null.
*
* @see IIOParamController
* @see #setController(IIOParamController)
* @see #hasController()
* @see #activateController()
*/
protected IIOParamController controller = null;
/**
* Protected constructor may be called only by subclasses.
*/
protected IIOParam() {
controller = defaultController;
}
/**
* Sets the source region of interest. The region of interest is
* described as a rectangle, with the upper-left corner of the
* source image as pixel (0, 0) and increasing values down and to
* the right. The actual number of pixels used will depend on
* the subsampling factors set by <code>setSourceSubsampling</code>.
* If subsampling has been set such that this number is zero,
* an <code>IllegalStateException</code> will be thrown.
*
* <p> The source region of interest specified by this method will
* be clipped as needed to fit within the source bounds, as well
* as the destination offsets, width, and height at the time of
* actual I/O.
*
* <p> A value of <code>null</code> for <code>sourceRegion</code>
* will remove any region specification, causing the entire image
* to be used.
*
* @param sourceRegion a <code>Rectangle</code> specifying the
* source region of interest, or <code>null</code>.
*
* @exception IllegalArgumentException if
* <code>sourceRegion</code> is non-<code>null</code> and either
* <code>sourceRegion.x</code> or <code>sourceRegion.y</code> is
* negative.
* @exception IllegalArgumentException if
* <code>sourceRegion</code> is non-<code>null</code> and either
* <code>sourceRegion.width</code> or
* <code>sourceRegion.height</code> is negative or 0.
* @exception IllegalStateException if subsampling is such that
* this region will have a subsampled width or height of zero.
*
* @see #getSourceRegion
* @see #setSourceSubsampling
* @see ImageReadParam#setDestinationOffset
* @see ImageReadParam#getDestinationOffset
*/
public void setSourceRegion(Rectangle sourceRegion) {
if (sourceRegion == null) {
this.sourceRegion = null;
return;
}
if (sourceRegion.x < 0) {
throw new IllegalArgumentException("sourceRegion.x < 0!");
}
if (sourceRegion.y < 0){
throw new IllegalArgumentException("sourceRegion.y < 0!");
}
if (sourceRegion.width <= 0) {
throw new IllegalArgumentException("sourceRegion.width <= 0!");
}
if (sourceRegion.height <= 0) {
throw new IllegalArgumentException("sourceRegion.height <= 0!");
}
// Throw an IllegalStateException if region falls between subsamples
if (sourceRegion.width <= subsamplingXOffset) {
throw new IllegalStateException
("sourceRegion.width <= subsamplingXOffset!");
}
if (sourceRegion.height <= subsamplingYOffset) {
throw new IllegalStateException
("sourceRegion.height <= subsamplingYOffset!");
}
this.sourceRegion = (Rectangle)sourceRegion.clone();
}
/**
* Returns the source region to be used. The returned value is
* that set by the most recent call to
* <code>setSourceRegion</code>, and will be <code>null</code> if
* there is no region set.
*
* @return the source region of interest as a
* <code>Rectangle</code>, or <code>null</code>.
*
* @see #setSourceRegion
*/
public Rectangle getSourceRegion() {
if (sourceRegion == null) {
return null;
}
return (Rectangle)sourceRegion.clone();
}
/**
* Specifies a decimation subsampling to apply on I/O. The
* <code>sourceXSubsampling</code> and
* <code>sourceYSubsampling</code> parameters specify the
* subsampling period (<i>i.e.</i>, the number of rows and columns
* to advance after every source pixel). Specifically, a period of
* 1 will use every row or column; a period of 2 will use every
* other row or column. The <code>subsamplingXOffset</code> and
* <code>subsamplingYOffset</code> parameters specify an offset
* from the region (or image) origin for the first subsampled pixel.
* Adjusting the origin of the subsample grid is useful for avoiding
* seams when subsampling a very large source image into destination
* regions that will be assembled into a complete subsampled image.
* Most users will want to simply leave these parameters at 0.
*
* <p> The number of pixels and scanlines to be used are calculated
* as follows.
* <p>
* The number of subsampled pixels in a scanline is given by
* <p>
* <code>truncate[(width - subsamplingXOffset + sourceXSubsampling - 1)
* / sourceXSubsampling]</code>.
* <p>
* If the region is such that this width is zero, an
* <code>IllegalStateException</code> is thrown.
* <p>
* The number of scanlines to be used can be computed similarly.
*
* <p>The ability to set the subsampling grid to start somewhere
* other than the source region origin is useful if the
* region is being used to create subsampled tiles of a large image,
* where the tile width and height are not multiples of the
* subsampling periods. If the subsampling grid does not remain
* consistent from tile to tile, there will be artifacts at the tile
* boundaries. By adjusting the subsampling grid offset for each
* tile to compensate, these artifacts can be avoided. The tradeoff
* is that in order to avoid these artifacts, the tiles are not all
* the same size. The grid offset to use in this case is given by:
* <br>
* grid offset = [period - (region offset modulo period)] modulo period)
*
* <p> If either <code>sourceXSubsampling</code> or
* <code>sourceYSubsampling</code> is 0 or negative, an
* <code>IllegalArgumentException</code> will be thrown.
*
* <p> If either <code>subsamplingXOffset</code> or
* <code>subsamplingYOffset</code> is negative or greater than or
* equal to the corresponding period, an
* <code>IllegalArgumentException</code> will be thrown.
*
* <p> There is no <code>unsetSourceSubsampling</code> method;
* simply call <code>setSourceSubsampling(1, 1, 0, 0)</code> to
* restore default values.
*
* @param sourceXSubsampling the number of columns to advance
* between pixels.
* @param sourceYSubsampling the number of rows to advance between
* pixels.
* @param subsamplingXOffset the horizontal offset of the first subsample
* within the region, or within the image if no region is set.
* @param subsamplingYOffset the horizontal offset of the first subsample
* within the region, or within the image if no region is set.
* @exception IllegalArgumentException if either period is
* negative or 0, or if either grid offset is negative or greater than
* the corresponding period.
* @exception IllegalStateException if the source region is such that
* the subsampled output would contain no pixels.
*/
public void setSourceSubsampling(int sourceXSubsampling,
int sourceYSubsampling,
int subsamplingXOffset,
int subsamplingYOffset) {
if (sourceXSubsampling <= 0) {
throw new IllegalArgumentException("sourceXSubsampling <= 0!");
}
if (sourceYSubsampling <= 0) {
throw new IllegalArgumentException("sourceYSubsampling <= 0!");
}
if (subsamplingXOffset < 0 ||
subsamplingXOffset >= sourceXSubsampling) {
throw new IllegalArgumentException
("subsamplingXOffset out of range!");
}
if (subsamplingYOffset < 0 ||
subsamplingYOffset >= sourceYSubsampling) {
throw new IllegalArgumentException
("subsamplingYOffset out of range!");
}
// Throw an IllegalStateException if region falls between subsamples
if (sourceRegion != null) {
if (subsamplingXOffset >= sourceRegion.width ||
subsamplingYOffset >= sourceRegion.height) {
throw new IllegalStateException("region contains no pixels!");
}
}
this.sourceXSubsampling = sourceXSubsampling;
this.sourceYSubsampling = sourceYSubsampling;
this.subsamplingXOffset = subsamplingXOffset;
this.subsamplingYOffset = subsamplingYOffset;
}
/**
* Returns the number of source columns to advance for each pixel.
*
* <p>If <code>setSourceSubsampling</code> has not been called, 1
* is returned (which is the correct value).
*
* @return the source subsampling X period.
*
* @see #setSourceSubsampling
* @see #getSourceYSubsampling
*/
public int getSourceXSubsampling() {
return sourceXSubsampling;
}
/**
* Returns the number of rows to advance for each pixel.
*
* <p>If <code>setSourceSubsampling</code> has not been called, 1
* is returned (which is the correct value).
*
* @return the source subsampling Y period.
*
* @see #setSourceSubsampling
* @see #getSourceXSubsampling
*/
public int getSourceYSubsampling() {
return sourceYSubsampling;
}
/**
* Returns the horizontal offset of the subsampling grid.
*
* <p>If <code>setSourceSubsampling</code> has not been called, 0
* is returned (which is the correct value).
*
* @return the source subsampling grid X offset.
*
* @see #setSourceSubsampling
* @see #getSubsamplingYOffset
*/
public int getSubsamplingXOffset() {
return subsamplingXOffset;
}
/**
* Returns the vertical offset of the subsampling grid.
*
* <p>If <code>setSourceSubsampling</code> has not been called, 0
* is returned (which is the correct value).
*
* @return the source subsampling grid Y offset.
*
* @see #setSourceSubsampling
* @see #getSubsamplingXOffset
*/
public int getSubsamplingYOffset() {
return subsamplingYOffset;
}
/**
* Sets the indices of the source bands to be used. Duplicate
* indices are not allowed.
*
* <p> A <code>null</code> value indicates that all source bands
* will be used.
*
* <p> At the time of reading, an
* <code>IllegalArgumentException</code> will be thrown by the
* reader or writer if a value larger than the largest available
* source band index has been specified or if the number of source
* bands and destination bands to be used differ. The
* <code>ImageReader.checkReadParamBandSettings</code> method may
* be used to automate this test.
*
* <p> Semantically, a copy is made of the array; changes to the
* array contents subsequent to this call have no effect on
* this <code>IIOParam</code>.
*
* @param sourceBands an array of integer band indices to be
* used.
*
* @exception IllegalArgumentException if <code>sourceBands</code>
* contains a negative or duplicate value.
*
* @see #getSourceBands
* @see ImageReadParam#setDestinationBands
* @see ImageReader#checkReadParamBandSettings
*/
public void setSourceBands(int[] sourceBands) {
if (sourceBands == null) {
this.sourceBands = null;
} else {
int numBands = sourceBands.length;
for (int i = 0; i < numBands; i++) {
int band = sourceBands[i];
if (band < 0) {
throw new IllegalArgumentException("Band value < 0!");
}
for (int j = i + 1; j < numBands; j++) {
if (band == sourceBands[j]) {
throw new IllegalArgumentException("Duplicate band value!");
}
}
}
this.sourceBands = (int[])(sourceBands.clone());
}
}
/**
* Returns the set of of source bands to be used. The returned
* value is that set by the most recent call to
* <code>setSourceBands</code>, or <code>null</code> if there have
* been no calls to <code>setSourceBands</code>.
*
* <p> Semantically, the array returned is a copy; changes to
* array contents subsequent to this call have no effect on this
* <code>IIOParam</code>.
*
* @return the set of source bands to be used, or
* <code>null</code>.
*
* @see #setSourceBands
*/
public int[] getSourceBands() {
if (sourceBands == null) {
return null;
}
return (int[])(sourceBands.clone());
}
/**
* Sets the desired image type for the destination image, using an
* <code>ImageTypeSpecifier</code>.
*
* <p> When reading, if the layout of the destination has been set
* using this method, each call to an <code>ImageReader</code>
* <code>read</code> method will return a new
* <code>BufferedImage</code> using the format specified by the
* supplied type specifier. As a side effect, any destination
* <code>BufferedImage</code> set by
* <code>ImageReadParam.setDestination(BufferedImage)</code> will
* no longer be set as the destination. In other words, this
* method may be thought of as calling
* <code>setDestination((BufferedImage)null)</code>.
*
* <p> When writing, the destination type maybe used to determine
* the color type of the image. The <code>SampleModel</code>
* information will be ignored, and may be <code>null</code>. For
* example, a 4-banded image could represent either CMYK or RGBA
* data. If a destination type is set, its
* <code>ColorModel</code> will override any
* <code>ColorModel</code> on the image itself. This is crucial
* when <code>setSourceBands</code> is used since the image's
* <code>ColorModel</code> will refer to the entire image rather
* than to the subset of bands being written.
*
* @param destinationType the <code>ImageTypeSpecifier</code> to
* be used to determine the destination layout and color type.
*
* @see #getDestinationType
*/
public void setDestinationType(ImageTypeSpecifier destinationType) {
this.destinationType = destinationType;
}
/**
* Returns the type of image to be returned by the read, if one
* was set by a call to
* <code>setDestination(ImageTypeSpecifier)</code>, as an
* <code>ImageTypeSpecifier</code>. If none was set,
* <code>null</code> is returned.
*
* @return an <code>ImageTypeSpecifier</code> describing the
* destination type, or <code>null</code>.
*
* @see #setDestinationType
*/
public ImageTypeSpecifier getDestinationType() {
return destinationType;
}
/**
* Specifies the offset in the destination image at which future
* decoded pixels are to be placed, when reading, or where a
* region will be written, when writing.
*
* <p> When reading, the region to be written within the
* destination <code>BufferedImage</code> will start at this
* offset and have a width and height determined by the source
* region of interest, the subsampling parameters, and the
* destination bounds.
*
* <p> Normal writes are not affected by this method, only writes
* performed using <code>ImageWriter.replacePixels</code>. For
* such writes, the offset specified is within the output stream
* image whose pixels are being modified.
*
* <p> There is no <code>unsetDestinationOffset</code> method;
* simply call <code>setDestinationOffset(new Point(0, 0))</code> to
* restore default values.
*
* @param destinationOffset the offset in the destination, as a
* <code>Point</code>.
*
* @exception IllegalArgumentException if
* <code>destinationOffset</code> is <code>null</code>.
*
* @see #getDestinationOffset
* @see ImageWriter#replacePixels
*/
public void setDestinationOffset(Point destinationOffset) {
if (destinationOffset == null) {
throw new IllegalArgumentException("destinationOffset == null!");
}
this.destinationOffset = (Point)destinationOffset.clone();
}
/**
* Returns the offset in the destination image at which pixels are
* to be placed.
*
* <p> If <code>setDestinationOffsets</code> has not been called,
* a <code>Point</code> with zero X and Y values is returned
* (which is the correct value).
*
* @return the destination offset as a <code>Point</code>.
*
* @see #setDestinationOffset
*/
public Point getDestinationOffset() {
return (Point)destinationOffset.clone();
}
/**
* Sets the <code>IIOParamController</code> to be used
* to provide settings for this <code>IIOParam</code>
* object when the <code>activateController</code> method
* is called, overriding any default controller. If the
* argument is <code>null</code>, no controller will be
* used, including any default. To restore the default, use
* <code>setController(getDefaultController())</code>.
*
* @param controller An appropriate
* <code>IIOParamController</code>, or <code>null</code>.
*
* @see IIOParamController
* @see #getController
* @see #getDefaultController
* @see #hasController
* @see #activateController()
*/
public void setController(IIOParamController controller) {
this.controller = controller;
}
/**
* Returns whatever <code>IIOParamController</code> is currently
* installed. This could be the default if there is one,
* <code>null</code>, or the argument of the most recent call
* to <code>setController</code>.
*
* @return the currently installed
* <code>IIOParamController</code>, or <code>null</code>.
*
* @see IIOParamController
* @see #setController
* @see #getDefaultController
* @see #hasController
* @see #activateController()
*/
public IIOParamController getController() {
return controller;
}
/**
* Returns the default <code>IIOParamController</code>, if there
* is one, regardless of the currently installed controller. If
* there is no default controller, returns <code>null</code>.
*
* @return the default <code>IIOParamController</code>, or
* <code>null</code>.
*
* @see IIOParamController
* @see #setController(IIOParamController)
* @see #getController
* @see #hasController
* @see #activateController()
*/
public IIOParamController getDefaultController() {
return defaultController;
}
/**
* Returns <code>true</code> if there is a controller installed
* for this <code>IIOParam</code> object. This will return
* <code>true</code> if <code>getController</code> would not
* return <code>null</code>.
*
* @return <code>true</code> if a controller is installed.
*
* @see IIOParamController
* @see #setController(IIOParamController)
* @see #getController
* @see #getDefaultController
* @see #activateController()
*/
public boolean hasController() {
return (controller != null);
}
/**
* Activates the installed <code>IIOParamController</code> for
* this <code>IIOParam</code> object and returns the resulting
* value. When this method returns <code>true</code>, all values
* for this <code>IIOParam</code> object will be ready for the
* next read or write operation. If <code>false</code> is
* returned, no settings in this object will have been disturbed
* (<i>i.e.</i>, the user canceled the operation).
*
* <p> Ordinarily, the controller will be a GUI providing a user
* interface for a subclass of <code>IIOParam</code> for a
* particular plug-in. Controllers need not be GUIs, however.
*
* @return <code>true</code> if the controller completed normally.
*
* @exception IllegalStateException if there is no controller
* currently installed.
*
* @see IIOParamController
* @see #setController(IIOParamController)
* @see #getController
* @see #getDefaultController
* @see #hasController
*/
public boolean activateController() {
if (!hasController()) {
throw new IllegalStateException("hasController() == false!");
}
return getController().activate(this);
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio;
/**
* An interface to be implemented by objects that can determine the
* settings of an <code>IIOParam</code> object, either by putting up a
* GUI to obtain values from a user, or by other means. This
* interface merely specifies a generic <code>activate</code> method
* that invokes the controller, without regard for how the controller
* obtains values (<i>i.e.</i>, whether the controller puts up a GUI
* or merely computes a set of values is irrelevant to this
* interface).
*
* <p> Within the <code>activate</code> method, a controller obtains
* initial values by querying the <code>IIOParam</code> object's
* <code>get</code> methods, modifies values by whatever means, then
* invokes the <code>IIOParam</code> object's <code>set</code> methods
* to modify the appropriate settings. Normally, these
* <code>set</code> methods will be invoked all at once at a final
* commit in order that a cancel operation not disturb existing
* values. In general, applications may expect that when the
* <code>activate</code> method returns <code>true</code>, the
* <code>IIOParam</code> object is ready for use in a read or write
* operation.
*
* <p> Vendors may choose to provide GUIs for the
* <code>IIOParam</code> subclasses they define for a particular
* plug-in. These can be set up as default controllers in the
* corresponding <code>IIOParam</code> subclasses.
*
* <p> Applications may override any default GUIs and provide their
* own controllers embedded in their own framework. All that is
* required is that the<code>activate</code> method behave modally
* (not returning until either cancelled or committed), though it need
* not put up an explicitly modal dialog. Such a non-modal GUI
* component would be coded roughly as follows:
*
* <br>
* <pre>
* class MyGUI extends SomeComponent implements IIOParamController {
*
* public MyGUI() {
* // ...
* setEnabled(false);
* }
*
* public boolean activate(IIOParam param) {
* // disable other components if desired
* setEnabled(true);
* // go to sleep until either cancelled or committed
* boolean ret = false;
* if (!cancelled) {
* // set values on param
* ret = true;
* }
* setEnabled(false);
* // enable any components disabled above
* return ret;
* }
* </pre>
*
* <p> Alternatively, an algorithmic process such as a database lookup
* or the parsing of a command line could be used as a controller, in
* which case the <code>activate</code> method would simply look up or
* compute the settings, call the <code>IIOParam.setXXX</code>
* methods, and return <code>true</code>.
*
* @see IIOParam#setController
* @see IIOParam#getController
* @see IIOParam#getDefaultController
* @see IIOParam#hasController
* @see IIOParam#activateController
*
*/
public interface IIOParamController {
/**
* Activates the controller. If <code>true</code> is returned,
* all settings in the <code>IIOParam</code> object should be
* ready for use in a read or write operation. If
* <code>false</code> is returned, no settings in the
* <code>IIOParam</code> object will be disturbed (<i>i.e.</i>,
* the user canceled the operation).
*
* @param param the <code>IIOParam</code> object to be modified.
*
* @return <code>true</code> if the <code>IIOParam</code> has been
* modified, <code>false</code> otherwise.
*
* @exception IllegalArgumentException if <code>param</code> is
* <code>null</code> or is not an instance of the correct class.
*/
boolean activate(IIOParam param);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,508 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
/**
* A class describing how a stream is to be decoded. Instances of
* this class or its subclasses are used to supply prescriptive
* "how-to" information to instances of <code>ImageReader</code>.
*
* <p> An image encoded as part of a file or stream may be thought of
* extending out in multiple dimensions: the spatial dimensions of
* width and height, a number of bands, and a number of progressive
* decoding passes. This class allows a contiguous (hyper)rectangular
* subarea of the image in all of these dimensions to be selected for
* decoding. Additionally, the spatial dimensions may be subsampled
* discontinuously. Finally, color and format conversions may be
* specified by controlling the <code>ColorModel</code> and
* <code>SampleModel</code> of the destination image, either by
* providing a <code>BufferedImage</code> or by using an
* <code>ImageTypeSpecifier</code>.
*
* <p> An <code>ImageReadParam</code> object is used to specify how an
* image, or a set of images, will be converted on input from
* a stream in the context of the Java Image I/O framework. A plug-in for a
* specific image format will return instances of
* <code>ImageReadParam</code> from the
* <code>getDefaultReadParam</code> method of its
* <code>ImageReader</code> implementation.
*
* <p> The state maintained by an instance of
* <code>ImageReadParam</code> is independent of any particular image
* being decoded. When actual decoding takes place, the values set in
* the read param are combined with the actual properties of the image
* being decoded from the stream and the destination
* <code>BufferedImage</code> that will receive the decoded pixel
* data. For example, the source region set using
* <code>setSourceRegion</code> will first be intersected with the
* actual valid source area. The result will be translated by the
* value returned by <code>getDestinationOffset</code>, and the
* resulting rectangle intersected with the actual valid destination
* area to yield the destination area that will be written.
*
* <p> The parameters specified by an <code>ImageReadParam</code> are
* applied to an image as follows. First, if a rendering size has
* been set by <code>setSourceRenderSize</code>, the entire decoded
* image is rendered at the size given by
* <code>getSourceRenderSize</code>. Otherwise, the image has its
* natural size given by <code>ImageReader.getWidth</code> and
* <code>ImageReader.getHeight</code>.
*
* <p> Next, the image is clipped against the source region
* specified by <code>getSourceXOffset</code>, <code>getSourceYOffset</code>,
* <code>getSourceWidth</code>, and <code>getSourceHeight</code>.
*
* <p> The resulting region is then subsampled according to the
* factors given in {@link IIOParam#setSourceSubsampling
* IIOParam.setSourceSubsampling}. The first pixel,
* the number of pixels per row, and the number of rows all depend
* on the subsampling settings.
* Call the minimum X and Y coordinates of the resulting rectangle
* (<code>minX</code>, <code>minY</code>), its width <code>w</code>
* and its height <code>h</code>.
*
* <p> This rectangle is offset by
* (<code>getDestinationOffset().x</code>,
* <code>getDestinationOffset().y</code>) and clipped against the
* destination bounds. If no destination image has been set, the
* destination is defined to have a width of
* <code>getDestinationOffset().x</code> + <code>w</code>, and a
* height of <code>getDestinationOffset().y</code> + <code>h</code> so
* that all pixels of the source region may be written to the
* destination.
*
* <p> Pixels that land, after subsampling, within the destination
* image, and that are written in one of the progressive passes
* specified by <code>getSourceMinProgressivePass</code> and
* <code>getSourceNumProgressivePasses</code> are passed along to the
* next step.
*
* <p> Finally, the source samples of each pixel are mapped into
* destination bands according to the algorithm described in the
* comment for <code>setDestinationBands</code>.
*
* <p> Plug-in writers may extend the functionality of
* <code>ImageReadParam</code> by providing a subclass that implements
* additional, plug-in specific interfaces. It is up to the plug-in
* to document what interfaces are available and how they are to be
* used. Readers will silently ignore any extended features of an
* <code>ImageReadParam</code> subclass of which they are not aware.
* Also, they may ignore any optional features that they normally
* disable when creating their own <code>ImageReadParam</code>
* instances via <code>getDefaultReadParam</code>.
*
* <p> Note that unless a query method exists for a capability, it must
* be supported by all <code>ImageReader</code> implementations
* (<i>e.g.</i> source render size is optional, but subsampling must be
* supported).
*
*
* @see ImageReader
* @see ImageWriter
* @see ImageWriteParam
*/
public class ImageReadParam extends IIOParam {
/**
* <code>true</code> if this <code>ImageReadParam</code> allows
* the source rendering dimensions to be set. By default, the
* value is <code>false</code>. Subclasses must set this value
* manually.
*
* <p> <code>ImageReader</code>s that do not support setting of
* the source render size should set this value to
* <code>false</code>.
*/
protected boolean canSetSourceRenderSize = false;
/**
* The desired rendering width and height of the source, if
* <code>canSetSourceRenderSize</code> is <code>true</code>, or
* <code>null</code>.
*
* <p> <code>ImageReader</code>s that do not support setting of
* the source render size may ignore this value.
*/
protected Dimension sourceRenderSize = null;
/**
* The current destination <code>BufferedImage</code>, or
* <code>null</code> if none has been set. By default, the value
* is <code>null</code>.
*/
protected BufferedImage destination = null;
/**
* The set of destination bands to be used, as an array of
* <code>int</code>s. By default, the value is <code>null</code>,
* indicating all destination bands should be written in order.
*/
protected int[] destinationBands = null;
/**
* The minimum index of a progressive pass to read from the
* source. By default, the value is set to 0, which indicates
* that passes starting with the first available pass should be
* decoded.
*
* <p> Subclasses should ensure that this value is
* non-negative.
*/
protected int minProgressivePass = 0;
/**
* The maximum number of progressive passes to read from the
* source. By default, the value is set to
* <code>Integer.MAX_VALUE</code>, which indicates that passes up
* to and including the last available pass should be decoded.
*
* <p> Subclasses should ensure that this value is positive.
* Additionally, if the value is not
* <code>Integer.MAX_VALUE</code>, then <code>minProgressivePass +
* numProgressivePasses - 1</code> should not exceed
* <code>Integer.MAX_VALUE</code>.
*/
protected int numProgressivePasses = Integer.MAX_VALUE;
/**
* Constructs an <code>ImageReadParam</code>.
*/
public ImageReadParam() {}
// Comment inherited
public void setDestinationType(ImageTypeSpecifier destinationType) {
super.setDestinationType(destinationType);
setDestination(null);
}
/**
* Supplies a <code>BufferedImage</code> to be used as the
* destination for decoded pixel data. The currently set image
* will be written to by the <code>read</code>,
* <code>readAll</code>, and <code>readRaster</code> methods, and
* a reference to it will be returned by those methods.
*
* <p> Pixel data from the aforementioned methods will be written
* starting at the offset specified by
* <code>getDestinationOffset</code>.
*
* <p> If <code>destination</code> is <code>null</code>, a
* newly-created <code>BufferedImage</code> will be returned by
* those methods.
*
* <p> At the time of reading, the image is checked to verify that
* its <code>ColorModel</code> and <code>SampleModel</code>
* correspond to one of the <code>ImageTypeSpecifier</code>s
* returned from the <code>ImageReader</code>'s
* <code>getImageTypes</code> method. If it does not, the reader
* will throw an <code>IIOException</code>.
*
* @param destination the BufferedImage to be written to, or
* <code>null</code>.
*
* @see #getDestination
*/
public void setDestination(BufferedImage destination) {
this.destination = destination;
}
/**
* Returns the <code>BufferedImage</code> currently set by the
* <code>setDestination</code> method, or <code>null</code>
* if none is set.
*
* @return the BufferedImage to be written to.
*
* @see #setDestination
*/
public BufferedImage getDestination() {
return destination;
}
/**
* Sets the indices of the destination bands where data
* will be placed. Duplicate indices are not allowed.
*
* <p> A <code>null</code> value indicates that all destination
* bands will be used.
*
* <p> Choosing a destination band subset will not affect the
* number of bands in the output image of a read if no destination
* image is specified; the created destination image will still
* have the same number of bands as if this method had never been
* called. If a different number of bands in the destination
* image is desired, an image must be supplied using the
* <code>ImageReadParam.setDestination</code> method.
*
* <p> At the time of reading or writing, an
* <code>IllegalArgumentException</code> will be thrown by the
* reader or writer if a value larger than the largest destination
* band index has been specified, or if the number of source bands
* and destination bands to be used differ. The
* <code>ImageReader.checkReadParamBandSettings</code> method may
* be used to automate this test.
*
* @param destinationBands an array of integer band indices to be
* used.
*
* @exception IllegalArgumentException if <code>destinationBands</code>
* contains a negative or duplicate value.
*
* @see #getDestinationBands
* @see #getSourceBands
* @see ImageReader#checkReadParamBandSettings
*/
public void setDestinationBands(int[] destinationBands) {
if (destinationBands == null) {
this.destinationBands = null;
} else {
int numBands = destinationBands.length;
for (int i = 0; i < numBands; i++) {
int band = destinationBands[i];
if (band < 0) {
throw new IllegalArgumentException("Band value < 0!");
}
for (int j = i + 1; j < numBands; j++) {
if (band == destinationBands[j]) {
throw new IllegalArgumentException("Duplicate band value!");
}
}
}
this.destinationBands = (int[])destinationBands.clone();
}
}
/**
* Returns the set of band indices where data will be placed.
* If no value has been set, <code>null</code> is returned to
* indicate that all destination bands will be used.
*
* @return the indices of the destination bands to be used,
* or <code>null</code>.
*
* @see #setDestinationBands
*/
public int[] getDestinationBands() {
if (destinationBands == null) {
return null;
} else {
return (int[])(destinationBands.clone());
}
}
/**
* Returns <code>true</code> if this reader allows the source
* image to be rendered at an arbitrary size as part of the
* decoding process, by means of the
* <code>setSourceRenderSize</code> method. If this method
* returns <code>false</code>, calls to
* <code>setSourceRenderSize</code> will throw an
* <code>UnsupportedOperationException</code>.
*
* @return <code>true</code> if setting source rendering size is
* supported.
*
* @see #setSourceRenderSize
*/
public boolean canSetSourceRenderSize() {
return canSetSourceRenderSize;
}
/**
* If the image is able to be rendered at an arbitrary size, sets
* the source width and height to the supplied values. Note that
* the values returned from the <code>getWidth</code> and
* <code>getHeight</code> methods on <code>ImageReader</code> are
* not affected by this method; they will continue to return the
* default size for the image. Similarly, if the image is also
* tiled the tile width and height are given in terms of the default
* size.
*
* <p> Typically, the width and height should be chosen such that
* the ratio of width to height closely approximates the aspect
* ratio of the image, as returned from
* <code>ImageReader.getAspectRatio</code>.
*
* <p> If this plug-in does not allow the rendering size to be
* set, an <code>UnsupportedOperationException</code> will be
* thrown.
*
* <p> To remove the render size setting, pass in a value of
* <code>null</code> for <code>size</code>.
*
* @param size a <code>Dimension</code> indicating the desired
* width and height.
*
* @exception IllegalArgumentException if either the width or the
* height is negative or 0.
* @exception UnsupportedOperationException if image resizing
* is not supported by this plug-in.
*
* @see #getSourceRenderSize
* @see ImageReader#getWidth
* @see ImageReader#getHeight
* @see ImageReader#getAspectRatio
*/
public void setSourceRenderSize(Dimension size)
throws UnsupportedOperationException {
if (!canSetSourceRenderSize()) {
throw new UnsupportedOperationException
("Can't set source render size!");
}
if (size == null) {
this.sourceRenderSize = null;
} else {
if (size.width <= 0 || size.height <= 0) {
throw new IllegalArgumentException("width or height <= 0!");
}
this.sourceRenderSize = (Dimension)size.clone();
}
}
/**
* Returns the width and height of the source image as it
* will be rendered during decoding, if they have been set via the
* <code>setSourceRenderSize</code> method. A
* <code>null</code>value indicates that no setting has been made.
*
* @return the rendered width and height of the source image
* as a <code>Dimension</code>.
*
* @see #setSourceRenderSize
*/
public Dimension getSourceRenderSize() {
return (sourceRenderSize == null) ?
null : (Dimension)sourceRenderSize.clone();
}
/**
* Sets the range of progressive passes that will be decoded.
* Passes outside of this range will be ignored.
*
* <p> A progressive pass is a re-encoding of the entire image,
* generally at progressively higher effective resolutions, but
* requiring greater transmission bandwidth. The most common use
* of progressive encoding is found in the JPEG format, where
* successive passes include more detailed representations of the
* high-frequency image content.
*
* <p> The actual number of passes to be decoded is determined
* during decoding, based on the number of actual passes available
* in the stream. Thus if <code>minPass + numPasses - 1</code> is
* larger than the index of the last available passes, decoding
* will end with that pass.
*
* <p> A value of <code>numPasses</code> of
* <code>Integer.MAX_VALUE</code> indicates that all passes from
* <code>minPass</code> forward should be read. Otherwise, the
* index of the last pass (<i>i.e.</i>, <code>minPass + numPasses
* - 1</code>) must not exceed <code>Integer.MAX_VALUE</code>.
*
* <p> There is no <code>unsetSourceProgressivePasses</code>
* method; the same effect may be obtained by calling
* <code>setSourceProgressivePasses(0, Integer.MAX_VALUE)</code>.
*
* @param minPass the index of the first pass to be decoded.
* @param numPasses the maximum number of passes to be decoded.
*
* @exception IllegalArgumentException if <code>minPass</code> is
* negative, <code>numPasses</code> is negative or 0, or
* <code>numPasses</code> is smaller than
* <code>Integer.MAX_VALUE</code> but <code>minPass +
* numPasses - 1</code> is greater than
* <code>INTEGER.MAX_VALUE</code>.
*
* @see #getSourceMinProgressivePass
* @see #getSourceMaxProgressivePass
*/
public void setSourceProgressivePasses(int minPass, int numPasses) {
if (minPass < 0) {
throw new IllegalArgumentException("minPass < 0!");
}
if (numPasses <= 0) {
throw new IllegalArgumentException("numPasses <= 0!");
}
if ((numPasses != Integer.MAX_VALUE) &&
(((minPass + numPasses - 1) & 0x80000000) != 0)) {
throw new IllegalArgumentException
("minPass + numPasses - 1 > INTEGER.MAX_VALUE!");
}
this.minProgressivePass = minPass;
this.numProgressivePasses = numPasses;
}
/**
* Returns the index of the first progressive pass that will be
* decoded. If no value has been set, 0 will be returned (which is
* the correct value).
*
* @return the index of the first pass that will be decoded.
*
* @see #setSourceProgressivePasses
* @see #getSourceNumProgressivePasses
*/
public int getSourceMinProgressivePass() {
return minProgressivePass;
}
/**
* If <code>getSourceNumProgressivePasses</code> is equal to
* <code>Integer.MAX_VALUE</code>, returns
* <code>Integer.MAX_VALUE</code>. Otherwise, returns
* <code>getSourceMinProgressivePass() +
* getSourceNumProgressivePasses() - 1</code>.
*
* @return the index of the last pass to be read, or
* <code>Integer.MAX_VALUE</code>.
*/
public int getSourceMaxProgressivePass() {
if (numProgressivePasses == Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
} else {
return minProgressivePass + numProgressivePasses - 1;
}
}
/**
* Returns the number of the progressive passes that will be
* decoded. If no value has been set,
* <code>Integer.MAX_VALUE</code> will be returned (which is the
* correct value).
*
* @return the number of the passes that will be decoded.
*
* @see #setSourceProgressivePasses
* @see #getSourceMinProgressivePass
*/
public int getSourceNumProgressivePasses() {
return numProgressivePasses;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,152 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio;
import javax.imageio.metadata.IIOMetadata;
/**
* An interface providing metadata transcoding capability.
*
* <p> Any image may be transcoded (written to a different format
* than the one it was originally stored in) simply by performing
* a read operation followed by a write operation. However, loss
* of data may occur in this process due to format differences.
*
* <p> In general, the best results will be achieved when
* format-specific metadata objects can be created to encapsulate as
* much information about the image and its associated metadata as
* possible, in terms that are understood by the specific
* <code>ImageWriter</code> used to perform the encoding.
*
* <p> An <code>ImageTranscoder</code> may be used to convert the
* <code>IIOMetadata</code> objects supplied by the
* <code>ImageReader</code> (representing per-stream and per-image
* metadata) into corresponding objects suitable for encoding by a
* particular <code>ImageWriter</code>. In the case where the methods
* of this interface are being called directly on an
* <code>ImageWriter</code>, the output will be suitable for that
* writer.
*
* <p> The internal details of converting an <code>IIOMetadata</code>
* object into a writer-specific format will vary according to the
* context of the operation. Typically, an <code>ImageWriter</code>
* will inspect the incoming object to see if it implements additional
* interfaces with which the writer is familiar. This might be the
* case, for example, if the object was obtained by means of a read
* operation on a reader plug-in written by the same vendor as the
* writer. In this case, the writer may access the incoming object by
* means of its plug-in specific interfaces. In this case, the
* re-encoding may be close to lossless if the image file format is
* kept constant. If the format is changing, the writer may still
* attempt to preserve as much information as possible.
*
* <p> If the incoming object does not implement any additional
* interfaces known to the writer, the writer has no choice but to
* access it via the standard <code>IIOMetadata</code> interfaces such
* as the tree view provided by <code>IIOMetadata.getAsTree</code>.
* In this case, there is likely to be significant loss of
* information.
*
* <p> An independent <code>ImageTranscoder</code> essentially takes
* on the same role as the writer plug-in in the above examples. It
* must be familiar with the private interfaces used by both the
* reader and writer plug-ins, and manually instantiate an object that
* will be usable by the writer. The resulting metadata objects may
* be used by the writer directly.
*
* <p> No independent implementations of <code>ImageTranscoder</code>
* are provided as part of the standard API. Instead, the intention
* of this interface is to provide a way for implementations to be
* created and discovered by applications as the need arises.
*
*/
public interface ImageTranscoder {
/**
* Returns an <code>IIOMetadata</code> object that may be used for
* encoding and optionally modified using its document interfaces
* or other interfaces specific to the writer plug-in that will be
* used for encoding.
*
* <p> An optional <code>ImageWriteParam</code> may be supplied
* for cases where it may affect the structure of the stream
* metadata.
*
* <p> If the supplied <code>ImageWriteParam</code> contains
* optional setting values not understood by this writer or
* transcoder, they will be ignored.
*
* @param inData an <code>IIOMetadata</code> object representing
* stream metadata, used to initialize the state of the returned
* object.
* @param param an <code>ImageWriteParam</code> that will be used to
* encode the image, or <code>null</code>.
*
* @return an <code>IIOMetadata</code> object, or
* <code>null</code> if the plug-in does not provide metadata
* encoding capabilities.
*
* @exception IllegalArgumentException if <code>inData</code> is
* <code>null</code>.
*/
IIOMetadata convertStreamMetadata(IIOMetadata inData,
ImageWriteParam param);
/**
* Returns an <code>IIOMetadata</code> object that may be used for
* encoding and optionally modified using its document interfaces
* or other interfaces specific to the writer plug-in that will be
* used for encoding.
*
* <p> An optional <code>ImageWriteParam</code> may be supplied
* for cases where it may affect the structure of the image
* metadata.
*
* <p> If the supplied <code>ImageWriteParam</code> contains
* optional setting values not understood by this writer or
* transcoder, they will be ignored.
*
* @param inData an <code>IIOMetadata</code> object representing
* image metadata, used to initialize the state of the returned
* object.
* @param imageType an <code>ImageTypeSpecifier</code> indicating
* the layout and color information of the image with which the
* metadata will be associated.
* @param param an <code>ImageWriteParam</code> that will be used to
* encode the image, or <code>null</code>.
*
* @return an <code>IIOMetadata</code> object,
* or <code>null</code> if the plug-in does not provide
* metadata encoding capabilities.
*
* @exception IllegalArgumentException if either of
* <code>inData</code> or <code>imageType</code> is
* <code>null</code>.
*/
IIOMetadata convertImageMetadata(IIOMetadata inData,
ImageTypeSpecifier imageType,
ImageWriteParam param);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,170 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.event;
import java.util.EventListener;
import javax.imageio.ImageReader;
/**
* An interface used by <code>ImageReader</code> implementations to
* notify callers of their image and thumbnail reading methods of
* progress.
*
* <p> This interface receives general indications of decoding
* progress (via the <code>imageProgress</code> and
* <code>thumbnailProgress</code> methods), and events indicating when
* an entire image has been updated (via the
* <code>imageStarted</code>, <code>imageComplete</code>,
* <code>thumbnailStarted</code> and <code>thumbnailComplete</code>
* methods). Applications that wish to be informed of pixel updates
* as they happen (for example, during progressive decoding), should
* provide an <code>IIOReadUpdateListener</code>.
*
* @see IIOReadUpdateListener
* @see javax.imageio.ImageReader#addIIOReadProgressListener
* @see javax.imageio.ImageReader#removeIIOReadProgressListener
*
*/
public interface IIOReadProgressListener extends EventListener {
/**
* Reports that a sequence of read operations is beginning.
* <code>ImageReader</code> implementations are required to call
* this method exactly once from their
* <code>readAll(Iterator)</code> method.
*
* @param source the <code>ImageReader</code> object calling this method.
* @param minIndex the index of the first image to be read.
*/
void sequenceStarted(ImageReader source, int minIndex);
/**
* Reports that a sequence of read operations has completed.
* <code>ImageReader</code> implementations are required to call
* this method exactly once from their
* <code>readAll(Iterator)</code> method.
*
* @param source the <code>ImageReader</code> object calling this method.
*/
void sequenceComplete(ImageReader source);
/**
* Reports that an image read operation is beginning. All
* <code>ImageReader</code> implementations are required to call
* this method exactly once when beginning an image read
* operation.
*
* @param source the <code>ImageReader</code> object calling this method.
* @param imageIndex the index of the image being read within its
* containing input file or stream.
*/
void imageStarted(ImageReader source, int imageIndex);
/**
* Reports the approximate degree of completion of the current
* <code>read</code> call of the associated
* <code>ImageReader</code>.
*
* <p> The degree of completion is expressed as a percentage
* varying from <code>0.0F</code> to <code>100.0F</code>. The
* percentage should ideally be calculated in terms of the
* remaining time to completion, but it is usually more practical
* to use a more well-defined metric such as pixels decoded or
* portion of input stream consumed. In any case, a sequence of
* calls to this method during a given read operation should
* supply a monotonically increasing sequence of percentage
* values. It is not necessary to supply the exact values
* <code>0</code> and <code>100</code>, as these may be inferred
* by the callee from other methods.
*
* <p> Each particular <code>ImageReader</code> implementation may
* call this method at whatever frequency it desires. A rule of
* thumb is to call it around each 5 percent mark.
*
* @param source the <code>ImageReader</code> object calling this method.
* @param percentageDone the approximate percentage of decoding that
* has been completed.
*/
void imageProgress(ImageReader source, float percentageDone);
/**
* Reports that the current image read operation has completed.
* All <code>ImageReader</code> implementations are required to
* call this method exactly once upon completion of each image
* read operation.
*
* @param source the <code>ImageReader</code> object calling this
* method.
*/
void imageComplete(ImageReader source);
/**
* Reports that a thumbnail read operation is beginning. All
* <code>ImageReader</code> implementations are required to call
* this method exactly once when beginning a thumbnail read
* operation.
*
* @param source the <code>ImageReader</code> object calling this method.
* @param imageIndex the index of the image being read within its
* containing input file or stream.
* @param thumbnailIndex the index of the thumbnail being read.
*/
void thumbnailStarted(ImageReader source,
int imageIndex, int thumbnailIndex);
/**
* Reports the approximate degree of completion of the current
* <code>getThumbnail</code> call within the associated
* <code>ImageReader</code>. The semantics are identical to those
* of <code>imageProgress</code>.
*
* @param source the <code>ImageReader</code> object calling this method.
* @param percentageDone the approximate percentage of decoding that
* has been completed.
*/
void thumbnailProgress(ImageReader source, float percentageDone);
/**
* Reports that a thumbnail read operation has completed. All
* <code>ImageReader</code> implementations are required to call
* this method exactly once upon completion of each thumbnail read
* operation.
*
* @param source the <code>ImageReader</code> object calling this
* method.
*/
void thumbnailComplete(ImageReader source);
/**
* Reports that a read has been aborted via the reader's
* <code>abort</code> method. No further notifications will be
* given.
*
* @param source the <code>ImageReader</code> object calling this
* method.
*/
void readAborted(ImageReader source);
}

View File

@@ -0,0 +1,249 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.event;
import java.awt.image.BufferedImage;
import java.util.EventListener;
import javax.imageio.ImageReader;
/**
* An interface used by <code>ImageReader</code> implementations to
* notify callers of their image and thumbnail reading methods of
* pixel updates.
*
* @see javax.imageio.ImageReader#addIIOReadUpdateListener
* @see javax.imageio.ImageReader#removeIIOReadUpdateListener
*
*/
public interface IIOReadUpdateListener extends EventListener {
/**
* Reports that the current read operation is about to begin a
* progressive pass. Readers of formats that support progressive
* encoding should use this to notify clients when each pass is
* completed when reading a progressively encoded image.
*
* <p> An estimate of the area that will be updated by the pass is
* indicated by the <code>minX</code>, <code>minY</code>,
* <code>width</code>, and <code>height</code> parameters. If the
* pass is interlaced, that is, it only updates selected rows or
* columns, the <code>periodX</code> and <code>periodY</code>
* parameters will indicate the degree of subsampling. The set of
* bands that may be affected is indicated by the value of
* <code>bands</code>.
*
* @param source the <code>ImageReader</code> object calling this
* method.
* @param theImage the <code>BufferedImage</code> being updated.
* @param pass the number of the pass that is about to begin,
* starting with 0.
* @param minPass the index of the first pass that will be decoded.
* @param maxPass the index of the last pass that will be decoded.
* @param minX the X coordinate of the leftmost updated column
* of pixels.
* @param minY the Y coordinate of the uppermost updated row
* of pixels.
* @param periodX the horizontal spacing between updated pixels;
* a value of 1 means no gaps.
* @param periodY the vertical spacing between updated pixels;
* a value of 1 means no gaps.
* @param bands an array of <code>int</code>s indicating the the
* set bands that may be updated.
*/
void passStarted(ImageReader source,
BufferedImage theImage,
int pass,
int minPass, int maxPass,
int minX, int minY,
int periodX, int periodY,
int[] bands);
/**
* Reports that a given region of the image has been updated.
* The application might choose to redisplay the specified area,
* for example, in order to provide a progressive display effect,
* or perform other incremental processing.
*
* <p> Note that different image format readers may produce
* decoded pixels in a variety of different orders. Many readers
* will produce pixels in a simple top-to-bottom,
* left-to-right-order, but others may use multiple passes of
* interlacing, tiling, etc. The sequence of updates may even
* differ from call to call depending on network speeds, for
* example. A call to this method does not guarantee that all the
* specified pixels have actually been updated, only that some
* activity has taken place within some subregion of the one
* specified.
*
* <p> The particular <code>ImageReader</code> implementation may
* choose how often to provide updates. Each update specifies
* that a given region of the image has been updated since the
* last update. A region is described by its spatial bounding box
* (<code>minX</code>, <code>minY</code>, <code>width</code>, and
* <code>height</code>); X and Y subsampling factors
* (<code>periodX</code> and <code>periodY</code>); and a set of
* updated bands (<code>bands</code>). For example, the update:
*
* <pre>
* minX = 10
* minY = 20
* width = 3
* height = 4
* periodX = 2
* periodY = 3
* bands = { 1, 3 }
* </pre>
*
* would indicate that bands 1 and 3 of the following pixels were
* updated:
*
* <pre>
* (10, 20) (12, 20) (14, 20)
* (10, 23) (12, 23) (14, 23)
* (10, 26) (12, 26) (14, 26)
* (10, 29) (12, 29) (14, 29)
* </pre>
*
* @param source the <code>ImageReader</code> object calling this method.
* @param theImage the <code>BufferedImage</code> being updated.
* @param minX the X coordinate of the leftmost updated column
* of pixels.
* @param minY the Y coordinate of the uppermost updated row
* of pixels.
* @param width the number of updated pixels horizontally.
* @param height the number of updated pixels vertically.
* @param periodX the horizontal spacing between updated pixels;
* a value of 1 means no gaps.
* @param periodY the vertical spacing between updated pixels;
* a value of 1 means no gaps.
* @param bands an array of <code>int</code>s indicating which
* bands are being updated.
*/
void imageUpdate(ImageReader source,
BufferedImage theImage,
int minX, int minY,
int width, int height,
int periodX, int periodY,
int[] bands);
/**
* Reports that the current read operation has completed a
* progressive pass. Readers of formats that support
* progressive encoding should use this to notify clients when
* each pass is completed when reading a progressively
* encoded image.
*
* @param source the <code>ImageReader</code> object calling this
* method.
* @param theImage the <code>BufferedImage</code> being updated.
*
* @see javax.imageio.ImageReadParam#setSourceProgressivePasses(int, int)
*/
void passComplete(ImageReader source, BufferedImage theImage);
/**
* Reports that the current thumbnail read operation is about to
* begin a progressive pass. Readers of formats that support
* progressive encoding should use this to notify clients when
* each pass is completed when reading a progressively encoded
* thumbnail image.
*
* @param source the <code>ImageReader</code> object calling this
* method.
* @param theThumbnail the <code>BufferedImage</code> thumbnail
* being updated.
* @param pass the number of the pass that is about to begin,
* starting with 0.
* @param minPass the index of the first pass that will be decoded.
* @param maxPass the index of the last pass that will be decoded.
* @param minX the X coordinate of the leftmost updated column
* of pixels.
* @param minY the Y coordinate of the uppermost updated row
* of pixels.
* @param periodX the horizontal spacing between updated pixels;
* a value of 1 means no gaps.
* @param periodY the vertical spacing between updated pixels;
* a value of 1 means no gaps.
* @param bands an array of <code>int</code>s indicating the the
* set bands that may be updated.
*
* @see #passStarted
*/
void thumbnailPassStarted(ImageReader source,
BufferedImage theThumbnail,
int pass,
int minPass, int maxPass,
int minX, int minY,
int periodX, int periodY,
int[] bands);
/**
* Reports that a given region of a thumbnail image has been updated.
* The application might choose to redisplay the specified area,
* for example, in order to provide a progressive display effect,
* or perform other incremental processing.
*
* @param source the <code>ImageReader</code> object calling this method.
* @param theThumbnail the <code>BufferedImage</code> thumbnail
* being updated.
* @param minX the X coordinate of the leftmost updated column
* of pixels.
* @param minY the Y coordinate of the uppermost updated row
* of pixels.
* @param width the number of updated pixels horizontally.
* @param height the number of updated pixels vertically.
* @param periodX the horizontal spacing between updated pixels;
* a value of 1 means no gaps.
* @param periodY the vertical spacing between updated pixels;
* a value of 1 means no gaps.
* @param bands an array of <code>int</code>s indicating which
* bands are being updated.
*
* @see #imageUpdate
*/
void thumbnailUpdate(ImageReader source,
BufferedImage theThumbnail,
int minX, int minY,
int width, int height,
int periodX, int periodY,
int[] bands);
/**
* Reports that the current thumbnail read operation has completed
* a progressive pass. Readers of formats that support
* progressive encoding should use this to notify clients when
* each pass is completed when reading a progressively encoded
* thumbnail image.
*
* @param source the <code>ImageReader</code> object calling this
* method.
* @param theThumbnail the <code>BufferedImage</code> thumbnail
* being updated.
*
* @see #passComplete
*/
void thumbnailPassComplete(ImageReader source, BufferedImage theThumbnail);
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.event;
import java.util.EventListener;
import javax.imageio.ImageReader;
/**
* An interface used by <code>ImageReader</code> implementations to
* notify callers of their image and thumbnail reading methods of
* warnings (non-fatal errors). Fatal errors cause the relevant
* read method to throw an <code>IIOException</code>.
*
* <p> Localization is handled by associating a <code>Locale</code>
* with each <code>IIOReadWarningListener</code> as it is registered
* with an <code>ImageReader</code>. It is up to the
* <code>ImageReader</code> to provide localized messages.
*
* @see javax.imageio.ImageReader#addIIOReadWarningListener
* @see javax.imageio.ImageReader#removeIIOReadWarningListener
*
*/
public interface IIOReadWarningListener extends EventListener {
/**
* Reports the occurrence of a non-fatal error in decoding. Decoding
* will continue following the call to this method. The application
* may choose to display a dialog, print the warning to the console,
* ignore the warning, or take any other action it chooses.
*
* @param source the <code>ImageReader</code> object calling this method.
* @param warning a <code>String</code> containing the warning.
*/
void warningOccurred(ImageReader source, String warning);
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.event;
import java.util.EventListener;
import javax.imageio.ImageWriter;
/**
* An interface used by <code>ImageWriter</code> implementations to notify
* callers of their image writing methods of progress.
*
* @see javax.imageio.ImageWriter#write
*
*/
public interface IIOWriteProgressListener extends EventListener {
/**
* Reports that an image write operation is beginning. All
* <code>ImageWriter</code> implementations are required to call
* this method exactly once when beginning an image write
* operation.
*
* @param source the <code>ImageWriter</code> object calling this
* method.
* @param imageIndex the index of the image being written within
* its containing input file or stream.
*/
void imageStarted(ImageWriter source, int imageIndex);
/**
* Reports the approximate degree of completion of the current
* <code>write</code> call within the associated
* <code>ImageWriter</code>.
*
* <p> The degree of completion is expressed as an index
* indicating which image is being written, and a percentage
* varying from <code>0.0F</code> to <code>100.0F</code>
* indicating how much of the current image has been output. The
* percentage should ideally be calculated in terms of the
* remaining time to completion, but it is usually more practical
* to use a more well-defined metric such as pixels decoded or
* portion of input stream consumed. In any case, a sequence of
* calls to this method during a given read operation should
* supply a monotonically increasing sequence of percentage
* values. It is not necessary to supply the exact values
* <code>0</code> and <code>100</code>, as these may be inferred
* by the callee from other methods.
*
* <p> Each particular <code>ImageWriter</code> implementation may
* call this method at whatever frequency it desires. A rule of
* thumb is to call it around each 5 percent mark.
*
* @param source the <code>ImageWriter</code> object calling this method.
* @param percentageDone the approximate percentage of decoding that
* has been completed.
*/
void imageProgress(ImageWriter source,
float percentageDone);
/**
* Reports that the image write operation has completed. All
* <code>ImageWriter</code> implementations are required to call
* this method exactly once upon completion of each image write
* operation.
*
* @param source the <code>ImageWriter</code> object calling this method.
*/
void imageComplete(ImageWriter source);
/**
* Reports that a thumbnail write operation is beginning. All
* <code>ImageWriter</code> implementations are required to call
* this method exactly once when beginning a thumbnail write
* operation.
*
* @param source the <code>ImageWrite</code> object calling this method.
* @param imageIndex the index of the image being written within its
* containing input file or stream.
* @param thumbnailIndex the index of the thumbnail being written.
*/
void thumbnailStarted(ImageWriter source,
int imageIndex, int thumbnailIndex);
/**
* Reports the approximate degree of completion of the current
* thumbnail write within the associated <code>ImageWriter</code>.
* The semantics are identical to those of
* <code>imageProgress</code>.
*
* @param source the <code>ImageWriter</code> object calling this
* method.
* @param percentageDone the approximate percentage of decoding that
* has been completed.
*/
void thumbnailProgress(ImageWriter source, float percentageDone);
/**
* Reports that a thumbnail write operation has completed. All
* <code>ImageWriter</code> implementations are required to call
* this method exactly once upon completion of each thumbnail
* write operation.
*
* @param source the <code>ImageWriter</code> object calling this
* method.
*/
void thumbnailComplete(ImageWriter source);
/**
* Reports that a write has been aborted via the writer's
* <code>abort</code> method. No further notifications will be
* given.
*
* @param source the <code>ImageWriter</code> object calling this
* method.
*/
void writeAborted(ImageWriter source);
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.event;
import java.util.EventListener;
import javax.imageio.ImageWriter;
/**
* An interface used by <code>ImageWriter</code> implementations to
* notify callers of their image and thumbnail reading methods of
* warnings (non-fatal errors). Fatal errors cause the relevant
* read method to throw an <code>IIOException</code>.
*
* <p> Localization is handled by associating a <code>Locale</code>
* with each <code>IIOWriteWarningListener</code> as it is registered
* with an <code>ImageWriter</code>. It is up to the
* <code>ImageWriter</code> to provide localized messages.
*
* @see javax.imageio.ImageWriter#addIIOWriteWarningListener
* @see javax.imageio.ImageWriter#removeIIOWriteWarningListener
*
*/
public interface IIOWriteWarningListener extends EventListener {
/**
* Reports the occurrence of a non-fatal error in encoding. Encoding
* will continue following the call to this method. The application
* may choose to display a dialog, print the warning to the console,
* ignore the warning, or take any other action it chooses.
*
* @param source the <code>ImageWriter</code> object calling this method.
* @param imageIndex the index, starting with 0, of the image
* generating the warning.
* @param warning a <code>String</code> containing the warning.
*/
void warningOccurred(ImageWriter source,
int imageIndex,
String warning);
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.metadata;
import javax.imageio.IIOException;
import org.w3c.dom.Node;
/**
* An <code>IIOInvalidTreeException</code> is thrown when an attempt
* by an <code>IIOMetadata</code> object to parse a tree of
* <code>IIOMetadataNode</code>s fails. The node that led to the
* parsing error may be stored. As with any parsing error, the actual
* error may occur at a different point that that where it is
* detected. The node returned by <code>getOffendingNode</code>
* should merely be considered as a clue to the actual nature of the
* problem.
*
* @see IIOMetadata#setFromTree
* @see IIOMetadata#mergeTree
* @see IIOMetadataNode
*
*/
public class IIOInvalidTreeException extends IIOException {
/**
* The <code>Node</code> that led to the parsing error, or
* <code>null</code>.
*/
protected Node offendingNode = null;
/**
* Constructs an <code>IIOInvalidTreeException</code> with a
* message string and a reference to the <code>Node</code> that
* caused the parsing error.
*
* @param message a <code>String</code> containing the reason for
* the parsing failure.
* @param offendingNode the DOM <code>Node</code> that caused the
* exception, or <code>null</code>.
*/
public IIOInvalidTreeException(String message, Node offendingNode) {
super(message);
this.offendingNode = offendingNode;
}
/**
* Constructs an <code>IIOInvalidTreeException</code> with a
* message string, a reference to an exception that caused this
* exception, and a reference to the <code>Node</code> that caused
* the parsing error.
*
* @param message a <code>String</code> containing the reason for
* the parsing failure.
* @param cause the <code>Throwable</code> (<code>Error</code> or
* <code>Exception</code>) that caused this exception to occur,
* or <code>null</code>.
* @param offendingNode the DOM <code>Node</code> that caused the
* exception, or <code>null</code>.
*/
public IIOInvalidTreeException(String message, Throwable cause,
Node offendingNode) {
super(message, cause);
this.offendingNode = offendingNode;
}
/**
* Returns the <code>Node</code> that caused the error in parsing.
*
* @return the offending <code>Node</code>.
*/
public Node getOffendingNode() {
return offendingNode;
}
}

View File

@@ -0,0 +1,900 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.metadata;
import org.w3c.dom.Node;
import java.lang.reflect.Method;
/**
* An abstract class to be extended by objects that represent metadata
* (non-image data) associated with images and streams. Plug-ins
* represent metadata using opaque, plug-in specific objects. These
* objects, however, provide the ability to access their internal
* information as a tree of <code>IIOMetadataNode</code> objects that
* support the XML DOM interfaces as well as additional interfaces for
* storing non-textual data and retrieving information about legal
* data values. The format of such trees is plug-in dependent, but
* plug-ins may choose to support a plug-in neutral format described
* below. A single plug-in may support multiple metadata formats,
* whose names maybe determined by calling
* <code>getMetadataFormatNames</code>. The plug-in may also support
* a single special format, referred to as the "native" format, which
* is designed to encode its metadata losslessly. This format will
* typically be designed specifically to work with a specific file
* format, so that images may be loaded and saved in the same format
* with no loss of metadata, but may be less useful for transferring
* metadata between an <code>ImageReader</code> and an
* <code>ImageWriter</code> for different image formats. To convert
* between two native formats as losslessly as the image file formats
* will allow, an <code>ImageTranscoder</code> object must be used.
*
* @see javax.imageio.ImageReader#getImageMetadata
* @see javax.imageio.ImageReader#getStreamMetadata
* @see javax.imageio.ImageReader#readAll
* @see javax.imageio.ImageWriter#getDefaultStreamMetadata
* @see javax.imageio.ImageWriter#getDefaultImageMetadata
* @see javax.imageio.ImageWriter#write
* @see javax.imageio.ImageWriter#convertImageMetadata
* @see javax.imageio.ImageWriter#convertStreamMetadata
* @see javax.imageio.IIOImage
* @see javax.imageio.ImageTranscoder
*
*/
public abstract class IIOMetadata {
/**
* A boolean indicating whether the concrete subclass supports the
* standard metadata format, set via the constructor.
*/
protected boolean standardFormatSupported;
/**
* The name of the native metadata format for this object,
* initialized to <code>null</code> and set via the constructor.
*/
protected String nativeMetadataFormatName = null;
/**
* The name of the class implementing <code>IIOMetadataFormat</code>
* and representing the native metadata format, initialized to
* <code>null</code> and set via the constructor.
*/
protected String nativeMetadataFormatClassName = null;
/**
* An array of names of formats, other than the standard and
* native formats, that are supported by this plug-in,
* initialized to <code>null</code> and set via the constructor.
*/
protected String[] extraMetadataFormatNames = null;
/**
* An array of names of classes implementing <code>IIOMetadataFormat</code>
* and representing the metadata formats, other than the standard and
* native formats, that are supported by this plug-in,
* initialized to <code>null</code> and set via the constructor.
*/
protected String[] extraMetadataFormatClassNames = null;
/**
* An <code>IIOMetadataController</code> that is suggested for use
* as the controller for this <code>IIOMetadata</code> object. It
* may be retrieved via <code>getDefaultController</code>. To
* install the default controller, call
* <code>setController(getDefaultController())</code>. This
* instance variable should be set by subclasses that choose to
* provide their own default controller, usually a GUI, for
* setting parameters.
*
* @see IIOMetadataController
* @see #getDefaultController
*/
protected IIOMetadataController defaultController = null;
/**
* The <code>IIOMetadataController</code> that will be
* used to provide settings for this <code>IIOMetadata</code>
* object when the <code>activateController</code> method
* is called. This value overrides any default controller,
* even when <code>null</code>.
*
* @see IIOMetadataController
* @see #setController(IIOMetadataController)
* @see #hasController()
* @see #activateController()
*/
protected IIOMetadataController controller = null;
/**
* Constructs an empty <code>IIOMetadata</code> object. The
* subclass is responsible for supplying values for all protected
* instance variables that will allow any non-overridden default
* implementations of methods to satisfy their contracts. For example,
* <code>extraMetadataFormatNames</code> should not have length 0.
*/
protected IIOMetadata() {}
/**
* Constructs an <code>IIOMetadata</code> object with the given
* format names and format class names, as well as a boolean
* indicating whether the standard format is supported.
*
* <p> This constructor does not attempt to check the class names
* for validity. Invalid class names may cause exceptions in
* subsequent calls to <code>getMetadataFormat</code>.
*
* @param standardMetadataFormatSupported <code>true</code> if
* this object can return or accept a DOM tree using the standard
* metadata format.
* @param nativeMetadataFormatName the name of the native metadata
* format, as a <code>String</code>, or <code>null</code> if there
* is no native format.
* @param nativeMetadataFormatClassName the name of the class of
* the native metadata format, or <code>null</code> if there is
* no native format.
* @param extraMetadataFormatNames an array of <code>String</code>s
* indicating additional formats supported by this object, or
* <code>null</code> if there are none.
* @param extraMetadataFormatClassNames an array of <code>String</code>s
* indicating the class names of any additional formats supported by
* this object, or <code>null</code> if there are none.
*
* @exception IllegalArgumentException if
* <code>extraMetadataFormatNames</code> has length 0.
* @exception IllegalArgumentException if
* <code>extraMetadataFormatNames</code> and
* <code>extraMetadataFormatClassNames</code> are neither both
* <code>null</code>, nor of the same length.
*/
protected IIOMetadata(boolean standardMetadataFormatSupported,
String nativeMetadataFormatName,
String nativeMetadataFormatClassName,
String[] extraMetadataFormatNames,
String[] extraMetadataFormatClassNames) {
this.standardFormatSupported = standardMetadataFormatSupported;
this.nativeMetadataFormatName = nativeMetadataFormatName;
this.nativeMetadataFormatClassName = nativeMetadataFormatClassName;
if (extraMetadataFormatNames != null) {
if (extraMetadataFormatNames.length == 0) {
throw new IllegalArgumentException
("extraMetadataFormatNames.length == 0!");
}
if (extraMetadataFormatClassNames == null) {
throw new IllegalArgumentException
("extraMetadataFormatNames != null && extraMetadataFormatClassNames == null!");
}
if (extraMetadataFormatClassNames.length !=
extraMetadataFormatNames.length) {
throw new IllegalArgumentException
("extraMetadataFormatClassNames.length != extraMetadataFormatNames.length!");
}
this.extraMetadataFormatNames =
(String[]) extraMetadataFormatNames.clone();
this.extraMetadataFormatClassNames =
(String[]) extraMetadataFormatClassNames.clone();
} else {
if (extraMetadataFormatClassNames != null) {
throw new IllegalArgumentException
("extraMetadataFormatNames == null && extraMetadataFormatClassNames != null!");
}
}
}
/**
* Returns <code>true</code> if the standard metadata format is
* supported by <code>getMetadataFormat</code>,
* <code>getAsTree</code>, <code>setFromTree</code>, and
* <code>mergeTree</code>.
*
* <p> The default implementation returns the value of the
* <code>standardFormatSupported</code> instance variable.
*
* @return <code>true</code> if the standard metadata format
* is supported.
*
* @see #getAsTree
* @see #setFromTree
* @see #mergeTree
* @see #getMetadataFormat
*/
public boolean isStandardMetadataFormatSupported() {
return standardFormatSupported;
}
/**
* Returns <code>true</code> if this object does not support the
* <code>mergeTree</code>, <code>setFromTree</code>, and
* <code>reset</code> methods.
*
* @return true if this <code>IIOMetadata</code> object cannot be
* modified.
*/
public abstract boolean isReadOnly();
/**
* Returns the name of the "native" metadata format for this
* plug-in, which typically allows for lossless encoding and
* transmission of the metadata stored in the format handled by
* this plug-in. If no such format is supported,
* <code>null</code>will be returned.
*
* <p> The structure and contents of the "native" metadata format
* are defined by the plug-in that created this
* <code>IIOMetadata</code> object. Plug-ins for simple formats
* will usually create a dummy node for the root, and then a
* series of child nodes representing individual tags, chunks, or
* keyword/value pairs. A plug-in may choose whether or not to
* document its native format.
*
* <p> The default implementation returns the value of the
* <code>nativeMetadataFormatName</code> instance variable.
*
* @return the name of the native format, or <code>null</code>.
*
* @see #getExtraMetadataFormatNames
* @see #getMetadataFormatNames
*/
public String getNativeMetadataFormatName() {
return nativeMetadataFormatName;
}
/**
* Returns an array of <code>String</code>s containing the names
* of additional metadata formats, other than the native and standard
* formats, recognized by this plug-in's
* <code>getAsTree</code>, <code>setFromTree</code>, and
* <code>mergeTree</code> methods. If there are no such additional
* formats, <code>null</code> is returned.
*
* <p> The default implementation returns a clone of the
* <code>extraMetadataFormatNames</code> instance variable.
*
* @return an array of <code>String</code>s with length at least
* 1, or <code>null</code>.
*
* @see #getAsTree
* @see #setFromTree
* @see #mergeTree
* @see #getNativeMetadataFormatName
* @see #getMetadataFormatNames
*/
public String[] getExtraMetadataFormatNames() {
if (extraMetadataFormatNames == null) {
return null;
}
return (String[])extraMetadataFormatNames.clone();
}
/**
* Returns an array of <code>String</code>s containing the names
* of all metadata formats, including the native and standard
* formats, recognized by this plug-in's <code>getAsTree</code>,
* <code>setFromTree</code>, and <code>mergeTree</code> methods.
* If there are no such formats, <code>null</code> is returned.
*
* <p> The default implementation calls
* <code>getNativeMetadataFormatName</code>,
* <code>isStandardMetadataFormatSupported</code>, and
* <code>getExtraMetadataFormatNames</code> and returns the
* combined results.
*
* @return an array of <code>String</code>s.
*
* @see #getNativeMetadataFormatName
* @see #isStandardMetadataFormatSupported
* @see #getExtraMetadataFormatNames
*/
public String[] getMetadataFormatNames() {
String nativeName = getNativeMetadataFormatName();
String standardName = isStandardMetadataFormatSupported() ?
IIOMetadataFormatImpl.standardMetadataFormatName : null;
String[] extraNames = getExtraMetadataFormatNames();
int numFormats = 0;
if (nativeName != null) {
++numFormats;
}
if (standardName != null) {
++numFormats;
}
if (extraNames != null) {
numFormats += extraNames.length;
}
if (numFormats == 0) {
return null;
}
String[] formats = new String[numFormats];
int index = 0;
if (nativeName != null) {
formats[index++] = nativeName;
}
if (standardName != null) {
formats[index++] = standardName;
}
if (extraNames != null) {
for (int i = 0; i < extraNames.length; i++) {
formats[index++] = extraNames[i];
}
}
return formats;
}
/**
* Returns an <code>IIOMetadataFormat</code> object describing the
* given metadata format, or <code>null</code> if no description
* is available. The supplied name must be one of those returned
* by <code>getMetadataFormatNames</code> (<i>i.e.</i>, either the
* native format name, the standard format name, or one of those
* returned by <code>getExtraMetadataFormatNames</code>).
*
* <p> The default implementation checks the name against the
* global standard metadata format name, and returns that format
* if it is supported. Otherwise, it checks against the native
* format names followed by any additional format names. If a
* match is found, it retrieves the name of the
* <code>IIOMetadataFormat</code> class from
* <code>nativeMetadataFormatClassName</code> or
* <code>extraMetadataFormatClassNames</code> as appropriate, and
* constructs an instance of that class using its
* <code>getInstance</code> method.
*
* @param formatName the desired metadata format.
*
* @return an <code>IIOMetadataFormat</code> object.
*
* @exception IllegalArgumentException if <code>formatName</code>
* is <code>null</code> or is not one of the names recognized by
* the plug-in.
* @exception IllegalStateException if the class corresponding to
* the format name cannot be loaded.
*/
public IIOMetadataFormat getMetadataFormat(String formatName) {
if (formatName == null) {
throw new IllegalArgumentException("formatName == null!");
}
if (standardFormatSupported
&& formatName.equals
(IIOMetadataFormatImpl.standardMetadataFormatName)) {
return IIOMetadataFormatImpl.getStandardFormatInstance();
}
String formatClassName = null;
if (formatName.equals(nativeMetadataFormatName)) {
formatClassName = nativeMetadataFormatClassName;
} else if (extraMetadataFormatNames != null) {
for (int i = 0; i < extraMetadataFormatNames.length; i++) {
if (formatName.equals(extraMetadataFormatNames[i])) {
formatClassName = extraMetadataFormatClassNames[i];
break; // out of for
}
}
}
if (formatClassName == null) {
throw new IllegalArgumentException("Unsupported format name");
}
try {
Class cls = null;
final Object o = this;
// firstly we try to use classloader used for loading
// the IIOMetadata implemantation for this plugin.
ClassLoader loader = (ClassLoader)
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
return o.getClass().getClassLoader();
}
});
try {
cls = Class.forName(formatClassName, true,
loader);
} catch (ClassNotFoundException e) {
// we failed to load IIOMetadataFormat class by
// using IIOMetadata classloader.Next try is to
// use thread context classloader.
loader = (ClassLoader)
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
return Thread.currentThread().getContextClassLoader();
}
});
try {
cls = Class.forName(formatClassName, true,
loader);
} catch (ClassNotFoundException e1) {
// finally we try to use system classloader in case
// if we failed to load IIOMetadataFormat implementation
// class above.
cls = Class.forName(formatClassName, true,
ClassLoader.getSystemClassLoader());
}
}
Method meth = cls.getMethod("getInstance");
return (IIOMetadataFormat) meth.invoke(null);
} catch (Exception e) {
RuntimeException ex =
new IllegalStateException ("Can't obtain format");
ex.initCause(e);
throw ex;
}
}
/**
* Returns an XML DOM <code>Node</code> object that represents the
* root of a tree of metadata contained within this object
* according to the conventions defined by a given metadata
* format.
*
* <p> The names of the available metadata formats may be queried
* using the <code>getMetadataFormatNames</code> method.
*
* @param formatName the desired metadata format.
*
* @return an XML DOM <code>Node</code> object forming the
* root of a tree.
*
* @exception IllegalArgumentException if <code>formatName</code>
* is <code>null</code> or is not one of the names returned by
* <code>getMetadataFormatNames</code>.
*
* @see #getMetadataFormatNames
* @see #setFromTree
* @see #mergeTree
*/
public abstract Node getAsTree(String formatName);
/**
* Alters the internal state of this <code>IIOMetadata</code>
* object from a tree of XML DOM <code>Node</code>s whose syntax
* is defined by the given metadata format. The previous state is
* altered only as necessary to accommodate the nodes that are
* present in the given tree. If the tree structure or contents
* are invalid, an <code>IIOInvalidTreeException</code> will be
* thrown.
*
* <p> As the semantics of how a tree or subtree may be merged with
* another tree are completely format-specific, plug-in authors may
* implement this method in whatever manner is most appropriate for
* the format, including simply replacing all existing state with the
* contents of the given tree.
*
* @param formatName the desired metadata format.
* @param root an XML DOM <code>Node</code> object forming the
* root of a tree.
*
* @exception IllegalStateException if this object is read-only.
* @exception IllegalArgumentException if <code>formatName</code>
* is <code>null</code> or is not one of the names returned by
* <code>getMetadataFormatNames</code>.
* @exception IllegalArgumentException if <code>root</code> is
* <code>null</code>.
* @exception IIOInvalidTreeException if the tree cannot be parsed
* successfully using the rules of the given format.
*
* @see #getMetadataFormatNames
* @see #getAsTree
* @see #setFromTree
*/
public abstract void mergeTree(String formatName, Node root)
throws IIOInvalidTreeException;
/**
* Returns an <code>IIOMetadataNode</code> representing the chroma
* information of the standard <code>javax_imageio_1.0</code>
* metadata format, or <code>null</code> if no such information is
* available. This method is intended to be called by the utility
* routine <code>getStandardTree</code>.
*
* <p> The default implementation returns <code>null</code>.
*
* <p> Subclasses should override this method to produce an
* appropriate subtree if they wish to support the standard
* metadata format.
*
* @return an <code>IIOMetadataNode</code>, or <code>null</code>.
*
* @see #getStandardTree
*/
protected IIOMetadataNode getStandardChromaNode() {
return null;
}
/**
* Returns an <code>IIOMetadataNode</code> representing the
* compression information of the standard
* <code>javax_imageio_1.0</code> metadata format, or
* <code>null</code> if no such information is available. This
* method is intended to be called by the utility routine
* <code>getStandardTree</code>.
*
* <p> The default implementation returns <code>null</code>.
*
* <p> Subclasses should override this method to produce an
* appropriate subtree if they wish to support the standard
* metadata format.
*
* @return an <code>IIOMetadataNode</code>, or <code>null</code>.
*
* @see #getStandardTree
*/
protected IIOMetadataNode getStandardCompressionNode() {
return null;
}
/**
* Returns an <code>IIOMetadataNode</code> representing the data
* format information of the standard
* <code>javax_imageio_1.0</code> metadata format, or
* <code>null</code> if no such information is available. This
* method is intended to be called by the utility routine
* <code>getStandardTree</code>.
*
* <p> The default implementation returns <code>null</code>.
*
* <p> Subclasses should override this method to produce an
* appropriate subtree if they wish to support the standard
* metadata format.
*
* @return an <code>IIOMetadataNode</code>, or <code>null</code>.
*
* @see #getStandardTree
*/
protected IIOMetadataNode getStandardDataNode() {
return null;
}
/**
* Returns an <code>IIOMetadataNode</code> representing the
* dimension information of the standard
* <code>javax_imageio_1.0</code> metadata format, or
* <code>null</code> if no such information is available. This
* method is intended to be called by the utility routine
* <code>getStandardTree</code>.
*
* <p> The default implementation returns <code>null</code>.
*
* <p> Subclasses should override this method to produce an
* appropriate subtree if they wish to support the standard
* metadata format.
*
* @return an <code>IIOMetadataNode</code>, or <code>null</code>.
*
* @see #getStandardTree
*/
protected IIOMetadataNode getStandardDimensionNode() {
return null;
}
/**
* Returns an <code>IIOMetadataNode</code> representing the document
* information of the standard <code>javax_imageio_1.0</code>
* metadata format, or <code>null</code> if no such information is
* available. This method is intended to be called by the utility
* routine <code>getStandardTree</code>.
*
* <p> The default implementation returns <code>null</code>.
*
* <p> Subclasses should override this method to produce an
* appropriate subtree if they wish to support the standard
* metadata format.
*
* @return an <code>IIOMetadataNode</code>, or <code>null</code>.
*
* @see #getStandardTree
*/
protected IIOMetadataNode getStandardDocumentNode() {
return null;
}
/**
* Returns an <code>IIOMetadataNode</code> representing the textual
* information of the standard <code>javax_imageio_1.0</code>
* metadata format, or <code>null</code> if no such information is
* available. This method is intended to be called by the utility
* routine <code>getStandardTree</code>.
*
* <p> The default implementation returns <code>null</code>.
*
* <p> Subclasses should override this method to produce an
* appropriate subtree if they wish to support the standard
* metadata format.
*
* @return an <code>IIOMetadataNode</code>, or <code>null</code>.
*
* @see #getStandardTree
*/
protected IIOMetadataNode getStandardTextNode() {
return null;
}
/**
* Returns an <code>IIOMetadataNode</code> representing the tiling
* information of the standard <code>javax_imageio_1.0</code>
* metadata format, or <code>null</code> if no such information is
* available. This method is intended to be called by the utility
* routine <code>getStandardTree</code>.
*
* <p> The default implementation returns <code>null</code>.
*
* <p> Subclasses should override this method to produce an
* appropriate subtree if they wish to support the standard
* metadata format.
*
* @return an <code>IIOMetadataNode</code>, or <code>null</code>.
*
* @see #getStandardTree
*/
protected IIOMetadataNode getStandardTileNode() {
return null;
}
/**
* Returns an <code>IIOMetadataNode</code> representing the
* transparency information of the standard
* <code>javax_imageio_1.0</code> metadata format, or
* <code>null</code> if no such information is available. This
* method is intended to be called by the utility routine
* <code>getStandardTree</code>.
*
* <p> The default implementation returns <code>null</code>.
*
* <p> Subclasses should override this method to produce an
* appropriate subtree if they wish to support the standard
* metadata format.
*
* @return an <code>IIOMetadataNode</code>, or <code>null</code>.
*/
protected IIOMetadataNode getStandardTransparencyNode() {
return null;
}
/**
* Appends a new node to an existing node, if the new node is
* non-<code>null</code>.
*/
private void append(IIOMetadataNode root, IIOMetadataNode node) {
if (node != null) {
root.appendChild(node);
}
}
/**
* A utility method to return a tree of
* <code>IIOMetadataNode</code>s representing the metadata
* contained within this object according to the conventions of
* the standard <code>javax_imageio_1.0</code> metadata format.
*
* <p> This method calls the various <code>getStandard*Node</code>
* methods to supply each of the subtrees rooted at the children
* of the root node. If any of those methods returns
* <code>null</code>, the corresponding subtree will be omitted.
* If all of them return <code>null</code>, a tree consisting of a
* single root node will be returned.
*
* @return an <code>IIOMetadataNode</code> representing the root
* of a metadata tree in the <code>javax_imageio_1.0</code>
* format.
*
* @see #getStandardChromaNode
* @see #getStandardCompressionNode
* @see #getStandardDataNode
* @see #getStandardDimensionNode
* @see #getStandardDocumentNode
* @see #getStandardTextNode
* @see #getStandardTileNode
* @see #getStandardTransparencyNode
*/
protected final IIOMetadataNode getStandardTree() {
IIOMetadataNode root = new IIOMetadataNode
(IIOMetadataFormatImpl.standardMetadataFormatName);
append(root, getStandardChromaNode());
append(root, getStandardCompressionNode());
append(root, getStandardDataNode());
append(root, getStandardDimensionNode());
append(root, getStandardDocumentNode());
append(root, getStandardTextNode());
append(root, getStandardTileNode());
append(root, getStandardTransparencyNode());
return root;
}
/**
* Sets the internal state of this <code>IIOMetadata</code> object
* from a tree of XML DOM <code>Node</code>s whose syntax is
* defined by the given metadata format. The previous state is
* discarded. If the tree's structure or contents are invalid, an
* <code>IIOInvalidTreeException</code> will be thrown.
*
* <p> The default implementation calls <code>reset</code>
* followed by <code>mergeTree(formatName, root)</code>.
*
* @param formatName the desired metadata format.
* @param root an XML DOM <code>Node</code> object forming the
* root of a tree.
*
* @exception IllegalStateException if this object is read-only.
* @exception IllegalArgumentException if <code>formatName</code>
* is <code>null</code> or is not one of the names returned by
* <code>getMetadataFormatNames</code>.
* @exception IllegalArgumentException if <code>root</code> is
* <code>null</code>.
* @exception IIOInvalidTreeException if the tree cannot be parsed
* successfully using the rules of the given format.
*
* @see #getMetadataFormatNames
* @see #getAsTree
* @see #mergeTree
*/
public void setFromTree(String formatName, Node root)
throws IIOInvalidTreeException {
reset();
mergeTree(formatName, root);
}
/**
* Resets all the data stored in this object to default values,
* usually to the state this object was in immediately after
* construction, though the precise semantics are plug-in specific.
* Note that there are many possible default values, depending on
* how the object was created.
*
* @exception IllegalStateException if this object is read-only.
*
* @see javax.imageio.ImageReader#getStreamMetadata
* @see javax.imageio.ImageReader#getImageMetadata
* @see javax.imageio.ImageWriter#getDefaultStreamMetadata
* @see javax.imageio.ImageWriter#getDefaultImageMetadata
*/
public abstract void reset();
/**
* Sets the <code>IIOMetadataController</code> to be used
* to provide settings for this <code>IIOMetadata</code>
* object when the <code>activateController</code> method
* is called, overriding any default controller. If the
* argument is <code>null</code>, no controller will be
* used, including any default. To restore the default, use
* <code>setController(getDefaultController())</code>.
*
* <p> The default implementation sets the <code>controller</code>
* instance variable to the supplied value.
*
* @param controller An appropriate
* <code>IIOMetadataController</code>, or <code>null</code>.
*
* @see IIOMetadataController
* @see #getController
* @see #getDefaultController
* @see #hasController
* @see #activateController()
*/
public void setController(IIOMetadataController controller) {
this.controller = controller;
}
/**
* Returns whatever <code>IIOMetadataController</code> is currently
* installed. This could be the default if there is one,
* <code>null</code>, or the argument of the most recent call
* to <code>setController</code>.
*
* <p> The default implementation returns the value of the
* <code>controller</code> instance variable.
*
* @return the currently installed
* <code>IIOMetadataController</code>, or <code>null</code>.
*
* @see IIOMetadataController
* @see #setController
* @see #getDefaultController
* @see #hasController
* @see #activateController()
*/
public IIOMetadataController getController() {
return controller;
}
/**
* Returns the default <code>IIOMetadataController</code>, if there
* is one, regardless of the currently installed controller. If
* there is no default controller, returns <code>null</code>.
*
* <p> The default implementation returns the value of the
* <code>defaultController</code> instance variable.
*
* @return the default <code>IIOMetadataController</code>, or
* <code>null</code>.
*
* @see IIOMetadataController
* @see #setController(IIOMetadataController)
* @see #getController
* @see #hasController
* @see #activateController()
*/
public IIOMetadataController getDefaultController() {
return defaultController;
}
/**
* Returns <code>true</code> if there is a controller installed
* for this <code>IIOMetadata</code> object.
*
* <p> The default implementation returns <code>true</code> if the
* <code>getController</code> method returns a
* non-<code>null</code> value.
*
* @return <code>true</code> if a controller is installed.
*
* @see IIOMetadataController
* @see #setController(IIOMetadataController)
* @see #getController
* @see #getDefaultController
* @see #activateController()
*/
public boolean hasController() {
return (getController() != null);
}
/**
* Activates the installed <code>IIOMetadataController</code> for
* this <code>IIOMetadata</code> object and returns the resulting
* value. When this method returns <code>true</code>, all values for this
* <code>IIOMetadata</code> object will be ready for the next write
* operation. If <code>false</code> is
* returned, no settings in this object will have been disturbed
* (<i>i.e.</i>, the user canceled the operation).
*
* <p> Ordinarily, the controller will be a GUI providing a user
* interface for a subclass of <code>IIOMetadata</code> for a
* particular plug-in. Controllers need not be GUIs, however.
*
* <p> The default implementation calls <code>getController</code>
* and the calls <code>activate</code> on the returned object if
* <code>hasController</code> returns <code>true</code>.
*
* @return <code>true</code> if the controller completed normally.
*
* @exception IllegalStateException if there is no controller
* currently installed.
*
* @see IIOMetadataController
* @see #setController(IIOMetadataController)
* @see #getController
* @see #getDefaultController
* @see #hasController
*/
public boolean activateController() {
if (!hasController()) {
throw new IllegalStateException("hasController() == false!");
}
return getController().activate(this);
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.metadata;
/**
* An interface to be implemented by objects that can determine the
* settings of an <code>IIOMetadata</code> object, either by putting
* up a GUI to obtain values from a user, or by other means. This
* interface merely specifies a generic <code>activate</code> method
* that invokes the controller, without regard for how the controller
* obtains values (<i>i.e.</i>, whether the controller puts up a GUI
* or merely computes a set of values is irrelevant to this
* interface).
*
* <p> Within the <code>activate</code> method, a controller obtains
* initial values by querying the <code>IIOMetadata</code> object's
* settings, either using the XML DOM tree or a plug-in specific
* interface, modifies values by whatever means, then modifies the
* <code>IIOMetadata</code> object's settings, using either the
* <code>setFromTree</code> or <code>mergeTree</code> methods, or a
* plug-in specific interface. In general, applications may expect
* that when the <code>activate</code> method returns
* <code>true</code>, the <code>IIOMetadata</code> object is ready for
* use in a write operation.
*
* <p> Vendors may choose to provide GUIs for the
* <code>IIOMetadata</code> subclasses they define for a particular
* plug-in. These can be set up as default controllers in the
* corresponding <code>IIOMetadata</code> subclasses.
*
* <p> Alternatively, an algorithmic process such as a database lookup
* or the parsing of a command line could be used as a controller, in
* which case the <code>activate</code> method would simply look up or
* compute the settings, call methods on <code>IIOMetadata</code> to
* set its state, and return <code>true</code>.
*
* @see IIOMetadata#setController
* @see IIOMetadata#getController
* @see IIOMetadata#getDefaultController
* @see IIOMetadata#hasController
* @see IIOMetadata#activateController
*
*/
public interface IIOMetadataController {
/**
* Activates the controller. If <code>true</code> is returned,
* all settings in the <code>IIOMetadata</code> object should be
* ready for use in a write operation. If <code>false</code> is
* returned, no settings in the <code>IIOMetadata</code> object
* will be disturbed (<i>i.e.</i>, the user canceled the
* operation).
*
* @param metadata the <code>IIOMetadata</code> object to be modified.
*
* @return <code>true</code> if the <code>IIOMetadata</code> has been
* modified, <code>false</code> otherwise.
*
* @exception IllegalArgumentException if <code>metadata</code> is
* <code>null</code> or is not an instance of the correct class.
*/
boolean activate(IIOMetadata metadata);
}

View File

@@ -0,0 +1,839 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.metadata;
import java.util.Locale;
import javax.imageio.ImageTypeSpecifier;
/**
* An object describing the structure of metadata documents returned
* from <code>IIOMetadata.getAsTree</code> and passed to
* <code>IIOMetadata.setFromTree</code> and <code>mergeTree</code>.
* Document structures are described by a set of constraints on the
* type and number of child elements that may belong to a given parent
* element type, the names, types, and values of attributes that may
* belong to an element, and the type and values of
* <code>Object</code> reference that may be stored at a node.
*
* <p> N.B: classes that implement this interface should contain a
* method declared as <code>public static getInstance()</code> which
* returns an instance of the class. Commonly, an implementation will
* construct only a single instance and cache it for future
* invocations of <code>getInstance</code>.
*
* <p> The structures that may be described by this class are a subset
* of those expressible using XML document type definitions (DTDs),
* with the addition of some basic information on the datatypes of
* attributes and the ability to store an <code>Object</code>
* reference within a node. In the future, XML Schemas could be used
* to represent these structures, and many others.
*
* <p> The differences between
* <code>IIOMetadataFormat</code>-described structures and DTDs are as
* follows:
*
* <ul>
* <li> Elements may not contain text or mix text with embedded
* tags.
*
* <li> The children of an element must conform to one of a few simple
* patterns, described in the documentation for the
* <code>CHILD_*</code> constants;
*
* <li> The in-memory representation of an elements may contain a
* reference to an <code>Object</code>. There is no provision for
* representing such objects textually.
* </ul>
*
*/
public interface IIOMetadataFormat {
// Child policies
/**
* A constant returned by <code>getChildPolicy</code> to indicate
* that an element may not have any children. In other words, it
* is required to be a leaf node.
*/
int CHILD_POLICY_EMPTY = 0;
/**
* A constant returned by <code>getChildPolicy</code> to indicate
* that an element must have a single instance of each of its
* legal child elements, in order. In DTD terms, the contents of
* the element are defined by a sequence <code>a,b,c,d,...</code>.
*/
int CHILD_POLICY_ALL = 1;
/**
* A constant returned by <code>getChildPolicy</code> to indicate
* that an element must have zero or one instance of each of its
* legal child elements, in order. In DTD terms, the contents of
* the element are defined by a sequence
* <code>a?,b?,c?,d?,...</code>.
*/
int CHILD_POLICY_SOME = 2;
/**
* A constant returned by <code>getChildPolicy</code> to indicate
* that an element must have zero or one children, selected from
* among its legal child elements. In DTD terms, the contents of
* the element are defined by a selection
* <code>a|b|c|d|...</code>.
*/
int CHILD_POLICY_CHOICE = 3;
/**
* A constant returned by <code>getChildPolicy</code> to indicate
* that an element must have a sequence of instances of any of its
* legal child elements. In DTD terms, the contents of the
* element are defined by a sequence <code>(a|b|c|d|...)*</code>.
*/
int CHILD_POLICY_SEQUENCE = 4;
/**
* A constant returned by <code>getChildPolicy</code> to indicate
* that an element must have zero or more instances of its unique
* legal child element. In DTD terms, the contents of the element
* are defined by a starred expression <code>a*</code>.
*/
int CHILD_POLICY_REPEAT = 5;
/**
* The largest valid <code>CHILD_POLICY_*</code> constant,
* to be used for range checks.
*/
int CHILD_POLICY_MAX = CHILD_POLICY_REPEAT;
/**
* A constant returned by <code>getObjectValueType</code> to
* indicate the absence of a user object.
*/
int VALUE_NONE = 0;
/**
* A constant returned by <code>getAttributeValueType</code> and
* <code>getObjectValueType</code> to indicate that the attribute
* or user object may be set a single, arbitrary value.
*/
int VALUE_ARBITRARY = 1;
/**
* A constant returned by <code>getAttributeValueType</code> and
* <code>getObjectValueType</code> to indicate that the attribute
* or user object may be set a range of values. Both the minimum
* and maximum values of the range are exclusive. It is
* recommended that ranges of integers be inclusive on both ends,
* and that exclusive ranges be used only for floating-point data.
*
* @see #VALUE_RANGE_MIN_MAX_INCLUSIVE
*/
int VALUE_RANGE = 2;
/**
* A value that may be or'ed with <code>VALUE_RANGE</code> to
* obtain <code>VALUE_RANGE_MIN_INCLUSIVE</code>, and with
* <code>VALUE_RANGE_MAX_INCLUSIVE</code> to obtain
* <code>VALUE_RANGE_MIN_MAX_INCLUSIVE</code>.
*
* <p> Similarly, the value may be and'ed with the value of
* <code>getAttributeValueType</code>or
* <code>getObjectValueType</code> to determine if the minimum
* value of the range is inclusive.
*/
int VALUE_RANGE_MIN_INCLUSIVE_MASK = 4;
/**
* A value that may be or'ed with <code>VALUE_RANGE</code> to
* obtain <code>VALUE_RANGE_MAX_INCLUSIVE</code>, and with
* <code>VALUE_RANGE_MIN_INCLUSIVE</code> to obtain
* <code>VALUE_RANGE_MIN_MAX_INCLUSIVE</code>.
*
* <p> Similarly, the value may be and'ed with the value of
* <code>getAttributeValueType</code>or
* <code>getObjectValueType</code> to determine if the maximum
* value of the range is inclusive.
*/
int VALUE_RANGE_MAX_INCLUSIVE_MASK = 8;
/**
* A constant returned by <code>getAttributeValueType</code> and
* <code>getObjectValueType</code> to indicate that the attribute
* or user object may be set to a range of values. The minimum
* (but not the maximum) value of the range is inclusive.
*/
int VALUE_RANGE_MIN_INCLUSIVE = VALUE_RANGE |
VALUE_RANGE_MIN_INCLUSIVE_MASK;
/**
* A constant returned by <code>getAttributeValueType</code> and
* <code>getObjectValueType</code> to indicate that the attribute
* or user object may be set to a range of values. The maximum
* (but not the minimum) value of the range is inclusive.
*/
int VALUE_RANGE_MAX_INCLUSIVE = VALUE_RANGE |
VALUE_RANGE_MAX_INCLUSIVE_MASK;
/**
* A constant returned by <code>getAttributeValueType</code> and
* <code>getObjectValueType</code> to indicate that the attribute
* or user object may be set a range of values. Both the minimum
* and maximum values of the range are inclusive. It is
* recommended that ranges of integers be inclusive on both ends,
* and that exclusive ranges be used only for floating-point data.
*/
int VALUE_RANGE_MIN_MAX_INCLUSIVE =
VALUE_RANGE |
VALUE_RANGE_MIN_INCLUSIVE_MASK |
VALUE_RANGE_MAX_INCLUSIVE_MASK;
/**
* A constant returned by <code>getAttributeValueType</code> and
* <code>getObjectValueType</code> to indicate that the attribute
* or user object may be set one of a number of enumerated values.
* In the case of attributes, these values are
* <code>String</code>s; for objects, they are
* <code>Object</code>s implementing a given class or interface.
*
* <p> Attribute values of type <code>DATATYPE_BOOLEAN</code>
* should be marked as enumerations.
*/
int VALUE_ENUMERATION = 16;
/**
* A constant returned by <code>getAttributeValueType</code> and
* <code>getObjectValueType</code> to indicate that the attribute
* or user object may be set to a list or array of values. In the
* case of attributes, the list will consist of
* whitespace-separated values within a <code>String</code>; for
* objects, an array will be used.
*/
int VALUE_LIST = 32;
/**
* A constant returned by <code>getAttributeDataType</code>
* indicating that the value of an attribute is a general Unicode
* string.
*/
int DATATYPE_STRING = 0;
/**
* A constant returned by <code>getAttributeDataType</code>
* indicating that the value of an attribute is one of the boolean
* values 'true' or 'false'.
* Attribute values of type DATATYPE_BOOLEAN should be marked as
* enumerations, and the permitted values should be the string
* literal values "TRUE" or "FALSE", although a plugin may also
* recognise lower or mixed case equivalents.
*/
int DATATYPE_BOOLEAN = 1;
/**
* A constant returned by <code>getAttributeDataType</code>
* indicating that the value of an attribute is a string
* representation of an integer.
*/
int DATATYPE_INTEGER = 2;
/**
* A constant returned by <code>getAttributeDataType</code>
* indicating that the value of an attribute is a string
* representation of a decimal floating-point number.
*/
int DATATYPE_FLOAT = 3;
/**
* A constant returned by <code>getAttributeDataType</code>
* indicating that the value of an attribute is a string
* representation of a double-precision decimal floating-point
* number.
*/
int DATATYPE_DOUBLE = 4;
// Root
/**
* Returns the name of the root element of the format.
*
* @return a <code>String</code>.
*/
String getRootName();
// Multiplicity
/**
* Returns <code>true</code> if the element (and the subtree below
* it) is allowed to appear in a metadata document for an image of
* the given type, defined by an <code>ImageTypeSpecifier</code>.
* For example, a metadata document format might contain an
* element that describes the primary colors of the image, which
* would not be allowed when writing a grayscale image.
*
* @param elementName the name of the element being queried.
* @param imageType an <code>ImageTypeSpecifier</code> indicating
* the type of the image that will be associated with the
* metadata.
*
* @return <code>true</code> if the node is meaningful for images
* of the given type.
*/
boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType);
/**
* Returns the minimum number of children of the named element
* with child policy <code>CHILD_POLICY_REPEAT</code>. For
* example, an element representing color primary information
* might be required to have at least 3 children, one for each
* primary.
*
* @param elementName the name of the element being queried.
*
* @return an <code>int</code>.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if the named element does
* not have a child policy of <code>CHILD_POLICY_REPEAT</code>.
*/
int getElementMinChildren(String elementName);
/**
* Returns the maximum number of children of the named element
* with child policy <code>CHILD_POLICY_REPEAT</code>. For
* example, an element representing an entry in an 8-bit color
* palette might be allowed to repeat up to 256 times. A value of
* <code>Integer.MAX_VALUE</code> may be used to specify that
* there is no upper bound.
*
* @param elementName the name of the element being queried.
*
* @return an <code>int</code>.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if the named element does
* not have a child policy of <code>CHILD_POLICY_REPEAT</code>.
*/
int getElementMaxChildren(String elementName);
/**
* Returns a <code>String</code> containing a description of the
* named element, or <code>null</code>. The description will be
* localized for the supplied <code>Locale</code> if possible.
*
* <p> If <code>locale</code> is <code>null</code>, the current
* default <code>Locale</code> returned by <code>Locale.getLocale</code>
* will be used.
*
* @param elementName the name of the element.
* @param locale the <code>Locale</code> for which localization
* will be attempted.
*
* @return the element description.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code>, or is not a legal element name for this format.
*/
String getElementDescription(String elementName, Locale locale);
// Children
/**
* Returns one of the constants starting with
* <code>CHILD_POLICY_</code>, indicating the legal pattern of
* children for the named element.
*
* @param elementName the name of the element being queried.
*
* @return one of the <code>CHILD_POLICY_*</code> constants.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
*/
int getChildPolicy(String elementName);
/**
* Returns an array of <code>String</code>s indicating the names
* of the element which are allowed to be children of the named
* element, in the order in which they should appear. If the
* element cannot have children, <code>null</code> is returned.
*
* @param elementName the name of the element being queried.
*
* @return an array of <code>String</code>s, or null.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
*/
String[] getChildNames(String elementName);
// Attributes
/**
* Returns an array of <code>String</code>s listing the names of
* the attributes that may be associated with the named element.
*
* @param elementName the name of the element being queried.
*
* @return an array of <code>String</code>s.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
*/
String[] getAttributeNames(String elementName);
/**
* Returns one of the constants starting with <code>VALUE_</code>,
* indicating whether the values of the given attribute within the
* named element are arbitrary, constrained to lie within a
* specified range, constrained to be one of a set of enumerated
* values, or are a whitespace-separated list of arbitrary values.
*
* @param elementName the name of the element being queried.
* @param attrName the name of the attribute being queried.
*
* @return one of the <code>VALUE_*</code> constants.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if <code>attrName</code> is
* <code>null</code> or is not a legal attribute name for this
* element.
*/
int getAttributeValueType(String elementName, String attrName);
/**
* Returns one of the constants starting with
* <code>DATATYPE_</code>, indicating the format and
* interpretation of the value of the given attribute within the
* named element. If <code>getAttributeValueType</code> returns
* <code>VALUE_LIST</code>, then the legal value is a
* whitespace-spearated list of values of the returned datatype.
*
* @param elementName the name of the element being queried.
* @param attrName the name of the attribute being queried.
*
* @return one of the <code>DATATYPE_*</code> constants.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if <code>attrName</code> is
* <code>null</code> or is not a legal attribute name for this
* element.
*/
int getAttributeDataType(String elementName, String attrName);
/**
* Returns <code>true</code> if the named attribute must be
* present within the named element.
*
* @param elementName the name of the element being queried.
* @param attrName the name of the attribute being queried.
*
* @return <code>true</code> if the attribute must be present.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if <code>attrName</code> is
* <code>null</code> or is not a legal attribute name for this
* element.
*/
boolean isAttributeRequired(String elementName, String attrName);
/**
* Returns the default value of the named attribute, if it is not
* explicitly present within the named element, as a
* <code>String</code>, or <code>null</code> if no default value
* is available.
*
* @param elementName the name of the element being queried.
* @param attrName the name of the attribute being queried.
*
* @return a <code>String</code> containing the default value, or
* <code>null</code>.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if <code>attrName</code> is
* <code>null</code> or is not a legal attribute name for this
* element.
*/
String getAttributeDefaultValue(String elementName, String attrName);
/**
* Returns an array of <code>String</code>s containing the legal
* enumerated values for the given attribute within the named
* element. This method should only be called if
* <code>getAttributeValueType</code> returns
* <code>VALUE_ENUMERATION</code>.
*
* @param elementName the name of the element being queried.
* @param attrName the name of the attribute being queried.
*
* @return an array of <code>String</code>s.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if <code>attrName</code> is
* <code>null</code> or is not a legal attribute name for this
* element.
* @exception IllegalArgumentException if the given attribute is
* not defined as an enumeration.
*/
String[] getAttributeEnumerations(String elementName, String attrName);
/**
* Returns the minimum legal value for the attribute. Whether
* this value is inclusive or exclusive may be determined by the
* value of <code>getAttributeValueType</code>. The value is
* returned as a <code>String</code>; its interpretation is
* dependent on the value of <code>getAttributeDataType</code>.
* This method should only be called if
* <code>getAttributeValueType</code> returns
* <code>VALUE_RANGE_*</code>.
*
* @param elementName the name of the element being queried.
* @param attrName the name of the attribute being queried.
*
* @return a <code>String</code> containing the smallest legal
* value for the attribute.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if <code>attrName</code> is
* <code>null</code> or is not a legal attribute name for this
* element.
* @exception IllegalArgumentException if the given attribute is
* not defined as a range.
*/
String getAttributeMinValue(String elementName, String attrName);
/**
* Returns the maximum legal value for the attribute. Whether
* this value is inclusive or exclusive may be determined by the
* value of <code>getAttributeValueType</code>. The value is
* returned as a <code>String</code>; its interpretation is
* dependent on the value of <code>getAttributeDataType</code>.
* This method should only be called if
* <code>getAttributeValueType</code> returns
* <code>VALUE_RANGE_*</code>.
*
* @param elementName the name of the element being queried, as a
* <code>String</code>.
* @param attrName the name of the attribute being queried.
*
* @return a <code>String</code> containing the largest legal
* value for the attribute.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if <code>attrName</code> is
* <code>null</code> or is not a legal attribute name for this
* element.
* @exception IllegalArgumentException if the given attribute is
* not defined as a range.
*/
String getAttributeMaxValue(String elementName, String attrName);
/**
* Returns the minimum number of list items that may be used to
* define this attribute. The attribute itself is defined as a
* <code>String</code> containing multiple whitespace-separated
* items. This method should only be called if
* <code>getAttributeValueType</code> returns
* <code>VALUE_LIST</code>.
*
* @param elementName the name of the element being queried.
* @param attrName the name of the attribute being queried.
*
* @return the smallest legal number of list items for the
* attribute.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if <code>attrName</code> is
* <code>null</code> or is not a legal attribute name for this
* element.
* @exception IllegalArgumentException if the given attribute is
* not defined as a list.
*/
int getAttributeListMinLength(String elementName, String attrName);
/**
* Returns the maximum number of list items that may be used to
* define this attribute. A value of
* <code>Integer.MAX_VALUE</code> may be used to specify that
* there is no upper bound. The attribute itself is defined as a
* <code>String</code> containing multiple whitespace-separated
* items. This method should only be called if
* <code>getAttributeValueType</code> returns
* <code>VALUE_LIST</code>.
*
* @param elementName the name of the element being queried.
* @param attrName the name of the attribute being queried.
*
* @return the largest legal number of list items for the
* attribute.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if <code>attrName</code> is
* <code>null</code> or is not a legal attribute name for this
* element.
* @exception IllegalArgumentException if the given attribute is
* not defined as a list.
*/
int getAttributeListMaxLength(String elementName, String attrName);
/**
* Returns a <code>String</code> containing a description of the
* named attribute, or <code>null</code>. The description will be
* localized for the supplied <code>Locale</code> if possible.
*
* <p> If <code>locale</code> is <code>null</code>, the current
* default <code>Locale</code> returned by <code>Locale.getLocale</code>
* will be used.
*
* @param elementName the name of the element.
* @param attrName the name of the attribute.
* @param locale the <code>Locale</code> for which localization
* will be attempted.
*
* @return the attribute description.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code>, or is not a legal element name for this format.
* @exception IllegalArgumentException if <code>attrName</code> is
* <code>null</code> or is not a legal attribute name for this
* element.
*/
String getAttributeDescription(String elementName, String attrName,
Locale locale);
// Object value
/**
* Returns one of the enumerated values starting with
* <code>VALUE_</code>, indicating the type of values
* (enumeration, range, or array) that are allowed for the
* <code>Object</code> reference. If no object value can be
* stored within the given element, the result of this method will
* be <code>VALUE_NONE</code>.
*
* <p> <code>Object</code> references whose legal values are
* defined as a range must implement the <code>Comparable</code>
* interface.
*
* @param elementName the name of the element being queried.
*
* @return one of the <code>VALUE_*</code> constants.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
*
* @see Comparable
*/
int getObjectValueType(String elementName);
/**
* Returns the <code>Class</code> type of the <code>Object</code>
* reference stored within the element. If this element may not
* contain an <code>Object</code> reference, an
* <code>IllegalArgumentException</code> will be thrown. If the
* class type is an array, this field indicates the underlying
* class type (<i>e.g</i>, for an array of <code>int</code>s, this
* method would return <code>int.class</code>).
*
* <p> <code>Object</code> references whose legal values are
* defined as a range must implement the <code>Comparable</code>
* interface.
*
* @param elementName the name of the element being queried.
*
* @return a <code>Class</code> object.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if the named element cannot
* contain an object value (<i>i.e.</i>, if
* <code>getObjectValueType(elementName) == VALUE_NONE</code>).
*/
Class<?> getObjectClass(String elementName);
/**
* Returns an <code>Object</code>s containing the default
* value for the <code>Object</code> reference within
* the named element.
*
* @param elementName the name of the element being queried.
*
* @return an <code>Object</code>.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if the named element cannot
* contain an object value (<i>i.e.</i>, if
* <code>getObjectValueType(elementName) == VALUE_NONE</code>).
*/
Object getObjectDefaultValue(String elementName);
/**
* Returns an array of <code>Object</code>s containing the legal
* enumerated values for the <code>Object</code> reference within
* the named element. This method should only be called if
* <code>getObjectValueType</code> returns
* <code>VALUE_ENUMERATION</code>.
*
* <p> The <code>Object</code> associated with a node that accepts
* enumerated values must be equal to one of the values returned by
* this method, as defined by the <code>==</code> operator (as
* opposed to the <code>Object.equals</code> method).
*
* @param elementName the name of the element being queried.
*
* @return an array of <code>Object</code>s.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if the named element cannot
* contain an object value (<i>i.e.</i>, if
* <code>getObjectValueType(elementName) == VALUE_NONE</code>).
* @exception IllegalArgumentException if the <code>Object</code>
* is not defined as an enumeration.
*/
Object[] getObjectEnumerations(String elementName);
/**
* Returns the minimum legal value for the <code>Object</code>
* reference within the named element. Whether this value is
* inclusive or exclusive may be determined by the value of
* <code>getObjectValueType</code>. This method should only be
* called if <code>getObjectValueType</code> returns one of the
* constants starting with <code>VALUE_RANGE</code>.
*
* @param elementName the name of the element being queried.
*
* @return the smallest legal value for the attribute.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if the named element cannot
* contain an object value (<i>i.e.</i>, if
* <code>getObjectValueType(elementName) == VALUE_NONE</code>).
* @exception IllegalArgumentException if the <code>Object</code>
* is not defined as a range.
*/
Comparable<?> getObjectMinValue(String elementName);
/**
* Returns the maximum legal value for the <code>Object</code>
* reference within the named element. Whether this value is
* inclusive or exclusive may be determined by the value of
* <code>getObjectValueType</code>. This method should only be
* called if <code>getObjectValueType</code> returns one of the
* constants starting with <code>VALUE_RANGE</code>.
*
* @return the smallest legal value for the attribute.
*
* @param elementName the name of the element being queried.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if the named element cannot
* contain an object value (<i>i.e.</i>, if
* <code>getObjectValueType(elementName) == VALUE_NONE</code>).
* @exception IllegalArgumentException if the <code>Object</code>
* is not defined as a range.
*/
Comparable<?> getObjectMaxValue(String elementName);
/**
* Returns the minimum number of array elements that may be used
* to define the <code>Object</code> reference within the named
* element. This method should only be called if
* <code>getObjectValueType</code> returns
* <code>VALUE_LIST</code>.
*
* @param elementName the name of the element being queried.
*
* @return the smallest valid array length for the
* <code>Object</code> reference.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if the named element cannot
* contain an object value (<i>i.e.</i>, if
* <code>getObjectValueType(elementName) == VALUE_NONE</code>).
* @exception IllegalArgumentException if the <code>Object</code> is not
* an array.
*/
int getObjectArrayMinLength(String elementName);
/**
* Returns the maximum number of array elements that may be used
* to define the <code>Object</code> reference within the named
* element. A value of <code>Integer.MAX_VALUE</code> may be used
* to specify that there is no upper bound. This method should
* only be called if <code>getObjectValueType</code> returns
* <code>VALUE_LIST</code>.
*
* @param elementName the name of the element being queried.
*
* @return the largest valid array length for the
* <code>Object</code> reference.
*
* @exception IllegalArgumentException if <code>elementName</code>
* is <code>null</code> or is not a legal element name for this
* format.
* @exception IllegalArgumentException if the named element cannot
* contain an object value (<i>i.e.</i>, if
* <code>getObjectValueType(elementName) == VALUE_NONE</code>).
* @exception IllegalArgumentException if the <code>Object</code> is not
* an array.
*/
int getObjectArrayMaxLength(String elementName);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.plugins.bmp;
import java.util.Locale;
import javax.imageio.ImageWriteParam;
import com.sun.imageio.plugins.bmp.BMPConstants;
import com.sun.imageio.plugins.bmp.BMPCompressionTypes;
/**
* A subclass of <code>ImageWriteParam</code> for encoding images in
* the BMP format.
*
* <p> This class allows for the specification of various parameters
* while writing a BMP format image file. By default, the data layout
* is bottom-up, such that the pixels are stored in bottom-up order,
* the first scanline being stored last.
*
* <p>The particular compression scheme to be used can be specified by using
* the <code>setCompressionType()</code> method with the appropriate type
* string. The compression scheme specified will be honored if and only if it
* is compatible with the type of image being written. If the specified
* compression scheme is not compatible with the type of image being written
* then the <code>IOException</code> will be thrown by the BMP image writer.
* If the compression type is not set explicitly then <code>getCompressionType()</code>
* will return <code>null</code>. In this case the BMP image writer will select
* a compression type that supports encoding of the given image without loss
* of the color resolution.
* <p>The compression type strings and the image type(s) each supports are
* listed in the following
* table:
*
* <p><table border=1>
* <caption><b>Compression Types</b></caption>
* <tr><th>Type String</th> <th>Description</th> <th>Image Types</th></tr>
* <tr><td>BI_RGB</td> <td>Uncompressed RLE</td> <td>{@literal <= } 8-bits/sample</td></tr>
* <tr><td>BI_RLE8</td> <td>8-bit Run Length Encoding</td> <td>{@literal <=} 8-bits/sample</td></tr>
* <tr><td>BI_RLE4</td> <td>4-bit Run Length Encoding</td> <td>{@literal <=} 4-bits/sample</td></tr>
* <tr><td>BI_BITFIELDS</td> <td>Packed data</td> <td> 16 or 32 bits/sample</td></tr>
* </table>
*/
public class BMPImageWriteParam extends ImageWriteParam {
private boolean topDown = false;
/**
* Constructs a <code>BMPImageWriteParam</code> set to use a given
* <code>Locale</code> and with default values for all parameters.
*
* @param locale a <code>Locale</code> to be used to localize
* compression type names and quality descriptions, or
* <code>null</code>.
*/
public BMPImageWriteParam(Locale locale) {
super(locale);
// Set compression types ("BI_RGB" denotes uncompressed).
compressionTypes = BMPCompressionTypes.getCompressionTypes();
// Set compression flag.
canWriteCompressed = true;
compressionMode = MODE_COPY_FROM_METADATA;
compressionType = compressionTypes[BMPConstants.BI_RGB];
}
/**
* Constructs an <code>BMPImageWriteParam</code> object with default
* values for all parameters and a <code>null</code> <code>Locale</code>.
*/
public BMPImageWriteParam() {
this(null);
}
/**
* If set, the data will be written out in a top-down manner, the first
* scanline being written first.
*
* @param topDown whether the data are written in top-down order.
*/
public void setTopDown(boolean topDown) {
this.topDown = topDown;
}
/**
* Returns the value of the <code>topDown</code> parameter.
* The default is <code>false</code>.
*
* @return whether the data are written in top-down order.
*/
public boolean isTopDown() {
return topDown;
}
}

View File

@@ -0,0 +1,256 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.plugins.jpeg;
import java.util.Arrays;
/**
* A class encapsulating a single JPEG Huffman table.
* Fields are provided for the "standard" tables taken
* from Annex K of the JPEG specification.
* These are the tables used as defaults.
* <p>
* For more information about the operation of the standard JPEG plug-in,
* see the <A HREF="../../metadata/doc-files/jpeg_metadata.html">JPEG
* metadata format specification and usage notes</A>
*/
public class JPEGHuffmanTable {
/* The data for the publically defined tables, as specified in ITU T.81
* JPEG specification section K3.3 and used in the IJG library.
*/
private static final short[] StdDCLuminanceLengths = {
0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
private static final short[] StdDCLuminanceValues = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b,
};
private static final short[] StdDCChrominanceLengths = {
0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
};
private static final short[] StdDCChrominanceValues = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b,
};
private static final short[] StdACLuminanceLengths = {
0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
};
private static final short[] StdACLuminanceValues = {
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa,
};
private static final short[] StdACChrominanceLengths = {
0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
};
private static final short[] StdACChrominanceValues = {
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa,
};
/**
* The standard DC luminance Huffman table.
*/
public static final JPEGHuffmanTable
StdDCLuminance = new JPEGHuffmanTable(StdDCLuminanceLengths,
StdDCLuminanceValues, false);
/**
* The standard DC chrominance Huffman table.
*/
public static final JPEGHuffmanTable
StdDCChrominance = new JPEGHuffmanTable(StdDCChrominanceLengths,
StdDCChrominanceValues, false);
/**
* The standard AC luminance Huffman table.
*/
public static final JPEGHuffmanTable
StdACLuminance = new JPEGHuffmanTable(StdACLuminanceLengths,
StdACLuminanceValues, false);
/**
* The standard AC chrominance Huffman table.
*/
public static final JPEGHuffmanTable
StdACChrominance = new JPEGHuffmanTable(StdACChrominanceLengths,
StdACChrominanceValues, false);
private short[] lengths;
private short[] values;
/**
* Creates a Huffman table and initializes it. The input arrays are copied.
* The arrays must describe a possible Huffman table.
* For example, 3 codes cannot be expressed with a single bit.
*
* @param lengths an array of {@code short}s where <code>lengths[k]</code>
* is equal to the number of values with corresponding codes of
* length <code>k + 1</code> bits.
* @param values an array of shorts containing the values in
* order of increasing code length.
* @throws IllegalArgumentException if <code>lengths</code> or
* <code>values</code> are null, the length of <code>lengths</code> is
* greater than 16, the length of <code>values</code> is greater than 256,
* if any value in <code>lengths</code> or <code>values</code> is less
* than zero, or if the arrays do not describe a valid Huffman table.
*/
public JPEGHuffmanTable(short[] lengths, short[] values) {
if (lengths == null || values == null ||
lengths.length == 0 || values.length == 0 ||
lengths.length > 16 || values.length > 256) {
throw new IllegalArgumentException("Illegal lengths or values");
}
for (int i = 0; i<lengths.length; i++) {
if (lengths[i] < 0) {
throw new IllegalArgumentException("lengths["+i+"] < 0");
}
}
for (int i = 0; i<values.length; i++) {
if (values[i] < 0) {
throw new IllegalArgumentException("values["+i+"] < 0");
}
}
this.lengths = Arrays.copyOf(lengths, lengths.length);
this.values = Arrays.copyOf(values, values.length);
validate();
}
private void validate() {
int sumOfLengths = 0;
for (int i=0; i<lengths.length; i++) {
sumOfLengths += lengths[i];
}
if (sumOfLengths != values.length) {
throw new IllegalArgumentException("lengths do not correspond " +
"to length of value table");
}
}
/* Internal version which avoids the overhead of copying and checking */
private JPEGHuffmanTable(short[] lengths, short[] values, boolean copy) {
if (copy) {
this.lengths = Arrays.copyOf(lengths, lengths.length);
this.values = Arrays.copyOf(values, values.length);
} else {
this.lengths = lengths;
this.values = values;
}
}
/**
* Returns an array of <code>short</code>s containing the number of values
* for each length in the Huffman table. The returned array is a copy.
*
* @return a <code>short</code> array where <code>array[k-1]</code>
* is equal to the number of values in the table of length <code>k</code>.
* @see #getValues
*/
public short[] getLengths() {
return Arrays.copyOf(lengths, lengths.length);
}
/**
* Returns an array of <code>short</code>s containing the values arranged
* by increasing length of their corresponding codes.
* The interpretation of the array is dependent on the values returned
* from <code>getLengths</code>. The returned array is a copy.
*
* @return a <code>short</code> array of values.
* @see #getLengths
*/
public short[] getValues() {
return Arrays.copyOf(values, values.length);
}
/**
* Returns a {@code String} representing this Huffman table.
* @return a {@code String} representing this Huffman table.
*/
public String toString() {
String ls = System.getProperty("line.separator", "\n");
StringBuilder sb = new StringBuilder("JPEGHuffmanTable");
sb.append(ls).append("lengths:");
for (int i=0; i<lengths.length; i++) {
sb.append(" ").append(lengths[i]);
}
sb.append(ls).append("values:");
for (int i=0; i<values.length; i++) {
sb.append(" ").append(values[i]);
}
return sb.toString();
}
}

View File

@@ -0,0 +1,197 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.plugins.jpeg;
import javax.imageio.ImageReadParam;
/**
* This class adds the ability to set JPEG quantization and Huffman
* tables when using the built-in JPEG reader plug-in. An instance of
* this class will be returned from the
* <code>getDefaultImageReadParam</code> methods of the built-in JPEG
* <code>ImageReader</code>.
*
* <p> The sole purpose of these additions is to allow the
* specification of tables for use in decoding abbreviated streams.
* The built-in JPEG reader will also accept an ordinary
* <code>ImageReadParam</code>, which is sufficient for decoding
* non-abbreviated streams.
*
* <p> While tables for abbreviated streams are often obtained by
* first reading another abbreviated stream containing only the
* tables, in some applications the tables are fixed ahead of time.
* This class allows the tables to be specified directly from client
* code. If no tables are specified either in the stream or in a
* <code>JPEGImageReadParam</code>, then the stream is presumed to use
* the "standard" visually lossless tables. See {@link JPEGQTable JPEGQTable}
* and {@link JPEGHuffmanTable JPEGHuffmanTable} for more information
* on the default tables.
*
* <p> The default <code>JPEGImageReadParam</code> returned by the
* <code>getDefaultReadParam</code> method of the builtin JPEG reader
* contains no tables. Default tables may be obtained from the table
* classes {@link JPEGQTable JPEGQTable} and
* {@link JPEGHuffmanTable JPEGHuffmanTable}.
*
* <p> If a stream does contain tables, the tables given in a
* <code>JPEGImageReadParam</code> are ignored. Furthermore, if the
* first image in a stream does contain tables and subsequent ones do
* not, then the tables given in the first image are used for all the
* abbreviated images. Once tables have been read from a stream, they
* can be overridden only by tables subsequently read from the same
* stream. In order to specify new tables, the {@link
* javax.imageio.ImageReader#setInput setInput} method of
* the reader must be called to change the stream.
*
* <p> Note that this class does not provide a means for obtaining the
* tables found in a stream. These may be extracted from a stream by
* consulting the IIOMetadata object returned by the reader.
*
* <p>
* For more information about the operation of the built-in JPEG plug-ins,
* see the <A HREF="../../metadata/doc-files/jpeg_metadata.html">JPEG
* metadata format specification and usage notes</A>.
*
*/
public class JPEGImageReadParam extends ImageReadParam {
private JPEGQTable[] qTables = null;
private JPEGHuffmanTable[] DCHuffmanTables = null;
private JPEGHuffmanTable[] ACHuffmanTables = null;
/**
* Constructs a <code>JPEGImageReadParam</code>.
*/
public JPEGImageReadParam() {
super();
}
/**
* Returns <code>true</code> if tables are currently set.
*
* @return <code>true</code> if tables are present.
*/
public boolean areTablesSet() {
return (qTables != null);
}
/**
* Sets the quantization and Huffman tables to use in decoding
* abbreviated streams. There may be a maximum of 4 tables of
* each type. These tables are ignored once tables are
* encountered in the stream. All arguments must be
* non-<code>null</code>. The two arrays of Huffman tables must
* have the same number of elements. The table specifiers in the
* frame and scan headers in the stream are assumed to be
* equivalent to indices into these arrays. The argument arrays
* are copied by this method.
*
* @param qTables an array of quantization table objects.
* @param DCHuffmanTables an array of Huffman table objects.
* @param ACHuffmanTables an array of Huffman table objects.
*
* @exception IllegalArgumentException if any of the arguments
* is <code>null</code>, has more than 4 elements, or if the
* numbers of DC and AC tables differ.
*
* @see #unsetDecodeTables
*/
public void setDecodeTables(JPEGQTable[] qTables,
JPEGHuffmanTable[] DCHuffmanTables,
JPEGHuffmanTable[] ACHuffmanTables) {
if ((qTables == null) ||
(DCHuffmanTables == null) ||
(ACHuffmanTables == null) ||
(qTables.length > 4) ||
(DCHuffmanTables.length > 4) ||
(ACHuffmanTables.length > 4) ||
(DCHuffmanTables.length != ACHuffmanTables.length)) {
throw new IllegalArgumentException
("Invalid JPEG table arrays");
}
this.qTables = (JPEGQTable[])qTables.clone();
this.DCHuffmanTables = (JPEGHuffmanTable[])DCHuffmanTables.clone();
this.ACHuffmanTables = (JPEGHuffmanTable[])ACHuffmanTables.clone();
}
/**
* Removes any quantization and Huffman tables that are currently
* set.
*
* @see #setDecodeTables
*/
public void unsetDecodeTables() {
this.qTables = null;
this.DCHuffmanTables = null;
this.ACHuffmanTables = null;
}
/**
* Returns a copy of the array of quantization tables set on the
* most recent call to <code>setDecodeTables</code>, or
* <code>null</code> if tables are not currently set.
*
* @return an array of <code>JPEGQTable</code> objects, or
* <code>null</code>.
*
* @see #setDecodeTables
*/
public JPEGQTable[] getQTables() {
return (qTables != null) ? (JPEGQTable[])qTables.clone() : null;
}
/**
* Returns a copy of the array of DC Huffman tables set on the
* most recent call to <code>setDecodeTables</code>, or
* <code>null</code> if tables are not currently set.
*
* @return an array of <code>JPEGHuffmanTable</code> objects, or
* <code>null</code>.
*
* @see #setDecodeTables
*/
public JPEGHuffmanTable[] getDCHuffmanTables() {
return (DCHuffmanTables != null)
? (JPEGHuffmanTable[])DCHuffmanTables.clone()
: null;
}
/**
* Returns a copy of the array of AC Huffman tables set on the
* most recent call to <code>setDecodeTables</code>, or
* <code>null</code> if tables are not currently set.
*
* @return an array of <code>JPEGHuffmanTable</code> objects, or
* <code>null</code>.
*
* @see #setDecodeTables
*/
public JPEGHuffmanTable[] getACHuffmanTables() {
return (ACHuffmanTables != null)
? (JPEGHuffmanTable[])ACHuffmanTables.clone()
: null;
}
}

View File

@@ -0,0 +1,320 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.plugins.jpeg;
import java.util.Locale;
import javax.imageio.ImageWriteParam;
import com.sun.imageio.plugins.jpeg.JPEG;
/**
* This class adds the ability to set JPEG quantization and Huffman
* tables when using the built-in JPEG writer plug-in, and to request that
* optimized Huffman tables be computed for an image. An instance of
* this class will be returned from the
* <code>getDefaultImageWriteParam</code> methods of the built-in JPEG
* <code>ImageWriter</code>.
* <p> The principal purpose of these additions is to allow the
* specification of tables to use in encoding abbreviated streams.
* The built-in JPEG writer will also accept an ordinary
* <code>ImageWriteParam</code>, in which case the writer will
* construct the necessary tables internally.
*
* <p> In either case, the quality setting in an <code>ImageWriteParam</code>
* has the same meaning as for the underlying library: 1.00 means a
* quantization table of all 1's, 0.75 means the "standard", visually
* lossless quantization table, and 0.00 means aquantization table of
* all 255's.
*
* <p> While tables for abbreviated streams are often specified by
* first writing an abbreviated stream containing only the tables, in
* some applications the tables are fixed ahead of time. This class
* allows the tables to be specified directly from client code.
*
* <p> Normally, the tables are specified in the
* <code>IIOMetadata</code> objects passed in to the writer, and any
* tables included in these objects are written to the stream.
* If no tables are specified in the metadata, then an abbreviated
* stream is written. If no tables are included in the metadata and
* no tables are specified in a <code>JPEGImageWriteParam</code>, then
* an abbreviated stream is encoded using the "standard" visually
* lossless tables. This class is necessary for specifying tables
* when an abbreviated stream must be written without writing any tables
* to a stream first. In order to use this class, the metadata object
* passed into the writer must contain no tables, and no stream metadata
* must be provided. See {@link JPEGQTable JPEGQTable} and
* {@link JPEGHuffmanTable JPEGHuffmanTable} for more
* information on the default tables.
*
* <p> The default <code>JPEGImageWriteParam</code> returned by the
* <code>getDefaultWriteParam</code> method of the writer contains no
* tables. Default tables are included in the default
* <code>IIOMetadata</code> objects returned by the writer.
*
* <p> If the metadata does contain tables, the tables given in a
* <code>JPEGImageWriteParam</code> are ignored. Furthermore, once a
* set of tables has been written, only tables in the metadata can
* override them for subsequent writes, whether to the same stream or
* a different one. In order to specify new tables using this class,
* the {@link javax.imageio.ImageWriter#reset reset}
* method of the writer must be called.
*
* <p>
* For more information about the operation of the built-in JPEG plug-ins,
* see the <A HREF="../../metadata/doc-files/jpeg_metadata.html">JPEG
* metadata format specification and usage notes</A>.
*
*/
public class JPEGImageWriteParam extends ImageWriteParam {
private JPEGQTable[] qTables = null;
private JPEGHuffmanTable[] DCHuffmanTables = null;
private JPEGHuffmanTable[] ACHuffmanTables = null;
private boolean optimizeHuffman = false;
private String[] compressionNames = {"JPEG"};
private float[] qualityVals = { 0.00F, 0.30F, 0.75F, 1.00F };
private String[] qualityDescs = {
"Low quality", // 0.00 -> 0.30
"Medium quality", // 0.30 -> 0.75
"Visually lossless" // 0.75 -> 1.00
};
/**
* Constructs a <code>JPEGImageWriteParam</code>. Tiling is not
* supported. Progressive encoding is supported. The default
* progressive mode is MODE_DISABLED. A single form of compression,
* named "JPEG", is supported. The default compression quality is
* 0.75.
*
* @param locale a <code>Locale</code> to be used by the
* superclass to localize compression type names and quality
* descriptions, or <code>null</code>.
*/
public JPEGImageWriteParam(Locale locale) {
super(locale);
this.canWriteProgressive = true;
this.progressiveMode = MODE_DISABLED;
this.canWriteCompressed = true;
this.compressionTypes = compressionNames;
this.compressionType = compressionTypes[0];
this.compressionQuality = JPEG.DEFAULT_QUALITY;
}
/**
* Removes any previous compression quality setting.
*
* <p> The default implementation resets the compression quality
* to <code>0.75F</code>.
*
* @exception IllegalStateException if the compression mode is not
* <code>MODE_EXPLICIT</code>.
*/
public void unsetCompression() {
if (getCompressionMode() != MODE_EXPLICIT) {
throw new IllegalStateException
("Compression mode not MODE_EXPLICIT!");
}
this.compressionQuality = JPEG.DEFAULT_QUALITY;
}
/**
* Returns <code>false</code> since the JPEG plug-in only supports
* lossy compression.
*
* @return <code>false</code>.
*
* @exception IllegalStateException if the compression mode is not
* <code>MODE_EXPLICIT</code>.
*/
public boolean isCompressionLossless() {
if (getCompressionMode() != MODE_EXPLICIT) {
throw new IllegalStateException
("Compression mode not MODE_EXPLICIT!");
}
return false;
}
public String[] getCompressionQualityDescriptions() {
if (getCompressionMode() != MODE_EXPLICIT) {
throw new IllegalStateException
("Compression mode not MODE_EXPLICIT!");
}
if ((getCompressionTypes() != null) &&
(getCompressionType() == null)) {
throw new IllegalStateException("No compression type set!");
}
return (String[])qualityDescs.clone();
}
public float[] getCompressionQualityValues() {
if (getCompressionMode() != MODE_EXPLICIT) {
throw new IllegalStateException
("Compression mode not MODE_EXPLICIT!");
}
if ((getCompressionTypes() != null) &&
(getCompressionType() == null)) {
throw new IllegalStateException("No compression type set!");
}
return (float[])qualityVals.clone();
}
/**
* Returns <code>true</code> if tables are currently set.
*
* @return <code>true</code> if tables are present.
*/
public boolean areTablesSet() {
return (qTables != null);
}
/**
* Sets the quantization and Huffman tables to use in encoding
* abbreviated streams. There may be a maximum of 4 tables of
* each type. These tables are ignored if tables are specified in
* the metadata. All arguments must be non-<code>null</code>.
* The two arrays of Huffman tables must have the same number of
* elements. The table specifiers in the frame and scan headers
* in the metadata are assumed to be equivalent to indices into
* these arrays. The argument arrays are copied by this method.
*
* @param qTables An array of quantization table objects.
* @param DCHuffmanTables An array of Huffman table objects.
* @param ACHuffmanTables An array of Huffman table objects.
*
* @exception IllegalArgumentException if any of the arguments
* is <code>null</code> or has more than 4 elements, or if the
* numbers of DC and AC tables differ.
*
* @see #unsetEncodeTables
*/
public void setEncodeTables(JPEGQTable[] qTables,
JPEGHuffmanTable[] DCHuffmanTables,
JPEGHuffmanTable[] ACHuffmanTables) {
if ((qTables == null) ||
(DCHuffmanTables == null) ||
(ACHuffmanTables == null) ||
(qTables.length > 4) ||
(DCHuffmanTables.length > 4) ||
(ACHuffmanTables.length > 4) ||
(DCHuffmanTables.length != ACHuffmanTables.length)) {
throw new IllegalArgumentException("Invalid JPEG table arrays");
}
this.qTables = (JPEGQTable[])qTables.clone();
this.DCHuffmanTables = (JPEGHuffmanTable[])DCHuffmanTables.clone();
this.ACHuffmanTables = (JPEGHuffmanTable[])ACHuffmanTables.clone();
}
/**
* Removes any quantization and Huffman tables that are currently
* set.
*
* @see #setEncodeTables
*/
public void unsetEncodeTables() {
this.qTables = null;
this.DCHuffmanTables = null;
this.ACHuffmanTables = null;
}
/**
* Returns a copy of the array of quantization tables set on the
* most recent call to <code>setEncodeTables</code>, or
* <code>null</code> if tables are not currently set.
*
* @return an array of <code>JPEGQTable</code> objects, or
* <code>null</code>.
*
* @see #setEncodeTables
*/
public JPEGQTable[] getQTables() {
return (qTables != null) ? (JPEGQTable[])qTables.clone() : null;
}
/**
* Returns a copy of the array of DC Huffman tables set on the
* most recent call to <code>setEncodeTables</code>, or
* <code>null</code> if tables are not currently set.
*
* @return an array of <code>JPEGHuffmanTable</code> objects, or
* <code>null</code>.
*
* @see #setEncodeTables
*/
public JPEGHuffmanTable[] getDCHuffmanTables() {
return (DCHuffmanTables != null)
? (JPEGHuffmanTable[])DCHuffmanTables.clone()
: null;
}
/**
* Returns a copy of the array of AC Huffman tables set on the
* most recent call to <code>setEncodeTables</code>, or
* <code>null</code> if tables are not currently set.
*
* @return an array of <code>JPEGHuffmanTable</code> objects, or
* <code>null</code>.
*
* @see #setEncodeTables
*/
public JPEGHuffmanTable[] getACHuffmanTables() {
return (ACHuffmanTables != null)
? (JPEGHuffmanTable[])ACHuffmanTables.clone()
: null;
}
/**
* Tells the writer to generate optimized Huffman tables
* for the image as part of the writing process. The
* default is <code>false</code>. If this flag is set
* to <code>true</code>, it overrides any tables specified
* in the metadata. Note that this means that any image
* written with this flag set to <code>true</code> will
* always contain Huffman tables.
*
* @param optimize A boolean indicating whether to generate
* optimized Huffman tables when writing.
*
* @see #getOptimizeHuffmanTables
*/
public void setOptimizeHuffmanTables(boolean optimize) {
optimizeHuffman = optimize;
}
/**
* Returns the value passed into the most recent call
* to <code>setOptimizeHuffmanTables</code>, or
* <code>false</code> if <code>setOptimizeHuffmanTables</code>
* has never been called.
*
* @return <code>true</code> if the writer will generate optimized
* Huffman tables.
*
* @see #setOptimizeHuffmanTables
*/
public boolean getOptimizeHuffmanTables() {
return optimizeHuffman;
}
}

View File

@@ -0,0 +1,210 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.plugins.jpeg;
import java.util.Arrays;
/**
* A class encapsulating a single JPEG quantization table.
* The elements appear in natural order (as opposed to zig-zag order).
* Static variables are provided for the "standard" tables taken from
* Annex K of the JPEG specification, as well as the default tables
* conventionally used for visually lossless encoding.
* <p>
* For more information about the operation of the standard JPEG plug-in,
* see the <A HREF="../../metadata/doc-files/jpeg_metadata.html">JPEG
* metadata format specification and usage notes</A>
*/
public class JPEGQTable {
private static final int[] k1 = {
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99,
};
private static final int[] k1div2 = {
8, 6, 5, 8, 12, 20, 26, 31,
6, 6, 7, 10, 13, 29, 30, 28,
7, 7, 8, 12, 20, 29, 35, 28,
7, 9, 11, 15, 26, 44, 40, 31,
9, 11, 19, 28, 34, 55, 52, 39,
12, 18, 28, 32, 41, 52, 57, 46,
25, 32, 39, 44, 52, 61, 60, 51,
36, 46, 48, 49, 56, 50, 52, 50,
};
private static final int[] k2 = {
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
};
private static final int[] k2div2 = {
9, 9, 12, 24, 50, 50, 50, 50,
9, 11, 13, 33, 50, 50, 50, 50,
12, 13, 28, 50, 50, 50, 50, 50,
24, 33, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50,
};
/**
* The sample luminance quantization table given in the JPEG
* specification, table K.1. According to the specification,
* these values produce "good" quality output.
* @see #K1Div2Luminance
*/
public static final JPEGQTable
K1Luminance = new JPEGQTable(k1, false);
/**
* The sample luminance quantization table given in the JPEG
* specification, table K.1, with all elements divided by 2.
* According to the specification, these values produce "very good"
* quality output. This is the table usually used for "visually lossless"
* encoding, and is the default luminance table used if the default
* tables and quality settings are used.
* @see #K1Luminance
*/
public static final JPEGQTable
K1Div2Luminance = new JPEGQTable(k1div2, false);
/**
* The sample chrominance quantization table given in the JPEG
* specification, table K.2. According to the specification,
* these values produce "good" quality output.
* @see #K2Div2Chrominance
*/
public static final JPEGQTable K2Chrominance =
new JPEGQTable(k2, false);
/**
* The sample chrominance quantization table given in the JPEG
* specification, table K.1, with all elements divided by 2.
* According to the specification, these values produce "very good"
* quality output. This is the table usually used for "visually lossless"
* encoding, and is the default chrominance table used if the default
* tables and quality settings are used.
* @see #K2Chrominance
*/
public static final JPEGQTable K2Div2Chrominance =
new JPEGQTable(k2div2, false);
private int[] qTable;
private JPEGQTable(int[] table, boolean copy) {
qTable = (copy) ? Arrays.copyOf(table, table.length) : table;
}
/**
* Constructs a quantization table from the argument, which must
* contain 64 elements in natural order (not zig-zag order).
* A copy is made of the the input array.
* @param table the quantization table, as an <code>int</code> array.
* @throws IllegalArgumentException if <code>table</code> is
* <code>null</code> or <code>table.length</code> is not equal to 64.
*/
public JPEGQTable(int[] table) {
if (table == null) {
throw new IllegalArgumentException("table must not be null.");
}
if (table.length != 64) {
throw new IllegalArgumentException("table.length != 64");
}
qTable = Arrays.copyOf(table, table.length);
}
/**
* Returns a copy of the current quantization table as an array
* of {@code int}s in natural (not zig-zag) order.
* @return A copy of the current quantization table.
*/
public int[] getTable() {
return Arrays.copyOf(qTable, qTable.length);
}
/**
* Returns a new quantization table where the values are multiplied
* by <code>scaleFactor</code> and then clamped to the range 1..32767
* (or to 1..255 if <code>forceBaseline</code> is true).
* <p>
* Values of <code>scaleFactor</code> less than 1 tend to improve
* the quality level of the table, and values greater than 1.0
* degrade the quality level of the table.
* @param scaleFactor multiplication factor for the table.
* @param forceBaseline if <code>true</code>,
* the values will be clamped to the range 1..255
* @return a new quantization table that is a linear multiple
* of the current table.
*/
public JPEGQTable getScaledInstance(float scaleFactor,
boolean forceBaseline) {
int max = (forceBaseline) ? 255 : 32767;
int[] scaledTable = new int[qTable.length];
for (int i=0; i<qTable.length; i++) {
int sv = (int)((qTable[i] * scaleFactor)+0.5f);
if (sv < 1) {
sv = 1;
}
if (sv > max) {
sv = max;
}
scaledTable[i] = sv;
}
return new JPEGQTable(scaledTable);
}
/**
* Returns a {@code String} representing this quantization table.
* @return a {@code String} representing this quantization table.
*/
public String toString() {
String ls = System.getProperty("line.separator", "\n");
StringBuilder sb = new StringBuilder("JPEGQTable:"+ls);
for (int i=0; i < qTable.length; i++) {
if (i % 8 == 0) {
sb.append('\t');
}
sb.append(qTable[i]);
sb.append(((i % 8) == 7) ? ls : ' ');
}
return sb.toString();
}
}

View File

@@ -0,0 +1,161 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* A node in a directed graph. In addition to an arbitrary
* <code>Object</code> containing user data associated with the node,
* each node maintains a <code>Set</code>s of nodes which are pointed
* to by the current node (available from <code>getOutNodes</code>).
* The in-degree of the node (that is, number of nodes that point to
* the current node) may be queried.
*
*/
class DigraphNode implements Cloneable, Serializable {
/** The data associated with this node. */
protected Object data;
/**
* A <code>Set</code> of neighboring nodes pointed to by this
* node.
*/
protected Set outNodes = new HashSet();
/** The in-degree of the node. */
protected int inDegree = 0;
/**
* A <code>Set</code> of neighboring nodes that point to this
* node.
*/
private Set inNodes = new HashSet();
public DigraphNode(Object data) {
this.data = data;
}
/** Returns the <code>Object</code> referenced by this node. */
public Object getData() {
return data;
}
/**
* Returns an <code>Iterator</code> containing the nodes pointed
* to by this node.
*/
public Iterator getOutNodes() {
return outNodes.iterator();
}
/**
* Adds a directed edge to the graph. The outNodes list of this
* node is updated and the in-degree of the other node is incremented.
*
* @param node a <code>DigraphNode</code>.
*
* @return <code>true</code> if the node was not previously the
* target of an edge.
*/
public boolean addEdge(DigraphNode node) {
if (outNodes.contains(node)) {
return false;
}
outNodes.add(node);
node.inNodes.add(this);
node.incrementInDegree();
return true;
}
/**
* Returns <code>true</code> if an edge exists between this node
* and the given node.
*
* @param node a <code>DigraphNode</code>.
*
* @return <code>true</code> if the node is the target of an edge.
*/
public boolean hasEdge(DigraphNode node) {
return outNodes.contains(node);
}
/**
* Removes a directed edge from the graph. The outNodes list of this
* node is updated and the in-degree of the other node is decremented.
*
* @return <code>true</code> if the node was previously the target
* of an edge.
*/
public boolean removeEdge(DigraphNode node) {
if (!outNodes.contains(node)) {
return false;
}
outNodes.remove(node);
node.inNodes.remove(this);
node.decrementInDegree();
return true;
}
/**
* Removes this node from the graph, updating neighboring nodes
* appropriately.
*/
public void dispose() {
Object[] inNodesArray = inNodes.toArray();
for(int i=0; i<inNodesArray.length; i++) {
DigraphNode node = (DigraphNode) inNodesArray[i];
node.removeEdge(this);
}
Object[] outNodesArray = outNodes.toArray();
for(int i=0; i<outNodesArray.length; i++) {
DigraphNode node = (DigraphNode) outNodesArray[i];
removeEdge(node);
}
}
/** Returns the in-degree of this node. */
public int getInDegree() {
return inDegree;
}
/** Increments the in-degree of this node. */
private void incrementInDegree() {
++inDegree;
}
/** Decrements the in-degree of this node. */
private void decrementInDegree() {
--inDegree;
}
}

View File

@@ -0,0 +1,253 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.security.PrivilegedAction;
import java.security.AccessController;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Vector;
import com.sun.imageio.spi.FileImageInputStreamSpi;
import com.sun.imageio.spi.FileImageOutputStreamSpi;
import com.sun.imageio.spi.InputStreamImageInputStreamSpi;
import com.sun.imageio.spi.OutputStreamImageOutputStreamSpi;
import com.sun.imageio.spi.RAFImageInputStreamSpi;
import com.sun.imageio.spi.RAFImageOutputStreamSpi;
import com.sun.imageio.plugins.gif.GIFImageReaderSpi;
import com.sun.imageio.plugins.gif.GIFImageWriterSpi;
import com.sun.imageio.plugins.jpeg.JPEGImageReaderSpi;
import com.sun.imageio.plugins.jpeg.JPEGImageWriterSpi;
import com.sun.imageio.plugins.png.PNGImageReaderSpi;
import com.sun.imageio.plugins.png.PNGImageWriterSpi;
import com.sun.imageio.plugins.bmp.BMPImageReaderSpi;
import com.sun.imageio.plugins.bmp.BMPImageWriterSpi;
import com.sun.imageio.plugins.wbmp.WBMPImageReaderSpi;
import com.sun.imageio.plugins.wbmp.WBMPImageWriterSpi;
import sun.awt.AppContext;
import java.util.ServiceLoader;
import java.util.ServiceConfigurationError;
/**
* A registry for service provider instances. Service provider
* classes may be detected at run time by means of meta-information in
* the JAR files containing them. The intent is that it be relatively
* inexpensive to load and inspect all available service provider
* classes. These classes may them be used to locate and instantiate
* more heavyweight classes that will perform actual work, in this
* case instances of <code>ImageReader</code>,
* <code>ImageWriter</code>, <code>ImageTranscoder</code>,
* <code>ImageInputStream</code>, and <code>ImageOutputStream</code>.
*
* <p> Service providers found on the system classpath (typically
* the <code>lib/ext</code> directory in the Java
* installation directory) are automatically loaded as soon as this class is
* instantiated.
*
* <p> When the <code>registerApplicationClasspathSpis</code> method
* is called, service provider instances declared in the
* meta-information section of JAR files on the application class path
* are loaded. To declare a service provider, a <code>services</code>
* subdirectory is placed within the <code>META-INF</code> directory
* that is present in every JAR file. This directory contains a file
* for each service provider interface that has one or more
* implementation classes present in the JAR file. For example, if
* the JAR file contained a class named
* <code>com.mycompany.imageio.MyFormatReaderSpi</code> which
* implements the <code>ImageReaderSpi</code> interface, the JAR file
* would contain a file named:
*
* <pre>
* META-INF/services/javax.imageio.spi.ImageReaderSpi
* </pre>
*
* containing the line:
*
* <pre>
* com.mycompany.imageio.MyFormatReaderSpi
* </pre>
*
* <p> The service provider classes are intended to be lightweight
* and quick to load. Implementations of these interfaces
* should avoid complex dependencies on other classes and on
* native code.
*
* <p> It is also possible to manually add service providers not found
* automatically, as well as to remove those that are using the
* interfaces of the <code>ServiceRegistry</code> class. Thus
* the application may customize the contents of the registry as it
* sees fit.
*
* <p> For more details on declaring service providers, and the JAR
* format in general, see the <a
* href="{@docRoot}/../technotes/guides/jar/jar.html">
* JAR File Specification</a>.
*
*/
public final class IIORegistry extends ServiceRegistry {
/**
* A <code>Vector</code> containing the valid IIO registry
* categories (superinterfaces) to be used in the constructor.
*/
private static final Vector initialCategories = new Vector(5);
static {
initialCategories.add(ImageReaderSpi.class);
initialCategories.add(ImageWriterSpi.class);
initialCategories.add(ImageTranscoderSpi.class);
initialCategories.add(ImageInputStreamSpi.class);
initialCategories.add(ImageOutputStreamSpi.class);
}
/**
* Set up the valid service provider categories and automatically
* register all available service providers.
*
* <p> The constructor is private in order to prevent creation of
* additional instances.
*/
private IIORegistry() {
super(initialCategories.iterator());
registerStandardSpis();
registerApplicationClasspathSpis();
}
/**
* Returns the default <code>IIORegistry</code> instance used by
* the Image I/O API. This instance should be used for all
* registry functions.
*
* <p> Each <code>ThreadGroup</code> will receive its own
* instance; this allows different <code>Applet</code>s in the
* same browser (for example) to each have their own registry.
*
* @return the default registry for the current
* <code>ThreadGroup</code>.
*/
public static IIORegistry getDefaultInstance() {
AppContext context = AppContext.getAppContext();
IIORegistry registry =
(IIORegistry)context.get(IIORegistry.class);
if (registry == null) {
// Create an instance for this AppContext
registry = new IIORegistry();
context.put(IIORegistry.class, registry);
}
return registry;
}
private void registerStandardSpis() {
// Hardwire standard SPIs
registerServiceProvider(new GIFImageReaderSpi());
registerServiceProvider(new GIFImageWriterSpi());
registerServiceProvider(new BMPImageReaderSpi());
registerServiceProvider(new BMPImageWriterSpi());
registerServiceProvider(new WBMPImageReaderSpi());
registerServiceProvider(new WBMPImageWriterSpi());
registerServiceProvider(new PNGImageReaderSpi());
registerServiceProvider(new PNGImageWriterSpi());
registerServiceProvider(new JPEGImageReaderSpi());
registerServiceProvider(new JPEGImageWriterSpi());
registerServiceProvider(new FileImageInputStreamSpi());
registerServiceProvider(new FileImageOutputStreamSpi());
registerServiceProvider(new InputStreamImageInputStreamSpi());
registerServiceProvider(new OutputStreamImageOutputStreamSpi());
registerServiceProvider(new RAFImageInputStreamSpi());
registerServiceProvider(new RAFImageOutputStreamSpi());
registerInstalledProviders();
}
/**
* Registers all available service providers found on the
* application class path, using the default
* <code>ClassLoader</code>. This method is typically invoked by
* the <code>ImageIO.scanForPlugins</code> method.
*
* @see javax.imageio.ImageIO#scanForPlugins
* @see ClassLoader#getResources
*/
public void registerApplicationClasspathSpis() {
// FIX: load only from application classpath
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Iterator categories = getCategories();
while (categories.hasNext()) {
Class<IIOServiceProvider> c = (Class)categories.next();
Iterator<IIOServiceProvider> riter =
ServiceLoader.load(c, loader).iterator();
while (riter.hasNext()) {
try {
// Note that the next() call is required to be inside
// the try/catch block; see 6342404.
IIOServiceProvider r = riter.next();
registerServiceProvider(r);
} catch (ServiceConfigurationError err) {
if (System.getSecurityManager() != null) {
// In the applet case, we will catch the error so
// registration of other plugins can proceed
err.printStackTrace();
} else {
// In the application case, we will throw the
// error to indicate app/system misconfiguration
throw err;
}
}
}
}
}
private void registerInstalledProviders() {
/*
We need to load installed providers from the
system classpath (typically the <code>lib/ext</code>
directory in in the Java installation directory)
in the privileged mode in order to
be able read corresponding jar files even if
file read capability is restricted (like the
applet context case).
*/
PrivilegedAction doRegistration =
new PrivilegedAction() {
public Object run() {
Iterator categories = getCategories();
while (categories.hasNext()) {
Class<IIOServiceProvider> c = (Class)categories.next();
for (IIOServiceProvider p : ServiceLoader.loadInstalled(c)) {
registerServiceProvider(p);
}
}
return this;
}
};
AccessController.doPrivileged(doRegistration);
}
}

View File

@@ -0,0 +1,172 @@
/*
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.util.Locale;
import javax.imageio.spi.RegisterableService;
import javax.imageio.spi.ServiceRegistry;
/**
* A superinterface for functionality common to all Image I/O service
* provider interfaces (SPIs). For more information on service
* provider classes, see the class comment for the
* <code>IIORegistry</code> class.
*
* @see IIORegistry
* @see javax.imageio.spi.ImageReaderSpi
* @see javax.imageio.spi.ImageWriterSpi
* @see javax.imageio.spi.ImageTranscoderSpi
* @see javax.imageio.spi.ImageInputStreamSpi
*
*/
public abstract class IIOServiceProvider implements RegisterableService {
/**
* A <code>String</code> to be returned from
* <code>getVendorName</code>, initially <code>null</code>.
* Constructors should set this to a non-<code>null</code> value.
*/
protected String vendorName;
/**
* A <code>String</code> to be returned from
* <code>getVersion</code>, initially null. Constructors should
* set this to a non-<code>null</code> value.
*/
protected String version;
/**
* Constructs an <code>IIOServiceProvider</code> with a given
* vendor name and version identifier.
*
* @param vendorName the vendor name.
* @param version a version identifier.
*
* @exception IllegalArgumentException if <code>vendorName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>version</code>
* is <code>null</code>.
*/
public IIOServiceProvider(String vendorName,
String version) {
if (vendorName == null) {
throw new IllegalArgumentException("vendorName == null!");
}
if (version == null) {
throw new IllegalArgumentException("version == null!");
}
this.vendorName = vendorName;
this.version = version;
}
/**
* Constructs a blank <code>IIOServiceProvider</code>. It is up
* to the subclass to initialize instance variables and/or
* override method implementations in order to ensure that the
* <code>getVendorName</code> and <code>getVersion</code> methods
* will return non-<code>null</code> values.
*/
public IIOServiceProvider() {
}
/**
* A callback that will be called exactly once after the Spi class
* has been instantiated and registered in a
* <code>ServiceRegistry</code>. This may be used to verify that
* the environment is suitable for this service, for example that
* native libraries can be loaded. If the service cannot function
* in the environment where it finds itself, it should deregister
* itself from the registry.
*
* <p> Only the registry should call this method.
*
* <p> The default implementation does nothing.
*
* @see ServiceRegistry#registerServiceProvider(Object provider)
*/
public void onRegistration(ServiceRegistry registry,
Class<?> category) {}
/**
* A callback that will be whenever the Spi class has been
* deregistered from a <code>ServiceRegistry</code>.
*
* <p> Only the registry should call this method.
*
* <p> The default implementation does nothing.
*
* @see ServiceRegistry#deregisterServiceProvider(Object provider)
*/
public void onDeregistration(ServiceRegistry registry,
Class<?> category) {}
/**
* Returns the name of the vendor responsible for creating this
* service provider and its associated implementation. Because
* the vendor name may be used to select a service provider,
* it is not localized.
*
* <p> The default implementation returns the value of the
* <code>vendorName</code> instance variable.
*
* @return a non-<code>null</code> <code>String</code> containing
* the name of the vendor.
*/
public String getVendorName() {
return vendorName;
}
/**
* Returns a string describing the version
* number of this service provider and its associated
* implementation. Because the version may be used by transcoders
* to identify the service providers they understand, this method
* is not localized.
*
* <p> The default implementation returns the value of the
* <code>version</code> instance variable.
*
* @return a non-<code>null</code> <code>String</code> containing
* the version of this service provider.
*/
public String getVersion() {
return version;
}
/**
* Returns a brief, human-readable description of this service
* provider and its associated implementation. The resulting
* string should be localized for the supplied
* <code>Locale</code>, if possible.
*
* @param locale a <code>Locale</code> for which the return value
* should be localized.
*
* @return a <code>String</code> containing a description of this
* service provider.
*/
public abstract String getDescription(Locale locale);
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.io.File;
import java.io.IOException;
import javax.imageio.stream.ImageInputStream;
/**
* The service provider interface (SPI) for
* <code>ImageInputStream</code>s. For more information on service
* provider interfaces, see the class comment for the
* <code>IIORegistry</code> class.
*
* <p> This interface allows arbitrary objects to be "wrapped" by
* instances of <code>ImageInputStream</code>. For example,
* a particular <code>ImageInputStreamSpi</code> might allow
* a generic <code>InputStream</code> to be used as an input source;
* another might take input from a <code>URL</code>.
*
* <p> By treating the creation of <code>ImageInputStream</code>s as a
* pluggable service, it becomes possible to handle future input
* sources without changing the API. Also, high-performance
* implementations of <code>ImageInputStream</code> (for example,
* native implementations for a particular platform) can be installed
* and used transparently by applications.
*
* @see IIORegistry
* @see javax.imageio.stream.ImageInputStream
*
*/
public abstract class ImageInputStreamSpi extends IIOServiceProvider {
/**
* A <code>Class</code> object indicating the legal object type
* for use by the <code>createInputStreamInstance</code> method.
*/
protected Class<?> inputClass;
/**
* Constructs a blank <code>ImageInputStreamSpi</code>. It is up
* to the subclass to initialize instance variables and/or
* override method implementations in order to provide working
* versions of all methods.
*/
protected ImageInputStreamSpi() {
}
/**
* Constructs an <code>ImageInputStreamSpi</code> with a given set
* of values.
*
* @param vendorName the vendor name.
* @param version a version identifier.
* @param inputClass a <code>Class</code> object indicating the
* legal object type for use by the
* <code>createInputStreamInstance</code> method.
*
* @exception IllegalArgumentException if <code>vendorName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>version</code>
* is <code>null</code>.
*/
public ImageInputStreamSpi(String vendorName,
String version,
Class<?> inputClass) {
super(vendorName, version);
this.inputClass = inputClass;
}
/**
* Returns a <code>Class</code> object representing the class or
* interface type that must be implemented by an input source in
* order to be "wrapped" in an <code>ImageInputStream</code> via
* the <code>createInputStreamInstance</code> method.
*
* <p> Typical return values might include
* <code>InputStream.class</code> or <code>URL.class</code>, but
* any class may be used.
*
* @return a <code>Class</code> variable.
*
* @see #createInputStreamInstance(Object, boolean, File)
*/
public Class<?> getInputClass() {
return inputClass;
}
/**
* Returns <code>true</code> if the <code>ImageInputStream</code>
* implementation associated with this service provider can
* optionally make use of a cache file for improved performance
* and/or memory footrprint. If <code>false</code>, the value of
* the <code>useCache</code> argument to
* <code>createInputStreamInstance</code> will be ignored.
*
* <p> The default implementation returns <code>false</code>.
*
* @return <code>true</code> if a cache file can be used by the
* input streams created by this service provider.
*/
public boolean canUseCacheFile() {
return false;
}
/**
* Returns <code>true</code> if the <code>ImageInputStream</code>
* implementation associated with this service provider requires
* the use of a cache <code>File</code>. If <code>true</code>,
* the value of the <code>useCache</code> argument to
* <code>createInputStreamInstance</code> will be ignored.
*
* <p> The default implementation returns <code>false</code>.
*
* @return <code>true</code> if a cache file is needed by the
* input streams created by this service provider.
*/
public boolean needsCacheFile() {
return false;
}
/**
* Returns an instance of the <code>ImageInputStream</code>
* implementation associated with this service provider. If the
* use of a cache file is optional, the <code>useCache</code>
* parameter will be consulted. Where a cache is required, or
* not applicable, the value of <code>useCache</code> will be ignored.
*
* @param input an object of the class type returned by
* <code>getInputClass</code>.
* @param useCache a <code>boolean</code> indicating whether a
* cache file should be used, in cases where it is optional.
* @param cacheDir a <code>File</code> indicating where the
* cache file should be created, or <code>null</code> to use the
* system directory.
*
* @return an <code>ImageInputStream</code> instance.
*
* @exception IllegalArgumentException if <code>input</code> is
* not an instance of the correct class or is <code>null</code>.
* @exception IllegalArgumentException if a cache file is needed
* but <code>cacheDir</code> is non-<code>null</code> and is not a
* directory.
* @exception IOException if a cache file is needed but cannot be
* created.
*
* @see #getInputClass
* @see #canUseCacheFile
* @see #needsCacheFile
*/
public abstract ImageInputStream
createInputStreamInstance(Object input,
boolean useCache,
File cacheDir) throws IOException;
/**
* Returns an instance of the <code>ImageInputStream</code>
* implementation associated with this service provider. A cache
* file will be created in the system-dependent default
* temporary-file directory, if needed.
*
* @param input an object of the class type returned by
* <code>getInputClass</code>.
*
* @return an <code>ImageInputStream</code> instance.
*
* @exception IllegalArgumentException if <code>input</code> is
* not an instance of the correct class or is <code>null</code>.
* @exception IOException if a cache file is needed but cannot be
* created.
*
* @see #getInputClass()
*/
public ImageInputStream createInputStreamInstance(Object input)
throws IOException {
return createInputStreamInstance(input, true, null);
}
}

View File

@@ -0,0 +1,200 @@
/*
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.io.File;
import java.io.IOException;
import javax.imageio.stream.ImageOutputStream;
/**
* The service provider interface (SPI) for
* <code>ImageOutputStream</code>s. For more information on service
* provider interfaces, see the class comment for the
* <code>IIORegistry</code> class.
*
* <p> This interface allows arbitrary objects to be "wrapped" by
* instances of <code>ImageOutputStream</code>. For example, a
* particular <code>ImageOutputStreamSpi</code> might allow a generic
* <code>OutputStream</code> to be used as a destination; another
* might output to a <code>File</code> or to a device such as a serial
* port.
*
* <p> By treating the creation of <code>ImageOutputStream</code>s as
* a pluggable service, it becomes possible to handle future output
* destinations without changing the API. Also, high-performance
* implementations of <code>ImageOutputStream</code> (for example,
* native implementations for a particular platform) can be installed
* and used transparently by applications.
*
* @see IIORegistry
* @see javax.imageio.stream.ImageOutputStream
*
*/
public abstract class ImageOutputStreamSpi extends IIOServiceProvider {
/**
* A <code>Class</code> object indicating the legal object type
* for use by the <code>createInputStreamInstance</code> method.
*/
protected Class<?> outputClass;
/**
* Constructs a blank <code>ImageOutputStreamSpi</code>. It is up
* to the subclass to initialize instance variables and/or
* override method implementations in order to provide working
* versions of all methods.
*/
protected ImageOutputStreamSpi() {
}
/**
* Constructs an <code>ImageOutputStreamSpi</code> with a given
* set of values.
*
* @param vendorName the vendor name.
* @param version a version identifier.
* @param outputClass a <code>Class</code> object indicating the
* legal object type for use by the
* <code>createOutputStreamInstance</code> method.
*
* @exception IllegalArgumentException if <code>vendorName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>version</code>
* is <code>null</code>.
*/
public ImageOutputStreamSpi(String vendorName,
String version,
Class<?> outputClass) {
super(vendorName, version);
this.outputClass = outputClass;
}
/**
* Returns a <code>Class</code> object representing the class or
* interface type that must be implemented by an output
* destination in order to be "wrapped" in an
* <code>ImageOutputStream</code> via the
* <code>createOutputStreamInstance</code> method.
*
* <p> Typical return values might include
* <code>OutputStream.class</code> or <code>File.class</code>, but
* any class may be used.
*
* @return a <code>Class</code> variable.
*
* @see #createOutputStreamInstance(Object, boolean, File)
*/
public Class<?> getOutputClass() {
return outputClass;
}
/**
* Returns <code>true</code> if the <code>ImageOutputStream</code>
* implementation associated with this service provider can
* optionally make use of a cache <code>File</code> for improved
* performance and/or memory footrprint. If <code>false</code>,
* the value of the <code>cacheFile</code> argument to
* <code>createOutputStreamInstance</code> will be ignored.
*
* <p> The default implementation returns <code>false</code>.
*
* @return <code>true</code> if a cache file can be used by the
* output streams created by this service provider.
*/
public boolean canUseCacheFile() {
return false;
}
/**
* Returns <code>true</code> if the <code>ImageOutputStream</code>
* implementation associated with this service provider requires
* the use of a cache <code>File</code>.
*
* <p> The default implementation returns <code>false</code>.
*
* @return <code>true</code> if a cache file is needed by the
* output streams created by this service provider.
*/
public boolean needsCacheFile() {
return false;
}
/**
* Returns an instance of the <code>ImageOutputStream</code>
* implementation associated with this service provider. If the
* use of a cache file is optional, the <code>useCache</code>
* parameter will be consulted. Where a cache is required, or
* not applicable, the value of <code>useCache</code> will be ignored.
*
* @param output an object of the class type returned by
* <code>getOutputClass</code>.
* @param useCache a <code>boolean</code> indicating whether a
* cache file should be used, in cases where it is optional.
* @param cacheDir a <code>File</code> indicating where the
* cache file should be created, or <code>null</code> to use the
* system directory.
*
* @return an <code>ImageOutputStream</code> instance.
*
* @exception IllegalArgumentException if <code>output</code> is
* not an instance of the correct class or is <code>null</code>.
* @exception IllegalArgumentException if a cache file is needed,
* but <code>cacheDir</code> is non-<code>null</code> and is not a
* directory.
* @exception IOException if a cache file is needed but cannot be
* created.
*
* @see #getOutputClass
*/
public abstract
ImageOutputStream createOutputStreamInstance(Object output,
boolean useCache,
File cacheDir)
throws IOException;
/**
* Returns an instance of the <code>ImageOutputStream</code>
* implementation associated with this service provider. A cache
* file will be created in the system-dependent default
* temporary-file directory, if needed.
*
* @param output an object of the class type returned by
* <code>getOutputClass</code>.
*
* @return an <code>ImageOutputStream</code> instance.
*
* @exception IllegalArgumentException if <code>output</code> is
* not an instance of the correct class or is <code>null</code>.
* @exception IOException if a cache file is needed but cannot be
* created.
*
* @see #getOutputClass()
*/
public ImageOutputStream createOutputStreamInstance(Object output)
throws IOException {
return createOutputStreamInstance(output, true, null);
}
}

View File

@@ -0,0 +1,413 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.io.IOException;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
/**
* The service provider interface (SPI) for <code>ImageReader</code>s.
* For more information on service provider classes, see the class comment
* for the <code>IIORegistry</code> class.
*
* <p> Each <code>ImageReaderSpi</code> provides several types of information
* about the <code>ImageReader</code> class with which it is associated.
*
* <p> The name of the vendor who defined the SPI class and a
* brief description of the class are available via the
* <code>getVendorName</code>, <code>getDescription</code>,
* and <code>getVersion</code> methods.
* These methods may be internationalized to provide locale-specific
* output. These methods are intended mainly to provide short,
* human-readable information that might be used to organize a pop-up
* menu or other list.
*
* <p> Lists of format names, file suffixes, and MIME types associated
* with the service may be obtained by means of the
* <code>getFormatNames</code>, <code>getFileSuffixes</code>, and
* <code>getMIMETypes</code> methods. These methods may be used to
* identify candidate <code>ImageReader</code>s for decoding a
* particular file or stream based on manual format selection, file
* naming, or MIME associations (for example, when accessing a file
* over HTTP or as an email attachment).
*
* <p> A more reliable way to determine which <code>ImageReader</code>s
* are likely to be able to parse a particular data stream is provided
* by the <code>canDecodeInput</code> method. This methods allows the
* service provider to inspect the actual stream contents.
*
* <p> Finally, an instance of the <code>ImageReader</code> class
* associated with this service provider may be obtained by calling
* the <code>createReaderInstance</code> method. Any heavyweight
* initialization, such as the loading of native libraries or creation
* of large tables, should be deferred at least until the first
* invocation of this method.
*
* @see IIORegistry
* @see javax.imageio.ImageReader
*
*/
public abstract class ImageReaderSpi extends ImageReaderWriterSpi {
/**
* A single-element array, initially containing
* <code>ImageInputStream.class</code>, to be returned from
* <code>getInputTypes</code>.
* @deprecated Instead of using this field, directly create
* the equivalent array <code>{ ImageInputStream.class }</code>.
*/
@Deprecated
public static final Class[] STANDARD_INPUT_TYPE =
{ ImageInputStream.class };
/**
* An array of <code>Class</code> objects to be returned from
* <code>getInputTypes</code>, initially <code>null</code>.
*/
protected Class[] inputTypes = null;
/**
* An array of strings to be returned from
* <code>getImageWriterSpiNames</code>, initially
* <code>null</code>.
*/
protected String[] writerSpiNames = null;
/**
* The <code>Class</code> of the reader, initially
* <code>null</code>.
*/
private Class readerClass = null;
/**
* Constructs a blank <code>ImageReaderSpi</code>. It is up to
* the subclass to initialize instance variables and/or override
* method implementations in order to provide working versions of
* all methods.
*/
protected ImageReaderSpi() {
}
/**
* Constructs an <code>ImageReaderSpi</code> with a given
* set of values.
*
* @param vendorName the vendor name, as a non-<code>null</code>
* <code>String</code>.
* @param version a version identifier, as a non-<code>null</code>
* <code>String</code>.
* @param names a non-<code>null</code> array of
* <code>String</code>s indicating the format names. At least one
* entry must be present.
* @param suffixes an array of <code>String</code>s indicating the
* common file suffixes. If no suffixes are defined,
* <code>null</code> should be supplied. An array of length 0
* will be normalized to <code>null</code>.
* @param MIMETypes an array of <code>String</code>s indicating
* the format's MIME types. If no MIME types are defined,
* <code>null</code> should be supplied. An array of length 0
* will be normalized to <code>null</code>.
* @param readerClassName the fully-qualified name of the
* associated <code>ImageReader</code> class, as a
* non-<code>null</code> <code>String</code>.
* @param inputTypes a non-<code>null</code> array of
* <code>Class</code> objects of length at least 1 indicating the
* legal input types.
* @param writerSpiNames an array <code>String</code>s naming the
* classes of all associated <code>ImageWriter</code>s, or
* <code>null</code>. An array of length 0 is normalized to
* <code>null</code>.
* @param supportsStandardStreamMetadataFormat a
* <code>boolean</code> that indicates whether a stream metadata
* object can use trees described by the standard metadata format.
* @param nativeStreamMetadataFormatName a
* <code>String</code>, or <code>null</code>, to be returned from
* <code>getNativeStreamMetadataFormatName</code>.
* @param nativeStreamMetadataFormatClassName a
* <code>String</code>, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getNativeStreamMetadataFormat</code>.
* @param extraStreamMetadataFormatNames an array of
* <code>String</code>s, or <code>null</code>, to be returned from
* <code>getExtraStreamMetadataFormatNames</code>. An array of length
* 0 is normalized to <code>null</code>.
* @param extraStreamMetadataFormatClassNames an array of
* <code>String</code>s, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getStreamMetadataFormat</code>. An array of length
* 0 is normalized to <code>null</code>.
* @param supportsStandardImageMetadataFormat a
* <code>boolean</code> that indicates whether an image metadata
* object can use trees described by the standard metadata format.
* @param nativeImageMetadataFormatName a
* <code>String</code>, or <code>null</code>, to be returned from
* <code>getNativeImageMetadataFormatName</code>.
* @param nativeImageMetadataFormatClassName a
* <code>String</code>, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getNativeImageMetadataFormat</code>.
* @param extraImageMetadataFormatNames an array of
* <code>String</code>s to be returned from
* <code>getExtraImageMetadataFormatNames</code>. An array of length 0
* is normalized to <code>null</code>.
* @param extraImageMetadataFormatClassNames an array of
* <code>String</code>s, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getImageMetadataFormat</code>. An array of length
* 0 is normalized to <code>null</code>.
*
* @exception IllegalArgumentException if <code>vendorName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>version</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>names</code>
* is <code>null</code> or has length 0.
* @exception IllegalArgumentException if <code>readerClassName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>inputTypes</code>
* is <code>null</code> or has length 0.
*/
public ImageReaderSpi(String vendorName,
String version,
String[] names,
String[] suffixes,
String[] MIMETypes,
String readerClassName,
Class[] inputTypes,
String[] writerSpiNames,
boolean supportsStandardStreamMetadataFormat,
String nativeStreamMetadataFormatName,
String nativeStreamMetadataFormatClassName,
String[] extraStreamMetadataFormatNames,
String[] extraStreamMetadataFormatClassNames,
boolean supportsStandardImageMetadataFormat,
String nativeImageMetadataFormatName,
String nativeImageMetadataFormatClassName,
String[] extraImageMetadataFormatNames,
String[] extraImageMetadataFormatClassNames) {
super(vendorName, version,
names, suffixes, MIMETypes, readerClassName,
supportsStandardStreamMetadataFormat,
nativeStreamMetadataFormatName,
nativeStreamMetadataFormatClassName,
extraStreamMetadataFormatNames,
extraStreamMetadataFormatClassNames,
supportsStandardImageMetadataFormat,
nativeImageMetadataFormatName,
nativeImageMetadataFormatClassName,
extraImageMetadataFormatNames,
extraImageMetadataFormatClassNames);
if (inputTypes == null) {
throw new IllegalArgumentException
("inputTypes == null!");
}
if (inputTypes.length == 0) {
throw new IllegalArgumentException
("inputTypes.length == 0!");
}
this.inputTypes = (inputTypes == STANDARD_INPUT_TYPE) ?
new Class<?>[] { ImageInputStream.class } :
inputTypes.clone();
// If length == 0, leave it null
if (writerSpiNames != null && writerSpiNames.length > 0) {
this.writerSpiNames = (String[])writerSpiNames.clone();
}
}
/**
* Returns an array of <code>Class</code> objects indicating what
* types of objects may be used as arguments to the reader's
* <code>setInput</code> method.
*
* <p> For most readers, which only accept input from an
* <code>ImageInputStream</code>, a single-element array
* containing <code>ImageInputStream.class</code> should be
* returned.
*
* @return a non-<code>null</code> array of
* <code>Class</code>objects of length at least 1.
*/
public Class[] getInputTypes() {
return (Class[])inputTypes.clone();
}
/**
* Returns <code>true</code> if the supplied source object appears
* to be of the format supported by this reader. Returning
* <code>true</code> from this method does not guarantee that
* reading will succeed, only that there appears to be a
* reasonable chance of success based on a brief inspection of the
* stream contents. If the source is an
* <code>ImageInputStream</code>, implementations will commonly
* check the first several bytes of the stream for a "magic
* number" associated with the format. Once actual reading has
* commenced, the reader may still indicate failure at any time
* prior to the completion of decoding.
*
* <p> It is important that the state of the object not be
* disturbed in order that other <code>ImageReaderSpi</code>s can
* properly determine whether they are able to decode the object.
* In particular, if the source is an
* <code>ImageInputStream</code>, a
* <code>mark</code>/<code>reset</code> pair should be used to
* preserve the stream position.
*
* <p> Formats such as "raw," which can potentially attempt
* to read nearly any stream, should return <code>false</code>
* in order to avoid being invoked in preference to a closer
* match.
*
* <p> If <code>source</code> is not an instance of one of the
* classes returned by <code>getInputTypes</code>, the method
* should simply return <code>false</code>.
*
* @param source the object (typically an
* <code>ImageInputStream</code>) to be decoded.
*
* @return <code>true</code> if it is likely that this stream can
* be decoded.
*
* @exception IllegalArgumentException if <code>source</code> is
* <code>null</code>.
* @exception IOException if an I/O error occurs while reading the
* stream.
*/
public abstract boolean canDecodeInput(Object source) throws IOException;
/**
* Returns an instance of the <code>ImageReader</code>
* implementation associated with this service provider.
* The returned object will initially be in an initial state
* as if its <code>reset</code> method had been called.
*
* <p> The default implementation simply returns
* <code>createReaderInstance(null)</code>.
*
* @return an <code>ImageReader</code> instance.
*
* @exception IOException if an error occurs during loading,
* or initialization of the reader class, or during instantiation
* or initialization of the reader object.
*/
public ImageReader createReaderInstance() throws IOException {
return createReaderInstance(null);
}
/**
* Returns an instance of the <code>ImageReader</code>
* implementation associated with this service provider.
* The returned object will initially be in an initial state
* as if its <code>reset</code> method had been called.
*
* <p> An <code>Object</code> may be supplied to the plug-in at
* construction time. The nature of the object is entirely
* plug-in specific.
*
* <p> Typically, a plug-in will implement this method using code
* such as <code>return new MyImageReader(this)</code>.
*
* @param extension a plug-in specific extension object, which may
* be <code>null</code>.
*
* @return an <code>ImageReader</code> instance.
*
* @exception IOException if the attempt to instantiate
* the reader fails.
* @exception IllegalArgumentException if the
* <code>ImageReader</code>'s constructor throws an
* <code>IllegalArgumentException</code> to indicate that the
* extension object is unsuitable.
*/
public abstract ImageReader createReaderInstance(Object extension)
throws IOException;
/**
* Returns <code>true</code> if the <code>ImageReader</code> object
* passed in is an instance of the <code>ImageReader</code>
* associated with this service provider.
*
* <p> The default implementation compares the fully-qualified
* class name of the <code>reader</code> argument with the class
* name passed into the constructor. This method may be overridden
* if more sophisticated checking is required.
*
* @param reader an <code>ImageReader</code> instance.
*
* @return <code>true</code> if <code>reader</code> is recognized.
*
* @exception IllegalArgumentException if <code>reader</code> is
* <code>null</code>.
*/
public boolean isOwnReader(ImageReader reader) {
if (reader == null) {
throw new IllegalArgumentException("reader == null!");
}
String name = reader.getClass().getName();
return name.equals(pluginClassName);
}
/**
* Returns an array of <code>String</code>s containing the fully
* qualified names of all the <code>ImageWriterSpi</code> classes
* that can understand the internal metadata representation used
* by the <code>ImageReader</code> associated with this service
* provider, or <code>null</code> if there are no such
* <code>ImageWriter</code>s specified. If a
* non-<code>null</code> value is returned, it must have non-zero
* length.
*
* <p> The first item in the array must be the name of the service
* provider for the "preferred" writer, as it will be used to
* instantiate the <code>ImageWriter</code> returned by
* <code>ImageIO.getImageWriter(ImageReader)</code>.
*
* <p> This mechanism may be used to obtain
* <code>ImageWriters</code> that will understand the internal
* structure of non-pixel meta-data (see
* <code>IIOTreeInfo</code>) generated by an
* <code>ImageReader</code>. By obtaining this data from the
* <code>ImageReader</code> and passing it on to one of the
* <code>ImageWriters</code> obtained with this method, a client
* program can read an image, modify it in some way, and write it
* back out while preserving all meta-data, without having to
* understand anything about the internal structure of the
* meta-data, or even about the image format.
*
* @return an array of <code>String</code>s of length at least 1
* containing names of <code>ImageWriterSpi</code>, or
* <code>null</code>.
*
* @see javax.imageio.ImageIO#getImageWriter(ImageReader)
*/
public String[] getImageWriterSpiNames() {
return writerSpiNames == null ?
null : (String[])writerSpiNames.clone();
}
}

View File

@@ -0,0 +1,601 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Iterator;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataFormat;
import javax.imageio.metadata.IIOMetadataFormatImpl;
import javax.imageio.stream.ImageInputStream;
/**
* A superclass containing instance variables and methods common to
* <code>ImageReaderSpi</code> and <code>ImageWriterSpi</code>.
*
* @see IIORegistry
* @see ImageReaderSpi
* @see ImageWriterSpi
*
*/
public abstract class ImageReaderWriterSpi extends IIOServiceProvider {
/**
* An array of strings to be returned from
* <code>getFormatNames</code>, initially <code>null</code>.
* Constructors should set this to a non-<code>null</code> value.
*/
protected String[] names = null;
/**
* An array of strings to be returned from
* <code>getFileSuffixes</code>, initially <code>null</code>.
*/
protected String[] suffixes = null;
/**
* An array of strings to be returned from
* <code>getMIMETypes</code>, initially <code>null</code>.
*/
protected String[] MIMETypes = null;
/**
* A <code>String</code> containing the name of the associated
* plug-in class, initially <code>null</code>.
*/
protected String pluginClassName = null;
/**
* A boolean indicating whether this plug-in supports the
* standard metadata format for stream metadata, initially
* <code>false</code>.
*/
protected boolean supportsStandardStreamMetadataFormat = false;
/**
* A <code>String</code> containing the name of the native stream
* metadata format supported by this plug-in, initially
* <code>null</code>.
*/
protected String nativeStreamMetadataFormatName = null;
/**
* A <code>String</code> containing the class name of the native
* stream metadata format supported by this plug-in, initially
* <code>null</code>.
*/
protected String nativeStreamMetadataFormatClassName = null;
/**
* An array of <code>String</code>s containing the names of any
* additional stream metadata formats supported by this plug-in,
* initially <code>null</code>.
*/
protected String[] extraStreamMetadataFormatNames = null;
/**
* An array of <code>String</code>s containing the class names of
* any additional stream metadata formats supported by this plug-in,
* initially <code>null</code>.
*/
protected String[] extraStreamMetadataFormatClassNames = null;
/**
* A boolean indicating whether this plug-in supports the
* standard metadata format for image metadata, initially
* <code>false</code>.
*/
protected boolean supportsStandardImageMetadataFormat = false;
/**
* A <code>String</code> containing the name of the
* native stream metadata format supported by this plug-in,
* initially <code>null</code>.
*/
protected String nativeImageMetadataFormatName = null;
/**
* A <code>String</code> containing the class name of the
* native stream metadata format supported by this plug-in,
* initially <code>null</code>.
*/
protected String nativeImageMetadataFormatClassName = null;
/**
* An array of <code>String</code>s containing the names of any
* additional image metadata formats supported by this plug-in,
* initially <code>null</code>.
*/
protected String[] extraImageMetadataFormatNames = null;
/**
* An array of <code>String</code>s containing the class names of
* any additional image metadata formats supported by this
* plug-in, initially <code>null</code>.
*/
protected String[] extraImageMetadataFormatClassNames = null;
/**
* Constructs an <code>ImageReaderWriterSpi</code> with a given
* set of values.
*
* @param vendorName the vendor name, as a non-<code>null</code>
* <code>String</code>.
* @param version a version identifier, as a non-<code>null</code>
* <code>String</code>.
* @param names a non-<code>null</code> array of
* <code>String</code>s indicating the format names. At least one
* entry must be present.
* @param suffixes an array of <code>String</code>s indicating the
* common file suffixes. If no suffixes are defined,
* <code>null</code> should be supplied. An array of length 0
* will be normalized to <code>null</code>.
* @param MIMETypes an array of <code>String</code>s indicating
* the format's MIME types. If no MIME types are defined,
* <code>null</code> should be supplied. An array of length 0
* will be normalized to <code>null</code>.
* @param pluginClassName the fully-qualified name of the
* associated <code>ImageReader</code> or <code>ImageWriter</code>
* class, as a non-<code>null</code> <code>String</code>.
* @param supportsStandardStreamMetadataFormat a
* <code>boolean</code> that indicates whether a stream metadata
* object can use trees described by the standard metadata format.
* @param nativeStreamMetadataFormatName a
* <code>String</code>, or <code>null</code>, to be returned from
* <code>getNativeStreamMetadataFormatName</code>.
* @param nativeStreamMetadataFormatClassName a
* <code>String</code>, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getNativeStreamMetadataFormat</code>.
* @param extraStreamMetadataFormatNames an array of
* <code>String</code>s, or <code>null</code>, to be returned from
* <code>getExtraStreamMetadataFormatNames</code>. An array of length
* 0 is normalized to <code>null</code>.
* @param extraStreamMetadataFormatClassNames an array of
* <code>String</code>s, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getStreamMetadataFormat</code>. An array of length
* 0 is normalized to <code>null</code>.
* @param supportsStandardImageMetadataFormat a
* <code>boolean</code> that indicates whether an image metadata
* object can use trees described by the standard metadata format.
* @param nativeImageMetadataFormatName a
* <code>String</code>, or <code>null</code>, to be returned from
* <code>getNativeImageMetadataFormatName</code>.
* @param nativeImageMetadataFormatClassName a
* <code>String</code>, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getNativeImageMetadataFormat</code>.
* @param extraImageMetadataFormatNames an array of
* <code>String</code>s to be returned from
* <code>getExtraImageMetadataFormatNames</code>. An array of length 0
* is normalized to <code>null</code>.
* @param extraImageMetadataFormatClassNames an array of
* <code>String</code>s, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getImageMetadataFormat</code>. An array of length
* 0 is normalized to <code>null</code>.
*
* @exception IllegalArgumentException if <code>vendorName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>version</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>names</code>
* is <code>null</code> or has length 0.
* @exception IllegalArgumentException if <code>pluginClassName</code>
* is <code>null</code>.
*/
public ImageReaderWriterSpi(String vendorName,
String version,
String[] names,
String[] suffixes,
String[] MIMETypes,
String pluginClassName,
boolean supportsStandardStreamMetadataFormat,
String nativeStreamMetadataFormatName,
String nativeStreamMetadataFormatClassName,
String[] extraStreamMetadataFormatNames,
String[] extraStreamMetadataFormatClassNames,
boolean supportsStandardImageMetadataFormat,
String nativeImageMetadataFormatName,
String nativeImageMetadataFormatClassName,
String[] extraImageMetadataFormatNames,
String[] extraImageMetadataFormatClassNames) {
super(vendorName, version);
if (names == null) {
throw new IllegalArgumentException("names == null!");
}
if (names.length == 0) {
throw new IllegalArgumentException("names.length == 0!");
}
if (pluginClassName == null) {
throw new IllegalArgumentException("pluginClassName == null!");
}
this.names = (String[])names.clone();
// If length == 0, leave it null
if (suffixes != null && suffixes.length > 0) {
this.suffixes = (String[])suffixes.clone();
}
// If length == 0, leave it null
if (MIMETypes != null && MIMETypes.length > 0) {
this.MIMETypes = (String[])MIMETypes.clone();
}
this.pluginClassName = pluginClassName;
this.supportsStandardStreamMetadataFormat =
supportsStandardStreamMetadataFormat;
this.nativeStreamMetadataFormatName = nativeStreamMetadataFormatName;
this.nativeStreamMetadataFormatClassName =
nativeStreamMetadataFormatClassName;
// If length == 0, leave it null
if (extraStreamMetadataFormatNames != null &&
extraStreamMetadataFormatNames.length > 0) {
this.extraStreamMetadataFormatNames =
(String[])extraStreamMetadataFormatNames.clone();
}
// If length == 0, leave it null
if (extraStreamMetadataFormatClassNames != null &&
extraStreamMetadataFormatClassNames.length > 0) {
this.extraStreamMetadataFormatClassNames =
(String[])extraStreamMetadataFormatClassNames.clone();
}
this.supportsStandardImageMetadataFormat =
supportsStandardImageMetadataFormat;
this.nativeImageMetadataFormatName = nativeImageMetadataFormatName;
this.nativeImageMetadataFormatClassName =
nativeImageMetadataFormatClassName;
// If length == 0, leave it null
if (extraImageMetadataFormatNames != null &&
extraImageMetadataFormatNames.length > 0) {
this.extraImageMetadataFormatNames =
(String[])extraImageMetadataFormatNames.clone();
}
// If length == 0, leave it null
if (extraImageMetadataFormatClassNames != null &&
extraImageMetadataFormatClassNames.length > 0) {
this.extraImageMetadataFormatClassNames =
(String[])extraImageMetadataFormatClassNames.clone();
}
}
/**
* Constructs a blank <code>ImageReaderWriterSpi</code>. It is up
* to the subclass to initialize instance variables and/or
* override method implementations in order to provide working
* versions of all methods.
*/
public ImageReaderWriterSpi() {
}
/**
* Returns an array of <code>String</code>s containing
* human-readable names for the formats that are generally usable
* by the <code>ImageReader</code> or <code>ImageWriter</code>
* implementation associated with this service provider. For
* example, a single <code>ImageReader</code> might be able to
* process both PBM and PNM files.
*
* @return a non-<code>null</code> array of <code>String</code>s
* or length at least 1 containing informal format names
* associated with this reader or writer.
*/
public String[] getFormatNames() {
return (String[])names.clone();
}
/**
* Returns an array of <code>String</code>s containing a list of
* file suffixes associated with the formats that are generally
* usable by the <code>ImageReader</code> or
* <code>ImageWriter</code> implementation associated with this
* service provider. For example, a single
* <code>ImageReader</code> might be able to process files with
* '.pbm' and '.pnm' suffixes, or both '.jpg' and '.jpeg'
* suffixes. If there are no known file suffixes,
* <code>null</code> will be returned.
*
* <p> Returning a particular suffix does not guarantee that files
* with that suffix can be processed; it merely indicates that it
* may be worthwhile attempting to decode or encode such files
* using this service provider.
*
* @return an array of <code>String</code>s or length at least 1
* containing common file suffixes associated with this reader or
* writer, or <code>null</code>.
*/
public String[] getFileSuffixes() {
return suffixes == null ? null : (String[])suffixes.clone();
}
/**
* Returns an array of <code>String</code>s containing a list of
* MIME types associated with the formats that are generally
* usable by the <code>ImageReader</code> or
* <code>ImageWriter</code> implementation associated with this
* service provider.
*
* <p> Ideally, only a single MIME type would be required in order
* to describe a particular format. However, for several reasons
* it is necessary to associate a list of types with each service
* provider. First, many common image file formats do not have
* standard MIME types, so a list of commonly used unofficial
* names will be required, such as <code>image/x-pbm</code> and
* <code>image/x-portable-bitmap</code>. Some file formats have
* official MIME types but may sometimes be referred to using
* their previous unofficial designations, such as
* <code>image/x-png</code> instead of the official
* <code>image/png</code>. Finally, a single service provider may
* be capable of parsing multiple distinct types from the MIME
* point of view, for example <code>image/x-xbitmap</code> and
* <code>image/x-xpixmap</code>.
*
* <p> Returning a particular MIME type does not guarantee that
* files claiming to be of that type can be processed; it merely
* indicates that it may be worthwhile attempting to decode or
* encode such files using this service provider.
*
* @return an array of <code>String</code>s or length at least 1
* containing MIME types associated with this reader or writer, or
* <code>null</code>.
*/
public String[] getMIMETypes() {
return MIMETypes == null ? null : (String[])MIMETypes.clone();
}
/**
* Returns the fully-qualified class name of the
* <code>ImageReader</code> or <code>ImageWriter</code> plug-in
* associated with this service provider.
*
* @return the class name, as a non-<code>null</code>
* <code>String</code>.
*/
public String getPluginClassName() {
return pluginClassName;
}
/**
* Returns <code>true</code> if the standard metadata format is
* among the document formats recognized by the
* <code>getAsTree</code> and <code>setFromTree</code> methods on
* the stream metadata objects produced or consumed by this
* plug-in.
*
* @return <code>true</code> if the standard format is supported
* for stream metadata.
*/
public boolean isStandardStreamMetadataFormatSupported() {
return supportsStandardStreamMetadataFormat;
}
/**
* Returns the name of the "native" stream metadata format for
* this plug-in, which typically allows for lossless encoding and
* transmission of the stream metadata stored in the format handled by
* this plug-in. If no such format is supported,
* <code>null</code>will be returned.
*
* <p> The default implementation returns the
* <code>nativeStreamMetadataFormatName</code> instance variable,
* which is typically set by the constructor.
*
* @return the name of the native stream metadata format, or
* <code>null</code>.
*
*/
public String getNativeStreamMetadataFormatName() {
return nativeStreamMetadataFormatName;
}
/**
* Returns an array of <code>String</code>s containing the names
* of additional document formats, other than the native and
* standard formats, recognized by the
* <code>getAsTree</code> and <code>setFromTree</code> methods on
* the stream metadata objects produced or consumed by this
* plug-in.
*
* <p> If the plug-in does not handle metadata, null should be
* returned.
*
* <p> The set of formats may differ according to the particular
* images being read or written; this method should indicate all
* the additional formats supported by the plug-in under any
* circumstances.
*
* <p> The default implementation returns a clone of the
* <code>extraStreamMetadataFormatNames</code> instance variable,
* which is typically set by the constructor.
*
* @return an array of <code>String</code>s, or null.
*
* @see IIOMetadata#getMetadataFormatNames
* @see #getExtraImageMetadataFormatNames
* @see #getNativeStreamMetadataFormatName
*/
public String[] getExtraStreamMetadataFormatNames() {
return extraStreamMetadataFormatNames == null ?
null : (String[])extraStreamMetadataFormatNames.clone();
}
/**
* Returns <code>true</code> if the standard metadata format is
* among the document formats recognized by the
* <code>getAsTree</code> and <code>setFromTree</code> methods on
* the image metadata objects produced or consumed by this
* plug-in.
*
* @return <code>true</code> if the standard format is supported
* for image metadata.
*/
public boolean isStandardImageMetadataFormatSupported() {
return supportsStandardImageMetadataFormat;
}
/**
* Returns the name of the "native" image metadata format for
* this plug-in, which typically allows for lossless encoding and
* transmission of the image metadata stored in the format handled by
* this plug-in. If no such format is supported,
* <code>null</code>will be returned.
*
* <p> The default implementation returns the
* <code>nativeImageMetadataFormatName</code> instance variable,
* which is typically set by the constructor.
*
* @return the name of the native image metadata format, or
* <code>null</code>.
*
* @see #getExtraImageMetadataFormatNames
*/
public String getNativeImageMetadataFormatName() {
return nativeImageMetadataFormatName;
}
/**
* Returns an array of <code>String</code>s containing the names
* of additional document formats, other than the native and
* standard formats, recognized by the
* <code>getAsTree</code> and <code>setFromTree</code> methods on
* the image metadata objects produced or consumed by this
* plug-in.
*
* <p> If the plug-in does not handle image metadata, null should
* be returned.
*
* <p> The set of formats may differ according to the particular
* images being read or written; this method should indicate all
* the additional formats supported by the plug-in under any circumstances.
*
* <p> The default implementation returns a clone of the
* <code>extraImageMetadataFormatNames</code> instance variable,
* which is typically set by the constructor.
*
* @return an array of <code>String</code>s, or null.
*
* @see IIOMetadata#getMetadataFormatNames
* @see #getExtraStreamMetadataFormatNames
* @see #getNativeImageMetadataFormatName
*/
public String[] getExtraImageMetadataFormatNames() {
return extraImageMetadataFormatNames == null ?
null : (String[])extraImageMetadataFormatNames.clone();
}
/**
* Returns an <code>IIOMetadataFormat</code> object describing the
* given stream metadata format, or <code>null</code> if no
* description is available. The supplied name must be the native
* stream metadata format name, the standard metadata format name,
* or one of those returned by
* <code>getExtraStreamMetadataFormatNames</code>.
*
* @param formatName the desired stream metadata format.
*
* @return an <code>IIOMetadataFormat</code> object.
*
* @exception IllegalArgumentException if <code>formatName</code>
* is <code>null</code> or is not a supported name.
*/
public IIOMetadataFormat getStreamMetadataFormat(String formatName) {
return getMetadataFormat(formatName,
supportsStandardStreamMetadataFormat,
nativeStreamMetadataFormatName,
nativeStreamMetadataFormatClassName,
extraStreamMetadataFormatNames,
extraStreamMetadataFormatClassNames);
}
/**
* Returns an <code>IIOMetadataFormat</code> object describing the
* given image metadata format, or <code>null</code> if no
* description is available. The supplied name must be the native
* image metadata format name, the standard metadata format name,
* or one of those returned by
* <code>getExtraImageMetadataFormatNames</code>.
*
* @param formatName the desired image metadata format.
*
* @return an <code>IIOMetadataFormat</code> object.
*
* @exception IllegalArgumentException if <code>formatName</code>
* is <code>null</code> or is not a supported name.
*/
public IIOMetadataFormat getImageMetadataFormat(String formatName) {
return getMetadataFormat(formatName,
supportsStandardImageMetadataFormat,
nativeImageMetadataFormatName,
nativeImageMetadataFormatClassName,
extraImageMetadataFormatNames,
extraImageMetadataFormatClassNames);
}
private IIOMetadataFormat getMetadataFormat(String formatName,
boolean supportsStandard,
String nativeName,
String nativeClassName,
String [] extraNames,
String [] extraClassNames) {
if (formatName == null) {
throw new IllegalArgumentException("formatName == null!");
}
if (supportsStandard && formatName.equals
(IIOMetadataFormatImpl.standardMetadataFormatName)) {
return IIOMetadataFormatImpl.getStandardFormatInstance();
}
String formatClassName = null;
if (formatName.equals(nativeName)) {
formatClassName = nativeClassName;
} else if (extraNames != null) {
for (int i = 0; i < extraNames.length; i++) {
if (formatName.equals(extraNames[i])) {
formatClassName = extraClassNames[i];
break; // out of for
}
}
}
if (formatClassName == null) {
throw new IllegalArgumentException("Unsupported format name");
}
try {
Class cls = Class.forName(formatClassName, true,
ClassLoader.getSystemClassLoader());
Method meth = cls.getMethod("getInstance");
return (IIOMetadataFormat) meth.invoke(null);
} catch (Exception e) {
RuntimeException ex =
new IllegalStateException ("Can't obtain format");
ex.initCause(e);
throw ex;
}
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import javax.imageio.ImageTranscoder;
/**
* The service provider interface (SPI) for <code>ImageTranscoder</code>s.
* For more information on service provider classes, see the class comment
* for the <code>IIORegistry</code> class.
*
* @see IIORegistry
* @see javax.imageio.ImageTranscoder
*
*/
public abstract class ImageTranscoderSpi extends IIOServiceProvider {
/**
* Constructs a blank <code>ImageTranscoderSpi</code>. It is up
* to the subclass to initialize instance variables and/or
* override method implementations in order to provide working
* versions of all methods.
*/
protected ImageTranscoderSpi() {
}
/**
* Constructs an <code>ImageTranscoderSpi</code> with a given set
* of values.
*
* @param vendorName the vendor name.
* @param version a version identifier.
*/
public ImageTranscoderSpi(String vendorName,
String version) {
super(vendorName, version);
}
/**
* Returns the fully qualified class name of an
* <code>ImageReaderSpi</code> class that generates
* <code>IIOMetadata</code> objects that may be used as input to
* this transcoder.
*
* @return a <code>String</code> containing the fully-qualified
* class name of the <code>ImageReaderSpi</code> implementation class.
*
* @see ImageReaderSpi
*/
public abstract String getReaderServiceProviderName();
/**
* Returns the fully qualified class name of an
* <code>ImageWriterSpi</code> class that generates
* <code>IIOMetadata</code> objects that may be used as input to
* this transcoder.
*
* @return a <code>String</code> containing the fully-qualified
* class name of the <code>ImageWriterSpi</code> implementation class.
*
* @see ImageWriterSpi
*/
public abstract String getWriterServiceProviderName();
/**
* Returns an instance of the <code>ImageTranscoder</code>
* implementation associated with this service provider.
*
* @return an <code>ImageTranscoder</code> instance.
*/
public abstract ImageTranscoder createTranscoderInstance();
}

View File

@@ -0,0 +1,440 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.awt.image.RenderedImage;
import java.io.IOException;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
/**
* The service provider interface (SPI) for <code>ImageWriter</code>s.
* For more information on service provider classes, see the class comment
* for the <code>IIORegistry</code> class.
*
* <p> Each <code>ImageWriterSpi</code> provides several types of information
* about the <code>ImageWriter</code> class with which it is associated.
*
* <p> The name of the vendor who defined the SPI class and a
* brief description of the class are available via the
* <code>getVendorName</code>, <code>getDescription</code>,
* and <code>getVersion</code> methods.
* These methods may be internationalized to provide locale-specific
* output. These methods are intended mainly to provide short,
* human-writable information that might be used to organize a pop-up
* menu or other list.
*
* <p> Lists of format names, file suffixes, and MIME types associated
* with the service may be obtained by means of the
* <code>getFormatNames</code>, <code>getFileSuffixes</code>, and
* <code>getMIMEType</code> methods. These methods may be used to
* identify candidate <code>ImageWriter</code>s for writing a
* particular file or stream based on manual format selection, file
* naming, or MIME associations.
*
* <p> A more reliable way to determine which <code>ImageWriter</code>s
* are likely to be able to parse a particular data stream is provided
* by the <code>canEncodeImage</code> method. This methods allows the
* service provider to inspect the actual image contents.
*
* <p> Finally, an instance of the <code>ImageWriter</code> class
* associated with this service provider may be obtained by calling
* the <code>createWriterInstance</code> method. Any heavyweight
* initialization, such as the loading of native libraries or creation
* of large tables, should be deferred at least until the first
* invocation of this method.
*
* @see IIORegistry
* @see javax.imageio.ImageTypeSpecifier
* @see javax.imageio.ImageWriter
*
*/
public abstract class ImageWriterSpi extends ImageReaderWriterSpi {
/**
* A single-element array, initially containing
* <code>ImageOutputStream.class</code>, to be returned from
* <code>getOutputTypes</code>.
* @deprecated Instead of using this field, directly create
* the equivalent array <code>{ ImageOutputStream.class }</code>.
*/
@Deprecated
public static final Class[] STANDARD_OUTPUT_TYPE =
{ ImageOutputStream.class };
/**
* An array of <code>Class</code> objects to be returned from
* <code>getOutputTypes</code>, initially <code>null</code>.
*/
protected Class[] outputTypes = null;
/**
* An array of strings to be returned from
* <code>getImageReaderSpiNames</code>, initially
* <code>null</code>.
*/
protected String[] readerSpiNames = null;
/**
* The <code>Class</code> of the writer, initially
* <code>null</code>.
*/
private Class writerClass = null;
/**
* Constructs a blank <code>ImageWriterSpi</code>. It is up to
* the subclass to initialize instance variables and/or override
* method implementations in order to provide working versions of
* all methods.
*/
protected ImageWriterSpi() {
}
/**
* Constructs an <code>ImageWriterSpi</code> with a given
* set of values.
*
* @param vendorName the vendor name, as a non-<code>null</code>
* <code>String</code>.
* @param version a version identifier, as a non-<code>null</code>
* <code>String</code>.
* @param names a non-<code>null</code> array of
* <code>String</code>s indicating the format names. At least one
* entry must be present.
* @param suffixes an array of <code>String</code>s indicating the
* common file suffixes. If no suffixes are defined,
* <code>null</code> should be supplied. An array of length 0
* will be normalized to <code>null</code>.
* @param MIMETypes an array of <code>String</code>s indicating
* the format's MIME types. If no suffixes are defined,
* <code>null</code> should be supplied. An array of length 0
* will be normalized to <code>null</code>.
* @param writerClassName the fully-qualified name of the
* associated <code>ImageWriterSpi</code> class, as a
* non-<code>null</code> <code>String</code>.
* @param outputTypes an array of <code>Class</code> objects of
* length at least 1 indicating the legal output types.
* @param readerSpiNames an array <code>String</code>s of length
* at least 1 naming the classes of all associated
* <code>ImageReader</code>s, or <code>null</code>. An array of
* length 0 is normalized to <code>null</code>.
* @param supportsStandardStreamMetadataFormat a
* <code>boolean</code> that indicates whether a stream metadata
* object can use trees described by the standard metadata format.
* @param nativeStreamMetadataFormatName a
* <code>String</code>, or <code>null</code>, to be returned from
* <code>getNativeStreamMetadataFormatName</code>.
* @param nativeStreamMetadataFormatClassName a
* <code>String</code>, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getNativeStreamMetadataFormat</code>.
* @param extraStreamMetadataFormatNames an array of
* <code>String</code>s, or <code>null</code>, to be returned from
* <code>getExtraStreamMetadataFormatNames</code>. An array of length
* 0 is normalized to <code>null</code>.
* @param extraStreamMetadataFormatClassNames an array of
* <code>String</code>s, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getStreamMetadataFormat</code>. An array of length
* 0 is normalized to <code>null</code>.
* @param supportsStandardImageMetadataFormat a
* <code>boolean</code> that indicates whether an image metadata
* object can use trees described by the standard metadata format.
* @param nativeImageMetadataFormatName a
* <code>String</code>, or <code>null</code>, to be returned from
* <code>getNativeImageMetadataFormatName</code>.
* @param nativeImageMetadataFormatClassName a
* <code>String</code>, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getNativeImageMetadataFormat</code>.
* @param extraImageMetadataFormatNames an array of
* <code>String</code>s to be returned from
* <code>getExtraImageMetadataFormatNames</code>. An array of length 0
* is normalized to <code>null</code>.
* @param extraImageMetadataFormatClassNames an array of
* <code>String</code>s, or <code>null</code>, to be used to instantiate
* a metadata format object to be returned from
* <code>getImageMetadataFormat</code>. An array of length
* 0 is normalized to <code>null</code>.
*
* @exception IllegalArgumentException if <code>vendorName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>version</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>names</code>
* is <code>null</code> or has length 0.
* @exception IllegalArgumentException if <code>writerClassName</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>outputTypes</code>
* is <code>null</code> or has length 0.
*/
public ImageWriterSpi(String vendorName,
String version,
String[] names,
String[] suffixes,
String[] MIMETypes,
String writerClassName,
Class[] outputTypes,
String[] readerSpiNames,
boolean supportsStandardStreamMetadataFormat,
String nativeStreamMetadataFormatName,
String nativeStreamMetadataFormatClassName,
String[] extraStreamMetadataFormatNames,
String[] extraStreamMetadataFormatClassNames,
boolean supportsStandardImageMetadataFormat,
String nativeImageMetadataFormatName,
String nativeImageMetadataFormatClassName,
String[] extraImageMetadataFormatNames,
String[] extraImageMetadataFormatClassNames) {
super(vendorName, version,
names, suffixes, MIMETypes, writerClassName,
supportsStandardStreamMetadataFormat,
nativeStreamMetadataFormatName,
nativeStreamMetadataFormatClassName,
extraStreamMetadataFormatNames,
extraStreamMetadataFormatClassNames,
supportsStandardImageMetadataFormat,
nativeImageMetadataFormatName,
nativeImageMetadataFormatClassName,
extraImageMetadataFormatNames,
extraImageMetadataFormatClassNames);
if (outputTypes == null) {
throw new IllegalArgumentException
("outputTypes == null!");
}
if (outputTypes.length == 0) {
throw new IllegalArgumentException
("outputTypes.length == 0!");
}
this.outputTypes = (outputTypes == STANDARD_OUTPUT_TYPE) ?
new Class<?>[] { ImageOutputStream.class } :
outputTypes.clone();
// If length == 0, leave it null
if (readerSpiNames != null && readerSpiNames.length > 0) {
this.readerSpiNames = (String[])readerSpiNames.clone();
}
}
/**
* Returns <code>true</code> if the format that this writer
* outputs preserves pixel data bit-accurately. The default
* implementation returns <code>true</code>.
*
* @return <code>true</code> if the format preserves full pixel
* accuracy.
*/
public boolean isFormatLossless() {
return true;
}
/**
* Returns an array of <code>Class</code> objects indicating what
* types of objects may be used as arguments to the writer's
* <code>setOutput</code> method.
*
* <p> For most writers, which only output to an
* <code>ImageOutputStream</code>, a single-element array
* containing <code>ImageOutputStream.class</code> should be
* returned.
*
* @return a non-<code>null</code> array of
* <code>Class</code>objects of length at least 1.
*/
public Class[] getOutputTypes() {
return (Class[])outputTypes.clone();
}
/**
* Returns <code>true</code> if the <code>ImageWriter</code>
* implementation associated with this service provider is able to
* encode an image with the given layout. The layout
* (<i>i.e.</i>, the image's <code>SampleModel</code> and
* <code>ColorModel</code>) is described by an
* <code>ImageTypeSpecifier</code> object.
*
* <p> A return value of <code>true</code> is not an absolute
* guarantee of successful encoding; the encoding process may still
* produce errors due to factors such as I/O errors, inconsistent
* or malformed data structures, etc. The intent is that a
* reasonable inspection of the basic structure of the image be
* performed in order to determine if it is within the scope of
* the encoding format. For example, a service provider for a
* format that can only encode greyscale would return
* <code>false</code> if handed an RGB <code>BufferedImage</code>.
* Similarly, a service provider for a format that can encode
* 8-bit RGB imagery might refuse to encode an image with an
* associated alpha channel.
*
* <p> Different <code>ImageWriter</code>s, and thus service
* providers, may choose to be more or less strict. For example,
* they might accept an image with premultiplied alpha even though
* it will have to be divided out of each pixel, at some loss of
* precision, in order to be stored.
*
* @param type an <code>ImageTypeSpecifier</code> specifying the
* layout of the image to be written.
*
* @return <code>true</code> if this writer is likely to be able
* to encode images with the given layout.
*
* @exception IllegalArgumentException if <code>type</code>
* is <code>null</code>.
*/
public abstract boolean canEncodeImage(ImageTypeSpecifier type);
/**
* Returns <code>true</code> if the <code>ImageWriter</code>
* implementation associated with this service provider is able to
* encode the given <code>RenderedImage</code> instance. Note
* that this includes instances of
* <code>java.awt.image.BufferedImage</code>.
*
* <p> See the discussion for
* <code>canEncodeImage(ImageTypeSpecifier)</code> for information
* on the semantics of this method.
*
* @param im an instance of <code>RenderedImage</code> to be encoded.
*
* @return <code>true</code> if this writer is likely to be able
* to encode this image.
*
* @exception IllegalArgumentException if <code>im</code>
* is <code>null</code>.
*/
public boolean canEncodeImage(RenderedImage im) {
return canEncodeImage(ImageTypeSpecifier.createFromRenderedImage(im));
}
/**
* Returns an instance of the <code>ImageWriter</code>
* implementation associated with this service provider.
* The returned object will initially be in an initial state as if
* its <code>reset</code> method had been called.
*
* <p> The default implementation simply returns
* <code>createWriterInstance(null)</code>.
*
* @return an <code>ImageWriter</code> instance.
*
* @exception IOException if an error occurs during loading,
* or initialization of the writer class, or during instantiation
* or initialization of the writer object.
*/
public ImageWriter createWriterInstance() throws IOException {
return createWriterInstance(null);
}
/**
* Returns an instance of the <code>ImageWriter</code>
* implementation associated with this service provider.
* The returned object will initially be in an initial state
* as if its <code>reset</code> method had been called.
*
* <p> An <code>Object</code> may be supplied to the plug-in at
* construction time. The nature of the object is entirely
* plug-in specific.
*
* <p> Typically, a plug-in will implement this method using code
* such as <code>return new MyImageWriter(this)</code>.
*
* @param extension a plug-in specific extension object, which may
* be <code>null</code>.
*
* @return an <code>ImageWriter</code> instance.
*
* @exception IOException if the attempt to instantiate
* the writer fails.
* @exception IllegalArgumentException if the
* <code>ImageWriter</code>'s constructor throws an
* <code>IllegalArgumentException</code> to indicate that the
* extension object is unsuitable.
*/
public abstract ImageWriter createWriterInstance(Object extension)
throws IOException;
/**
* Returns <code>true</code> if the <code>ImageWriter</code> object
* passed in is an instance of the <code>ImageWriter</code>
* associated with this service provider.
*
* @param writer an <code>ImageWriter</code> instance.
*
* @return <code>true</code> if <code>writer</code> is recognized
*
* @exception IllegalArgumentException if <code>writer</code> is
* <code>null</code>.
*/
public boolean isOwnWriter(ImageWriter writer) {
if (writer == null) {
throw new IllegalArgumentException("writer == null!");
}
String name = writer.getClass().getName();
return name.equals(pluginClassName);
}
/**
* Returns an array of <code>String</code>s containing all the
* fully qualified names of all the <code>ImageReaderSpi</code>
* classes that can understand the internal metadata
* representation used by the <code>ImageWriter</code> associated
* with this service provider, or <code>null</code> if there are
* no such <code>ImageReaders</code> specified. If a
* non-<code>null</code> value is returned, it must have non-zero
* length.
*
* <p> The first item in the array must be the name of the service
* provider for the "preferred" reader, as it will be used to
* instantiate the <code>ImageReader</code> returned by
* <code>ImageIO.getImageReader(ImageWriter)</code>.
*
* <p> This mechanism may be used to obtain
* <code>ImageReaders</code> that will generated non-pixel
* meta-data (see <code>IIOExtraDataInfo</code>) in a structure
* understood by an <code>ImageWriter</code>. By reading the
* image and obtaining this data from one of the
* <code>ImageReaders</code> obtained with this method and passing
* it on to the <code>ImageWriter</code>, a client program can
* read an image, modify it in some way, and write it back out
* preserving all meta-data, without having to understand anything
* about the internal structure of the meta-data, or even about
* the image format.
*
* @return an array of <code>String</code>s of length at least 1
* containing names of <code>ImageReaderSpi</code>s, or
* <code>null</code>.
*
* @see javax.imageio.ImageIO#getImageReader(ImageWriter)
* @see ImageReaderSpi#getImageWriterSpiNames()
*/
public String[] getImageReaderSpiNames() {
return readerSpiNames == null ?
null : (String[])readerSpiNames.clone();
}
}

View File

@@ -0,0 +1,214 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.util.AbstractSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
/**
* A set of <code>Object</code>s with pairwise orderings between them.
* The <code>iterator</code> method provides the elements in
* topologically sorted order. Elements participating in a cycle
* are not returned.
*
* Unlike the <code>SortedSet</code> and <code>SortedMap</code>
* interfaces, which require their elements to implement the
* <code>Comparable</code> interface, this class receives ordering
* information via its <code>setOrdering</code> and
* <code>unsetPreference</code> methods. This difference is due to
* the fact that the relevant ordering between elements is unlikely to
* be inherent in the elements themselves; rather, it is set
* dynamically accoring to application policy. For example, in a
* service provider registry situation, an application might allow the
* user to set a preference order for service provider objects
* supplied by a trusted vendor over those supplied by another.
*
*/
class PartiallyOrderedSet extends AbstractSet {
// The topological sort (roughly) follows the algorithm described in
// Horowitz and Sahni, _Fundamentals of Data Structures_ (1976),
// p. 315.
// Maps Objects to DigraphNodes that contain them
private Map poNodes = new HashMap();
// The set of Objects
private Set nodes = poNodes.keySet();
/**
* Constructs a <code>PartiallyOrderedSet</code>.
*/
public PartiallyOrderedSet() {}
public int size() {
return nodes.size();
}
public boolean contains(Object o) {
return nodes.contains(o);
}
/**
* Returns an iterator over the elements contained in this
* collection, with an ordering that respects the orderings set
* by the <code>setOrdering</code> method.
*/
public Iterator iterator() {
return new PartialOrderIterator(poNodes.values().iterator());
}
/**
* Adds an <code>Object</code> to this
* <code>PartiallyOrderedSet</code>.
*/
public boolean add(Object o) {
if (nodes.contains(o)) {
return false;
}
DigraphNode node = new DigraphNode(o);
poNodes.put(o, node);
return true;
}
/**
* Removes an <code>Object</code> from this
* <code>PartiallyOrderedSet</code>.
*/
public boolean remove(Object o) {
DigraphNode node = (DigraphNode)poNodes.get(o);
if (node == null) {
return false;
}
poNodes.remove(o);
node.dispose();
return true;
}
public void clear() {
poNodes.clear();
}
/**
* Sets an ordering between two nodes. When an iterator is
* requested, the first node will appear earlier in the
* sequence than the second node. If a prior ordering existed
* between the nodes in the opposite order, it is removed.
*
* @return <code>true</code> if no prior ordering existed
* between the nodes, <code>false</code>otherwise.
*/
public boolean setOrdering(Object first, Object second) {
DigraphNode firstPONode =
(DigraphNode)poNodes.get(first);
DigraphNode secondPONode =
(DigraphNode)poNodes.get(second);
secondPONode.removeEdge(firstPONode);
return firstPONode.addEdge(secondPONode);
}
/**
* Removes any ordering between two nodes.
*
* @return true if a prior prefence existed between the nodes.
*/
public boolean unsetOrdering(Object first, Object second) {
DigraphNode firstPONode =
(DigraphNode)poNodes.get(first);
DigraphNode secondPONode =
(DigraphNode)poNodes.get(second);
return firstPONode.removeEdge(secondPONode) ||
secondPONode.removeEdge(firstPONode);
}
/**
* Returns <code>true</code> if an ordering exists between two
* nodes.
*/
public boolean hasOrdering(Object preferred, Object other) {
DigraphNode preferredPONode =
(DigraphNode)poNodes.get(preferred);
DigraphNode otherPONode =
(DigraphNode)poNodes.get(other);
return preferredPONode.hasEdge(otherPONode);
}
}
class PartialOrderIterator implements Iterator {
LinkedList zeroList = new LinkedList();
Map inDegrees = new HashMap(); // DigraphNode -> Integer
public PartialOrderIterator(Iterator iter) {
// Initialize scratch in-degree values, zero list
while (iter.hasNext()) {
DigraphNode node = (DigraphNode)iter.next();
int inDegree = node.getInDegree();
inDegrees.put(node, new Integer(inDegree));
// Add nodes with zero in-degree to the zero list
if (inDegree == 0) {
zeroList.add(node);
}
}
}
public boolean hasNext() {
return !zeroList.isEmpty();
}
public Object next() {
DigraphNode first = (DigraphNode)zeroList.removeFirst();
// For each out node of the output node, decrement its in-degree
Iterator outNodes = first.getOutNodes();
while (outNodes.hasNext()) {
DigraphNode node = (DigraphNode)outNodes.next();
int inDegree = ((Integer)inDegrees.get(node)).intValue() - 1;
inDegrees.put(node, new Integer(inDegree));
// If the in-degree has fallen to 0, place the node on the list
if (inDegree == 0) {
zeroList.add(node);
}
}
return first.getData();
}
public void remove() {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
/**
* An optional interface that may be provided by service provider
* objects that will be registered with a
* <code>ServiceRegistry</code>. If this interface is present,
* notification of registration and deregistration will be performed.
*
* @see ServiceRegistry
*
*/
public interface RegisterableService {
/**
* Called when an object implementing this interface is added to
* the given <code>category</code> of the given
* <code>registry</code>. The object may already be registered
* under another category or categories.
*
* @param registry a <code>ServiceRegistry</code> where this
* object has been registered.
* @param category a <code>Class</code> object indicating the
* registry category under which this object has been registered.
*/
void onRegistration(ServiceRegistry registry, Class<?> category);
/**
* Called when an object implementing this interface is removed
* from the given <code>category</code> of the given
* <code>registry</code>. The object may still be registered
* under another category or categories.
*
* @param registry a <code>ServiceRegistry</code> from which this
* object is being (wholly or partially) deregistered.
* @param category a <code>Class</code> object indicating the
* registry category from which this object is being deregistered.
*/
void onDeregistration(ServiceRegistry registry, Class<?> category);
}

View File

@@ -0,0 +1,859 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.spi;
import java.io.File;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.ServiceLoader;
/**
* A registry for service provider instances.
*
* <p> A <i>service</i> is a well-known set of interfaces and (usually
* abstract) classes. A <i>service provider</i> is a specific
* implementation of a service. The classes in a provider typically
* implement the interface or subclass the class defined by the
* service itself.
*
* <p> Service providers are stored in one or more <i>categories</i>,
* each of which is defined by a class of interface (described by a
* <code>Class</code> object) that all of its members must implement.
* The set of categories may be changed dynamically.
*
* <p> Only a single instance of a given leaf class (that is, the
* actual class returned by <code>getClass()</code>, as opposed to any
* inherited classes or interfaces) may be registered. That is,
* suppose that the
* <code>com.mycompany.mypkg.GreenServiceProvider</code> class
* implements the <code>com.mycompany.mypkg.MyService</code>
* interface. If a <code>GreenServiceProvider</code> instance is
* registered, it will be stored in the category defined by the
* <code>MyService</code> class. If a new instance of
* <code>GreenServiceProvider</code> is registered, it will replace
* the previous instance. In practice, service provider objects are
* usually singletons so this behavior is appropriate.
*
* <p> To declare a service provider, a <code>services</code>
* subdirectory is placed within the <code>META-INF</code> directory
* that is present in every JAR file. This directory contains a file
* for each service provider interface that has one or more
* implementation classes present in the JAR file. For example, if
* the JAR file contained a class named
* <code>com.mycompany.mypkg.MyServiceImpl</code> which implements the
* <code>javax.someapi.SomeService</code> interface, the JAR file
* would contain a file named: <pre>
* META-INF/services/javax.someapi.SomeService </pre>
*
* containing the line:
*
* <pre>
* com.mycompany.mypkg.MyService
* </pre>
*
* <p> The service provider classes should be to be lightweight and
* quick to load. Implementations of these interfaces should avoid
* complex dependencies on other classes and on native code. The usual
* pattern for more complex services is to register a lightweight
* proxy for the heavyweight service.
*
* <p> An application may customize the contents of a registry as it
* sees fit, so long as it has the appropriate runtime permission.
*
* <p> For more details on declaring service providers, and the JAR
* format in general, see the <a
* href="../../../../technotes/guides/jar/jar.html">
* JAR File Specification</a>.
*
* @see RegisterableService
*
*/
public class ServiceRegistry {
// Class -> Registry
private Map categoryMap = new HashMap();
/**
* Constructs a <code>ServiceRegistry</code> instance with a
* set of categories taken from the <code>categories</code>
* argument.
*
* @param categories an <code>Iterator</code> containing
* <code>Class</code> objects to be used to define categories.
*
* @exception IllegalArgumentException if
* <code>categories</code> is <code>null</code>.
*/
public ServiceRegistry(Iterator<Class<?>> categories) {
if (categories == null) {
throw new IllegalArgumentException("categories == null!");
}
while (categories.hasNext()) {
Class category = (Class)categories.next();
SubRegistry reg = new SubRegistry(this, category);
categoryMap.put(category, reg);
}
}
// The following two methods expose functionality from
// sun.misc.Service. If that class is made public, they may be
// removed.
//
// The sun.misc.ServiceConfigurationError class may also be
// exposed, in which case the references to 'an
// <code>Error</code>' below should be changed to 'a
// <code>ServiceConfigurationError</code>'.
/**
* Searches for implementations of a particular service class
* using the given class loader.
*
* <p> This method transforms the name of the given service class
* into a provider-configuration filename as described in the
* class comment and then uses the <code>getResources</code>
* method of the given class loader to find all available files
* with that name. These files are then read and parsed to
* produce a list of provider-class names. The iterator that is
* returned uses the given class loader to look up and then
* instantiate each element of the list.
*
* <p> Because it is possible for extensions to be installed into
* a running Java virtual machine, this method may return
* different results each time it is invoked.
*
* @param providerClass a <code>Class</code>object indicating the
* class or interface of the service providers being detected.
*
* @param loader the class loader to be used to load
* provider-configuration files and instantiate provider classes,
* or <code>null</code> if the system class loader (or, failing that
* the bootstrap class loader) is to be used.
*
* @param <T> the type of the providerClass.
*
* @return An <code>Iterator</code> that yields provider objects
* for the given service, in some arbitrary order. The iterator
* will throw an <code>Error</code> if a provider-configuration
* file violates the specified format or if a provider class
* cannot be found and instantiated.
*
* @exception IllegalArgumentException if
* <code>providerClass</code> is <code>null</code>.
*/
public static <T> Iterator<T> lookupProviders(Class<T> providerClass,
ClassLoader loader)
{
if (providerClass == null) {
throw new IllegalArgumentException("providerClass == null!");
}
return ServiceLoader.load(providerClass, loader).iterator();
}
/**
* Locates and incrementally instantiates the available providers
* of a given service using the context class loader. This
* convenience method is equivalent to:
*
* <pre>
* ClassLoader cl = Thread.currentThread().getContextClassLoader();
* return Service.providers(service, cl);
* </pre>
*
* @param providerClass a <code>Class</code>object indicating the
* class or interface of the service providers being detected.
*
* @param <T> the type of the providerClass.
*
* @return An <code>Iterator</code> that yields provider objects
* for the given service, in some arbitrary order. The iterator
* will throw an <code>Error</code> if a provider-configuration
* file violates the specified format or if a provider class
* cannot be found and instantiated.
*
* @exception IllegalArgumentException if
* <code>providerClass</code> is <code>null</code>.
*/
public static <T> Iterator<T> lookupProviders(Class<T> providerClass) {
if (providerClass == null) {
throw new IllegalArgumentException("providerClass == null!");
}
return ServiceLoader.load(providerClass).iterator();
}
/**
* Returns an <code>Iterator</code> of <code>Class</code> objects
* indicating the current set of categories. The iterator will be
* empty if no categories exist.
*
* @return an <code>Iterator</code> containing
* <code>Class</code>objects.
*/
public Iterator<Class<?>> getCategories() {
Set keySet = categoryMap.keySet();
return keySet.iterator();
}
/**
* Returns an Iterator containing the subregistries to which the
* provider belongs.
*/
private Iterator getSubRegistries(Object provider) {
List l = new ArrayList();
Iterator iter = categoryMap.keySet().iterator();
while (iter.hasNext()) {
Class c = (Class)iter.next();
if (c.isAssignableFrom(provider.getClass())) {
l.add((SubRegistry)categoryMap.get(c));
}
}
return l.iterator();
}
/**
* Adds a service provider object to the registry. The provider
* is associated with the given category.
*
* <p> If <code>provider</code> implements the
* <code>RegisterableService</code> interface, its
* <code>onRegistration</code> method will be called. Its
* <code>onDeregistration</code> method will be called each time
* it is deregistered from a category, for example if a
* category is removed or the registry is garbage collected.
*
* @param provider the service provide object to be registered.
* @param category the category under which to register the
* provider.
* @param <T> the type of the provider.
*
* @return true if no provider of the same class was previously
* registered in the same category category.
*
* @exception IllegalArgumentException if <code>provider</code> is
* <code>null</code>.
* @exception IllegalArgumentException if there is no category
* corresponding to <code>category</code>.
* @exception ClassCastException if provider does not implement
* the <code>Class</code> defined by <code>category</code>.
*/
public <T> boolean registerServiceProvider(T provider,
Class<T> category) {
if (provider == null) {
throw new IllegalArgumentException("provider == null!");
}
SubRegistry reg = (SubRegistry)categoryMap.get(category);
if (reg == null) {
throw new IllegalArgumentException("category unknown!");
}
if (!category.isAssignableFrom(provider.getClass())) {
throw new ClassCastException();
}
return reg.registerServiceProvider(provider);
}
/**
* Adds a service provider object to the registry. The provider
* is associated within each category present in the registry
* whose <code>Class</code> it implements.
*
* <p> If <code>provider</code> implements the
* <code>RegisterableService</code> interface, its
* <code>onRegistration</code> method will be called once for each
* category it is registered under. Its
* <code>onDeregistration</code> method will be called each time
* it is deregistered from a category or when the registry is
* finalized.
*
* @param provider the service provider object to be registered.
*
* @exception IllegalArgumentException if
* <code>provider</code> is <code>null</code>.
*/
public void registerServiceProvider(Object provider) {
if (provider == null) {
throw new IllegalArgumentException("provider == null!");
}
Iterator regs = getSubRegistries(provider);
while (regs.hasNext()) {
SubRegistry reg = (SubRegistry)regs.next();
reg.registerServiceProvider(provider);
}
}
/**
* Adds a set of service provider objects, taken from an
* <code>Iterator</code> to the registry. Each provider is
* associated within each category present in the registry whose
* <code>Class</code> it implements.
*
* <p> For each entry of <code>providers</code> that implements
* the <code>RegisterableService</code> interface, its
* <code>onRegistration</code> method will be called once for each
* category it is registered under. Its
* <code>onDeregistration</code> method will be called each time
* it is deregistered from a category or when the registry is
* finalized.
*
* @param providers an Iterator containing service provider
* objects to be registered.
*
* @exception IllegalArgumentException if <code>providers</code>
* is <code>null</code> or contains a <code>null</code> entry.
*/
public void registerServiceProviders(Iterator<?> providers) {
if (providers == null) {
throw new IllegalArgumentException("provider == null!");
}
while (providers.hasNext()) {
registerServiceProvider(providers.next());
}
}
/**
* Removes a service provider object from the given category. If
* the provider was not previously registered, nothing happens and
* <code>false</code> is returned. Otherwise, <code>true</code>
* is returned. If an object of the same class as
* <code>provider</code> but not equal (using <code>==</code>) to
* <code>provider</code> is registered, it will not be
* deregistered.
*
* <p> If <code>provider</code> implements the
* <code>RegisterableService</code> interface, its
* <code>onDeregistration</code> method will be called.
*
* @param provider the service provider object to be deregistered.
* @param category the category from which to deregister the
* provider.
* @param <T> the type of the provider.
*
* @return <code>true</code> if the provider was previously
* registered in the same category category,
* <code>false</code> otherwise.
*
* @exception IllegalArgumentException if <code>provider</code> is
* <code>null</code>.
* @exception IllegalArgumentException if there is no category
* corresponding to <code>category</code>.
* @exception ClassCastException if provider does not implement
* the class defined by <code>category</code>.
*/
public <T> boolean deregisterServiceProvider(T provider,
Class<T> category) {
if (provider == null) {
throw new IllegalArgumentException("provider == null!");
}
SubRegistry reg = (SubRegistry)categoryMap.get(category);
if (reg == null) {
throw new IllegalArgumentException("category unknown!");
}
if (!category.isAssignableFrom(provider.getClass())) {
throw new ClassCastException();
}
return reg.deregisterServiceProvider(provider);
}
/**
* Removes a service provider object from all categories that
* contain it.
*
* @param provider the service provider object to be deregistered.
*
* @exception IllegalArgumentException if <code>provider</code> is
* <code>null</code>.
*/
public void deregisterServiceProvider(Object provider) {
if (provider == null) {
throw new IllegalArgumentException("provider == null!");
}
Iterator regs = getSubRegistries(provider);
while (regs.hasNext()) {
SubRegistry reg = (SubRegistry)regs.next();
reg.deregisterServiceProvider(provider);
}
}
/**
* Returns <code>true</code> if <code>provider</code> is currently
* registered.
*
* @param provider the service provider object to be queried.
*
* @return <code>true</code> if the given provider has been
* registered.
*
* @exception IllegalArgumentException if <code>provider</code> is
* <code>null</code>.
*/
public boolean contains(Object provider) {
if (provider == null) {
throw new IllegalArgumentException("provider == null!");
}
Iterator regs = getSubRegistries(provider);
while (regs.hasNext()) {
SubRegistry reg = (SubRegistry)regs.next();
if (reg.contains(provider)) {
return true;
}
}
return false;
}
/**
* Returns an <code>Iterator</code> containing all registered
* service providers in the given category. If
* <code>useOrdering</code> is <code>false</code>, the iterator
* will return all of the server provider objects in an arbitrary
* order. Otherwise, the ordering will respect any pairwise
* orderings that have been set. If the graph of pairwise
* orderings contains cycles, any providers that belong to a cycle
* will not be returned.
*
* @param category the category to be retrieved from.
* @param useOrdering <code>true</code> if pairwise orderings
* should be taken account in ordering the returned objects.
* @param <T> the type of the category.
*
* @return an <code>Iterator</code> containing service provider
* objects from the given category, possibly in order.
*
* @exception IllegalArgumentException if there is no category
* corresponding to <code>category</code>.
*/
public <T> Iterator<T> getServiceProviders(Class<T> category,
boolean useOrdering) {
SubRegistry reg = (SubRegistry)categoryMap.get(category);
if (reg == null) {
throw new IllegalArgumentException("category unknown!");
}
return reg.getServiceProviders(useOrdering);
}
/**
* A simple filter interface used by
* <code>ServiceRegistry.getServiceProviders</code> to select
* providers matching an arbitrary criterion. Classes that
* implement this interface should be defined in order to make use
* of the <code>getServiceProviders</code> method of
* <code>ServiceRegistry</code> that takes a <code>Filter</code>.
*
* @see ServiceRegistry#getServiceProviders(Class, ServiceRegistry.Filter, boolean)
*/
public interface Filter {
/**
* Returns <code>true</code> if the given
* <code>provider</code> object matches the criterion defined
* by this <code>Filter</code>.
*
* @param provider a service provider <code>Object</code>.
*
* @return true if the provider matches the criterion.
*/
boolean filter(Object provider);
}
/**
* Returns an <code>Iterator</code> containing service provider
* objects within a given category that satisfy a criterion
* imposed by the supplied <code>ServiceRegistry.Filter</code>
* object's <code>filter</code> method.
*
* <p> The <code>useOrdering</code> argument controls the
* ordering of the results using the same rules as
* <code>getServiceProviders(Class, boolean)</code>.
*
* @param category the category to be retrieved from.
* @param filter an instance of <code>ServiceRegistry.Filter</code>
* whose <code>filter</code> method will be invoked.
* @param useOrdering <code>true</code> if pairwise orderings
* should be taken account in ordering the returned objects.
* @param <T> the type of the category.
*
* @return an <code>Iterator</code> containing service provider
* objects from the given category, possibly in order.
*
* @exception IllegalArgumentException if there is no category
* corresponding to <code>category</code>.
*/
public <T> Iterator<T> getServiceProviders(Class<T> category,
Filter filter,
boolean useOrdering) {
SubRegistry reg = (SubRegistry)categoryMap.get(category);
if (reg == null) {
throw new IllegalArgumentException("category unknown!");
}
Iterator iter = getServiceProviders(category, useOrdering);
return new FilterIterator(iter, filter);
}
/**
* Returns the currently registered service provider object that
* is of the given class type. At most one object of a given
* class is allowed to be registered at any given time. If no
* registered object has the desired class type, <code>null</code>
* is returned.
*
* @param providerClass the <code>Class</code> of the desired
* service provider object.
* @param <T> the type of the provider.
*
* @return a currently registered service provider object with the
* desired <code>Class</code>type, or <code>null</code> is none is
* present.
*
* @exception IllegalArgumentException if <code>providerClass</code> is
* <code>null</code>.
*/
public <T> T getServiceProviderByClass(Class<T> providerClass) {
if (providerClass == null) {
throw new IllegalArgumentException("providerClass == null!");
}
Iterator iter = categoryMap.keySet().iterator();
while (iter.hasNext()) {
Class c = (Class)iter.next();
if (c.isAssignableFrom(providerClass)) {
SubRegistry reg = (SubRegistry)categoryMap.get(c);
T provider = reg.getServiceProviderByClass(providerClass);
if (provider != null) {
return provider;
}
}
}
return null;
}
/**
* Sets a pairwise ordering between two service provider objects
* within a given category. If one or both objects are not
* currently registered within the given category, or if the
* desired ordering is already set, nothing happens and
* <code>false</code> is returned. If the providers previously
* were ordered in the reverse direction, that ordering is
* removed.
*
* <p> The ordering will be used by the
* <code>getServiceProviders</code> methods when their
* <code>useOrdering</code> argument is <code>true</code>.
*
* @param category a <code>Class</code> object indicating the
* category under which the preference is to be established.
* @param firstProvider the preferred provider.
* @param secondProvider the provider to which
* <code>firstProvider</code> is preferred.
* @param <T> the type of the category.
*
* @return <code>true</code> if a previously unset ordering
* was established.
*
* @exception IllegalArgumentException if either provider is
* <code>null</code> or they are the same object.
* @exception IllegalArgumentException if there is no category
* corresponding to <code>category</code>.
*/
public <T> boolean setOrdering(Class<T> category,
T firstProvider,
T secondProvider) {
if (firstProvider == null || secondProvider == null) {
throw new IllegalArgumentException("provider is null!");
}
if (firstProvider == secondProvider) {
throw new IllegalArgumentException("providers are the same!");
}
SubRegistry reg = (SubRegistry)categoryMap.get(category);
if (reg == null) {
throw new IllegalArgumentException("category unknown!");
}
if (reg.contains(firstProvider) &&
reg.contains(secondProvider)) {
return reg.setOrdering(firstProvider, secondProvider);
}
return false;
}
/**
* Sets a pairwise ordering between two service provider objects
* within a given category. If one or both objects are not
* currently registered within the given category, or if no
* ordering is currently set between them, nothing happens
* and <code>false</code> is returned.
*
* <p> The ordering will be used by the
* <code>getServiceProviders</code> methods when their
* <code>useOrdering</code> argument is <code>true</code>.
*
* @param category a <code>Class</code> object indicating the
* category under which the preference is to be disestablished.
* @param firstProvider the formerly preferred provider.
* @param secondProvider the provider to which
* <code>firstProvider</code> was formerly preferred.
* @param <T> the type of the category.
*
* @return <code>true</code> if a previously set ordering was
* disestablished.
*
* @exception IllegalArgumentException if either provider is
* <code>null</code> or they are the same object.
* @exception IllegalArgumentException if there is no category
* corresponding to <code>category</code>.
*/
public <T> boolean unsetOrdering(Class<T> category,
T firstProvider,
T secondProvider) {
if (firstProvider == null || secondProvider == null) {
throw new IllegalArgumentException("provider is null!");
}
if (firstProvider == secondProvider) {
throw new IllegalArgumentException("providers are the same!");
}
SubRegistry reg = (SubRegistry)categoryMap.get(category);
if (reg == null) {
throw new IllegalArgumentException("category unknown!");
}
if (reg.contains(firstProvider) &&
reg.contains(secondProvider)) {
return reg.unsetOrdering(firstProvider, secondProvider);
}
return false;
}
/**
* Deregisters all service provider object currently registered
* under the given category.
*
* @param category the category to be emptied.
*
* @exception IllegalArgumentException if there is no category
* corresponding to <code>category</code>.
*/
public void deregisterAll(Class<?> category) {
SubRegistry reg = (SubRegistry)categoryMap.get(category);
if (reg == null) {
throw new IllegalArgumentException("category unknown!");
}
reg.clear();
}
/**
* Deregisters all currently registered service providers from all
* categories.
*/
public void deregisterAll() {
Iterator iter = categoryMap.values().iterator();
while (iter.hasNext()) {
SubRegistry reg = (SubRegistry)iter.next();
reg.clear();
}
}
/**
* Finalizes this object prior to garbage collection. The
* <code>deregisterAll</code> method is called to deregister all
* currently registered service providers. This method should not
* be called from application code.
*
* @exception Throwable if an error occurs during superclass
* finalization.
*/
public void finalize() throws Throwable {
deregisterAll();
super.finalize();
}
}
/**
* A portion of a registry dealing with a single superclass or
* interface.
*/
class SubRegistry {
ServiceRegistry registry;
Class category;
// Provider Objects organized by partial ordering
final PartiallyOrderedSet poset = new PartiallyOrderedSet();
// Class -> Provider Object of that class
final Map<Class<?>,Object> map = new HashMap();
final Map<Class<?>,AccessControlContext> accMap = new HashMap<>();
public SubRegistry(ServiceRegistry registry, Class category) {
this.registry = registry;
this.category = category;
}
public boolean registerServiceProvider(Object provider) {
Object oprovider = map.get(provider.getClass());
boolean present = oprovider != null;
if (present) {
deregisterServiceProvider(oprovider);
}
map.put(provider.getClass(), provider);
accMap.put(provider.getClass(), AccessController.getContext());
poset.add(provider);
if (provider instanceof RegisterableService) {
RegisterableService rs = (RegisterableService)provider;
rs.onRegistration(registry, category);
}
return !present;
}
/**
* If the provider was not previously registered, do nothing.
*
* @return true if the provider was previously registered.
*/
public boolean deregisterServiceProvider(Object provider) {
Object oprovider = map.get(provider.getClass());
if (provider == oprovider) {
map.remove(provider.getClass());
accMap.remove(provider.getClass());
poset.remove(provider);
if (provider instanceof RegisterableService) {
RegisterableService rs = (RegisterableService)provider;
rs.onDeregistration(registry, category);
}
return true;
}
return false;
}
public boolean contains(Object provider) {
Object oprovider = map.get(provider.getClass());
return oprovider == provider;
}
public boolean setOrdering(Object firstProvider,
Object secondProvider) {
return poset.setOrdering(firstProvider, secondProvider);
}
public boolean unsetOrdering(Object firstProvider,
Object secondProvider) {
return poset.unsetOrdering(firstProvider, secondProvider);
}
public Iterator getServiceProviders(boolean useOrdering) {
if (useOrdering) {
return poset.iterator();
} else {
return map.values().iterator();
}
}
public <T> T getServiceProviderByClass(Class<T> providerClass) {
return (T)map.get(providerClass);
}
public void clear() {
Iterator iter = map.values().iterator();
while (iter.hasNext()) {
Object provider = iter.next();
iter.remove();
if (provider instanceof RegisterableService) {
RegisterableService rs = (RegisterableService)provider;
AccessControlContext acc = accMap.get(provider.getClass());
if (acc != null || System.getSecurityManager() == null) {
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
rs.onDeregistration(registry, category);
return null;
}, acc);
}
}
}
poset.clear();
accMap.clear();
}
public void finalize() {
clear();
}
}
/**
* A class for wrapping <code>Iterators</code> with a filter function.
* This provides an iterator for a subset without duplication.
*/
class FilterIterator<T> implements Iterator<T> {
private Iterator<T> iter;
private ServiceRegistry.Filter filter;
private T next = null;
public FilterIterator(Iterator<T> iter,
ServiceRegistry.Filter filter) {
this.iter = iter;
this.filter = filter;
advance();
}
private void advance() {
while (iter.hasNext()) {
T elt = iter.next();
if (filter.filter(elt)) {
next = elt;
return;
}
}
next = null;
}
public boolean hasNext() {
return next != null;
}
public T next() {
if (next == null) {
throw new NoSuchElementException();
}
T o = next;
advance();
return o;
}
public void remove() {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,294 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.stream;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import com.sun.imageio.stream.StreamCloser;
import com.sun.imageio.stream.StreamFinalizer;
import sun.java2d.Disposer;
import sun.java2d.DisposerRecord;
/**
* An implementation of <code>ImageInputStream</code> that gets its
* input from a regular <code>InputStream</code>. A file is used to
* cache previously read data.
*
*/
public class FileCacheImageInputStream extends ImageInputStreamImpl {
private InputStream stream;
private File cacheFile;
private RandomAccessFile cache;
private static final int BUFFER_LENGTH = 1024;
private byte[] buf = new byte[BUFFER_LENGTH];
private long length = 0L;
private boolean foundEOF = false;
/** The referent to be registered with the Disposer. */
private final Object disposerReferent;
/** The DisposerRecord that closes the underlying cache. */
private final DisposerRecord disposerRecord;
/** The CloseAction that closes the stream in
* the StreamCloser's shutdown hook */
private final StreamCloser.CloseAction closeAction;
/**
* Constructs a <code>FileCacheImageInputStream</code> that will read
* from a given <code>InputStream</code>.
*
* <p> A temporary file is used as a cache. If
* <code>cacheDir</code>is non-<code>null</code> and is a
* directory, the file will be created there. If it is
* <code>null</code>, the system-dependent default temporary-file
* directory will be used (see the documentation for
* <code>File.createTempFile</code> for details).
*
* @param stream an <code>InputStream</code> to read from.
* @param cacheDir a <code>File</code> indicating where the
* cache file should be created, or <code>null</code> to use the
* system directory.
*
* @exception IllegalArgumentException if <code>stream</code> is
* <code>null</code>.
* @exception IllegalArgumentException if <code>cacheDir</code> is
* non-<code>null</code> but is not a directory.
* @exception IOException if a cache file cannot be created.
*/
public FileCacheImageInputStream(InputStream stream, File cacheDir)
throws IOException {
if (stream == null) {
throw new IllegalArgumentException("stream == null!");
}
if ((cacheDir != null) && !(cacheDir.isDirectory())) {
throw new IllegalArgumentException("Not a directory!");
}
this.stream = stream;
if (cacheDir == null)
this.cacheFile = Files.createTempFile("imageio", ".tmp").toFile();
else
this.cacheFile = Files.createTempFile(cacheDir.toPath(), "imageio", ".tmp")
.toFile();
this.cache = new RandomAccessFile(cacheFile, "rw");
this.closeAction = StreamCloser.createCloseAction(this);
StreamCloser.addToQueue(closeAction);
disposerRecord = new StreamDisposerRecord(cacheFile, cache);
if (getClass() == FileCacheImageInputStream.class) {
disposerReferent = new Object();
Disposer.addRecord(disposerReferent, disposerRecord);
} else {
disposerReferent = new StreamFinalizer(this);
}
}
/**
* Ensures that at least <code>pos</code> bytes are cached,
* or the end of the source is reached. The return value
* is equal to the smaller of <code>pos</code> and the
* length of the source file.
*/
private long readUntil(long pos) throws IOException {
// We've already got enough data cached
if (pos < length) {
return pos;
}
// pos >= length but length isn't getting any bigger, so return it
if (foundEOF) {
return length;
}
long len = pos - length;
cache.seek(length);
while (len > 0) {
// Copy a buffer's worth of data from the source to the cache
// BUFFER_LENGTH will always fit into an int so this is safe
int nbytes =
stream.read(buf, 0, (int)Math.min(len, (long)BUFFER_LENGTH));
if (nbytes == -1) {
foundEOF = true;
return length;
}
cache.write(buf, 0, nbytes);
len -= nbytes;
length += nbytes;
}
return pos;
}
public int read() throws IOException {
checkClosed();
bitOffset = 0;
long next = streamPos + 1;
long pos = readUntil(next);
if (pos >= next) {
cache.seek(streamPos++);
return cache.read();
} else {
return -1;
}
}
public int read(byte[] b, int off, int len) throws IOException {
checkClosed();
if (b == null) {
throw new NullPointerException("b == null!");
}
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off+len > b.length || off+len < 0!");
}
bitOffset = 0;
if (len == 0) {
return 0;
}
long pos = readUntil(streamPos + len);
// len will always fit into an int so this is safe
len = (int)Math.min((long)len, pos - streamPos);
if (len > 0) {
cache.seek(streamPos);
cache.readFully(b, off, len);
streamPos += len;
return len;
} else {
return -1;
}
}
/**
* Returns <code>true</code> since this
* <code>ImageInputStream</code> caches data in order to allow
* seeking backwards.
*
* @return <code>true</code>.
*
* @see #isCachedMemory
* @see #isCachedFile
*/
public boolean isCached() {
return true;
}
/**
* Returns <code>true</code> since this
* <code>ImageInputStream</code> maintains a file cache.
*
* @return <code>true</code>.
*
* @see #isCached
* @see #isCachedMemory
*/
public boolean isCachedFile() {
return true;
}
/**
* Returns <code>false</code> since this
* <code>ImageInputStream</code> does not maintain a main memory
* cache.
*
* @return <code>false</code>.
*
* @see #isCached
* @see #isCachedFile
*/
public boolean isCachedMemory() {
return false;
}
/**
* Closes this <code>FileCacheImageInputStream</code>, closing
* and removing the cache file. The source <code>InputStream</code>
* is not closed.
*
* @exception IOException if an error occurs.
*/
public void close() throws IOException {
super.close();
disposerRecord.dispose(); // this will close/delete the cache file
stream = null;
cache = null;
cacheFile = null;
StreamCloser.removeFromQueue(closeAction);
}
/**
* {@inheritDoc}
*/
protected void finalize() throws Throwable {
// Empty finalizer: for performance reasons we instead use the
// Disposer mechanism for ensuring that the underlying
// RandomAccessFile is closed/deleted prior to garbage collection
}
private static class StreamDisposerRecord implements DisposerRecord {
private File cacheFile;
private RandomAccessFile cache;
public StreamDisposerRecord(File cacheFile, RandomAccessFile cache) {
this.cacheFile = cacheFile;
this.cache = cache;
}
public synchronized void dispose() {
if (cache != null) {
try {
cache.close();
} catch (IOException e) {
} finally {
cache = null;
}
}
if (cacheFile != null) {
cacheFile.delete();
cacheFile = null;
}
// Note: Explicit removal of the stream from the StreamCloser
// queue is not mandatory in this case, as it will be removed
// automatically by GC shortly after this method is called.
}
}
}

View File

@@ -0,0 +1,261 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.stream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import com.sun.imageio.stream.StreamCloser;
/**
* An implementation of <code>ImageOutputStream</code> that writes its
* output to a regular <code>OutputStream</code>. A file is used to
* cache data until it is flushed to the output stream.
*
*/
public class FileCacheImageOutputStream extends ImageOutputStreamImpl {
private OutputStream stream;
private File cacheFile;
private RandomAccessFile cache;
// Pos after last (rightmost) byte written
private long maxStreamPos = 0L;
/** The CloseAction that closes the stream in
* the StreamCloser's shutdown hook */
private final StreamCloser.CloseAction closeAction;
/**
* Constructs a <code>FileCacheImageOutputStream</code> that will write
* to a given <code>outputStream</code>.
*
* <p> A temporary file is used as a cache. If
* <code>cacheDir</code>is non-<code>null</code> and is a
* directory, the file will be created there. If it is
* <code>null</code>, the system-dependent default temporary-file
* directory will be used (see the documentation for
* <code>File.createTempFile</code> for details).
*
* @param stream an <code>OutputStream</code> to write to.
* @param cacheDir a <code>File</code> indicating where the
* cache file should be created, or <code>null</code> to use the
* system directory.
*
* @exception IllegalArgumentException if <code>stream</code>
* is <code>null</code>.
* @exception IllegalArgumentException if <code>cacheDir</code> is
* non-<code>null</code> but is not a directory.
* @exception IOException if a cache file cannot be created.
*/
public FileCacheImageOutputStream(OutputStream stream, File cacheDir)
throws IOException {
if (stream == null) {
throw new IllegalArgumentException("stream == null!");
}
if ((cacheDir != null) && !(cacheDir.isDirectory())) {
throw new IllegalArgumentException("Not a directory!");
}
this.stream = stream;
if (cacheDir == null)
this.cacheFile = Files.createTempFile("imageio", ".tmp").toFile();
else
this.cacheFile = Files.createTempFile(cacheDir.toPath(), "imageio", ".tmp")
.toFile();
this.cache = new RandomAccessFile(cacheFile, "rw");
this.closeAction = StreamCloser.createCloseAction(this);
StreamCloser.addToQueue(closeAction);
}
public int read() throws IOException {
checkClosed();
bitOffset = 0;
int val = cache.read();
if (val != -1) {
++streamPos;
}
return val;
}
public int read(byte[] b, int off, int len) throws IOException {
checkClosed();
if (b == null) {
throw new NullPointerException("b == null!");
}
if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off+len > b.length || off+len < 0!");
}
bitOffset = 0;
if (len == 0) {
return 0;
}
int nbytes = cache.read(b, off, len);
if (nbytes != -1) {
streamPos += nbytes;
}
return nbytes;
}
public void write(int b) throws IOException {
flushBits(); // this will call checkClosed() for us
cache.write(b);
++streamPos;
maxStreamPos = Math.max(maxStreamPos, streamPos);
}
public void write(byte[] b, int off, int len) throws IOException {
flushBits(); // this will call checkClosed() for us
cache.write(b, off, len);
streamPos += len;
maxStreamPos = Math.max(maxStreamPos, streamPos);
}
public long length() {
try {
checkClosed();
return cache.length();
} catch (IOException e) {
return -1L;
}
}
/**
* Sets the current stream position and resets the bit offset to
* 0. It is legal to seek past the end of the file; an
* <code>EOFException</code> will be thrown only if a read is
* performed. The file length will not be increased until a write
* is performed.
*
* @exception IndexOutOfBoundsException if <code>pos</code> is smaller
* than the flushed position.
* @exception IOException if any other I/O error occurs.
*/
public void seek(long pos) throws IOException {
checkClosed();
if (pos < flushedPos) {
throw new IndexOutOfBoundsException();
}
cache.seek(pos);
this.streamPos = cache.getFilePointer();
maxStreamPos = Math.max(maxStreamPos, streamPos);
this.bitOffset = 0;
}
/**
* Returns <code>true</code> since this
* <code>ImageOutputStream</code> caches data in order to allow
* seeking backwards.
*
* @return <code>true</code>.
*
* @see #isCachedMemory
* @see #isCachedFile
*/
public boolean isCached() {
return true;
}
/**
* Returns <code>true</code> since this
* <code>ImageOutputStream</code> maintains a file cache.
*
* @return <code>true</code>.
*
* @see #isCached
* @see #isCachedMemory
*/
public boolean isCachedFile() {
return true;
}
/**
* Returns <code>false</code> since this
* <code>ImageOutputStream</code> does not maintain a main memory
* cache.
*
* @return <code>false</code>.
*
* @see #isCached
* @see #isCachedFile
*/
public boolean isCachedMemory() {
return false;
}
/**
* Closes this <code>FileCacheImageOutputStream</code>. All
* pending data is flushed to the output, and the cache file
* is closed and removed. The destination <code>OutputStream</code>
* is not closed.
*
* @exception IOException if an error occurs.
*/
public void close() throws IOException {
maxStreamPos = cache.length();
seek(maxStreamPos);
flushBefore(maxStreamPos);
super.close();
cache.close();
cache = null;
cacheFile.delete();
cacheFile = null;
stream.flush();
stream = null;
StreamCloser.removeFromQueue(closeAction);
}
public void flushBefore(long pos) throws IOException {
long oFlushedPos = flushedPos;
super.flushBefore(pos); // this will call checkClosed() for us
long flushBytes = flushedPos - oFlushedPos;
if (flushBytes > 0) {
int bufLen = 512;
byte[] buf = new byte[bufLen];
cache.seek(oFlushedPos);
while (flushBytes > 0) {
int len = (int)Math.min(flushBytes, bufLen);
cache.readFully(buf, 0, len);
stream.write(buf, 0, len);
flushBytes -= len;
}
stream.flush();
}
}
}

View File

@@ -0,0 +1,164 @@
/*
* Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.stream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import com.sun.imageio.stream.CloseableDisposerRecord;
import com.sun.imageio.stream.StreamFinalizer;
import sun.java2d.Disposer;
/**
* An implementation of <code>ImageInputStream</code> that gets its
* input from a <code>File</code> or <code>RandomAccessFile</code>.
* The file contents are assumed to be stable during the lifetime of
* the object.
*
*/
public class FileImageInputStream extends ImageInputStreamImpl {
private RandomAccessFile raf;
/** The referent to be registered with the Disposer. */
private final Object disposerReferent;
/** The DisposerRecord that closes the underlying RandomAccessFile. */
private final CloseableDisposerRecord disposerRecord;
/**
* Constructs a <code>FileImageInputStream</code> that will read
* from a given <code>File</code>.
*
* <p> The file contents must not change between the time this
* object is constructed and the time of the last call to a read
* method.
*
* @param f a <code>File</code> to read from.
*
* @exception IllegalArgumentException if <code>f</code> is
* <code>null</code>.
* @exception SecurityException if a security manager exists
* and does not allow read access to the file.
* @exception FileNotFoundException if <code>f</code> is a
* directory or cannot be opened for reading for any other reason.
* @exception IOException if an I/O error occurs.
*/
public FileImageInputStream(File f)
throws FileNotFoundException, IOException {
this(f == null ? null : new RandomAccessFile(f, "r"));
}
/**
* Constructs a <code>FileImageInputStream</code> that will read
* from a given <code>RandomAccessFile</code>.
*
* <p> The file contents must not change between the time this
* object is constructed and the time of the last call to a read
* method.
*
* @param raf a <code>RandomAccessFile</code> to read from.
*
* @exception IllegalArgumentException if <code>raf</code> is
* <code>null</code>.
*/
public FileImageInputStream(RandomAccessFile raf) {
if (raf == null) {
throw new IllegalArgumentException("raf == null!");
}
this.raf = raf;
disposerRecord = new CloseableDisposerRecord(raf);
if (getClass() == FileImageInputStream.class) {
disposerReferent = new Object();
Disposer.addRecord(disposerReferent, disposerRecord);
} else {
disposerReferent = new StreamFinalizer(this);
}
}
public int read() throws IOException {
checkClosed();
bitOffset = 0;
int val = raf.read();
if (val != -1) {
++streamPos;
}
return val;
}
public int read(byte[] b, int off, int len) throws IOException {
checkClosed();
bitOffset = 0;
int nbytes = raf.read(b, off, len);
if (nbytes != -1) {
streamPos += nbytes;
}
return nbytes;
}
/**
* Returns the length of the underlying file, or <code>-1</code>
* if it is unknown.
*
* @return the file length as a <code>long</code>, or
* <code>-1</code>.
*/
public long length() {
try {
checkClosed();
return raf.length();
} catch (IOException e) {
return -1L;
}
}
public void seek(long pos) throws IOException {
checkClosed();
if (pos < flushedPos) {
throw new IndexOutOfBoundsException("pos < flushedPos!");
}
bitOffset = 0;
raf.seek(pos);
streamPos = raf.getFilePointer();
}
public void close() throws IOException {
super.close();
disposerRecord.dispose(); // this closes the RandomAccessFile
raf = null;
}
/**
* {@inheritDoc}
*/
protected void finalize() throws Throwable {
// Empty finalizer: for performance reasons we instead use the
// Disposer mechanism for ensuring that the underlying
// RandomAccessFile is closed prior to garbage collection
}
}

View File

@@ -0,0 +1,172 @@
/*
* Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.stream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import com.sun.imageio.stream.CloseableDisposerRecord;
import com.sun.imageio.stream.StreamFinalizer;
import sun.java2d.Disposer;
/**
* An implementation of <code>ImageOutputStream</code> that writes its
* output directly to a <code>File</code> or
* <code>RandomAccessFile</code>.
*
*/
public class FileImageOutputStream extends ImageOutputStreamImpl {
private RandomAccessFile raf;
/** The referent to be registered with the Disposer. */
private final Object disposerReferent;
/** The DisposerRecord that closes the underlying RandomAccessFile. */
private final CloseableDisposerRecord disposerRecord;
/**
* Constructs a <code>FileImageOutputStream</code> that will write
* to a given <code>File</code>.
*
* @param f a <code>File</code> to write to.
*
* @exception IllegalArgumentException if <code>f</code> is
* <code>null</code>.
* @exception SecurityException if a security manager exists
* and does not allow write access to the file.
* @exception FileNotFoundException if <code>f</code> does not denote
* a regular file or it cannot be opened for reading and writing for any
* other reason.
* @exception IOException if an I/O error occurs.
*/
public FileImageOutputStream(File f)
throws FileNotFoundException, IOException {
this(f == null ? null : new RandomAccessFile(f, "rw"));
}
/**
* Constructs a <code>FileImageOutputStream</code> that will write
* to a given <code>RandomAccessFile</code>.
*
* @param raf a <code>RandomAccessFile</code> to write to.
*
* @exception IllegalArgumentException if <code>raf</code> is
* <code>null</code>.
*/
public FileImageOutputStream(RandomAccessFile raf) {
if (raf == null) {
throw new IllegalArgumentException("raf == null!");
}
this.raf = raf;
disposerRecord = new CloseableDisposerRecord(raf);
if (getClass() == FileImageOutputStream.class) {
disposerReferent = new Object();
Disposer.addRecord(disposerReferent, disposerRecord);
} else {
disposerReferent = new StreamFinalizer(this);
}
}
public int read() throws IOException {
checkClosed();
bitOffset = 0;
int val = raf.read();
if (val != -1) {
++streamPos;
}
return val;
}
public int read(byte[] b, int off, int len) throws IOException {
checkClosed();
bitOffset = 0;
int nbytes = raf.read(b, off, len);
if (nbytes != -1) {
streamPos += nbytes;
}
return nbytes;
}
public void write(int b) throws IOException {
flushBits(); // this will call checkClosed() for us
raf.write(b);
++streamPos;
}
public void write(byte[] b, int off, int len) throws IOException {
flushBits(); // this will call checkClosed() for us
raf.write(b, off, len);
streamPos += len;
}
public long length() {
try {
checkClosed();
return raf.length();
} catch (IOException e) {
return -1L;
}
}
/**
* Sets the current stream position and resets the bit offset to
* 0. It is legal to seeking past the end of the file; an
* <code>EOFException</code> will be thrown only if a read is
* performed. The file length will not be increased until a write
* is performed.
*
* @exception IndexOutOfBoundsException if <code>pos</code> is smaller
* than the flushed position.
* @exception IOException if any other I/O error occurs.
*/
public void seek(long pos) throws IOException {
checkClosed();
if (pos < flushedPos) {
throw new IndexOutOfBoundsException("pos < flushedPos!");
}
bitOffset = 0;
raf.seek(pos);
streamPos = raf.getFilePointer();
}
public void close() throws IOException {
super.close();
disposerRecord.dispose(); // this closes the RandomAccessFile
raf = null;
}
/**
* {@inheritDoc}
*/
protected void finalize() throws Throwable {
// Empty finalizer: for performance reasons we instead use the
// Disposer mechanism for ensuring that the underlying
// RandomAccessFile is closed prior to garbage collection
}
}

View File

@@ -0,0 +1,143 @@
/*
* Copyright (c) 1999, 2001, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.stream;
/**
* A class representing a mutable reference to an array of bytes and
* an offset and length within that array. <code>IIOByteBuffer</code>
* is used by <code>ImageInputStream</code> to supply a sequence of bytes
* to the caller, possibly with fewer copies than using the conventional
* <code>read</code> methods that take a user-supplied byte array.
*
* <p> The byte array referenced by an <code>IIOByteBuffer</code> will
* generally be part of an internal data structure belonging to an
* <code>ImageReader</code> implementation; its contents should be
* considered read-only and must not be modified.
*
*/
public class IIOByteBuffer {
private byte[] data;
private int offset;
private int length;
/**
* Constructs an <code>IIOByteBuffer</code> that references a
* given byte array, offset, and length.
*
* @param data a byte array.
* @param offset an int offset within the array.
* @param length an int specifying the length of the data of
* interest within byte array, in bytes.
*/
public IIOByteBuffer(byte[] data, int offset, int length) {
this.data = data;
this.offset = offset;
this.length = length;
}
/**
* Returns a reference to the byte array. The returned value should
* be treated as read-only, and only the portion specified by the
* values of <code>getOffset</code> and <code>getLength</code> should
* be used.
*
* @return a byte array reference.
*
* @see #getOffset
* @see #getLength
* @see #setData
*/
public byte[] getData() {
return data;
}
/**
* Updates the array reference that will be returned by subsequent calls
* to the <code>getData</code> method.
*
* @param data a byte array reference containing the new data value.
*
* @see #getData
*/
public void setData(byte[] data) {
this.data = data;
}
/**
* Returns the offset within the byte array returned by
* <code>getData</code> at which the data of interest start.
*
* @return an int offset.
*
* @see #getData
* @see #getLength
* @see #setOffset
*/
public int getOffset() {
return offset;
}
/**
* Updates the value that will be returned by subsequent calls
* to the <code>getOffset</code> method.
*
* @param offset an int containing the new offset value.
*
* @see #getOffset
*/
public void setOffset(int offset) {
this.offset = offset;
}
/**
* Returns the length of the data of interest within the byte
* array returned by <code>getData</code>.
*
* @return an int length.
*
* @see #getData
* @see #getOffset
* @see #setLength
*/
public int getLength() {
return length;
}
/**
* Updates the value that will be returned by subsequent calls
* to the <code>getLength</code> method.
*
* @param length an int containing the new length value.
*
* @see #getLength
*/
public void setLength(int length) {
this.length = length;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,880 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.stream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteOrder;
import java.util.Stack;
import javax.imageio.IIOException;
/**
* An abstract class implementing the <code>ImageInputStream</code> interface.
* This class is designed to reduce the number of methods that must
* be implemented by subclasses.
*
* <p> In particular, this class handles most or all of the details of
* byte order interpretation, buffering, mark/reset, discarding,
* closing, and disposing.
*/
public abstract class ImageInputStreamImpl implements ImageInputStream {
private Stack markByteStack = new Stack();
private Stack markBitStack = new Stack();
private boolean isClosed = false;
// Length of the buffer used for readFully(type[], int, int)
private static final int BYTE_BUF_LENGTH = 8192;
/**
* Byte buffer used for readFully(type[], int, int). Note that this
* array is also used for bulk reads in readShort(), readInt(), etc, so
* it should be large enough to hold a primitive value (i.e. >= 8 bytes).
* Also note that this array is package protected, so that it can be
* used by ImageOutputStreamImpl in a similar manner.
*/
byte[] byteBuf = new byte[BYTE_BUF_LENGTH];
/**
* The byte order of the stream as an instance of the enumeration
* class <code>java.nio.ByteOrder</code>, where
* <code>ByteOrder.BIG_ENDIAN</code> indicates network byte order
* and <code>ByteOrder.LITTLE_ENDIAN</code> indicates the reverse
* order. By default, the value is
* <code>ByteOrder.BIG_ENDIAN</code>.
*/
protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
/**
* The current read position within the stream. Subclasses are
* responsible for keeping this value current from any method they
* override that alters the read position.
*/
protected long streamPos;
/**
* The current bit offset within the stream. Subclasses are
* responsible for keeping this value current from any method they
* override that alters the bit offset.
*/
protected int bitOffset;
/**
* The position prior to which data may be discarded. Seeking
* to a smaller position is not allowed. <code>flushedPos</code>
* will always be {@literal >= 0}.
*/
protected long flushedPos = 0;
/**
* Constructs an <code>ImageInputStreamImpl</code>.
*/
public ImageInputStreamImpl() {
}
/**
* Throws an <code>IOException</code> if the stream has been closed.
* Subclasses may call this method from any of their methods that
* require the stream not to be closed.
*
* @exception IOException if the stream is closed.
*/
protected final void checkClosed() throws IOException {
if (isClosed) {
throw new IOException("closed");
}
}
public void setByteOrder(ByteOrder byteOrder) {
this.byteOrder = byteOrder;
}
public ByteOrder getByteOrder() {
return byteOrder;
}
/**
* Reads a single byte from the stream and returns it as an
* <code>int</code> between 0 and 255. If EOF is reached,
* <code>-1</code> is returned.
*
* <p> Subclasses must provide an implementation for this method.
* The subclass implementation should update the stream position
* before exiting.
*
* <p> The bit offset within the stream must be reset to zero before
* the read occurs.
*
* @return the value of the next byte in the stream, or <code>-1</code>
* if EOF is reached.
*
* @exception IOException if the stream has been closed.
*/
public abstract int read() throws IOException;
/**
* A convenience method that calls <code>read(b, 0, b.length)</code>.
*
* <p> The bit offset within the stream is reset to zero before
* the read occurs.
*
* @return the number of bytes actually read, or <code>-1</code>
* to indicate EOF.
*
* @exception NullPointerException if <code>b</code> is
* <code>null</code>.
* @exception IOException if an I/O error occurs.
*/
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
/**
* Reads up to <code>len</code> bytes from the stream, and stores
* them into <code>b</code> starting at index <code>off</code>.
* If no bytes can be read because the end of the stream has been
* reached, <code>-1</code> is returned.
*
* <p> The bit offset within the stream must be reset to zero before
* the read occurs.
*
* <p> Subclasses must provide an implementation for this method.
* The subclass implementation should update the stream position
* before exiting.
*
* @param b an array of bytes to be written to.
* @param off the starting position within <code>b</code> to write to.
* @param len the maximum number of bytes to read.
*
* @return the number of bytes actually read, or <code>-1</code>
* to indicate EOF.
*
* @exception IndexOutOfBoundsException if <code>off</code> is
* negative, <code>len</code> is negative, or <code>off +
* len</code> is greater than <code>b.length</code>.
* @exception NullPointerException if <code>b</code> is
* <code>null</code>.
* @exception IOException if an I/O error occurs.
*/
public abstract int read(byte[] b, int off, int len) throws IOException;
public void readBytes(IIOByteBuffer buf, int len) throws IOException {
if (len < 0) {
throw new IndexOutOfBoundsException("len < 0!");
}
if (buf == null) {
throw new NullPointerException("buf == null!");
}
byte[] data = new byte[len];
len = read(data, 0, len);
buf.setData(data);
buf.setOffset(0);
buf.setLength(len);
}
public boolean readBoolean() throws IOException {
int ch = this.read();
if (ch < 0) {
throw new EOFException();
}
return (ch != 0);
}
public byte readByte() throws IOException {
int ch = this.read();
if (ch < 0) {
throw new EOFException();
}
return (byte)ch;
}
public int readUnsignedByte() throws IOException {
int ch = this.read();
if (ch < 0) {
throw new EOFException();
}
return ch;
}
public short readShort() throws IOException {
if (read(byteBuf, 0, 2) != 2) {
throw new EOFException();
}
if (byteOrder == ByteOrder.BIG_ENDIAN) {
return (short)
(((byteBuf[0] & 0xff) << 8) | ((byteBuf[1] & 0xff) << 0));
} else {
return (short)
(((byteBuf[1] & 0xff) << 8) | ((byteBuf[0] & 0xff) << 0));
}
}
public int readUnsignedShort() throws IOException {
return ((int)readShort()) & 0xffff;
}
public char readChar() throws IOException {
return (char)readShort();
}
public int readInt() throws IOException {
if (read(byteBuf, 0, 4) != 4) {
throw new EOFException();
}
if (byteOrder == ByteOrder.BIG_ENDIAN) {
return
(((byteBuf[0] & 0xff) << 24) | ((byteBuf[1] & 0xff) << 16) |
((byteBuf[2] & 0xff) << 8) | ((byteBuf[3] & 0xff) << 0));
} else {
return
(((byteBuf[3] & 0xff) << 24) | ((byteBuf[2] & 0xff) << 16) |
((byteBuf[1] & 0xff) << 8) | ((byteBuf[0] & 0xff) << 0));
}
}
public long readUnsignedInt() throws IOException {
return ((long)readInt()) & 0xffffffffL;
}
public long readLong() throws IOException {
// REMIND: Once 6277756 is fixed, we should do a bulk read of all 8
// bytes here as we do in readShort() and readInt() for even better
// performance (see 6347575 for details).
int i1 = readInt();
int i2 = readInt();
if (byteOrder == ByteOrder.BIG_ENDIAN) {
return ((long)i1 << 32) + (i2 & 0xFFFFFFFFL);
} else {
return ((long)i2 << 32) + (i1 & 0xFFFFFFFFL);
}
}
public float readFloat() throws IOException {
return Float.intBitsToFloat(readInt());
}
public double readDouble() throws IOException {
return Double.longBitsToDouble(readLong());
}
public String readLine() throws IOException {
StringBuffer input = new StringBuffer();
int c = -1;
boolean eol = false;
while (!eol) {
switch (c = read()) {
case -1:
case '\n':
eol = true;
break;
case '\r':
eol = true;
long cur = getStreamPosition();
if ((read()) != '\n') {
seek(cur);
}
break;
default:
input.append((char)c);
break;
}
}
if ((c == -1) && (input.length() == 0)) {
return null;
}
return input.toString();
}
public String readUTF() throws IOException {
this.bitOffset = 0;
// Fix 4494369: method ImageInputStreamImpl.readUTF()
// does not work as specified (it should always assume
// network byte order).
ByteOrder oldByteOrder = getByteOrder();
setByteOrder(ByteOrder.BIG_ENDIAN);
String ret;
try {
ret = DataInputStream.readUTF(this);
} catch (IOException e) {
// Restore the old byte order even if an exception occurs
setByteOrder(oldByteOrder);
throw e;
}
setByteOrder(oldByteOrder);
return ret;
}
public void readFully(byte[] b, int off, int len) throws IOException {
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off + len > b.length!");
}
while (len > 0) {
int nbytes = read(b, off, len);
if (nbytes == -1) {
throw new EOFException();
}
off += nbytes;
len -= nbytes;
}
}
public void readFully(byte[] b) throws IOException {
readFully(b, 0, b.length);
}
public void readFully(short[] s, int off, int len) throws IOException {
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > s.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off + len > s.length!");
}
while (len > 0) {
int nelts = Math.min(len, byteBuf.length/2);
readFully(byteBuf, 0, nelts*2);
toShorts(byteBuf, s, off, nelts);
off += nelts;
len -= nelts;
}
}
public void readFully(char[] c, int off, int len) throws IOException {
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > c.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off + len > c.length!");
}
while (len > 0) {
int nelts = Math.min(len, byteBuf.length/2);
readFully(byteBuf, 0, nelts*2);
toChars(byteBuf, c, off, nelts);
off += nelts;
len -= nelts;
}
}
public void readFully(int[] i, int off, int len) throws IOException {
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > i.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off + len > i.length!");
}
while (len > 0) {
int nelts = Math.min(len, byteBuf.length/4);
readFully(byteBuf, 0, nelts*4);
toInts(byteBuf, i, off, nelts);
off += nelts;
len -= nelts;
}
}
public void readFully(long[] l, int off, int len) throws IOException {
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > l.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off + len > l.length!");
}
while (len > 0) {
int nelts = Math.min(len, byteBuf.length/8);
readFully(byteBuf, 0, nelts*8);
toLongs(byteBuf, l, off, nelts);
off += nelts;
len -= nelts;
}
}
public void readFully(float[] f, int off, int len) throws IOException {
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > f.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off + len > f.length!");
}
while (len > 0) {
int nelts = Math.min(len, byteBuf.length/4);
readFully(byteBuf, 0, nelts*4);
toFloats(byteBuf, f, off, nelts);
off += nelts;
len -= nelts;
}
}
public void readFully(double[] d, int off, int len) throws IOException {
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > d.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off + len > d.length!");
}
while (len > 0) {
int nelts = Math.min(len, byteBuf.length/8);
readFully(byteBuf, 0, nelts*8);
toDoubles(byteBuf, d, off, nelts);
off += nelts;
len -= nelts;
}
}
private void toShorts(byte[] b, short[] s, int off, int len) {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
s[off + j] = (short)((b0 << 8) | b1);
boff += 2;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 1];
int b1 = b[boff] & 0xff;
s[off + j] = (short)((b0 << 8) | b1);
boff += 2;
}
}
}
private void toChars(byte[] b, char[] c, int off, int len) {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
c[off + j] = (char)((b0 << 8) | b1);
boff += 2;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 1];
int b1 = b[boff] & 0xff;
c[off + j] = (char)((b0 << 8) | b1);
boff += 2;
}
}
}
private void toInts(byte[] b, int[] i, int off, int len) {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
int b2 = b[boff + 2] & 0xff;
int b3 = b[boff + 3] & 0xff;
i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
boff += 4;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 3];
int b1 = b[boff + 2] & 0xff;
int b2 = b[boff + 1] & 0xff;
int b3 = b[boff] & 0xff;
i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
boff += 4;
}
}
}
private void toLongs(byte[] b, long[] l, int off, int len) {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
int b2 = b[boff + 2] & 0xff;
int b3 = b[boff + 3] & 0xff;
int b4 = b[boff + 4];
int b5 = b[boff + 5] & 0xff;
int b6 = b[boff + 6] & 0xff;
int b7 = b[boff + 7] & 0xff;
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
l[off + j] = ((long)i0 << 32) | (i1 & 0xffffffffL);
boff += 8;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 7];
int b1 = b[boff + 6] & 0xff;
int b2 = b[boff + 5] & 0xff;
int b3 = b[boff + 4] & 0xff;
int b4 = b[boff + 3];
int b5 = b[boff + 2] & 0xff;
int b6 = b[boff + 1] & 0xff;
int b7 = b[boff] & 0xff;
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
l[off + j] = ((long)i0 << 32) | (i1 & 0xffffffffL);
boff += 8;
}
}
}
private void toFloats(byte[] b, float[] f, int off, int len) {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
int b2 = b[boff + 2] & 0xff;
int b3 = b[boff + 3] & 0xff;
int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
f[off + j] = Float.intBitsToFloat(i);
boff += 4;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 3];
int b1 = b[boff + 2] & 0xff;
int b2 = b[boff + 1] & 0xff;
int b3 = b[boff + 0] & 0xff;
int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
f[off + j] = Float.intBitsToFloat(i);
boff += 4;
}
}
}
private void toDoubles(byte[] b, double[] d, int off, int len) {
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int b0 = b[boff];
int b1 = b[boff + 1] & 0xff;
int b2 = b[boff + 2] & 0xff;
int b3 = b[boff + 3] & 0xff;
int b4 = b[boff + 4];
int b5 = b[boff + 5] & 0xff;
int b6 = b[boff + 6] & 0xff;
int b7 = b[boff + 7] & 0xff;
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
long l = ((long)i0 << 32) | (i1 & 0xffffffffL);
d[off + j] = Double.longBitsToDouble(l);
boff += 8;
}
} else {
for (int j = 0; j < len; j++) {
int b0 = b[boff + 7];
int b1 = b[boff + 6] & 0xff;
int b2 = b[boff + 5] & 0xff;
int b3 = b[boff + 4] & 0xff;
int b4 = b[boff + 3];
int b5 = b[boff + 2] & 0xff;
int b6 = b[boff + 1] & 0xff;
int b7 = b[boff] & 0xff;
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
long l = ((long)i0 << 32) | (i1 & 0xffffffffL);
d[off + j] = Double.longBitsToDouble(l);
boff += 8;
}
}
}
public long getStreamPosition() throws IOException {
checkClosed();
return streamPos;
}
public int getBitOffset() throws IOException {
checkClosed();
return bitOffset;
}
public void setBitOffset(int bitOffset) throws IOException {
checkClosed();
if (bitOffset < 0 || bitOffset > 7) {
throw new IllegalArgumentException("bitOffset must be betwwen 0 and 7!");
}
this.bitOffset = bitOffset;
}
public int readBit() throws IOException {
checkClosed();
// Compute final bit offset before we call read() and seek()
int newBitOffset = (this.bitOffset + 1) & 0x7;
int val = read();
if (val == -1) {
throw new EOFException();
}
if (newBitOffset != 0) {
// Move byte position back if in the middle of a byte
seek(getStreamPosition() - 1);
// Shift the bit to be read to the rightmost position
val >>= 8 - newBitOffset;
}
this.bitOffset = newBitOffset;
return val & 0x1;
}
public long readBits(int numBits) throws IOException {
checkClosed();
if (numBits < 0 || numBits > 64) {
throw new IllegalArgumentException();
}
if (numBits == 0) {
return 0L;
}
// Have to read additional bits on the left equal to the bit offset
int bitsToRead = numBits + bitOffset;
// Compute final bit offset before we call read() and seek()
int newBitOffset = (this.bitOffset + numBits) & 0x7;
// Read a byte at a time, accumulate
long accum = 0L;
while (bitsToRead > 0) {
int val = read();
if (val == -1) {
throw new EOFException();
}
accum <<= 8;
accum |= val;
bitsToRead -= 8;
}
// Move byte position back if in the middle of a byte
if (newBitOffset != 0) {
seek(getStreamPosition() - 1);
}
this.bitOffset = newBitOffset;
// Shift away unwanted bits on the right.
accum >>>= (-bitsToRead); // Negative of bitsToRead == extra bits read
// Mask out unwanted bits on the left
accum &= (-1L >>> (64 - numBits));
return accum;
}
/**
* Returns <code>-1L</code> to indicate that the stream has unknown
* length. Subclasses must override this method to provide actual
* length information.
*
* @return -1L to indicate unknown length.
*/
public long length() {
return -1L;
}
/**
* Advances the current stream position by calling
* <code>seek(getStreamPosition() + n)</code>.
*
* <p> The bit offset is reset to zero.
*
* @param n the number of bytes to seek forward.
*
* @return an <code>int</code> representing the number of bytes
* skipped.
*
* @exception IOException if <code>getStreamPosition</code>
* throws an <code>IOException</code> when computing either
* the starting or ending position.
*/
public int skipBytes(int n) throws IOException {
long pos = getStreamPosition();
seek(pos + n);
return (int)(getStreamPosition() - pos);
}
/**
* Advances the current stream position by calling
* <code>seek(getStreamPosition() + n)</code>.
*
* <p> The bit offset is reset to zero.
*
* @param n the number of bytes to seek forward.
*
* @return a <code>long</code> representing the number of bytes
* skipped.
*
* @exception IOException if <code>getStreamPosition</code>
* throws an <code>IOException</code> when computing either
* the starting or ending position.
*/
public long skipBytes(long n) throws IOException {
long pos = getStreamPosition();
seek(pos + n);
return getStreamPosition() - pos;
}
public void seek(long pos) throws IOException {
checkClosed();
// This test also covers pos < 0
if (pos < flushedPos) {
throw new IndexOutOfBoundsException("pos < flushedPos!");
}
this.streamPos = pos;
this.bitOffset = 0;
}
/**
* Pushes the current stream position onto a stack of marked
* positions.
*/
public void mark() {
try {
markByteStack.push(Long.valueOf(getStreamPosition()));
markBitStack.push(Integer.valueOf(getBitOffset()));
} catch (IOException e) {
}
}
/**
* Resets the current stream byte and bit positions from the stack
* of marked positions.
*
* <p> An <code>IOException</code> will be thrown if the previous
* marked position lies in the discarded portion of the stream.
*
* @exception IOException if an I/O error occurs.
*/
public void reset() throws IOException {
if (markByteStack.empty()) {
return;
}
long pos = ((Long)markByteStack.pop()).longValue();
if (pos < flushedPos) {
throw new IIOException
("Previous marked position has been discarded!");
}
seek(pos);
int offset = ((Integer)markBitStack.pop()).intValue();
setBitOffset(offset);
}
public void flushBefore(long pos) throws IOException {
checkClosed();
if (pos < flushedPos) {
throw new IndexOutOfBoundsException("pos < flushedPos!");
}
if (pos > getStreamPosition()) {
throw new IndexOutOfBoundsException("pos > getStreamPosition()!");
}
// Invariant: flushedPos >= 0
flushedPos = pos;
}
public void flush() throws IOException {
flushBefore(getStreamPosition());
}
public long getFlushedPosition() {
return flushedPos;
}
/**
* Default implementation returns false. Subclasses should
* override this if they cache data.
*/
public boolean isCached() {
return false;
}
/**
* Default implementation returns false. Subclasses should
* override this if they cache data in main memory.
*/
public boolean isCachedMemory() {
return false;
}
/**
* Default implementation returns false. Subclasses should
* override this if they cache data in a temporary file.
*/
public boolean isCachedFile() {
return false;
}
public void close() throws IOException {
checkClosed();
isClosed = true;
}
/**
* Finalizes this object prior to garbage collection. The
* <code>close</code> method is called to close any open input
* source. This method should not be called from application
* code.
*
* @exception Throwable if an error occurs during superclass
* finalization.
*/
protected void finalize() throws Throwable {
if (!isClosed) {
try {
close();
} catch (IOException e) {
}
}
super.finalize();
}
}

View File

@@ -0,0 +1,662 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.stream;
import java.io.DataOutput;
import java.io.IOException;
/**
* A seekable output stream interface for use by
* <code>ImageWriter</code>s. Various output destinations, such as
* <code>OutputStream</code>s and <code>File</code>s, as well as
* future fast I/O destinations may be "wrapped" by a suitable
* implementation of this interface for use by the Image I/O API.
*
* <p> Unlike a standard <code>OutputStream</code>, ImageOutputStream
* extends its counterpart, <code>ImageInputStream</code>. Thus it is
* possible to read from the stream as it is being written. The same
* seek and flush positions apply to both reading and writing, although
* the semantics for dealing with a non-zero bit offset before a byte-aligned
* write are necessarily different from the semantics for dealing with
* a non-zero bit offset before a byte-aligned read. When reading bytes,
* any bit offset is set to 0 before the read; when writing bytes, a
* non-zero bit offset causes the remaining bits in the byte to be written
* as 0s. The byte-aligned write then starts at the next byte position.
*
* @see ImageInputStream
*
*/
public interface ImageOutputStream extends ImageInputStream, DataOutput {
/**
* Writes a single byte to the stream at the current position.
* The 24 high-order bits of <code>b</code> are ignored.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write. Implementers can use the
* {@link ImageOutputStreamImpl#flushBits flushBits}
* method of {@link ImageOutputStreamImpl ImageOutputStreamImpl}
* to guarantee this.
*
* @param b an <code>int</code> whose lower 8 bits are to be
* written.
*
* @exception IOException if an I/O error occurs.
*/
void write(int b) throws IOException;
/**
* Writes a sequence of bytes to the stream at the current
* position. If <code>b.length</code> is 0, nothing is written.
* The byte <code>b[0]</code> is written first, then the byte
* <code>b[1]</code>, and so on.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param b an array of <code>byte</code>s to be written.
*
* @exception NullPointerException if <code>b</code> is
* <code>null</code>.
* @exception IOException if an I/O error occurs.
*/
void write(byte b[]) throws IOException;
/**
* Writes a sequence of bytes to the stream at the current
* position. If <code>len</code> is 0, nothing is written.
* The byte <code>b[off]</code> is written first, then the byte
* <code>b[off + 1]</code>, and so on.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write. Implementers can use the
* {@link ImageOutputStreamImpl#flushBits flushBits}
* method of {@link ImageOutputStreamImpl ImageOutputStreamImpl}
* to guarantee this.
*
* @param b an array of <code>byte</code>s to be written.
* @param off the start offset in the data.
* @param len the number of <code>byte</code>s to write.
*
* @exception IndexOutOfBoundsException if <code>off</code> is
* negative, <code>len</code> is negative, or <code>off +
* len</code> is greater than <code>b.length</code>.
* @exception NullPointerException if <code>b</code> is
* <code>null</code>.
* @exception IOException if an I/O error occurs.
*/
void write(byte b[], int off, int len) throws IOException;
/**
* Writes a <code>boolean</code> value to the stream. If
* <code>v</code> is true, the value <code>(byte)1</code> is
* written; if <code>v</code> is false, the value
* <code>(byte)0</code> is written.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param v the <code>boolean</code> to be written.
*
* @exception IOException if an I/O error occurs.
*/
void writeBoolean(boolean v) throws IOException;
/**
* Writes the 8 low-order bits of <code>v</code> to the
* stream. The 24 high-order bits of <code>v</code> are ignored.
* (This means that <code>writeByte</code> does exactly the same
* thing as <code>write</code> for an integer argument.)
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param v an <code>int</code> containing the byte value to be
* written.
*
* @exception IOException if an I/O error occurs.
*/
void writeByte(int v) throws IOException;
/**
* Writes the 16 low-order bits of <code>v</code> to the
* stream. The 16 high-order bits of <code>v</code> are ignored.
* If the stream uses network byte order, the bytes written, in
* order, will be:
*
* <pre>
* (byte)((v &gt;&gt; 8) &amp; 0xff)
* (byte)(v &amp; 0xff)
* </pre>
*
* Otherwise, the bytes written will be:
*
* <pre>
* (byte)(v &amp; 0xff)
* (byte)((v &gt;&gt; 8) &amp; 0xff)
* </pre>
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param v an <code>int</code> containing the short value to be
* written.
*
* @exception IOException if an I/O error occurs.
*/
void writeShort(int v) throws IOException;
/**
* This method is a synonym for {@link #writeShort writeShort}.
*
* @param v an <code>int</code> containing the char (unsigned
* short) value to be written.
*
* @exception IOException if an I/O error occurs.
*
* @see #writeShort(int)
*/
void writeChar(int v) throws IOException;
/**
* Writes the 32 bits of <code>v</code> to the stream. If the
* stream uses network byte order, the bytes written, in order,
* will be:
*
* <pre>
* (byte)((v &gt;&gt; 24) &amp; 0xff)
* (byte)((v &gt;&gt; 16) &amp; 0xff)
* (byte)((v &gt;&gt; 8) &amp; 0xff)
* (byte)(v &amp; 0xff)
* </pre>
*
* Otheriwse, the bytes written will be:
*
* <pre>
* (byte)(v &amp; 0xff)
* (byte)((v &gt;&gt; 8) &amp; 0xff)
* (byte)((v &gt;&gt; 16) &amp; 0xff)
* (byte)((v &gt;&gt; 24) &amp; 0xff)
* </pre>
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param v an <code>int</code> containing the value to be
* written.
*
* @exception IOException if an I/O error occurs.
*/
void writeInt(int v) throws IOException;
/**
* Writes the 64 bits of <code>v</code> to the stream. If the
* stream uses network byte order, the bytes written, in order,
* will be:
*
* <pre>
* (byte)((v &gt;&gt; 56) &amp; 0xff)
* (byte)((v &gt;&gt; 48) &amp; 0xff)
* (byte)((v &gt;&gt; 40) &amp; 0xff)
* (byte)((v &gt;&gt; 32) &amp; 0xff)
* (byte)((v &gt;&gt; 24) &amp; 0xff)
* (byte)((v &gt;&gt; 16) &amp; 0xff)
* (byte)((v &gt;&gt; 8) &amp; 0xff)
* (byte)(v &amp; 0xff)
* </pre>
*
* Otherwise, the bytes written will be:
*
* <pre>
* (byte)(v &amp; 0xff)
* (byte)((v &gt;&gt; 8) &amp; 0xff)
* (byte)((v &gt;&gt; 16) &amp; 0xff)
* (byte)((v &gt;&gt; 24) &amp; 0xff)
* (byte)((v &gt;&gt; 32) &amp; 0xff)
* (byte)((v &gt;&gt; 40) &amp; 0xff)
* (byte)((v &gt;&gt; 48) &amp; 0xff)
* (byte)((v &gt;&gt; 56) &amp; 0xff)
* </pre>
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param v a <code>long</code> containing the value to be
* written.
*
* @exception IOException if an I/O error occurs.
*/
void writeLong(long v) throws IOException;
/**
* Writes a <code>float</code> value, which is comprised of four
* bytes, to the output stream. It does this as if it first
* converts this <code>float</code> value to an <code>int</code>
* in exactly the manner of the <code>Float.floatToIntBits</code>
* method and then writes the int value in exactly the manner of
* the <code>writeInt</code> method.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param v a <code>float</code> containing the value to be
* written.
*
* @exception IOException if an I/O error occurs.
*/
void writeFloat(float v) throws IOException;
/**
* Writes a <code>double</code> value, which is comprised of four
* bytes, to the output stream. It does this as if it first
* converts this <code>double</code> value to an <code>long</code>
* in exactly the manner of the
* <code>Double.doubleToLongBits</code> method and then writes the
* long value in exactly the manner of the <code>writeLong</code>
* method.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param v a <code>double</code> containing the value to be
* written.
*
* @exception IOException if an I/O error occurs.
*/
void writeDouble(double v) throws IOException;
/**
* Writes a string to the output stream. For every character in
* the string <code>s</code>, taken in order, one byte is written
* to the output stream. If <code>s</code> is <code>null</code>, a
* <code>NullPointerException</code> is thrown.
*
* <p> If <code>s.length</code> is zero, then no bytes are
* written. Otherwise, the character <code>s[0]</code> is written
* first, then <code>s[1]</code>, and so on; the last character
* written is <code>s[s.length-1]</code>. For each character, one
* byte is written, the low-order byte, in exactly the manner of
* the <code>writeByte</code> method. The high-order eight bits of
* each character in the string are ignored.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param s a <code>String</code> containing the value to be
* written.
*
* @exception NullPointerException if <code>s</code> is
* <code>null</code>.
* @exception IOException if an I/O error occurs.
*/
void writeBytes(String s) throws IOException;
/**
* Writes a string to the output stream. For every character in
* the string <code>s</code>, taken in order, two bytes are
* written to the output stream, ordered according to the current
* byte order setting. If network byte order is being used, the
* high-order byte is written first; the order is reversed
* otherwise. If <code>s</code> is <code>null</code>, a
* <code>NullPointerException</code> is thrown.
*
* <p> If <code>s.length</code> is zero, then no bytes are
* written. Otherwise, the character <code>s[0]</code> is written
* first, then <code>s[1]</code>, and so on; the last character
* written is <code>s[s.length-1]</code>.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param s a <code>String</code> containing the value to be
* written.
*
* @exception NullPointerException if <code>s</code> is
* <code>null</code>.
* @exception IOException if an I/O error occurs.
*/
void writeChars(String s) throws IOException;
/**
* Writes two bytes of length information to the output stream in
* network byte order, followed by the
* <a href="../../../java/io/DataInput.html#modified-utf-8">modified
* UTF-8</a>
* representation of every character in the string <code>s</code>.
* If <code>s</code> is <code>null</code>, a
* <code>NullPointerException</code> is thrown. Each character in
* the string <code>s</code> is converted to a group of one, two,
* or three bytes, depending on the value of the character.
*
* <p> If a character <code>c</code> is in the range
* <code>&#92;u0001</code> through <code>&#92;u007f</code>, it is
* represented by one byte:
*
* <p><pre>
* (byte)c
* </pre>
*
* <p> If a character <code>c</code> is <code>&#92;u0000</code> or
* is in the range <code>&#92;u0080</code> through
* <code>&#92;u07ff</code>, then it is represented by two bytes,
* to be written in the order shown:
*
* <p> <pre><code>
* (byte)(0xc0 | (0x1f &amp; (c &gt;&gt; 6)))
* (byte)(0x80 | (0x3f &amp; c))
* </code></pre>
*
* <p> If a character <code>c</code> is in the range
* <code>&#92;u0800</code> through <code>uffff</code>, then it is
* represented by three bytes, to be written in the order shown:
*
* <p> <pre><code>
* (byte)(0xe0 | (0x0f &amp; (c &gt;&gt; 12)))
* (byte)(0x80 | (0x3f &amp; (c &gt;&gt; 6)))
* (byte)(0x80 | (0x3f &amp; c))
* </code></pre>
*
* <p> First, the total number of bytes needed to represent all
* the characters of <code>s</code> is calculated. If this number
* is larger than <code>65535</code>, then a
* <code>UTFDataFormatException</code> is thrown. Otherwise, this
* length is written to the output stream in exactly the manner of
* the <code>writeShort</code> method; after this, the one-, two-,
* or three-byte representation of each character in the string
* <code>s</code> is written.
*
* <p> The current byte order setting is ignored.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* <p><strong>Note:</strong> This method should not be used in
* the implementation of image formats that use standard UTF-8,
* because the modified UTF-8 used here is incompatible with
* standard UTF-8.
*
* @param s a <code>String</code> containing the value to be
* written.
*
* @exception NullPointerException if <code>s</code> is
* <code>null</code>.
* @exception java.io.UTFDataFormatException if the modified UTF-8
* representation of <code>s</code> requires more than 65536 bytes.
* @exception IOException if an I/O error occurs.
*/
void writeUTF(String s) throws IOException;
/**
* Writes a sequence of shorts to the stream at the current
* position. If <code>len</code> is 0, nothing is written.
* The short <code>s[off]</code> is written first, then the short
* <code>s[off + 1]</code>, and so on. The byte order of the
* stream is used to determine the order in which the individual
* bytes are written.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param s an array of <code>short</code>s to be written.
* @param off the start offset in the data.
* @param len the number of <code>short</code>s to write.
*
* @exception IndexOutOfBoundsException if <code>off</code> is
* negative, <code>len</code> is negative, or <code>off +
* len</code> is greater than <code>s.length</code>.
* @exception NullPointerException if <code>s</code> is
* <code>null</code>.
* @exception IOException if an I/O error occurs.
*/
void writeShorts(short[] s, int off, int len) throws IOException;
/**
* Writes a sequence of chars to the stream at the current
* position. If <code>len</code> is 0, nothing is written.
* The char <code>c[off]</code> is written first, then the char
* <code>c[off + 1]</code>, and so on. The byte order of the
* stream is used to determine the order in which the individual
* bytes are written.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param c an array of <code>char</code>s to be written.
* @param off the start offset in the data.
* @param len the number of <code>char</code>s to write.
*
* @exception IndexOutOfBoundsException if <code>off</code> is
* negative, <code>len</code> is negative, or <code>off +
* len</code> is greater than <code>c.length</code>.
* @exception NullPointerException if <code>c</code> is
* <code>null</code>.
* @exception IOException if an I/O error occurs.
*/
void writeChars(char[] c, int off, int len) throws IOException;
/**
* Writes a sequence of ints to the stream at the current
* position. If <code>len</code> is 0, nothing is written.
* The int <code>i[off]</code> is written first, then the int
* <code>i[off + 1]</code>, and so on. The byte order of the
* stream is used to determine the order in which the individual
* bytes are written.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param i an array of <code>int</code>s to be written.
* @param off the start offset in the data.
* @param len the number of <code>int</code>s to write.
*
* @exception IndexOutOfBoundsException if <code>off</code> is
* negative, <code>len</code> is negative, or <code>off +
* len</code> is greater than <code>i.length</code>.
* @exception NullPointerException if <code>i</code> is
* <code>null</code>.
* @exception IOException if an I/O error occurs.
*/
void writeInts(int[] i, int off, int len) throws IOException;
/**
* Writes a sequence of longs to the stream at the current
* position. If <code>len</code> is 0, nothing is written.
* The long <code>l[off]</code> is written first, then the long
* <code>l[off + 1]</code>, and so on. The byte order of the
* stream is used to determine the order in which the individual
* bytes are written.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param l an array of <code>long</code>s to be written.
* @param off the start offset in the data.
* @param len the number of <code>long</code>s to write.
*
* @exception IndexOutOfBoundsException if <code>off</code> is
* negative, <code>len</code> is negative, or <code>off +
* len</code> is greater than <code>l.length</code>.
* @exception NullPointerException if <code>l</code> is
* <code>null</code>.
* @exception IOException if an I/O error occurs.
*/
void writeLongs(long[] l, int off, int len) throws IOException;
/**
* Writes a sequence of floats to the stream at the current
* position. If <code>len</code> is 0, nothing is written.
* The float <code>f[off]</code> is written first, then the float
* <code>f[off + 1]</code>, and so on. The byte order of the
* stream is used to determine the order in which the individual
* bytes are written.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param f an array of <code>float</code>s to be written.
* @param off the start offset in the data.
* @param len the number of <code>float</code>s to write.
*
* @exception IndexOutOfBoundsException if <code>off</code> is
* negative, <code>len</code> is negative, or <code>off +
* len</code> is greater than <code>f.length</code>.
* @exception NullPointerException if <code>f</code> is
* <code>null</code>.
* @exception IOException if an I/O error occurs.
*/
void writeFloats(float[] f, int off, int len) throws IOException;
/**
* Writes a sequence of doubles to the stream at the current
* position. If <code>len</code> is 0, nothing is written.
* The double <code>d[off]</code> is written first, then the double
* <code>d[off + 1]</code>, and so on. The byte order of the
* stream is used to determine the order in which the individual
* bytes are written.
*
* <p> If the bit offset within the stream is non-zero, the
* remainder of the current byte is padded with 0s
* and written out first. The bit offset will be 0 after the
* write.
*
* @param d an array of <code>doubles</code>s to be written.
* @param off the start offset in the data.
* @param len the number of <code>double</code>s to write.
*
* @exception IndexOutOfBoundsException if <code>off</code> is
* negative, <code>len</code> is negative, or <code>off +
* len</code> is greater than <code>d.length</code>.
* @exception NullPointerException if <code>d</code> is
* <code>null</code>.
* @exception IOException if an I/O error occurs.
*/
void writeDoubles(double[] d, int off, int len) throws IOException;
/**
* Writes a single bit, given by the least significant bit of the
* argument, to the stream at the current bit offset within the
* current byte position. The upper 31 bits of the argument are
* ignored. The given bit replaces the previous bit at that
* position. The bit offset is advanced by one and reduced modulo
* 8.
*
* <p> If any bits of a particular byte have never been set
* at the time the byte is flushed to the destination, those
* bits will be set to 0 automatically.
*
* @param bit an <code>int</code> whose least significant bit
* is to be written to the stream.
*
* @exception IOException if an I/O error occurs.
*/
void writeBit(int bit) throws IOException;
/**
* Writes a sequence of bits, given by the <code>numBits</code>
* least significant bits of the <code>bits</code> argument in
* left-to-right order, to the stream at the current bit offset
* within the current byte position. The upper <code>64 -
* numBits</code> bits of the argument are ignored. The bit
* offset is advanced by <code>numBits</code> and reduced modulo
* 8. Note that a bit offset of 0 always indicates the
* most-significant bit of the byte, and bytes of bits are written
* out in sequence as they are encountered. Thus bit writes are
* always effectively in network byte order. The actual stream
* byte order setting is ignored.
*
* <p> Bit data may be accumulated in memory indefinitely, until
* <code>flushBefore</code> is called. At that time, all bit data
* prior to the flushed position will be written.
*
* <p> If any bits of a particular byte have never been set
* at the time the byte is flushed to the destination, those
* bits will be set to 0 automatically.
*
* @param bits a <code>long</code> containing the bits to be
* written, starting with the bit in position <code>numBits -
* 1</code> down to the least significant bit.
*
* @param numBits an <code>int</code> between 0 and 64, inclusive.
*
* @exception IllegalArgumentException if <code>numBits</code> is
* not between 0 and 64, inclusive.
* @exception IOException if an I/O error occurs.
*/
void writeBits(long bits, int numBits) throws IOException;
/**
* Flushes all data prior to the given position to the underlying
* destination, such as an <code>OutputStream</code> or
* <code>File</code>. Attempting to seek to the flushed portion
* of the stream will result in an
* <code>IndexOutOfBoundsException</code>.
*
* @param pos a <code>long</code> containing the length of the
* stream prefix that may be flushed to the destination.
*
* @exception IndexOutOfBoundsException if <code>pos</code> lies
* in the flushed portion of the stream or past the current stream
* position.
* @exception IOException if an I/O error occurs.
*/
void flushBefore(long pos) throws IOException;
}

View File

@@ -0,0 +1,510 @@
/*
* Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.stream;
import java.io.IOException;
import java.io.UTFDataFormatException;
import java.nio.ByteOrder;
/**
* An abstract class implementing the <code>ImageOutputStream</code> interface.
* This class is designed to reduce the number of methods that must
* be implemented by subclasses.
*
*/
public abstract class ImageOutputStreamImpl
extends ImageInputStreamImpl
implements ImageOutputStream {
/**
* Constructs an <code>ImageOutputStreamImpl</code>.
*/
public ImageOutputStreamImpl() {
}
public abstract void write(int b) throws IOException;
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
public abstract void write(byte b[], int off, int len) throws IOException;
public void writeBoolean(boolean v) throws IOException {
write(v ? 1 : 0);
}
public void writeByte(int v) throws IOException {
write(v);
}
public void writeShort(int v) throws IOException {
if (byteOrder == ByteOrder.BIG_ENDIAN) {
byteBuf[0] = (byte)(v >>> 8);
byteBuf[1] = (byte)(v >>> 0);
} else {
byteBuf[0] = (byte)(v >>> 0);
byteBuf[1] = (byte)(v >>> 8);
}
write(byteBuf, 0, 2);
}
public void writeChar(int v) throws IOException {
writeShort(v);
}
public void writeInt(int v) throws IOException {
if (byteOrder == ByteOrder.BIG_ENDIAN) {
byteBuf[0] = (byte)(v >>> 24);
byteBuf[1] = (byte)(v >>> 16);
byteBuf[2] = (byte)(v >>> 8);
byteBuf[3] = (byte)(v >>> 0);
} else {
byteBuf[0] = (byte)(v >>> 0);
byteBuf[1] = (byte)(v >>> 8);
byteBuf[2] = (byte)(v >>> 16);
byteBuf[3] = (byte)(v >>> 24);
}
write(byteBuf, 0, 4);
}
public void writeLong(long v) throws IOException {
if (byteOrder == ByteOrder.BIG_ENDIAN) {
byteBuf[0] = (byte)(v >>> 56);
byteBuf[1] = (byte)(v >>> 48);
byteBuf[2] = (byte)(v >>> 40);
byteBuf[3] = (byte)(v >>> 32);
byteBuf[4] = (byte)(v >>> 24);
byteBuf[5] = (byte)(v >>> 16);
byteBuf[6] = (byte)(v >>> 8);
byteBuf[7] = (byte)(v >>> 0);
} else {
byteBuf[0] = (byte)(v >>> 0);
byteBuf[1] = (byte)(v >>> 8);
byteBuf[2] = (byte)(v >>> 16);
byteBuf[3] = (byte)(v >>> 24);
byteBuf[4] = (byte)(v >>> 32);
byteBuf[5] = (byte)(v >>> 40);
byteBuf[6] = (byte)(v >>> 48);
byteBuf[7] = (byte)(v >>> 56);
}
// REMIND: Once 6277756 is fixed, we should do a bulk write of all 8
// bytes here as we do in writeShort() and writeInt() for even better
// performance. For now, two bulk writes of 4 bytes each is still
// faster than 8 individual write() calls (see 6347575 for details).
write(byteBuf, 0, 4);
write(byteBuf, 4, 4);
}
public void writeFloat(float v) throws IOException {
writeInt(Float.floatToIntBits(v));
}
public void writeDouble(double v) throws IOException {
writeLong(Double.doubleToLongBits(v));
}
public void writeBytes(String s) throws IOException {
int len = s.length();
for (int i = 0 ; i < len ; i++) {
write((byte)s.charAt(i));
}
}
public void writeChars(String s) throws IOException {
int len = s.length();
byte[] b = new byte[len*2];
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int i = 0; i < len ; i++) {
int v = s.charAt(i);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 0);
}
} else {
for (int i = 0; i < len ; i++) {
int v = s.charAt(i);
b[boff++] = (byte)(v >>> 0);
b[boff++] = (byte)(v >>> 8);
}
}
write(b, 0, len*2);
}
public void writeUTF(String s) throws IOException {
int strlen = s.length();
int utflen = 0;
char[] charr = new char[strlen];
int c, boff = 0;
s.getChars(0, strlen, charr, 0);
for (int i = 0; i < strlen; i++) {
c = charr[i];
if ((c >= 0x0001) && (c <= 0x007F)) {
utflen++;
} else if (c > 0x07FF) {
utflen += 3;
} else {
utflen += 2;
}
}
if (utflen > 65535) {
throw new UTFDataFormatException("utflen > 65536!");
}
byte[] b = new byte[utflen+2];
b[boff++] = (byte) ((utflen >>> 8) & 0xFF);
b[boff++] = (byte) ((utflen >>> 0) & 0xFF);
for (int i = 0; i < strlen; i++) {
c = charr[i];
if ((c >= 0x0001) && (c <= 0x007F)) {
b[boff++] = (byte) c;
} else if (c > 0x07FF) {
b[boff++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
b[boff++] = (byte) (0x80 | ((c >> 6) & 0x3F));
b[boff++] = (byte) (0x80 | ((c >> 0) & 0x3F));
} else {
b[boff++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
b[boff++] = (byte) (0x80 | ((c >> 0) & 0x3F));
}
}
write(b, 0, utflen + 2);
}
public void writeShorts(short[] s, int off, int len) throws IOException {
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > s.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off + len > s.length!");
}
byte[] b = new byte[len*2];
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int i = 0; i < len; i++) {
short v = s[off + i];
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 0);
}
} else {
for (int i = 0; i < len; i++) {
short v = s[off + i];
b[boff++] = (byte)(v >>> 0);
b[boff++] = (byte)(v >>> 8);
}
}
write(b, 0, len*2);
}
public void writeChars(char[] c, int off, int len) throws IOException {
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > c.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off + len > c.length!");
}
byte[] b = new byte[len*2];
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int i = 0; i < len; i++) {
char v = c[off + i];
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 0);
}
} else {
for (int i = 0; i < len; i++) {
char v = c[off + i];
b[boff++] = (byte)(v >>> 0);
b[boff++] = (byte)(v >>> 8);
}
}
write(b, 0, len*2);
}
public void writeInts(int[] i, int off, int len) throws IOException {
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > i.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off + len > i.length!");
}
byte[] b = new byte[len*4];
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int j = 0; j < len; j++) {
int v = i[off + j];
b[boff++] = (byte)(v >>> 24);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 0);
}
} else {
for (int j = 0; j < len; j++) {
int v = i[off + j];
b[boff++] = (byte)(v >>> 0);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 24);
}
}
write(b, 0, len*4);
}
public void writeLongs(long[] l, int off, int len) throws IOException {
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > l.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off + len > l.length!");
}
byte[] b = new byte[len*8];
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int i = 0; i < len; i++) {
long v = l[off + i];
b[boff++] = (byte)(v >>> 56);
b[boff++] = (byte)(v >>> 48);
b[boff++] = (byte)(v >>> 40);
b[boff++] = (byte)(v >>> 32);
b[boff++] = (byte)(v >>> 24);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 0);
}
} else {
for (int i = 0; i < len; i++) {
long v = l[off + i];
b[boff++] = (byte)(v >>> 0);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 24);
b[boff++] = (byte)(v >>> 32);
b[boff++] = (byte)(v >>> 40);
b[boff++] = (byte)(v >>> 48);
b[boff++] = (byte)(v >>> 56);
}
}
write(b, 0, len*8);
}
public void writeFloats(float[] f, int off, int len) throws IOException {
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > f.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off + len > f.length!");
}
byte[] b = new byte[len*4];
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int i = 0; i < len; i++) {
int v = Float.floatToIntBits(f[off + i]);
b[boff++] = (byte)(v >>> 24);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 0);
}
} else {
for (int i = 0; i < len; i++) {
int v = Float.floatToIntBits(f[off + i]);
b[boff++] = (byte)(v >>> 0);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 24);
}
}
write(b, 0, len*4);
}
public void writeDoubles(double[] d, int off, int len) throws IOException {
// Fix 4430357 - if off + len < 0, overflow occurred
if (off < 0 || len < 0 || off + len > d.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off + len > d.length!");
}
byte[] b = new byte[len*8];
int boff = 0;
if (byteOrder == ByteOrder.BIG_ENDIAN) {
for (int i = 0; i < len; i++) {
long v = Double.doubleToLongBits(d[off + i]);
b[boff++] = (byte)(v >>> 56);
b[boff++] = (byte)(v >>> 48);
b[boff++] = (byte)(v >>> 40);
b[boff++] = (byte)(v >>> 32);
b[boff++] = (byte)(v >>> 24);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 0);
}
} else {
for (int i = 0; i < len; i++) {
long v = Double.doubleToLongBits(d[off + i]);
b[boff++] = (byte)(v >>> 0);
b[boff++] = (byte)(v >>> 8);
b[boff++] = (byte)(v >>> 16);
b[boff++] = (byte)(v >>> 24);
b[boff++] = (byte)(v >>> 32);
b[boff++] = (byte)(v >>> 40);
b[boff++] = (byte)(v >>> 48);
b[boff++] = (byte)(v >>> 56);
}
}
write(b, 0, len*8);
}
public void writeBit(int bit) throws IOException {
writeBits((1L & bit), 1);
}
public void writeBits(long bits, int numBits) throws IOException {
checkClosed();
if (numBits < 0 || numBits > 64) {
throw new IllegalArgumentException("Bad value for numBits!");
}
if (numBits == 0) {
return;
}
// Prologue: deal with pre-existing bits
// Bug 4499158, 4507868 - if we're at the beginning of the stream
// and the bit offset is 0, there can't be any pre-existing bits
if ((getStreamPosition() > 0) || (bitOffset > 0)) {
int offset = bitOffset; // read() will reset bitOffset
int partialByte = read();
if (partialByte != -1) {
seek(getStreamPosition() - 1);
} else {
partialByte = 0;
}
if (numBits + offset < 8) {
// Notch out the partial byte and drop in the new bits
int shift = 8 - (offset+numBits);
int mask = -1 >>> (32 - numBits);
partialByte &= ~(mask << shift); // Clear out old bits
partialByte |= ((bits & mask) << shift); // Or in new ones
write(partialByte);
seek(getStreamPosition() - 1);
bitOffset = offset + numBits;
numBits = 0; // Signal that we are done
} else {
// Fill out the partial byte and reduce numBits
int num = 8 - offset;
int mask = -1 >>> (32 - num);
partialByte &= ~mask; // Clear out bits
partialByte |= ((bits >> (numBits - num)) & mask);
// Note that bitOffset is already 0, so there is no risk
// of this advancing to the next byte
write(partialByte);
numBits -= num;
}
}
// Now write any whole bytes
if (numBits > 7) {
int extra = numBits % 8;
for (int numBytes = numBits / 8; numBytes > 0; numBytes--) {
int shift = (numBytes-1)*8+extra;
int value = (int) ((shift == 0)
? bits & 0xFF
: (bits>>shift) & 0xFF);
write(value);
}
numBits = extra;
}
// Epilogue: write out remaining partial byte, if any
// Note that we may be at EOF, in which case we pad with 0,
// or not, in which case we must preserve the existing bits
if (numBits != 0) {
// If we are not at the end of the file, read the current byte
// If we are at the end of the file, initialize our byte to 0.
int partialByte = 0;
partialByte = read();
if (partialByte != -1) {
seek(getStreamPosition() - 1);
}
// Fix 4494976: writeBit(int) does not pad the remainder
// of the current byte with 0s
else { // EOF
partialByte = 0;
}
int shift = 8 - numBits;
int mask = -1 >>> (32 - numBits);
partialByte &= ~(mask << shift);
partialByte |= (bits & mask) << shift;
// bitOffset is always already 0 when we get here.
write(partialByte);
seek(getStreamPosition() - 1);
bitOffset = numBits;
}
}
/**
* If the bit offset is non-zero, forces the remaining bits
* in the current byte to 0 and advances the stream position
* by one. This method should be called by subclasses at the
* beginning of the <code>write(int)</code> and
* <code>write(byte[], int, int)</code> methods.
*
* @exception IOException if an I/O error occurs.
*/
protected final void flushBits() throws IOException {
checkClosed();
if (bitOffset != 0) {
int offset = bitOffset;
int partialByte = read(); // Sets bitOffset to 0
if (partialByte < 0) {
// Fix 4465683: When bitOffset is set
// to something non-zero beyond EOF,
// we should set that whole byte to
// zero and write it to stream.
partialByte = 0;
bitOffset = 0;
}
else {
seek(getStreamPosition() - 1);
partialByte &= -1 << (8 - offset);
}
write(partialByte);
}
}
}

View File

@@ -0,0 +1,364 @@
/*
* Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.stream;
import java.util.ArrayList;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
/**
* Package-visible class consolidating common code for
* <code>MemoryCacheImageInputStream</code> and
* <code>MemoryCacheImageOutputStream</code>.
* This class keeps an <code>ArrayList</code> of 8K blocks,
* loaded sequentially. Blocks may only be disposed of
* from the index 0 forward. As blocks are freed, the
* corresponding entries in the array list are set to
* <code>null</code>, but no compacting is performed.
* This allows the index for each block to never change,
* and the length of the cache is always the same as the
* total amount of data ever cached. Cached data is
* therefore always contiguous from the point of last
* disposal to the current length.
*
* <p> The total number of blocks resident in the cache must not
* exceed <code>Integer.MAX_VALUE</code>. In practice, the limit of
* available memory will be exceeded long before this becomes an
* issue, since a full cache would contain 8192*2^31 = 16 terabytes of
* data.
*
* A <code>MemoryCache</code> may be reused after a call
* to <code>reset()</code>.
*/
class MemoryCache {
private static final int BUFFER_LENGTH = 8192;
private ArrayList cache = new ArrayList();
private long cacheStart = 0L;
/**
* The largest position ever written to the cache.
*/
private long length = 0L;
private byte[] getCacheBlock(long blockNum) throws IOException {
long blockOffset = blockNum - cacheStart;
if (blockOffset > Integer.MAX_VALUE) {
// This can only happen when the cache hits 16 terabytes of
// contiguous data...
throw new IOException("Cache addressing limit exceeded!");
}
return (byte[])cache.get((int)blockOffset);
}
/**
* Ensures that at least <code>pos</code> bytes are cached,
* or the end of the source is reached. The return value
* is equal to the smaller of <code>pos</code> and the
* length of the source.
*/
public long loadFromStream(InputStream stream, long pos)
throws IOException {
// We've already got enough data cached
if (pos < length) {
return pos;
}
int offset = (int)(length % BUFFER_LENGTH);
byte [] buf = null;
long len = pos - length;
if (offset != 0) {
buf = getCacheBlock(length/BUFFER_LENGTH);
}
while (len > 0) {
if (buf == null) {
try {
buf = new byte[BUFFER_LENGTH];
} catch (OutOfMemoryError e) {
throw new IOException("No memory left for cache!");
}
offset = 0;
}
int left = BUFFER_LENGTH - offset;
int nbytes = (int)Math.min(len, (long)left);
nbytes = stream.read(buf, offset, nbytes);
if (nbytes == -1) {
return length; // EOF
}
if (offset == 0) {
cache.add(buf);
}
len -= nbytes;
length += nbytes;
offset += nbytes;
if (offset >= BUFFER_LENGTH) {
// we've filled the current buffer, so a new one will be
// allocated next time around (and offset will be reset to 0)
buf = null;
}
}
return pos;
}
/**
* Writes out a portion of the cache to an <code>OutputStream</code>.
* This method preserves no state about the output stream, and does
* not dispose of any blocks containing bytes written. To dispose
* blocks, use {@link #disposeBefore <code>disposeBefore()</code>}.
*
* @exception IndexOutOfBoundsException if any portion of
* the requested data is not in the cache (including if <code>pos</code>
* is in a block already disposed), or if either <code>pos</code> or
* <code>len</code> is < 0.
*/
public void writeToStream(OutputStream stream, long pos, long len)
throws IOException {
if (pos + len > length) {
throw new IndexOutOfBoundsException("Argument out of cache");
}
if ((pos < 0) || (len < 0)) {
throw new IndexOutOfBoundsException("Negative pos or len");
}
if (len == 0) {
return;
}
long bufIndex = pos/BUFFER_LENGTH;
if (bufIndex < cacheStart) {
throw new IndexOutOfBoundsException("pos already disposed");
}
int offset = (int)(pos % BUFFER_LENGTH);
byte[] buf = getCacheBlock(bufIndex++);
while (len > 0) {
if (buf == null) {
buf = getCacheBlock(bufIndex++);
offset = 0;
}
int nbytes = (int)Math.min(len, (long)(BUFFER_LENGTH - offset));
stream.write(buf, offset, nbytes);
buf = null;
len -= nbytes;
}
}
/**
* Ensure that there is space to write a byte at the given position.
*/
private void pad(long pos) throws IOException {
long currIndex = cacheStart + cache.size() - 1;
long lastIndex = pos/BUFFER_LENGTH;
long numNewBuffers = lastIndex - currIndex;
for (long i = 0; i < numNewBuffers; i++) {
try {
cache.add(new byte[BUFFER_LENGTH]);
} catch (OutOfMemoryError e) {
throw new IOException("No memory left for cache!");
}
}
}
/**
* Overwrites and/or appends the cache from a byte array.
* The length of the cache will be extended as needed to hold
* the incoming data.
*
* @param b an array of bytes containing data to be written.
* @param off the starting offset withing the data array.
* @param len the number of bytes to be written.
* @param pos the cache position at which to begin writing.
*
* @exception NullPointerException if <code>b</code> is <code>null</code>.
* @exception IndexOutOfBoundsException if <code>off</code>,
* <code>len</code>, or <code>pos</code> are negative,
* or if <code>off+len > b.length</code>.
*/
public void write(byte[] b, int off, int len, long pos)
throws IOException {
if (b == null) {
throw new NullPointerException("b == null!");
}
// Fix 4430357 - if off + len < 0, overflow occurred
if ((off < 0) || (len < 0) || (pos < 0) ||
(off + len > b.length) || (off + len < 0)) {
throw new IndexOutOfBoundsException();
}
// Ensure there is space for the incoming data
long lastPos = pos + len - 1;
if (lastPos >= length) {
pad(lastPos);
length = lastPos + 1;
}
// Copy the data into the cache, block by block
int offset = (int)(pos % BUFFER_LENGTH);
while (len > 0) {
byte[] buf = getCacheBlock(pos/BUFFER_LENGTH);
int nbytes = Math.min(len, BUFFER_LENGTH - offset);
System.arraycopy(b, off, buf, offset, nbytes);
pos += nbytes;
off += nbytes;
len -= nbytes;
offset = 0; // Always after the first time
}
}
/**
* Overwrites or appends a single byte to the cache.
* The length of the cache will be extended as needed to hold
* the incoming data.
*
* @param b an <code>int</code> whose 8 least significant bits
* will be written.
* @param pos the cache position at which to begin writing.
*
* @exception IndexOutOfBoundsException if <code>pos</code> is negative.
*/
public void write(int b, long pos) throws IOException {
if (pos < 0) {
throw new ArrayIndexOutOfBoundsException("pos < 0");
}
// Ensure there is space for the incoming data
if (pos >= length) {
pad(pos);
length = pos + 1;
}
// Insert the data.
byte[] buf = getCacheBlock(pos/BUFFER_LENGTH);
int offset = (int)(pos % BUFFER_LENGTH);
buf[offset] = (byte)b;
}
/**
* Returns the total length of data that has been cached,
* regardless of whether any early blocks have been disposed.
* This value will only ever increase.
*/
public long getLength() {
return length;
}
/**
* Returns the single byte at the given position, as an
* <code>int</code>. Returns -1 if this position has
* not been cached or has been disposed.
*/
public int read(long pos) throws IOException {
if (pos >= length) {
return -1;
}
byte[] buf = getCacheBlock(pos/BUFFER_LENGTH);
if (buf == null) {
return -1;
}
return buf[(int)(pos % BUFFER_LENGTH)] & 0xff;
}
/**
* Copy <code>len</code> bytes from the cache, starting
* at cache position <code>pos</code>, into the array
* <code>b</code> at offset <code>off</code>.
*
* @exception NullPointerException if b is <code>null</code>
* @exception IndexOutOfBoundsException if <code>off</code>,
* <code>len</code> or <code>pos</code> are negative or if
* <code>off + len > b.length</code> or if any portion of the
* requested data is not in the cache (including if
* <code>pos</code> is in a block that has already been disposed).
*/
public void read(byte[] b, int off, int len, long pos)
throws IOException {
if (b == null) {
throw new NullPointerException("b == null!");
}
// Fix 4430357 - if off + len < 0, overflow occurred
if ((off < 0) || (len < 0) || (pos < 0) ||
(off + len > b.length) || (off + len < 0)) {
throw new IndexOutOfBoundsException();
}
if (pos + len > length) {
throw new IndexOutOfBoundsException();
}
long index = pos/BUFFER_LENGTH;
int offset = (int)pos % BUFFER_LENGTH;
while (len > 0) {
int nbytes = Math.min(len, BUFFER_LENGTH - offset);
byte[] buf = getCacheBlock(index++);
System.arraycopy(buf, offset, b, off, nbytes);
len -= nbytes;
off += nbytes;
offset = 0; // Always after the first time
}
}
/**
* Free the blocks up to the position <code>pos</code>.
* The byte at <code>pos</code> remains available.
*
* @exception IndexOutOfBoundsException if <code>pos</code>
* is in a block that has already been disposed.
*/
public void disposeBefore(long pos) {
long index = pos/BUFFER_LENGTH;
if (index < cacheStart) {
throw new IndexOutOfBoundsException("pos already disposed");
}
long numBlocks = Math.min(index - cacheStart, cache.size());
for (long i = 0; i < numBlocks; i++) {
cache.remove(0);
}
this.cacheStart = index;
}
/**
* Erase the entire cache contents and reset the length to 0.
* The cache object may subsequently be reused as though it had just
* been allocated.
*/
public void reset() {
cache.clear();
cacheStart = 0;
length = 0L;
}
}

View File

@@ -0,0 +1,202 @@
/*
* Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.stream;
import java.io.InputStream;
import java.io.IOException;
import com.sun.imageio.stream.StreamFinalizer;
import sun.java2d.Disposer;
import sun.java2d.DisposerRecord;
/**
* An implementation of <code>ImageInputStream</code> that gets its
* input from a regular <code>InputStream</code>. A memory buffer is
* used to cache at least the data between the discard position and
* the current read position.
*
* <p> In general, it is preferable to use a
* <code>FileCacheImageInputStream</code> when reading from a regular
* <code>InputStream</code>. This class is provided for cases where
* it is not possible to create a writable temporary file.
*
*/
public class MemoryCacheImageInputStream extends ImageInputStreamImpl {
private InputStream stream;
private MemoryCache cache = new MemoryCache();
/** The referent to be registered with the Disposer. */
private final Object disposerReferent;
/** The DisposerRecord that resets the underlying MemoryCache. */
private final DisposerRecord disposerRecord;
/**
* Constructs a <code>MemoryCacheImageInputStream</code> that will read
* from a given <code>InputStream</code>.
*
* @param stream an <code>InputStream</code> to read from.
*
* @exception IllegalArgumentException if <code>stream</code> is
* <code>null</code>.
*/
public MemoryCacheImageInputStream(InputStream stream) {
if (stream == null) {
throw new IllegalArgumentException("stream == null!");
}
this.stream = stream;
disposerRecord = new StreamDisposerRecord(cache);
if (getClass() == MemoryCacheImageInputStream.class) {
disposerReferent = new Object();
Disposer.addRecord(disposerReferent, disposerRecord);
} else {
disposerReferent = new StreamFinalizer(this);
}
}
public int read() throws IOException {
checkClosed();
bitOffset = 0;
long pos = cache.loadFromStream(stream, streamPos+1);
if (pos >= streamPos+1) {
return cache.read(streamPos++);
} else {
return -1;
}
}
public int read(byte[] b, int off, int len) throws IOException {
checkClosed();
if (b == null) {
throw new NullPointerException("b == null!");
}
if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off+len > b.length || off+len < 0!");
}
bitOffset = 0;
if (len == 0) {
return 0;
}
long pos = cache.loadFromStream(stream, streamPos+len);
len = (int)(pos - streamPos); // In case stream ended early
if (len > 0) {
cache.read(b, off, len, streamPos);
streamPos += len;
return len;
} else {
return -1;
}
}
public void flushBefore(long pos) throws IOException {
super.flushBefore(pos); // this will call checkClosed() for us
cache.disposeBefore(pos);
}
/**
* Returns <code>true</code> since this
* <code>ImageInputStream</code> caches data in order to allow
* seeking backwards.
*
* @return <code>true</code>.
*
* @see #isCachedMemory
* @see #isCachedFile
*/
public boolean isCached() {
return true;
}
/**
* Returns <code>false</code> since this
* <code>ImageInputStream</code> does not maintain a file cache.
*
* @return <code>false</code>.
*
* @see #isCached
* @see #isCachedMemory
*/
public boolean isCachedFile() {
return false;
}
/**
* Returns <code>true</code> since this
* <code>ImageInputStream</code> maintains a main memory cache.
*
* @return <code>true</code>.
*
* @see #isCached
* @see #isCachedFile
*/
public boolean isCachedMemory() {
return true;
}
/**
* Closes this <code>MemoryCacheImageInputStream</code>, freeing
* the cache. The source <code>InputStream</code> is not closed.
*/
public void close() throws IOException {
super.close();
disposerRecord.dispose(); // this resets the MemoryCache
stream = null;
cache = null;
}
/**
* {@inheritDoc}
*/
protected void finalize() throws Throwable {
// Empty finalizer: for performance reasons we instead use the
// Disposer mechanism for ensuring that the underlying
// MemoryCache is reset prior to garbage collection
}
private static class StreamDisposerRecord implements DisposerRecord {
private MemoryCache cache;
public StreamDisposerRecord(MemoryCache cache) {
this.cache = cache;
}
public synchronized void dispose() {
if (cache != null) {
cache.reset();
cache = null;
}
}
}
}

View File

@@ -0,0 +1,196 @@
/*
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.imageio.stream;
import java.io.IOException;
import java.io.OutputStream;
/**
* An implementation of <code>ImageOutputStream</code> that writes its
* output to a regular <code>OutputStream</code>. A memory buffer is
* used to cache at least the data between the discard position and
* the current write position. The only constructor takes an
* <code>OutputStream</code>, so this class may not be used for
* read/modify/write operations. Reading can occur only on parts of
* the stream that have already been written to the cache and not
* yet flushed.
*
*/
public class MemoryCacheImageOutputStream extends ImageOutputStreamImpl {
private OutputStream stream;
private MemoryCache cache = new MemoryCache();
/**
* Constructs a <code>MemoryCacheImageOutputStream</code> that will write
* to a given <code>OutputStream</code>.
*
* @param stream an <code>OutputStream</code> to write to.
*
* @exception IllegalArgumentException if <code>stream</code> is
* <code>null</code>.
*/
public MemoryCacheImageOutputStream(OutputStream stream) {
if (stream == null) {
throw new IllegalArgumentException("stream == null!");
}
this.stream = stream;
}
public int read() throws IOException {
checkClosed();
bitOffset = 0;
int val = cache.read(streamPos);
if (val != -1) {
++streamPos;
}
return val;
}
public int read(byte[] b, int off, int len) throws IOException {
checkClosed();
if (b == null) {
throw new NullPointerException("b == null!");
}
// Fix 4467608: read([B,I,I) works incorrectly if len<=0
if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
throw new IndexOutOfBoundsException
("off < 0 || len < 0 || off+len > b.length || off+len < 0!");
}
bitOffset = 0;
if (len == 0) {
return 0;
}
// check if we're already at/past EOF i.e.
// no more bytes left to read from cache
long bytesLeftInCache = cache.getLength() - streamPos;
if (bytesLeftInCache <= 0) {
return -1; // EOF
}
// guaranteed by now that bytesLeftInCache > 0 && len > 0
// and so the rest of the error checking is done by cache.read()
// NOTE that alot of error checking is duplicated
len = (int)Math.min(bytesLeftInCache, (long)len);
cache.read(b, off, len, streamPos);
streamPos += len;
return len;
}
public void write(int b) throws IOException {
flushBits(); // this will call checkClosed() for us
cache.write(b, streamPos);
++streamPos;
}
public void write(byte[] b, int off, int len) throws IOException {
flushBits(); // this will call checkClosed() for us
cache.write(b, off, len, streamPos);
streamPos += len;
}
public long length() {
try {
checkClosed();
return cache.getLength();
} catch (IOException e) {
return -1L;
}
}
/**
* Returns <code>true</code> since this
* <code>ImageOutputStream</code> caches data in order to allow
* seeking backwards.
*
* @return <code>true</code>.
*
* @see #isCachedMemory
* @see #isCachedFile
*/
public boolean isCached() {
return true;
}
/**
* Returns <code>false</code> since this
* <code>ImageOutputStream</code> does not maintain a file cache.
*
* @return <code>false</code>.
*
* @see #isCached
* @see #isCachedMemory
*/
public boolean isCachedFile() {
return false;
}
/**
* Returns <code>true</code> since this
* <code>ImageOutputStream</code> maintains a main memory cache.
*
* @return <code>true</code>.
*
* @see #isCached
* @see #isCachedFile
*/
public boolean isCachedMemory() {
return true;
}
/**
* Closes this <code>MemoryCacheImageOutputStream</code>. All
* pending data is flushed to the output, and the cache
* is released. The destination <code>OutputStream</code>
* is not closed.
*/
public void close() throws IOException {
long length = cache.getLength();
seek(length);
flushBefore(length);
super.close();
cache.reset();
cache = null;
stream = null;
}
public void flushBefore(long pos) throws IOException {
long oFlushedPos = flushedPos;
super.flushBefore(pos); // this will call checkClosed() for us
long flushBytes = flushedPos - oFlushedPos;
cache.writeToStream(stream, oFlushedPos, flushBytes);
cache.disposeBefore(flushedPos);
stream.flush();
}
}