/* |
|
* 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; |
|
} |
|
} |