/* * Copyright (c) 2000, 2005, 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 enviroment. * * @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); } /**Lines 1–500 of 1619. Load more
/* * Copyright (c) 2000, 2005, 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 enviroment. * * @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); } /**