/* | 
|
 * 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.image.BufferedImage;  | 
|
import java.awt.image.RenderedImage;  | 
|
import java.io.File;  | 
|
import java.io.FilePermission;  | 
|
import java.io.InputStream;  | 
|
import java.io.IOException;  | 
|
import java.io.OutputStream;  | 
|
import java.lang.reflect.Method;  | 
|
import java.net.URL;  | 
|
import java.security.AccessController;  | 
|
import java.util.Arrays;  | 
|
import java.util.Collections;  | 
|
import java.util.HashSet;  | 
|
import java.util.Iterator;  | 
|
import java.util.NoSuchElementException;  | 
|
import java.util.Set;  | 
|
import javax.imageio.spi.IIORegistry;  | 
|
import javax.imageio.spi.ImageReaderSpi;  | 
|
import javax.imageio.spi.ImageReaderWriterSpi;  | 
|
import javax.imageio.spi.ImageWriterSpi;  | 
|
import javax.imageio.spi.ImageInputStreamSpi;  | 
|
import javax.imageio.spi.ImageOutputStreamSpi;  | 
|
import javax.imageio.spi.ImageTranscoderSpi;  | 
|
import javax.imageio.spi.ServiceRegistry;  | 
|
import javax.imageio.stream.ImageInputStream;  | 
|
import javax.imageio.stream.ImageOutputStream;  | 
|
import sun.awt.AppContext;  | 
|
import sun.security.action.GetPropertyAction;  | 
|
/** | 
|
 * A class containing static convenience methods for locating | 
|
 * <code>ImageReader</code>s and <code>ImageWriter</code>s, and | 
|
 * performing simple encoding and decoding. | 
|
 * | 
|
*/  | 
|
public final class ImageIO { | 
|
private static final IIORegistry theRegistry =  | 
|
IIORegistry.getDefaultInstance();  | 
|
    /** | 
|
     * Constructor is private to prevent instantiation. | 
|
*/  | 
|
    private ImageIO() {} | 
|
    /** | 
|
     * Scans for plug-ins on the application class path, | 
|
     * loads their service provider classes, and registers a service | 
|
     * provider instance for each one found with the | 
|
     * <code>IIORegistry</code>. | 
|
     * | 
|
     * <p>This method is needed because the application class path can | 
|
     * theoretically change, or additional plug-ins may become available. | 
|
     * Rather than re-scanning the classpath on every invocation of the | 
|
     * API, the class path is scanned automatically only on the first | 
|
     * invocation. Clients can call this method to prompt a re-scan. | 
|
     * Thus this method need only be invoked by sophisticated applications | 
|
     * which dynamically make new plug-ins available at runtime. | 
|
     * | 
|
     * <p> The <code>getResources</code> method of the context | 
|
     * <code>ClassLoader</code> is used locate JAR files containing | 
|
     * files named | 
|
     * <code>META-INF/services/javax.imageio.spi.</code><i>classname</i>, | 
|
     * where <i>classname</i> is one of <code>ImageReaderSpi</code>, | 
|
     * <code>ImageWriterSpi</code>, <code>ImageTranscoderSpi</code>, | 
|
     * <code>ImageInputStreamSpi</code>, or | 
|
     * <code>ImageOutputStreamSpi</code>, along the application class | 
|
     * path. | 
|
     * | 
|
     * <p> The contents of the located files indicate the names of | 
|
     * actual implementation classes which implement the | 
|
     * aforementioned service provider interfaces; the default class | 
|
     * loader is then used to load each of these classes and to | 
|
     * instantiate an instance of each class, which is then placed | 
|
     * into the registry for later retrieval. | 
|
     * | 
|
     * <p> The exact set of locations searched depends on the | 
|
     * implementation of the Java runtime environment. | 
|
     * | 
|
     * @see ClassLoader#getResources | 
|
*/  | 
|
    public static void scanForPlugins() { | 
|
theRegistry.registerApplicationClasspathSpis();  | 
|
}  | 
|
// ImageInputStreams  | 
|
    /** | 
|
     * A class to hold information about caching.  Each | 
|
     * <code>ThreadGroup</code> will have its own copy | 
|
     * via the <code>AppContext</code> mechanism. | 
|
*/  | 
|
    static class CacheInfo { | 
|
boolean useCache = true;  | 
|
File cacheDirectory = null;  | 
|
Boolean hasPermission = null;  | 
|
        public CacheInfo() {} | 
|
        public boolean getUseCache() { | 
|
return useCache;  | 
|
}  | 
|
        public void setUseCache(boolean useCache) { | 
|
this.useCache = useCache;  | 
|
}  | 
|
public File getCacheDirectory() {  | 
|
return cacheDirectory;  | 
|
}  | 
|
public void setCacheDirectory(File cacheDirectory) {  | 
|
this.cacheDirectory = cacheDirectory;  | 
|
}  | 
|
public Boolean getHasPermission() {  | 
|
return hasPermission;  | 
|
}  | 
|
public void setHasPermission(Boolean hasPermission) {  | 
|
this.hasPermission = hasPermission;  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns the <code>CacheInfo</code> object associated with this | 
|
     * <code>ThreadGroup</code>. | 
|
*/  | 
|
    private static synchronized CacheInfo getCacheInfo() { | 
|
AppContext context = AppContext.getAppContext();  | 
|
CacheInfo info = (CacheInfo)context.get(CacheInfo.class);  | 
|
if (info == null) {  | 
|
info = new CacheInfo();  | 
|
context.put(CacheInfo.class, info);  | 
|
}  | 
|
return info;  | 
|
}  | 
|
    /** | 
|
     * Returns the default temporary (cache) directory as defined by the | 
|
     * java.io.tmpdir system property. | 
|
*/  | 
|
private static String getTempDir() {  | 
|
GetPropertyAction a = new GetPropertyAction("java.io.tmpdir");  | 
|
return (String)AccessController.doPrivileged(a);  | 
|
}  | 
|
    /** | 
|
     * Determines whether the caller has write access to the cache | 
|
     * directory, stores the result in the <code>CacheInfo</code> object, | 
|
     * and returns the decision.  This method helps to prevent mysterious | 
|
     * SecurityExceptions to be thrown when this convenience class is used | 
|
     * in an applet, for example. | 
|
*/  | 
|
    private static boolean hasCachePermission() { | 
|
Boolean hasPermission = getCacheInfo().getHasPermission();  | 
|
if (hasPermission != null) {  | 
|
return hasPermission.booleanValue();  | 
|
        } else { | 
|
            try { | 
|
SecurityManager security = System.getSecurityManager();  | 
|
if (security != null) {  | 
|
File cachedir = getCacheDirectory();  | 
|
String cachepath;  | 
|
if (cachedir != null) {  | 
|
cachepath = cachedir.getPath();  | 
|
                    } else { | 
|
cachepath = getTempDir();  | 
|
if (cachepath == null || cachepath.isEmpty()) {  | 
|
getCacheInfo().setHasPermission(Boolean.FALSE);  | 
|
return false;  | 
|
}  | 
|
}  | 
|
// we have to check whether we can read, write,  | 
|
// and delete cache files.  | 
|
                    // So, compose cache file path and check it. | 
|
String filepath = cachepath;  | 
|
if (!filepath.endsWith(File.separator)) {  | 
|
filepath += File.separator;  | 
|
}  | 
|
filepath += "*";  | 
|
security.checkPermission(new FilePermission(filepath, "read, write, delete"));  | 
|
}  | 
|
} catch (SecurityException e) {  | 
|
getCacheInfo().setHasPermission(Boolean.FALSE);  | 
|
return false;  | 
|
}  | 
|
getCacheInfo().setHasPermission(Boolean.TRUE);  | 
|
return true;  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Sets a flag indicating whether a disk-based cache file should | 
|
     * be used when creating <code>ImageInputStream</code>s and | 
|
     * <code>ImageOutputStream</code>s. | 
|
     * | 
|
     * <p> When reading from a standard <code>InputStream</code>, it | 
|
     * may be necessary to save previously read information in a cache | 
|
     * since the underlying stream does not allow data to be re-read. | 
|
     * Similarly, when writing to a standard | 
|
     * <code>OutputStream</code>, a cache may be used to allow a | 
|
     * previously written value to be changed before flushing it to | 
|
     * the final destination. | 
|
     * | 
|
     * <p> The cache may reside in main memory or on disk.  Setting | 
|
     * this flag to <code>false</code> disallows the use of disk for | 
|
     * future streams, which may be advantageous when working with | 
|
     * small images, as the overhead of creating and destroying files | 
|
     * is removed. | 
|
     * | 
|
     * <p> On startup, the value is set to <code>true</code>. | 
|
     * | 
|
     * @param useCache a <code>boolean</code> indicating whether a | 
|
     * cache file should be used, in cases where it is optional. | 
|
     * | 
|
     * @see #getUseCache | 
|
*/  | 
|
    public static void setUseCache(boolean useCache) { | 
|
getCacheInfo().setUseCache(useCache);  | 
|
}  | 
|
    /** | 
|
     * Returns the current value set by <code>setUseCache</code>, or | 
|
     * <code>true</code> if no explicit setting has been made. | 
|
     * | 
|
     * @return true if a disk-based cache may be used for | 
|
     * <code>ImageInputStream</code>s and | 
|
     * <code>ImageOutputStream</code>s. | 
|
     * | 
|
     * @see #setUseCache | 
|
*/  | 
|
    public static boolean getUseCache() { | 
|
return getCacheInfo().getUseCache();  | 
|
}  | 
|
    /** | 
|
     * Sets the directory where cache files are to be created.  A | 
|
     * value of <code>null</code> indicates that the system-dependent | 
|
     * default temporary-file directory is to be used.  If | 
|
     * <code>getUseCache</code> returns false, this value is ignored. | 
|
     * | 
|
     * @param cacheDirectory a <code>File</code> specifying a directory. | 
|
     * | 
|
     * @see File#createTempFile(String, String, File) | 
|
     * | 
|
     * @exception SecurityException if the security manager denies | 
|
     * access to the directory. | 
|
     * @exception IllegalArgumentException if <code>cacheDir</code> is | 
|
     * non-<code>null</code> but is not a directory. | 
|
     * | 
|
     * @see #getCacheDirectory | 
|
*/  | 
|
public static void setCacheDirectory(File cacheDirectory) {  | 
|
if ((cacheDirectory != null) && !(cacheDirectory.isDirectory())) {  | 
|
throw new IllegalArgumentException("Not a directory!");  | 
|
}  | 
|
getCacheInfo().setCacheDirectory(cacheDirectory);  | 
|
getCacheInfo().setHasPermission(null);  | 
|
}  | 
|
    /** | 
|
     * Returns the current value set by | 
|
     * <code>setCacheDirectory</code>, or <code>null</code> if no | 
|
     * explicit setting has been made. | 
|
     * | 
|
     * @return a <code>File</code> indicating the directory where | 
|
     * cache files will be created, or <code>null</code> to indicate | 
|
     * the system-dependent default temporary-file directory. | 
|
     * | 
|
     * @see #setCacheDirectory | 
|
*/  | 
|
public static File getCacheDirectory() {  | 
|
return getCacheInfo().getCacheDirectory();  | 
|
}  | 
|
    /** | 
|
     * Returns an <code>ImageInputStream</code> that will take its | 
|
     * input from the given <code>Object</code>.  The set of | 
|
     * <code>ImageInputStreamSpi</code>s registered with the | 
|
     * <code>IIORegistry</code> class is queried and the first one | 
|
     * that is able to take input from the supplied object is used to | 
|
     * create the returned <code>ImageInputStream</code>.  If no | 
|
     * suitable <code>ImageInputStreamSpi</code> exists, | 
|
     * <code>null</code> is returned. | 
|
     * | 
|
     * <p> The current cache settings from <code>getUseCache</code>and | 
|
     * <code>getCacheDirectory</code> will be used to control caching. | 
|
     * | 
|
     * @param input an <code>Object</code> to be used as an input | 
|
     * source, such as a <code>File</code>, readable | 
|
     * <code>RandomAccessFile</code>, or <code>InputStream</code>. | 
|
     * | 
|
     * @return an <code>ImageInputStream</code>, or <code>null</code>. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>input</code> | 
|
     * is <code>null</code>. | 
|
     * @exception IOException if a cache file is needed but cannot be | 
|
     * created. | 
|
     * | 
|
     * @see javax.imageio.spi.ImageInputStreamSpi | 
|
*/  | 
|
public static ImageInputStream createImageInputStream(Object input)  | 
|
throws IOException {  | 
|
if (input == null) {  | 
|
throw new IllegalArgumentException("input == null!");  | 
|
}  | 
|
Iterator iter;  | 
|
        // Ensure category is present | 
|
        try { | 
|
iter = theRegistry.getServiceProviders(ImageInputStreamSpi.class,  | 
|
true);  | 
|
} catch (IllegalArgumentException e) {  | 
|
return null;  | 
|
}  | 
|
boolean usecache = getUseCache() && hasCachePermission();  | 
|
while (iter.hasNext()) {  | 
|
ImageInputStreamSpi spi = (ImageInputStreamSpi)iter.next();  | 
|
if (spi.getInputClass().isInstance(input)) {  | 
|
                try { | 
|
return spi.createInputStreamInstance(input,  | 
|
usecache,  | 
|
getCacheDirectory());  | 
|
} catch (IOException e) {  | 
|
throw new IIOException("Can't create cache file!", e);  | 
|
}  | 
|
}  | 
|
}  | 
|
return null;  | 
|
}  | 
|
// ImageOutputStreams  | 
|
    /** | 
|
     * Returns an <code>ImageOutputStream</code> that will send its | 
|
     * output to the given <code>Object</code>.  The set of | 
|
     * <code>ImageOutputStreamSpi</code>s registered with the | 
|
     * <code>IIORegistry</code> class is queried and the first one | 
|
     * that is able to send output from the supplied object is used to | 
|
     * create the returned <code>ImageOutputStream</code>.  If no | 
|
     * suitable <code>ImageOutputStreamSpi</code> exists, | 
|
     * <code>null</code> is returned. | 
|
     * | 
|
     * <p> The current cache settings from <code>getUseCache</code>and | 
|
     * <code>getCacheDirectory</code> will be used to control caching. | 
|
     * | 
|
     * @param output an <code>Object</code> to be used as an output | 
|
     * destination, such as a <code>File</code>, writable | 
|
     * <code>RandomAccessFile</code>, or <code>OutputStream</code>. | 
|
     * | 
|
     * @return an <code>ImageOutputStream</code>, or | 
|
     * <code>null</code>. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>output</code> is | 
|
     * <code>null</code>. | 
|
     * @exception IOException if a cache file is needed but cannot be | 
|
     * created. | 
|
     * | 
|
     * @see javax.imageio.spi.ImageOutputStreamSpi | 
|
*/  | 
|
public static ImageOutputStream createImageOutputStream(Object output)  | 
|
throws IOException {  | 
|
if (output == null) {  | 
|
throw new IllegalArgumentException("output == null!");  | 
|
}  | 
|
Iterator iter;  | 
|
        // Ensure category is present | 
|
        try { | 
|
iter = theRegistry.getServiceProviders(ImageOutputStreamSpi.class,  | 
|
true);  | 
|
} catch (IllegalArgumentException e) {  | 
|
return null;  | 
|
}  | 
|
boolean usecache = getUseCache() && hasCachePermission();  | 
|
while (iter.hasNext()) {  | 
|
ImageOutputStreamSpi spi = (ImageOutputStreamSpi)iter.next();  | 
|
if (spi.getOutputClass().isInstance(output)) {  | 
|
                try { | 
|
return spi.createOutputStreamInstance(output,  | 
|
usecache,  | 
|
getCacheDirectory());  | 
|
} catch (IOException e) {  | 
|
throw new IIOException("Can't create cache file!", e);  | 
|
}  | 
|
}  | 
|
}  | 
|
return null;  | 
|
}  | 
|
    private static enum SpiInfo { | 
|
        FORMAT_NAMES { | 
|
@Override  | 
|
String[] info(ImageReaderWriterSpi spi) {  | 
|
return spi.getFormatNames();  | 
|
}  | 
|
},  | 
|
        MIME_TYPES { | 
|
@Override  | 
|
String[] info(ImageReaderWriterSpi spi) {  | 
|
return spi.getMIMETypes();  | 
|
}  | 
|
},  | 
|
        FILE_SUFFIXES { | 
|
@Override  | 
|
String[] info(ImageReaderWriterSpi spi) {  | 
|
return spi.getFileSuffixes();  | 
|
}  | 
|
};  | 
|
abstract String[] info(ImageReaderWriterSpi spi);  | 
|
}  | 
|
private static <S extends ImageReaderWriterSpi>  | 
|
String[] getReaderWriterInfo(Class<S> spiClass, SpiInfo spiInfo)  | 
|
    { | 
|
        // Ensure category is present | 
|
Iterator<S> iter;  | 
|
        try { | 
|
iter = theRegistry.getServiceProviders(spiClass, true);  | 
|
} catch (IllegalArgumentException e) {  | 
|
return new String[0];  | 
|
}  | 
|
HashSet<String> s = new HashSet<String>();  | 
|
while (iter.hasNext()) {  | 
|
ImageReaderWriterSpi spi = iter.next();  | 
|
Collections.addAll(s, spiInfo.info(spi));  | 
|
}  | 
|
return s.toArray(new String[s.size()]);  | 
|
}  | 
|
// Readers  | 
|
    /** | 
|
     * Returns an array of <code>String</code>s listing all of the | 
|
     * informal format names understood by the current set of registered | 
|
     * readers. | 
|
     * | 
|
     * @return an array of <code>String</code>s. | 
|
*/  | 
|
public static String[] getReaderFormatNames() {  | 
|
return getReaderWriterInfo(ImageReaderSpi.class,  | 
|
SpiInfo.FORMAT_NAMES);  | 
|
}  | 
|
    /** | 
|
     * Returns an array of <code>String</code>s listing all of the | 
|
     * MIME types understood by the current set of registered | 
|
     * readers. | 
|
     * | 
|
     * @return an array of <code>String</code>s. | 
|
*/  | 
|
public static String[] getReaderMIMETypes() {  | 
|
return getReaderWriterInfo(ImageReaderSpi.class,  | 
|
SpiInfo.MIME_TYPES);  | 
|
}  | 
|
    /** | 
|
     * Returns an array of <code>String</code>s listing all of the | 
|
     * file suffixes associated with the formats understood | 
|
     * by the current set of registered readers. | 
|
     * | 
|
     * @return an array of <code>String</code>s. | 
|
     * @since 1.6 | 
|
*/  | 
|
public static String[] getReaderFileSuffixes() {  | 
|
return getReaderWriterInfo(ImageReaderSpi.class,  | 
|
SpiInfo.FILE_SUFFIXES);  | 
|
}  | 
|
static class ImageReaderIterator implements Iterator<ImageReader> {  | 
|
        // Contains ImageReaderSpis | 
|
public Iterator iter;  | 
|
public ImageReaderIterator(Iterator iter) {  | 
|
this.iter = iter;  | 
|
}  | 
|
        public boolean hasNext() { | 
|
return iter.hasNext();  | 
|
}  | 
|
public ImageReader next() {  | 
|
ImageReaderSpi spi = null;  | 
|
            try { | 
|
spi = (ImageReaderSpi)iter.next();  | 
|
return spi.createReaderInstance();  | 
|
} catch (IOException e) {  | 
|
// Deregister the spi in this case, but only as  | 
|
                // an ImageReaderSpi | 
|
theRegistry.deregisterServiceProvider(spi, ImageReaderSpi.class);  | 
|
}  | 
|
return null;  | 
|
}  | 
|
        public void remove() { | 
|
throw new UnsupportedOperationException();  | 
|
}  | 
|
}  | 
|
static class CanDecodeInputFilter  | 
|
implements ServiceRegistry.Filter {  | 
|
Object input;  | 
|
public CanDecodeInputFilter(Object input) {  | 
|
this.input = input;  | 
|
}  | 
|
public boolean filter(Object elt) {  | 
|
            try { | 
|
ImageReaderSpi spi = (ImageReaderSpi)elt;  | 
|
ImageInputStream stream = null;  | 
|
if (input instanceof ImageInputStream) {  | 
|
stream = (ImageInputStream)input;  | 
|
}  | 
|
// Perform mark/reset as a defensive measure  | 
|
// even though plug-ins are supposed to take  | 
|
                // care of it. | 
|
boolean canDecode = false;  | 
|
if (stream != null) {  | 
|
stream.mark();  | 
|
}  | 
|
canDecode = spi.canDecodeInput(input);  | 
|
if (stream != null) {  | 
|
stream.reset();  | 
|
}  | 
|
return canDecode;  | 
|
} catch (IOException e) {  | 
|
return false;  | 
|
}  | 
|
}  | 
|
}  | 
|
static class CanEncodeImageAndFormatFilter  | 
|
implements ServiceRegistry.Filter {  | 
|
ImageTypeSpecifier type;  | 
|
String formatName;  | 
|
public CanEncodeImageAndFormatFilter(ImageTypeSpecifier type,  | 
|
String formatName) {  | 
|
this.type = type;  | 
|
this.formatName = formatName;  | 
|
}  | 
|
public boolean filter(Object elt) {  | 
|
ImageWriterSpi spi = (ImageWriterSpi)elt;  | 
|
return Arrays.asList(spi.getFormatNames()).contains(formatName) &&  | 
|
spi.canEncodeImage(type);  | 
|
}  | 
|
}  | 
|
static class ContainsFilter  | 
|
implements ServiceRegistry.Filter {  | 
|
Method method;  | 
|
String name;  | 
|
        // method returns an array of Strings | 
|
public ContainsFilter(Method method,  | 
|
String name) {  | 
|
this.method = method;  | 
|
this.name = name;  | 
|
}  | 
|
public boolean filter(Object elt) {  | 
|
            try { | 
|
return contains((String[])method.invoke(elt), name);  | 
|
} catch (Exception e) {  | 
|
return false;  | 
|
}  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns an <code>Iterator</code> containing all currently | 
|
     * registered <code>ImageReader</code>s that claim to be able to | 
|
     * decode the supplied <code>Object</code>, typically an | 
|
     * <code>ImageInputStream</code>. | 
|
     * | 
|
     * <p> The stream position is left at its prior position upon | 
|
     * exit from this method. | 
|
     * | 
|
     * @param input an <code>ImageInputStream</code> or other | 
|
     * <code>Object</code> containing encoded image data. | 
|
     * | 
|
     * @return an <code>Iterator</code> containing <code>ImageReader</code>s. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>input</code> is | 
|
     * <code>null</code>. | 
|
     * | 
|
     * @see javax.imageio.spi.ImageReaderSpi#canDecodeInput | 
|
*/  | 
|
public static Iterator<ImageReader> getImageReaders(Object input) {  | 
|
if (input == null) {  | 
|
throw new IllegalArgumentException("input == null!");  | 
|
}  | 
|
Iterator iter;  | 
|
        // Ensure category is present | 
|
        try { | 
|
iter = theRegistry.getServiceProviders(ImageReaderSpi.class,  | 
|
new CanDecodeInputFilter(input),  | 
|
true);  | 
|
} catch (IllegalArgumentException e) {  | 
|
return Collections.emptyIterator();  | 
|
}  | 
|
return new ImageReaderIterator(iter);  | 
|
}  | 
|
private static Method readerFormatNamesMethod;  | 
|
private static Method readerFileSuffixesMethod;  | 
|
private static Method readerMIMETypesMethod;  | 
|
private static Method writerFormatNamesMethod;  | 
|
private static Method writerFileSuffixesMethod;  | 
|
private static Method writerMIMETypesMethod;  | 
|
    static { | 
|
        try { | 
|
readerFormatNamesMethod =  | 
|
ImageReaderSpi.class.getMethod("getFormatNames");  | 
|
readerFileSuffixesMethod =  | 
|
ImageReaderSpi.class.getMethod("getFileSuffixes");  | 
|
readerMIMETypesMethod =  | 
|
ImageReaderSpi.class.getMethod("getMIMETypes");  | 
|
writerFormatNamesMethod =  | 
|
ImageWriterSpi.class.getMethod("getFormatNames");  | 
|
writerFileSuffixesMethod =  | 
|
ImageWriterSpi.class.getMethod("getFileSuffixes");  | 
|
writerMIMETypesMethod =  | 
|
ImageWriterSpi.class.getMethod("getMIMETypes");  | 
|
} catch (NoSuchMethodException e) {  | 
|
e.printStackTrace();  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns an <code>Iterator</code> containing all currently | 
|
     * registered <code>ImageReader</code>s that claim to be able to | 
|
     * decode the named format. | 
|
     * | 
|
     * @param formatName a <code>String</code> containing the informal | 
|
     * name of a format (<i>e.g.</i>, "jpeg" or "tiff". | 
|
     * | 
|
     * @return an <code>Iterator</code> containing | 
|
     * <code>ImageReader</code>s. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>formatName</code> | 
|
     * is <code>null</code>. | 
|
     * | 
|
     * @see javax.imageio.spi.ImageReaderSpi#getFormatNames | 
|
*/  | 
|
public static Iterator<ImageReader>  | 
|
getImageReadersByFormatName(String formatName)  | 
|
    { | 
|
if (formatName == null) {  | 
|
throw new IllegalArgumentException("formatName == null!");  | 
|
}  | 
|
Iterator iter;  | 
|
        // Ensure category is present | 
|
        try { | 
|
iter = theRegistry.getServiceProviders(ImageReaderSpi.class,  | 
|
new ContainsFilter(readerFormatNamesMethod,  | 
|
formatName),  | 
|
true);  | 
|
} catch (IllegalArgumentException e) {  | 
|
return Collections.emptyIterator();  | 
|
}  | 
|
return new ImageReaderIterator(iter);  | 
|
}  | 
|
    /** | 
|
     * Returns an <code>Iterator</code> containing all currently | 
|
     * registered <code>ImageReader</code>s that claim to be able to | 
|
     * decode files with the given suffix. | 
|
     * | 
|
     * @param fileSuffix a <code>String</code> containing a file | 
|
     * suffix (<i>e.g.</i>, "jpg" or "tiff"). | 
|
     * | 
|
     * @return an <code>Iterator</code> containing | 
|
     * <code>ImageReader</code>s. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>fileSuffix</code> | 
|
     * is <code>null</code>. | 
|
     * | 
|
     * @see javax.imageio.spi.ImageReaderSpi#getFileSuffixes | 
|
*/  | 
|
public static Iterator<ImageReader>  | 
|
getImageReadersBySuffix(String fileSuffix)  | 
|
    { | 
|
if (fileSuffix == null) {  | 
|
throw new IllegalArgumentException("fileSuffix == null!");  | 
|
}  | 
|
        // Ensure category is present | 
|
Iterator iter;  | 
|
        try { | 
|
iter = theRegistry.getServiceProviders(ImageReaderSpi.class,  | 
|
new ContainsFilter(readerFileSuffixesMethod,  | 
|
fileSuffix),  | 
|
true);  | 
|
} catch (IllegalArgumentException e) {  | 
|
return Collections.emptyIterator();  | 
|
}  | 
|
return new ImageReaderIterator(iter);  | 
|
}  | 
|
    /** | 
|
     * Returns an <code>Iterator</code> containing all currently | 
|
     * registered <code>ImageReader</code>s that claim to be able to | 
|
     * decode files with the given MIME type. | 
|
     * | 
|
     * @param MIMEType a <code>String</code> containing a file | 
|
     * suffix (<i>e.g.</i>, "image/jpeg" or "image/x-bmp"). | 
|
     * | 
|
     * @return an <code>Iterator</code> containing | 
|
     * <code>ImageReader</code>s. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>MIMEType</code> is | 
|
     * <code>null</code>. | 
|
     * | 
|
     * @see javax.imageio.spi.ImageReaderSpi#getMIMETypes | 
|
*/  | 
|
public static Iterator<ImageReader>  | 
|
getImageReadersByMIMEType(String MIMEType)  | 
|
    { | 
|
if (MIMEType == null) {  | 
|
throw new IllegalArgumentException("MIMEType == null!");  | 
|
}  | 
|
        // Ensure category is present | 
|
Iterator iter;  | 
|
        try { | 
|
iter = theRegistry.getServiceProviders(ImageReaderSpi.class,  | 
|
new ContainsFilter(readerMIMETypesMethod,  | 
|
MIMEType),  | 
|
true);  | 
|
} catch (IllegalArgumentException e) {  | 
|
return Collections.emptyIterator();  | 
|
}  | 
|
return new ImageReaderIterator(iter);  | 
|
}  | 
|
// Writers  | 
|
    /** | 
|
     * Returns an array of <code>String</code>s listing all of the | 
|
     * informal format names understood by the current set of registered | 
|
     * writers. | 
|
     * | 
|
     * @return an array of <code>String</code>s. | 
|
*/  | 
|
public static String[] getWriterFormatNames() {  | 
|
return getReaderWriterInfo(ImageWriterSpi.class,  | 
|
SpiInfo.FORMAT_NAMES);  | 
|
}  | 
|
    /** | 
|
     * Returns an array of <code>String</code>s listing all of the | 
|
     * MIME types understood by the current set of registered | 
|
     * writers. | 
|
     * | 
|
     * @return an array of <code>String</code>s. | 
|
*/  | 
|
public static String[] getWriterMIMETypes() {  | 
|
return getReaderWriterInfo(ImageWriterSpi.class,  | 
|
SpiInfo.MIME_TYPES);  | 
|
}  | 
|
    /** | 
|
     * Returns an array of <code>String</code>s listing all of the | 
|
     * file suffixes associated with the formats understood | 
|
     * by the current set of registered writers. | 
|
     * | 
|
     * @return an array of <code>String</code>s. | 
|
     * @since 1.6 | 
|
*/  | 
|
public static String[] getWriterFileSuffixes() {  | 
|
return getReaderWriterInfo(ImageWriterSpi.class,  | 
|
SpiInfo.FILE_SUFFIXES);  | 
|
}  | 
|
static class ImageWriterIterator implements Iterator<ImageWriter> {  | 
|
        // Contains ImageWriterSpis | 
|
public Iterator iter;  | 
|
public ImageWriterIterator(Iterator iter) {  | 
|
this.iter = iter;  | 
|
}  | 
|
        public boolean hasNext() { | 
|
return iter.hasNext();  | 
|
}  | 
|
public ImageWriter next() {  | 
|
ImageWriterSpi spi = null;  | 
|
            try { | 
|
spi = (ImageWriterSpi)iter.next();  | 
|
return spi.createWriterInstance();  | 
|
} catch (IOException e) {  | 
|
                // Deregister the spi in this case, but only as a writerSpi | 
|
theRegistry.deregisterServiceProvider(spi, ImageWriterSpi.class);  | 
|
}  | 
|
return null;  | 
|
}  | 
|
        public void remove() { | 
|
throw new UnsupportedOperationException();  | 
|
}  | 
|
}  | 
|
private static boolean contains(String[] names, String name) {  | 
|
for (int i = 0; i < names.length; i++) {  | 
|
if (name.equalsIgnoreCase(names[i])) {  | 
|
return true;  | 
|
}  | 
|
}  | 
|
return false;  | 
|
}  | 
|
    /** | 
|
     * Returns an <code>Iterator</code> containing all currently | 
|
     * registered <code>ImageWriter</code>s that claim to be able to | 
|
     * encode the named format. | 
|
     * | 
|
     * @param formatName a <code>String</code> containing the informal | 
|
     * name of a format (<i>e.g.</i>, "jpeg" or "tiff". | 
|
     * | 
|
     * @return an <code>Iterator</code> containing | 
|
     * <code>ImageWriter</code>s. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>formatName</code> is | 
|
     * <code>null</code>. | 
|
     * | 
|
     * @see javax.imageio.spi.ImageWriterSpi#getFormatNames | 
|
*/  | 
|
public static Iterator<ImageWriter>  | 
|
getImageWritersByFormatName(String formatName)  | 
|
    { | 
|
if (formatName == null) {  | 
|
throw new IllegalArgumentException("formatName == null!");  | 
|
}  | 
|
Iterator iter;  | 
|
        // Ensure category is present | 
|
        try { | 
|
iter = theRegistry.getServiceProviders(ImageWriterSpi.class,  | 
|
new ContainsFilter(writerFormatNamesMethod,  | 
|
formatName),  | 
|
true);  | 
|
} catch (IllegalArgumentException e) {  | 
|
return Collections.emptyIterator();  | 
|
}  | 
|
return new ImageWriterIterator(iter);  | 
|
}  | 
|
    /** | 
|
     * Returns an <code>Iterator</code> containing all currently | 
|
     * registered <code>ImageWriter</code>s that claim to be able to | 
|
     * encode files with the given suffix. | 
|
     * | 
|
     * @param fileSuffix a <code>String</code> containing a file | 
|
     * suffix (<i>e.g.</i>, "jpg" or "tiff"). | 
|
     * | 
|
     * @return an <code>Iterator</code> containing <code>ImageWriter</code>s. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>fileSuffix</code> is | 
|
     * <code>null</code>. | 
|
     * | 
|
     * @see javax.imageio.spi.ImageWriterSpi#getFileSuffixes | 
|
*/  | 
|
public static Iterator<ImageWriter>  | 
|
getImageWritersBySuffix(String fileSuffix)  | 
|
    { | 
|
if (fileSuffix == null) {  | 
|
throw new IllegalArgumentException("fileSuffix == null!");  | 
|
}  | 
|
Iterator iter;  | 
|
        // Ensure category is present | 
|
        try { | 
|
iter = theRegistry.getServiceProviders(ImageWriterSpi.class,  | 
|
new ContainsFilter(writerFileSuffixesMethod,  | 
|
fileSuffix),  | 
|
true);  | 
|
} catch (IllegalArgumentException e) {  | 
|
return Collections.emptyIterator();  | 
|
}  | 
|
return new ImageWriterIterator(iter);  | 
|
}  | 
|
    /** | 
|
     * Returns an <code>Iterator</code> containing all currently | 
|
     * registered <code>ImageWriter</code>s that claim to be able to | 
|
     * encode files with the given MIME type. | 
|
     * | 
|
     * @param MIMEType a <code>String</code> containing a file | 
|
     * suffix (<i>e.g.</i>, "image/jpeg" or "image/x-bmp"). | 
|
     * | 
|
     * @return an <code>Iterator</code> containing <code>ImageWriter</code>s. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>MIMEType</code> is | 
|
     * <code>null</code>. | 
|
     * | 
|
     * @see javax.imageio.spi.ImageWriterSpi#getMIMETypes | 
|
*/  | 
|
public static Iterator<ImageWriter>  | 
|
getImageWritersByMIMEType(String MIMEType)  | 
|
    { | 
|
if (MIMEType == null) {  | 
|
throw new IllegalArgumentException("MIMEType == null!");  | 
|
}  | 
|
Iterator iter;  | 
|
        // Ensure category is present | 
|
        try { | 
|
iter = theRegistry.getServiceProviders(ImageWriterSpi.class,  | 
|
new ContainsFilter(writerMIMETypesMethod,  | 
|
MIMEType),  | 
|
true);  | 
|
} catch (IllegalArgumentException e) {  | 
|
return Collections.emptyIterator();  | 
|
}  | 
|
return new ImageWriterIterator(iter);  | 
|
}  | 
|
    /** | 
|
     * Returns an <code>ImageWriter</code>corresponding to the given | 
|
     * <code>ImageReader</code>, if there is one, or <code>null</code> | 
|
     * if the plug-in for this <code>ImageReader</code> does not | 
|
     * specify a corresponding <code>ImageWriter</code>, or if the | 
|
     * given <code>ImageReader</code> is not registered.  This | 
|
     * mechanism may be used to obtain an <code>ImageWriter</code> | 
|
     * that will understand the internal structure of non-pixel | 
|
     * metadata (as encoded by <code>IIOMetadata</code> objects) | 
|
     * generated by the <code>ImageReader</code>.  By obtaining this | 
|
     * data from the <code>ImageReader</code> and passing it on to the | 
|
     * <code>ImageWriter</code> obtained with this method, a client | 
|
     * program can read an image, modify it in some way, and write it | 
|
     * back out preserving all metadata, without having to understand | 
|
     * anything about the structure of the metadata, or even about | 
|
     * the image format.  Note that this method returns the | 
|
     * "preferred" writer, which is the first in the list returned by | 
|
     * <code>javax.imageio.spi.ImageReaderSpi.getImageWriterSpiNames()</code>. | 
|
     * | 
|
     * @param reader an instance of a registered <code>ImageReader</code>. | 
|
     * | 
|
     * @return an <code>ImageWriter</code>, or null. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>reader</code> is | 
|
     * <code>null</code>. | 
|
     * | 
|
     * @see #getImageReader(ImageWriter) | 
|
     * @see javax.imageio.spi.ImageReaderSpi#getImageWriterSpiNames() | 
|
*/  | 
|
public static ImageWriter getImageWriter(ImageReader reader) {  | 
|
if (reader == null) {  | 
|
throw new IllegalArgumentException("reader == null!");  | 
|
}  | 
|
ImageReaderSpi readerSpi = reader.getOriginatingProvider();  | 
|
if (readerSpi == null) {  | 
|
Iterator readerSpiIter;  | 
|
            // Ensure category is present | 
|
            try { | 
|
readerSpiIter =  | 
|
theRegistry.getServiceProviders(ImageReaderSpi.class,  | 
|
false);  | 
|
} catch (IllegalArgumentException e) {  | 
|
return null;  | 
|
}  | 
|
while (readerSpiIter.hasNext()) {  | 
|
ImageReaderSpi temp = (ImageReaderSpi) readerSpiIter.next();  | 
|
if (temp.isOwnReader(reader)) {  | 
|
readerSpi = temp;  | 
|
break;  | 
|
}  | 
|
}  | 
|
if (readerSpi == null) {  | 
|
return null;  | 
|
}  | 
|
}  | 
|
String[] writerNames = readerSpi.getImageWriterSpiNames();  | 
|
if (writerNames == null) {  | 
|
return null;  | 
|
}  | 
|
Class writerSpiClass = null;  | 
|
        try { | 
|
writerSpiClass = Class.forName(writerNames[0], true,  | 
|
ClassLoader.getSystemClassLoader());  | 
|
} catch (ClassNotFoundException e) {  | 
|
return null;  | 
|
}  | 
|
ImageWriterSpi writerSpi = (ImageWriterSpi)  | 
|
theRegistry.getServiceProviderByClass(writerSpiClass);  | 
|
if (writerSpi == null) {  | 
|
return null;  | 
|
}  | 
|
        try { | 
|
return writerSpi.createWriterInstance();  | 
|
} catch (IOException e) {  | 
|
            // Deregister the spi in this case, but only as a writerSpi | 
|
theRegistry.deregisterServiceProvider(writerSpi,  | 
|
ImageWriterSpi.class);  | 
|
return null;  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns an <code>ImageReader</code>corresponding to the given | 
|
     * <code>ImageWriter</code>, if there is one, or <code>null</code> | 
|
     * if the plug-in for this <code>ImageWriter</code> does not | 
|
     * specify a corresponding <code>ImageReader</code>, or if the | 
|
     * given <code>ImageWriter</code> is not registered.  This method | 
|
     * is provided principally for symmetry with | 
|
     * <code>getImageWriter(ImageReader)</code>.  Note that this | 
|
     * method returns the "preferred" reader, which is the first in | 
|
     * the list returned by | 
|
     * javax.imageio.spi.ImageWriterSpi.<code>getImageReaderSpiNames()</code>. | 
|
     * | 
|
     * @param writer an instance of a registered <code>ImageWriter</code>. | 
|
     * | 
|
     * @return an <code>ImageReader</code>, or null. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>writer</code> is | 
|
     * <code>null</code>. | 
|
     * | 
|
     * @see #getImageWriter(ImageReader) | 
|
     * @see javax.imageio.spi.ImageWriterSpi#getImageReaderSpiNames() | 
|
*/  | 
|
public static ImageReader getImageReader(ImageWriter writer) {  | 
|
if (writer == null) {  | 
|
throw new IllegalArgumentException("writer == null!");  | 
|
}  | 
|
ImageWriterSpi writerSpi = writer.getOriginatingProvider();  | 
|
if (writerSpi == null) {  | 
|
Iterator writerSpiIter;  | 
|
            // Ensure category is present | 
|
            try { | 
|
writerSpiIter =  | 
|
theRegistry.getServiceProviders(ImageWriterSpi.class,  | 
|
false);  | 
|
} catch (IllegalArgumentException e) {  | 
|
return null;  | 
|
}  | 
|
while (writerSpiIter.hasNext()) {  | 
|
ImageWriterSpi temp = (ImageWriterSpi) writerSpiIter.next();  | 
|
if (temp.isOwnWriter(writer)) {  | 
|
writerSpi = temp;  | 
|
break;  | 
|
}  | 
|
}  | 
|
if (writerSpi == null) {  | 
|
return null;  | 
|
}  | 
|
}  | 
|
String[] readerNames = writerSpi.getImageReaderSpiNames();  | 
|
if (readerNames == null) {  | 
|
return null;  | 
|
}  | 
|
Class readerSpiClass = null;  | 
|
        try { | 
|
readerSpiClass = Class.forName(readerNames[0], true,  | 
|
ClassLoader.getSystemClassLoader());  | 
|
} catch (ClassNotFoundException e) {  | 
|
return null;  | 
|
}  | 
|
ImageReaderSpi readerSpi = (ImageReaderSpi)  | 
|
theRegistry.getServiceProviderByClass(readerSpiClass);  | 
|
if (readerSpi == null) {  | 
|
return null;  | 
|
}  | 
|
        try { | 
|
return readerSpi.createReaderInstance();  | 
|
} catch (IOException e) {  | 
|
            // Deregister the spi in this case, but only as a readerSpi | 
|
theRegistry.deregisterServiceProvider(readerSpi,  | 
|
ImageReaderSpi.class);  | 
|
return null;  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns an <code>Iterator</code> containing all currently | 
|
     * registered <code>ImageWriter</code>s that claim to be able to | 
|
     * encode images of the given layout (specified using an | 
|
     * <code>ImageTypeSpecifier</code>) in the given format. | 
|
     * | 
|
     * @param type an <code>ImageTypeSpecifier</code> indicating the | 
|
     * layout of the image to be written. | 
|
     * @param formatName the informal name of the <code>format</code>. | 
|
     * | 
|
     * @return an <code>Iterator</code> containing <code>ImageWriter</code>s. | 
|
     * | 
|
     * @exception IllegalArgumentException if any parameter is | 
|
     * <code>null</code>. | 
|
     * | 
|
     * @see javax.imageio.spi.ImageWriterSpi#canEncodeImage(ImageTypeSpecifier) | 
|
*/  | 
|
public static Iterator<ImageWriter>  | 
|
getImageWriters(ImageTypeSpecifier type, String formatName)  | 
|
    { | 
|
if (type == null) {  | 
|
throw new IllegalArgumentException("type == null!");  | 
|
}  | 
|
if (formatName == null) {  | 
|
throw new IllegalArgumentException("formatName == null!");  | 
|
}  | 
|
Iterator iter;  | 
|
        // Ensure category is present | 
|
        try { | 
|
iter = theRegistry.getServiceProviders(ImageWriterSpi.class,  | 
|
new CanEncodeImageAndFormatFilter(type,  | 
|
formatName),  | 
|
true);  | 
|
} catch (IllegalArgumentException e) {  | 
|
return Collections.emptyIterator();  | 
|
}  | 
|
return new ImageWriterIterator(iter);  | 
|
}  | 
|
static class ImageTranscoderIterator  | 
|
implements Iterator<ImageTranscoder>  | 
|
    { | 
|
        // Contains ImageTranscoderSpis | 
|
public Iterator iter;  | 
|
public ImageTranscoderIterator(Iterator iter) {  | 
|
this.iter = iter;  | 
|
}  | 
|
        public boolean hasNext() { | 
|
return iter.hasNext();  | 
|
}  | 
|
public ImageTranscoder next() {  | 
|
ImageTranscoderSpi spi = null;  | 
|
spi = (ImageTranscoderSpi)iter.next();  | 
|
return spi.createTranscoderInstance();  | 
|
}  | 
|
        public void remove() { | 
|
throw new UnsupportedOperationException();  | 
|
}  | 
|
}  | 
|
static class TranscoderFilter  | 
|
implements ServiceRegistry.Filter {  | 
|
String readerSpiName;  | 
|
String writerSpiName;  | 
|
public TranscoderFilter(ImageReaderSpi readerSpi,  | 
|
ImageWriterSpi writerSpi) {  | 
|
this.readerSpiName = readerSpi.getClass().getName();  | 
|
this.writerSpiName = writerSpi.getClass().getName();  | 
|
}  | 
|
public boolean filter(Object elt) {  | 
|
ImageTranscoderSpi spi = (ImageTranscoderSpi)elt;  | 
|
String readerName = spi.getReaderServiceProviderName();  | 
|
String writerName = spi.getWriterServiceProviderName();  | 
|
return (readerName.equals(readerSpiName) &&  | 
|
writerName.equals(writerSpiName));  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns an <code>Iterator</code> containing all currently | 
|
     * registered <code>ImageTranscoder</code>s that claim to be | 
|
     * able to transcode between the metadata of the given | 
|
     * <code>ImageReader</code> and <code>ImageWriter</code>. | 
|
     * | 
|
     * @param reader an <code>ImageReader</code>. | 
|
     * @param writer an <code>ImageWriter</code>. | 
|
     * | 
|
     * @return an <code>Iterator</code> containing | 
|
     * <code>ImageTranscoder</code>s. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>reader</code> or | 
|
     * <code>writer</code> is <code>null</code>. | 
|
*/  | 
|
public static Iterator<ImageTranscoder>  | 
|
getImageTranscoders(ImageReader reader, ImageWriter writer)  | 
|
    { | 
|
if (reader == null) {  | 
|
throw new IllegalArgumentException("reader == null!");  | 
|
}  | 
|
if (writer == null) {  | 
|
throw new IllegalArgumentException("writer == null!");  | 
|
}  | 
|
ImageReaderSpi readerSpi = reader.getOriginatingProvider();  | 
|
ImageWriterSpi writerSpi = writer.getOriginatingProvider();  | 
|
ServiceRegistry.Filter filter =  | 
|
new TranscoderFilter(readerSpi, writerSpi);  | 
|
Iterator iter;  | 
|
        // Ensure category is present | 
|
        try { | 
|
iter = theRegistry.getServiceProviders(ImageTranscoderSpi.class,  | 
|
filter, true);  | 
|
} catch (IllegalArgumentException e) {  | 
|
return Collections.emptyIterator();  | 
|
}  | 
|
return new ImageTranscoderIterator(iter);  | 
|
}  | 
|
// All-in-one methods  | 
|
    /** | 
|
     * Returns a <code>BufferedImage</code> as the result of decoding | 
|
     * a supplied <code>File</code> with an <code>ImageReader</code> | 
|
     * chosen automatically from among those currently registered. | 
|
     * The <code>File</code> is wrapped in an | 
|
     * <code>ImageInputStream</code>.  If no registered | 
|
     * <code>ImageReader</code> claims to be able to read the | 
|
     * resulting stream, <code>null</code> is returned. | 
|
     * | 
|
     * <p> The current cache settings from <code>getUseCache</code>and | 
|
     * <code>getCacheDirectory</code> will be used to control caching in the | 
|
     * <code>ImageInputStream</code> that is created. | 
|
     * | 
|
     * <p> Note that there is no <code>read</code> method that takes a | 
|
     * filename as a <code>String</code>; use this method instead after | 
|
     * creating a <code>File</code> from the filename. | 
|
     * | 
|
     * <p> This method does not attempt to locate | 
|
     * <code>ImageReader</code>s that can read directly from a | 
|
     * <code>File</code>; that may be accomplished using | 
|
     * <code>IIORegistry</code> and <code>ImageReaderSpi</code>. | 
|
     * | 
|
     * @param input a <code>File</code> to read from. | 
|
     * | 
|
     * @return a <code>BufferedImage</code> containing the decoded | 
|
     * contents of the input, or <code>null</code>. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>input</code> is | 
|
     * <code>null</code>. | 
|
     * @exception IOException if an error occurs during reading or when not | 
|
     * able to create required ImageInputStream. | 
|
*/  | 
|
public static BufferedImage read(File input) throws IOException {  | 
|
if (input == null) {  | 
|
throw new IllegalArgumentException("input == null!");  | 
|
}  | 
|
if (!input.canRead()) {  | 
|
throw new IIOException("Can't read input file!");  | 
|
}  | 
|
ImageInputStream stream = createImageInputStream(input);  | 
|
if (stream == null) {  | 
|
throw new IIOException("Can't create an ImageInputStream!");  | 
|
}  | 
|
BufferedImage bi = read(stream);  | 
|
if (bi == null) {  | 
|
stream.close();  | 
|
}  | 
|
return bi;  | 
|
}  | 
|
    /** | 
|
     * Returns a <code>BufferedImage</code> as the result of decoding | 
|
     * a supplied <code>InputStream</code> with an <code>ImageReader</code> | 
|
     * chosen automatically from among those currently registered. | 
|
     * The <code>InputStream</code> is wrapped in an | 
|
     * <code>ImageInputStream</code>.  If no registered | 
|
     * <code>ImageReader</code> claims to be able to read the | 
|
     * resulting stream, <code>null</code> is returned. | 
|
     * | 
|
     * <p> The current cache settings from <code>getUseCache</code>and | 
|
     * <code>getCacheDirectory</code> will be used to control caching in the | 
|
     * <code>ImageInputStream</code> that is created. | 
|
     * | 
|
     * <p> This method does not attempt to locate | 
|
     * <code>ImageReader</code>s that can read directly from an | 
|
     * <code>InputStream</code>; that may be accomplished using | 
|
     * <code>IIORegistry</code> and <code>ImageReaderSpi</code>. | 
|
     * | 
|
     * <p> This method <em>does not</em> close the provided | 
|
     * <code>InputStream</code> after the read operation has completed; | 
|
     * it is the responsibility of the caller to close the stream, if desired. | 
|
     * | 
|
     * @param input an <code>InputStream</code> to read from. | 
|
     * | 
|
     * @return a <code>BufferedImage</code> containing the decoded | 
|
     * contents of the input, or <code>null</code>. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>input</code> is | 
|
     * <code>null</code>. | 
|
     * @exception IOException if an error occurs during reading or when not | 
|
     * able to create required ImageInputStream. | 
|
*/  | 
|
public static BufferedImage read(InputStream input) throws IOException {  | 
|
if (input == null) {  | 
|
throw new IllegalArgumentException("input == null!");  | 
|
}  | 
|
ImageInputStream stream = createImageInputStream(input);  | 
|
if (stream == null) {  | 
|
throw new IIOException("Can't create an ImageInputStream!");  | 
|
}  | 
|
BufferedImage bi = read(stream);  | 
|
if (bi == null) {  | 
|
stream.close();  | 
|
}  | 
|
return bi;  | 
|
}  | 
|
    /** | 
|
     * Returns a <code>BufferedImage</code> as the result of decoding | 
|
     * a supplied <code>URL</code> with an <code>ImageReader</code> | 
|
     * chosen automatically from among those currently registered.  An | 
|
     * <code>InputStream</code> is obtained from the <code>URL</code>, | 
|
     * which is wrapped in an <code>ImageInputStream</code>.  If no | 
|
     * registered <code>ImageReader</code> claims to be able to read | 
|
     * the resulting stream, <code>null</code> is returned. | 
|
     * | 
|
     * <p> The current cache settings from <code>getUseCache</code>and | 
|
     * <code>getCacheDirectory</code> will be used to control caching in the | 
|
     * <code>ImageInputStream</code> that is created. | 
|
     * | 
|
     * <p> This method does not attempt to locate | 
|
     * <code>ImageReader</code>s that can read directly from a | 
|
     * <code>URL</code>; that may be accomplished using | 
|
     * <code>IIORegistry</code> and <code>ImageReaderSpi</code>. | 
|
     * | 
|
     * @param input a <code>URL</code> to read from. | 
|
     * | 
|
     * @return a <code>BufferedImage</code> containing the decoded | 
|
     * contents of the input, or <code>null</code>. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>input</code> is | 
|
     * <code>null</code>. | 
|
     * @exception IOException if an error occurs during reading or when not | 
|
     * able to create required ImageInputStream. | 
|
*/  | 
|
public static BufferedImage read(URL input) throws IOException {  | 
|
if (input == null) {  | 
|
throw new IllegalArgumentException("input == null!");  | 
|
}  | 
|
InputStream istream = null;  | 
|
        try { | 
|
istream = input.openStream();  | 
|
} catch (IOException e) {  | 
|
throw new IIOException("Can't get input stream from URL!", e);  | 
|
}  | 
|
ImageInputStream stream = createImageInputStream(istream);  | 
|
if (stream == null) {  | 
|
            /* close the istream when stream is null so that if user has | 
|
             * given filepath as URL he can delete it, otherwise stream will | 
|
             * be open to that file and he will not be able to delete it. | 
|
*/  | 
|
istream.close();  | 
|
throw new IIOException("Can't create an ImageInputStream!");  | 
|
}  | 
|
BufferedImage bi;  | 
|
        try { | 
|
bi = read(stream);  | 
|
if (bi == null) {  | 
|
stream.close();  | 
|
}  | 
|
        } finally { | 
|
istream.close();  | 
|
}  | 
|
return bi;  | 
|
}  | 
|
    /** | 
|
     * Returns a <code>BufferedImage</code> as the result of decoding | 
|
     * a supplied <code>ImageInputStream</code> with an | 
|
     * <code>ImageReader</code> chosen automatically from among those | 
|
     * currently registered.  If no registered | 
|
     * <code>ImageReader</code> claims to be able to read the stream, | 
|
     * <code>null</code> is returned. | 
|
     * | 
|
     * <p> Unlike most other methods in this class, this method <em>does</em> | 
|
     * close the provided <code>ImageInputStream</code> after the read | 
|
     * operation has completed, unless <code>null</code> is returned, | 
|
     * in which case this method <em>does not</em> close the stream. | 
|
     * | 
|
     * @param stream an <code>ImageInputStream</code> to read from. | 
|
     * | 
|
     * @return a <code>BufferedImage</code> containing the decoded | 
|
     * contents of the input, or <code>null</code>. | 
|
     * | 
|
     * @exception IllegalArgumentException if <code>stream</code> is | 
|
     * <code>null</code>. | 
|
     * @exception IOException if an error occurs during reading. | 
|
*/  | 
|
public static BufferedImage read(ImageInputStream stream)  | 
|
throws IOException {  | 
|
if (stream == null) {  | 
|
throw new IllegalArgumentException("stream == null!");  | 
|
}  | 
|
Iterator iter = getImageReaders(stream);  | 
|
if (!iter.hasNext()) {  | 
|
return null;  | 
|
}  | 
|
ImageReader reader = (ImageReader)iter.next();  | 
|
ImageReadParam param = reader.getDefaultReadParam();  | 
|
reader.setInput(stream, true, true);  | 
|
BufferedImage bi;  | 
|
        try { | 
|
bi = reader.read(0, param);  | 
|
        } finally { | 
|
reader.dispose();  | 
|
stream.close();  | 
|
}  | 
|
return bi;  | 
|
}  | 
|
    /** | 
|
     * Writes an image using the an arbitrary <code>ImageWriter</code> | 
|
     * that supports the given format to an | 
|
     * <code>ImageOutputStream</code>.  The image is written to the | 
|
     * <code>ImageOutputStream</code> starting at the current stream | 
|
     * pointer, overwriting existing stream data from that point | 
|
     * forward, if present. | 
|
     * | 
|
     * <p> This method <em>does not</em> close the provided | 
|
     * <code>ImageOutputStream</code> after the write operation has completed; | 
|
     * it is the responsibility of the caller to close the stream, if desired. | 
|
     * | 
|
     * @param im a <code>RenderedImage</code> to be written. | 
|
     * @param formatName a <code>String</code> containing the informal | 
|
     * name of the format. | 
|
     * @param output an <code>ImageOutputStream</code> to be written to. | 
|
     * | 
|
     * @return <code>false</code> if no appropriate writer is found. | 
|
     * | 
|
     * @exception IllegalArgumentException if any parameter is | 
|
     * <code>null</code>. | 
|
     * @exception IOException if an error occurs during writing. | 
|
*/  | 
|
public static boolean write(RenderedImage im,  | 
|
String formatName,  | 
|
ImageOutputStream output) throws IOException {  | 
|
if (im == null) {  | 
|
throw new IllegalArgumentException("im == null!");  | 
|
}  | 
|
if (formatName == null) {  | 
|
throw new IllegalArgumentException("formatName == null!");  | 
|
}  | 
|
if (output == null) {  | 
|
throw new IllegalArgumentException("output == null!");  | 
|
}  | 
|
return doWrite(im, getWriter(im, formatName), output);  | 
|
}  | 
|
    /** | 
|
     * Writes an image using an arbitrary <code>ImageWriter</code> | 
|
     * that supports the given format to a <code>File</code>.  If | 
|
     * there is already a <code>File</code> present, its contents are | 
|
     * discarded. | 
|
     * | 
|
     * @param im a <code>RenderedImage</code> to be written. | 
|
     * @param formatName a <code>String</code> containing the informal | 
|
     * name of the format. | 
|
     * @param output a <code>File</code> to be written to. | 
|
     * | 
|
     * @return <code>false</code> if no appropriate writer is found. | 
|
     * | 
|
     * @exception IllegalArgumentException if any parameter is | 
|
     * <code>null</code>. | 
|
     * @exception IOException if an error occurs during writing or when not | 
|
     * able to create required ImageOutputStream. | 
|
*/  | 
|
public static boolean write(RenderedImage im,  | 
|
String formatName,  | 
|
File output) throws IOException {  | 
|
if (output == null) {  | 
|
throw new IllegalArgumentException("output == null!");  | 
|
}  | 
|
ImageWriter writer = getWriter(im, formatName);  | 
|
if (writer == null) {  | 
|
            /* Do not make changes in the file system if we have | 
|
             * no appropriate writer. | 
|
*/  | 
|
return false;  | 
|
}  | 
|
output.delete();  | 
|
ImageOutputStream stream = createImageOutputStream(output);  | 
|
if (stream == null) {  | 
|
throw new IIOException("Can't create an ImageOutputStream!");  | 
|
}  | 
|
        try { | 
|
return doWrite(im, writer, stream);  | 
|
        } finally { | 
|
stream.close();  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Writes an image using an arbitrary <code>ImageWriter</code> | 
|
     * that supports the given format to an <code>OutputStream</code>. | 
|
     * | 
|
     * <p> This method <em>does not</em> close the provided | 
|
     * <code>OutputStream</code> after the write operation has completed; | 
|
     * it is the responsibility of the caller to close the stream, if desired. | 
|
     * | 
|
     * <p> The current cache settings from <code>getUseCache</code>and | 
|
     * <code>getCacheDirectory</code> will be used to control caching. | 
|
     * | 
|
     * @param im a <code>RenderedImage</code> to be written. | 
|
     * @param formatName a <code>String</code> containing the informal | 
|
     * name of the format. | 
|
     * @param output an <code>OutputStream</code> to be written to. | 
|
     * | 
|
     * @return <code>false</code> if no appropriate writer is found. | 
|
     * | 
|
     * @exception IllegalArgumentException if any parameter is | 
|
     * <code>null</code>. | 
|
     * @exception IOException if an error occurs during writing or when not | 
|
     * able to create required ImageOutputStream. | 
|
*/  | 
|
public static boolean write(RenderedImage im,  | 
|
String formatName,  | 
|
OutputStream output) throws IOException {  | 
|
if (output == null) {  | 
|
throw new IllegalArgumentException("output == null!");  | 
|
}  | 
|
ImageOutputStream stream = createImageOutputStream(output);  | 
|
if (stream == null) {  | 
|
throw new IIOException("Can't create an ImageOutputStream!");  | 
|
}  | 
|
        try { | 
|
return doWrite(im, getWriter(im, formatName), stream);  | 
|
        } finally { | 
|
stream.close();  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns <code>ImageWriter</code> instance according to given | 
|
     * rendered image and image format or <code>null</code> if there | 
|
     * is no appropriate writer. | 
|
*/  | 
|
private static ImageWriter getWriter(RenderedImage im,  | 
|
String formatName) {  | 
|
ImageTypeSpecifier type =  | 
|
ImageTypeSpecifier.createFromRenderedImage(im);  | 
|
Iterator<ImageWriter> iter = getImageWriters(type, formatName);  | 
|
if (iter.hasNext()) {  | 
|
return iter.next();  | 
|
        } else { | 
|
return null;  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Writes image to output stream  using given image writer. | 
|
*/  | 
|
private static boolean doWrite(RenderedImage im, ImageWriter writer,  | 
|
ImageOutputStream output) throws IOException {  | 
|
if (writer == null) {  | 
|
return false;  | 
|
}  | 
|
writer.setOutput(output);  | 
|
        try { | 
|
writer.write(im);  | 
|
        } finally { | 
|
writer.dispose();  | 
|
output.flush();  | 
|
}  | 
|
return true;  | 
|
}  | 
|
}  |