Save This Page
Home » openjdk-7 » javax » imageio » [javadoc | source]
    1   /*
    2    * Copyright 2000-2005 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.imageio;
   27   
   28   import java.awt.image.BufferedImage;
   29   import java.awt.image.RenderedImage;
   30   import java.io.File;
   31   import java.io.InputStream;
   32   import java.io.IOException;
   33   import java.io.OutputStream;
   34   import java.lang.reflect.Method;
   35   import java.net.URL;
   36   import java.security.AccessController;
   37   import java.util.Arrays;
   38   import java.util.Collections;
   39   import java.util.HashSet;
   40   import java.util.Iterator;
   41   import java.util.NoSuchElementException;
   42   import java.util.Set;
   43   import javax.imageio.spi.IIORegistry;
   44   import javax.imageio.spi.ImageReaderSpi;
   45   import javax.imageio.spi.ImageReaderWriterSpi;
   46   import javax.imageio.spi.ImageWriterSpi;
   47   import javax.imageio.spi.ImageInputStreamSpi;
   48   import javax.imageio.spi.ImageOutputStreamSpi;
   49   import javax.imageio.spi.ImageTranscoderSpi;
   50   import javax.imageio.spi.ServiceRegistry;
   51   import javax.imageio.stream.ImageInputStream;
   52   import javax.imageio.stream.ImageOutputStream;
   53   import sun.awt.AppContext;
   54   import sun.security.action.GetPropertyAction;
   55   
   56   /**
   57    * A class containing static convenience methods for locating
   58    * <code>ImageReader</code>s and <code>ImageWriter</code>s, and
   59    * performing simple encoding and decoding.
   60    *
   61    */
   62   public final class ImageIO {
   63   
   64       private static final IIORegistry theRegistry =
   65           IIORegistry.getDefaultInstance();
   66   
   67       /**
   68        * Constructor is private to prevent instantiation.
   69        */
   70       private ImageIO() {}
   71   
   72       /**
   73        * Scans for plug-ins on the application class path,
   74        * loads their service provider classes, and registers a service
   75        * provider instance for each one found with the
   76        * <code>IIORegistry</code>.
   77        *
   78        * <p>This method is needed because the application class path can
   79        * theoretically change, or additional plug-ins may become available.
   80        * Rather than re-scanning the classpath on every invocation of the
   81        * API, the class path is scanned automatically only on the first
   82        * invocation. Clients can call this method to prompt a re-scan.
   83        * Thus this method need only be invoked by sophisticated applications
   84        * which dynamically make new plug-ins available at runtime.
   85        *
   86        * <p> The <code>getResources</code> method of the context
   87        * <code>ClassLoader</code> is used locate JAR files containing
   88        * files named
   89        * <code>META-INF/services/javax.imageio.spi.</code><i>classname</i>,
   90        * where <i>classname</i> is one of <code>ImageReaderSpi</code>,
   91        * <code>ImageWriterSpi</code>, <code>ImageTranscoderSpi</code>,
   92        * <code>ImageInputStreamSpi</code>, or
   93        * <code>ImageOutputStreamSpi</code>, along the application class
   94        * path.
   95        *
   96        * <p> The contents of the located files indicate the names of
   97        * actual implementation classes which implement the
   98        * aforementioned service provider interfaces; the default class
   99        * loader is then used to load each of these classes and to
  100        * instantiate an instance of each class, which is then placed
  101        * into the registry for later retrieval.
  102        *
  103        * <p> The exact set of locations searched depends on the
  104        * implementation of the Java runtime enviroment.
  105        *
  106        * @see ClassLoader#getResources
  107        */
  108       public static void scanForPlugins() {
  109           theRegistry.registerApplicationClasspathSpis();
  110       }
  111   
  112       // ImageInputStreams
  113   
  114       /**
  115        * A class to hold information about caching.  Each
  116        * <code>ThreadGroup</code> will have its own copy
  117        * via the <code>AppContext</code> mechanism.
  118        */
  119       static class CacheInfo {
  120           boolean useCache = true;
  121           File cacheDirectory = null;
  122           Boolean hasPermission = null;
  123   
  124           public CacheInfo() {}
  125   
  126           public boolean getUseCache() {
  127               return useCache;
  128           }
  129   
  130           public void setUseCache(boolean useCache) {
  131               this.useCache = useCache;
  132           }
  133   
  134           public File getCacheDirectory() {
  135               return cacheDirectory;
  136           }
  137   
  138           public void setCacheDirectory(File cacheDirectory) {
  139               this.cacheDirectory = cacheDirectory;
  140           }
  141   
  142           public Boolean getHasPermission() {
  143               return hasPermission;
  144           }
  145   
  146           public void setHasPermission(Boolean hasPermission) {
  147               this.hasPermission = hasPermission;
  148           }
  149       }
  150   
  151       /**
  152        * Returns the <code>CacheInfo</code> object associated with this
  153        * <code>ThreadGroup</code>.
  154        */
  155       private static synchronized CacheInfo getCacheInfo() {
  156           AppContext context = AppContext.getAppContext();
  157           CacheInfo info = (CacheInfo)context.get(CacheInfo.class);
  158           if (info == null) {
  159               info = new CacheInfo();
  160               context.put(CacheInfo.class, info);
  161           }
  162           return info;
  163       }
  164   
  165       /**
  166        * Returns the default temporary (cache) directory as defined by the
  167        * java.io.tmpdir system property.
  168        */
  169       private static String getTempDir() {
  170           GetPropertyAction a = new GetPropertyAction("java.io.tmpdir");
  171           return (String)AccessController.doPrivileged(a);
  172       }
  173   
  174       /**
  175        * Determines whether the caller has write access to the cache
  176        * directory, stores the result in the <code>CacheInfo</code> object,
  177        * and returns the decision.  This method helps to prevent mysterious
  178        * SecurityExceptions to be thrown when this convenience class is used
  179        * in an applet, for example.
  180        */
  181       private static boolean hasCachePermission() {
  182           Boolean hasPermission = getCacheInfo().getHasPermission();
  183   
  184           if (hasPermission != null) {
  185               return hasPermission.booleanValue();
  186           } else {
  187               try {
  188                   SecurityManager security = System.getSecurityManager();
  189                   if (security != null) {
  190                       File cachedir = getCacheDirectory();
  191                       String cachepath;
  192   
  193                       if (cachedir != null) {
  194                           cachepath = cachedir.getPath();
  195                       } else {
  196                           cachepath = getTempDir();
  197   
  198                           if (cachepath == null) {
  199                               getCacheInfo().setHasPermission(Boolean.FALSE);
  200                               return false;
  201                           }
  202                       }
  203   
  204                       security.checkWrite(cachepath);
  205                   }
  206               } catch (SecurityException e) {
  207                   getCacheInfo().setHasPermission(Boolean.FALSE);
  208                   return false;
  209               }
  210   
  211               getCacheInfo().setHasPermission(Boolean.TRUE);
  212               return true;
  213           }
  214       }
  215   
  216       /**
  217        * Sets a flag indicating whether a disk-based cache file should
  218        * be used when creating <code>ImageInputStream</code>s and
  219        * <code>ImageOutputStream</code>s.
  220        *
  221        * <p> When reading from a standard <code>InputStream</code>>, it
  222        * may be necessary to save previously read information in a cache
  223        * since the underlying stream does not allow data to be re-read.
  224        * Similarly, when writing to a standard
  225        * <code>OutputStream</code>, a cache may be used to allow a
  226        * previously written value to be changed before flushing it to
  227        * the final destination.
  228        *
  229        * <p> The cache may reside in main memory or on disk.  Setting
  230        * this flag to <code>false</code> disallows the use of disk for
  231        * future streams, which may be advantageous when working with
  232        * small images, as the overhead of creating and destroying files
  233        * is removed.
  234        *
  235        * <p> On startup, the value is set to <code>true</code>.
  236        *
  237        * @param useCache a <code>boolean</code> indicating whether a
  238        * cache file should be used, in cases where it is optional.
  239        *
  240        * @see #getUseCache
  241        */
  242       public static void setUseCache(boolean useCache) {
  243           getCacheInfo().setUseCache(useCache);
  244       }
  245   
  246       /**
  247        * Returns the current value set by <code>setUseCache</code>, or
  248        * <code>true</code> if no explicit setting has been made.
  249        *
  250        * @return true if a disk-based cache may be used for
  251        * <code>ImageInputStream</code>s and
  252        * <code>ImageOutputStream</code>s.
  253        *
  254        * @see #setUseCache
  255        */
  256       public static boolean getUseCache() {
  257           return getCacheInfo().getUseCache();
  258       }
  259   
  260       /**
  261        * Sets the directory where cache files are to be created.  A
  262        * value of <code>null</code> indicates that the system-dependent
  263        * default temporary-file directory is to be used.  If
  264        * <code>getUseCache</code> returns false, this value is ignored.
  265        *
  266        * @param cacheDirectory a <code>File</code> specifying a directory.
  267        *
  268        * @see File#createTempFile(String, String, File)
  269        *
  270        * @exception SecurityException if the security manager denies
  271        * access to the directory.
  272        * @exception IllegalArgumentException if <code>cacheDir</code> is
  273        * non-<code>null</code> but is not a directory.
  274        *
  275        * @see #getCacheDirectory
  276        */
  277       public static void setCacheDirectory(File cacheDirectory) {
  278           if ((cacheDirectory != null) && !(cacheDirectory.isDirectory())) {
  279               throw new IllegalArgumentException("Not a directory!");
  280           }
  281           getCacheInfo().setCacheDirectory(cacheDirectory);
  282           getCacheInfo().setHasPermission(null);
  283       }
  284   
  285       /**
  286        * Returns the current value set by
  287        * <code>setCacheDirectory</code>, or <code>null</code> if no
  288        * explicit setting has been made.
  289        *
  290        * @return a <code>File</code> indicating the directory where
  291        * cache files will be created, or <code>null</code> to indicate
  292        * the system-dependent default temporary-file directory.
  293        *
  294        * @see #setCacheDirectory
  295        */
  296       public static File getCacheDirectory() {
  297           return getCacheInfo().getCacheDirectory();
  298       }
  299   
  300       /**
  301        * Returns an <code>ImageInputStream</code> that will take its
  302        * input from the given <code>Object</code>.  The set of
  303        * <code>ImageInputStreamSpi</code>s registered with the
  304        * <code>IIORegistry</code> class is queried and the first one
  305        * that is able to take input from the supplied object is used to
  306        * create the returned <code>ImageInputStream</code>.  If no
  307        * suitable <code>ImageInputStreamSpi</code> exists,
  308        * <code>null</code> is returned.
  309        *
  310        * <p> The current cache settings from <code>getUseCache</code>and
  311        * <code>getCacheDirectory</code> will be used to control caching.
  312        *
  313        * @param input an <code>Object</code> to be used as an input
  314        * source, such as a <code>File</code>, readable
  315        * <code>RandomAccessFile</code>, or <code>InputStream</code>.
  316        *
  317        * @return an <code>ImageInputStream</code>, or <code>null</code>.
  318        *
  319        * @exception IllegalArgumentException if <code>input</code>
  320        * is <code>null</code>.
  321        * @exception IOException if a cache file is needed but cannot be
  322        * created.
  323        *
  324        * @see javax.imageio.spi.ImageInputStreamSpi
  325        */
  326       public static ImageInputStream createImageInputStream(Object input)
  327           throws IOException {
  328           if (input == null) {
  329               throw new IllegalArgumentException("input == null!");
  330           }
  331   
  332           Iterator iter;
  333           // Ensure category is present
  334           try {
  335               iter = theRegistry.getServiceProviders(ImageInputStreamSpi.class,
  336                                                      true);
  337           } catch (IllegalArgumentException e) {
  338               return null;
  339           }
  340   
  341           boolean usecache = getUseCache() && hasCachePermission();
  342   
  343           while (iter.hasNext()) {
  344               ImageInputStreamSpi spi = (ImageInputStreamSpi)iter.next();
  345               if (spi.getInputClass().isInstance(input)) {
  346                   try {
  347                       return spi.createInputStreamInstance(input,
  348                                                            usecache,
  349                                                            getCacheDirectory());
  350                   } catch (IOException e) {
  351                       throw new IIOException("Can't create cache file!", e);
  352                   }
  353               }
  354           }
  355   
  356           return null;
  357       }
  358   
  359       // ImageOutputStreams
  360   
  361       /**
  362        * Returns an <code>ImageOutputStream</code> that will send its
  363        * output to the given <code>Object</code>.  The set of
  364        * <code>ImageOutputStreamSpi</code>s registered with the
  365        * <code>IIORegistry</code> class is queried and the first one
  366        * that is able to send output from the supplied object is used to
  367        * create the returned <code>ImageOutputStream</code>.  If no
  368        * suitable <code>ImageOutputStreamSpi</code> exists,
  369        * <code>null</code> is returned.
  370        *
  371        * <p> The current cache settings from <code>getUseCache</code>and
  372        * <code>getCacheDirectory</code> will be used to control caching.
  373        *
  374        * @param output an <code>Object</code> to be used as an output
  375        * destination, such as a <code>File</code>, writable
  376        * <code>RandomAccessFile</code>, or <code>OutputStream</code>.
  377        *
  378        * @return an <code>ImageOutputStream</code>, or
  379        * <code>null</code>.
  380        *
  381        * @exception IllegalArgumentException if <code>output</code> is
  382        * <code>null</code>.
  383        * @exception IOException if a cache file is needed but cannot be
  384        * created.
  385        *
  386        * @see javax.imageio.spi.ImageOutputStreamSpi
  387        */
  388       public static ImageOutputStream createImageOutputStream(Object output)
  389           throws IOException {
  390           if (output == null) {
  391               throw new IllegalArgumentException("output == null!");
  392           }
  393   
  394           Iterator iter;
  395           // Ensure category is present
  396           try {
  397               iter = theRegistry.getServiceProviders(ImageOutputStreamSpi.class,
  398                                                      true);
  399           } catch (IllegalArgumentException e) {
  400               return null;
  401           }
  402   
  403           boolean usecache = getUseCache() && hasCachePermission();
  404   
  405           while (iter.hasNext()) {
  406               ImageOutputStreamSpi spi = (ImageOutputStreamSpi)iter.next();
  407               if (spi.getOutputClass().isInstance(output)) {
  408                   try {
  409                       return spi.createOutputStreamInstance(output,
  410                                                             usecache,
  411                                                             getCacheDirectory());
  412                   } catch (IOException e) {
  413                       throw new IIOException("Can't create cache file!", e);
  414                   }
  415               }
  416           }
  417   
  418           return null;
  419       }
  420   
  421       private static enum SpiInfo {
  422           FORMAT_NAMES {
  423               @Override
  424               String[] info(ImageReaderWriterSpi spi) {
  425                   return spi.getFormatNames();
  426               }
  427           },
  428           MIME_TYPES {
  429               @Override
  430               String[] info(ImageReaderWriterSpi spi) {
  431                   return spi.getMIMETypes();
  432               }
  433           },
  434           FILE_SUFFIXES {
  435               @Override
  436               String[] info(ImageReaderWriterSpi spi) {
  437                   return spi.getFileSuffixes();
  438               }
  439           };
  440   
  441           abstract String[] info(ImageReaderWriterSpi spi);
  442       }
  443   
  444       private static <S extends ImageReaderWriterSpi>
  445           String[] getReaderWriterInfo(Class<S> spiClass, SpiInfo spiInfo)
  446       {
  447           // Ensure category is present
  448           Iterator<S> iter;
  449           try {
  450               iter = theRegistry.getServiceProviders(spiClass, true);
  451           } catch (IllegalArgumentException e) {
  452               return new String[0];
  453           }
  454   
  455           HashSet<String> s = new HashSet<String>();
  456           while (iter.hasNext()) {
  457               ImageReaderWriterSpi spi = iter.next();
  458               Collections.addAll(s, spiInfo.info(spi));
  459           }
  460   
  461           return s.toArray(new String[s.size()]);
  462       }
  463   
  464       // Readers
  465   
  466       /**
  467        * Returns an array of <code>String</code>s listing all of the
  468        * informal format names understood by the current set of registered
  469        * readers.
  470        *
  471        * @return an array of <code>String</code>s.
  472        */
  473       public static String[] getReaderFormatNames() {
  474           return getReaderWriterInfo(ImageReaderSpi.class,
  475                                      SpiInfo.FORMAT_NAMES);
  476       }
  477   
  478       /**
  479        * Returns an array of <code>String</code>s listing all of the
  480        * MIME types understood by the current set of registered
  481        * readers.
  482        *
  483        * @return an array of <code>String</code>s.
  484        */
  485       public static String[] getReaderMIMETypes() {
  486           return getReaderWriterInfo(ImageReaderSpi.class,
  487                                      SpiInfo.MIME_TYPES);
  488       }
  489   
  490       /**
  491        * Returns an array of <code>String</code>s listing all of the
  492        * file suffixes associated with the formats understood
  493        * by the current set of registered readers.
  494        *
  495        * @return an array of <code>String</code>s.
  496        * @since 1.6
  497        */
  498       public static String[] getReaderFileSuffixes() {
  499           return getReaderWriterInfo(ImageReaderSpi.class,
  500                                      SpiInfo.FILE_SUFFIXES);
  501       }
  502   
  503       static class ImageReaderIterator implements Iterator<ImageReader> {
  504           // Contains ImageReaderSpis
  505           public Iterator iter;
  506   
  507           public ImageReaderIterator(Iterator iter) {
  508               this.iter = iter;
  509           }
  510   
  511           public boolean hasNext() {
  512               return iter.hasNext();
  513           }
  514   
  515           public ImageReader next() {
  516               ImageReaderSpi spi = null;
  517               try {
  518                   spi = (ImageReaderSpi)iter.next();
  519                   return spi.createReaderInstance();
  520               } catch (IOException e) {
  521                   // Deregister the spi in this case, but only as
  522                   // an ImageReaderSpi
  523                   theRegistry.deregisterServiceProvider(spi, ImageReaderSpi.class);
  524               }
  525               return null;
  526           }
  527   
  528           public void remove() {
  529               throw new UnsupportedOperationException();
  530           }
  531       }
  532   
  533       static class CanDecodeInputFilter
  534           implements ServiceRegistry.Filter {
  535   
  536           Object input;
  537   
  538           public CanDecodeInputFilter(Object input) {
  539               this.input = input;
  540           }
  541   
  542           public boolean filter(Object elt) {
  543               try {
  544                   ImageReaderSpi spi = (ImageReaderSpi)elt;
  545                   ImageInputStream stream = null;
  546                   if (input instanceof ImageInputStream) {
  547                       stream = (ImageInputStream)input;
  548                   }
  549   
  550                   // Perform mark/reset as a defensive measure
  551                   // even though plug-ins are supposed to take
  552                   // care of it.
  553                   boolean canDecode = false;
  554                   if (stream != null) {
  555                       stream.mark();
  556                   }
  557                   canDecode = spi.canDecodeInput(input);
  558                   if (stream != null) {
  559                       stream.reset();
  560                   }
  561   
  562                   return canDecode;
  563               } catch (IOException e) {
  564                   return false;
  565               }
  566           }
  567       }
  568   
  569       static class CanEncodeImageAndFormatFilter
  570           implements ServiceRegistry.Filter {
  571   
  572           ImageTypeSpecifier type;
  573           String formatName;
  574   
  575           public CanEncodeImageAndFormatFilter(ImageTypeSpecifier type,
  576                                                String formatName) {
  577               this.type = type;
  578               this.formatName = formatName;
  579           }
  580   
  581           public boolean filter(Object elt) {
  582               ImageWriterSpi spi = (ImageWriterSpi)elt;
  583               return Arrays.asList(spi.getFormatNames()).contains(formatName) &&
  584                   spi.canEncodeImage(type);
  585           }
  586       }
  587   
  588       static class ContainsFilter
  589           implements ServiceRegistry.Filter {
  590   
  591           Method method;
  592           String name;
  593   
  594           // method returns an array of Strings
  595           public ContainsFilter(Method method,
  596                                 String name) {
  597               this.method = method;
  598               this.name = name;
  599           }
  600   
  601           public boolean filter(Object elt) {
  602               try {
  603                   return contains((String[])method.invoke(elt), name);
  604               } catch (Exception e) {
  605                   return false;
  606               }
  607           }
  608       }
  609   
  610       /**
  611        * Returns an <code>Iterator</code> containing all currently
  612        * registered <code>ImageReader</code>s that claim to be able to
  613        * decode the supplied <code>Object</code>, typically an
  614        * <code>ImageInputStream</code>.
  615        *
  616        * <p> The stream position is left at its prior position upon
  617        * exit from this method.
  618        *
  619        * @param input an <code>ImageInputStream</code> or other
  620        * <code>Object</code> containing encoded image data.
  621        *
  622        * @return an <code>Iterator</code> containing <code>ImageReader</code>s.
  623        *
  624        * @exception IllegalArgumentException if <code>input</code> is
  625        * <code>null</code>.
  626        *
  627        * @see javax.imageio.spi.ImageReaderSpi#canDecodeInput
  628        */
  629       public static Iterator<ImageReader> getImageReaders(Object input) {
  630           if (input == null) {
  631               throw new IllegalArgumentException("input == null!");
  632           }
  633           Iterator iter;
  634           // Ensure category is present
  635           try {
  636               iter = theRegistry.getServiceProviders(ImageReaderSpi.class,
  637                                                 new CanDecodeInputFilter(input),
  638                                                 true);
  639           } catch (IllegalArgumentException e) {
  640               return Collections.emptyIterator();
  641           }
  642   
  643           return new ImageReaderIterator(iter);
  644       }
  645   
  646       private static Method readerFormatNamesMethod;
  647       private static Method readerFileSuffixesMethod;
  648       private static Method readerMIMETypesMethod;
  649       private static Method writerFormatNamesMethod;
  650       private static Method writerFileSuffixesMethod;
  651       private static Method writerMIMETypesMethod;
  652   
  653       static {
  654           try {
  655               readerFormatNamesMethod =
  656                   ImageReaderSpi.class.getMethod("getFormatNames");
  657               readerFileSuffixesMethod =
  658                   ImageReaderSpi.class.getMethod("getFileSuffixes");
  659               readerMIMETypesMethod =
  660                   ImageReaderSpi.class.getMethod("getMIMETypes");
  661   
  662               writerFormatNamesMethod =
  663                   ImageWriterSpi.class.getMethod("getFormatNames");
  664               writerFileSuffixesMethod =
  665                   ImageWriterSpi.class.getMethod("getFileSuffixes");
  666               writerMIMETypesMethod =
  667                   ImageWriterSpi.class.getMethod("getMIMETypes");
  668           } catch (NoSuchMethodException e) {
  669               e.printStackTrace();
  670           }
  671       }
  672   
  673       /**
  674        * Returns an <code>Iterator</code> containing all currently
  675        * registered <code>ImageReader</code>s that claim to be able to
  676        * decode the named format.
  677        *
  678        * @param formatName a <code>String</code> containing the informal
  679        * name of a format (<i>e.g.</i>, "jpeg" or "tiff".
  680        *
  681        * @return an <code>Iterator</code> containing
  682        * <code>ImageReader</code>s.
  683        *
  684        * @exception IllegalArgumentException if <code>formatName</code>
  685        * is <code>null</code>.
  686        *
  687        * @see javax.imageio.spi.ImageReaderSpi#getFormatNames
  688        */
  689       public static Iterator<ImageReader>
  690           getImageReadersByFormatName(String formatName)
  691       {
  692           if (formatName == null) {
  693               throw new IllegalArgumentException("formatName == null!");
  694           }
  695           Iterator iter;
  696           // Ensure category is present
  697           try {
  698               iter = theRegistry.getServiceProviders(ImageReaderSpi.class,
  699                                       new ContainsFilter(readerFormatNamesMethod,
  700                                                          formatName),
  701                                                   true);
  702           } catch (IllegalArgumentException e) {
  703               return Collections.emptyIterator();
  704           }
  705           return new ImageReaderIterator(iter);
  706       }
  707   
  708       /**
  709        * Returns an <code>Iterator</code> containing all currently
  710        * registered <code>ImageReader</code>s that claim to be able to
  711        * decode files with the given suffix.
  712        *
  713        * @param fileSuffix a <code>String</code> containing a file
  714        * suffix (<i>e.g.</i>, "jpg" or "tiff").
  715        *
  716        * @return an <code>Iterator</code> containing
  717        * <code>ImageReader</code>s.
  718        *
  719        * @exception IllegalArgumentException if <code>fileSuffix</code>
  720        * is <code>null</code>.
  721        *
  722        * @see javax.imageio.spi.ImageReaderSpi#getFileSuffixes
  723        */
  724       public static Iterator<ImageReader>
  725           getImageReadersBySuffix(String fileSuffix)
  726       {
  727           if (fileSuffix == null) {
  728               throw new IllegalArgumentException("fileSuffix == null!");
  729           }
  730           // Ensure category is present
  731           Iterator iter;
  732           try {
  733               iter = theRegistry.getServiceProviders(ImageReaderSpi.class,
  734                                      new ContainsFilter(readerFileSuffixesMethod,
  735                                                         fileSuffix),
  736                                                 true);
  737           } catch (IllegalArgumentException e) {
  738               return Collections.emptyIterator();
  739           }
  740           return new ImageReaderIterator(iter);
  741       }
  742   
  743       /**
  744        * Returns an <code>Iterator</code> containing all currently
  745        * registered <code>ImageReader</code>s that claim to be able to
  746        * decode files with the given MIME type.
  747        *
  748        * @param MIMEType a <code>String</code> containing a file
  749        * suffix (<i>e.g.</i>, "image/jpeg" or "image/x-bmp").
  750        *
  751        * @return an <code>Iterator</code> containing
  752        * <code>ImageReader</code>s.
  753        *
  754        * @exception IllegalArgumentException if <code>MIMEType</code> is
  755        * <code>null</code>.
  756        *
  757        * @see javax.imageio.spi.ImageReaderSpi#getMIMETypes
  758        */
  759       public static Iterator<ImageReader>
  760           getImageReadersByMIMEType(String MIMEType)
  761       {
  762           if (MIMEType == null) {
  763               throw new IllegalArgumentException("MIMEType == null!");
  764           }
  765           // Ensure category is present
  766           Iterator iter;
  767           try {
  768               iter = theRegistry.getServiceProviders(ImageReaderSpi.class,
  769                                         new ContainsFilter(readerMIMETypesMethod,
  770                                                            MIMEType),
  771                                                 true);
  772           } catch (IllegalArgumentException e) {
  773               return Collections.emptyIterator();
  774           }
  775           return new ImageReaderIterator(iter);
  776       }
  777   
  778       // Writers
  779   
  780       /**
  781        * Returns an array of <code>String</code>s listing all of the
  782        * informal format names understood by the current set of registered
  783        * writers.
  784        *
  785        * @return an array of <code>String</code>s.
  786        */
  787       public static String[] getWriterFormatNames() {
  788           return getReaderWriterInfo(ImageWriterSpi.class,
  789                                      SpiInfo.FORMAT_NAMES);
  790       }
  791   
  792       /**
  793        * Returns an array of <code>String</code>s listing all of the
  794        * MIME types understood by the current set of registered
  795        * writers.
  796        *
  797        * @return an array of <code>String</code>s.
  798        */
  799       public static String[] getWriterMIMETypes() {
  800           return getReaderWriterInfo(ImageWriterSpi.class,
  801                                      SpiInfo.MIME_TYPES);
  802       }
  803   
  804       /**
  805        * Returns an array of <code>String</code>s listing all of the
  806        * file suffixes associated with the formats understood
  807        * by the current set of registered writers.
  808        *
  809        * @return an array of <code>String</code>s.
  810        * @since 1.6
  811        */
  812       public static String[] getWriterFileSuffixes() {
  813           return getReaderWriterInfo(ImageWriterSpi.class,
  814                                      SpiInfo.FILE_SUFFIXES);
  815       }
  816   
  817       static class ImageWriterIterator implements Iterator<ImageWriter> {
  818           // Contains ImageWriterSpis
  819           public Iterator iter;
  820   
  821           public ImageWriterIterator(Iterator iter) {
  822               this.iter = iter;
  823           }
  824   
  825           public boolean hasNext() {
  826               return iter.hasNext();
  827           }
  828   
  829           public ImageWriter next() {
  830               ImageWriterSpi spi = null;
  831               try {
  832                   spi = (ImageWriterSpi)iter.next();
  833                   return spi.createWriterInstance();
  834               } catch (IOException e) {
  835                   // Deregister the spi in this case, but only as a writerSpi
  836                   theRegistry.deregisterServiceProvider(spi, ImageWriterSpi.class);
  837               }
  838               return null;
  839           }
  840   
  841           public void remove() {
  842               throw new UnsupportedOperationException();
  843           }
  844       }
  845   
  846       private static boolean contains(String[] names, String name) {
  847           for (int i = 0; i < names.length; i++) {
  848               if (name.equalsIgnoreCase(names[i])) {
  849                   return true;
  850               }
  851           }
  852   
  853           return false;
  854       }
  855   
  856       /**
  857        * Returns an <code>Iterator</code> containing all currently
  858        * registered <code>ImageWriter</code>s that claim to be able to
  859        * encode the named format.
  860        *
  861        * @param formatName a <code>String</code> containing the informal
  862        * name of a format (<i>e.g.</i>, "jpeg" or "tiff".
  863        *
  864        * @return an <code>Iterator</code> containing
  865        * <code>ImageWriter</code>s.
  866        *
  867        * @exception IllegalArgumentException if <code>formatName</code> is
  868        * <code>null</code>.
  869        *
  870        * @see javax.imageio.spi.ImageWriterSpi#getFormatNames
  871        */
  872       public static Iterator<ImageWriter>
  873           getImageWritersByFormatName(String formatName)
  874       {
  875           if (formatName == null) {
  876               throw new IllegalArgumentException("formatName == null!");
  877           }
  878           Iterator iter;
  879           // Ensure category is present
  880           try {
  881               iter = theRegistry.getServiceProviders(ImageWriterSpi.class,
  882                                       new ContainsFilter(writerFormatNamesMethod,
  883                                                          formatName),
  884                                               true);
  885           } catch (IllegalArgumentException e) {
  886               return Collections.emptyIterator();
  887           }
  888           return new ImageWriterIterator(iter);
  889       }
  890   
  891       /**
  892        * Returns an <code>Iterator</code> containing all currently
  893        * registered <code>ImageWriter</code>s that claim to be able to
  894        * encode files with the given suffix.
  895        *
  896        * @param fileSuffix a <code>String</code> containing a file
  897        * suffix (<i>e.g.</i>, "jpg" or "tiff").
  898        *
  899        * @return an <code>Iterator</code> containing <code>ImageWriter</code>s.
  900        *
  901        * @exception IllegalArgumentException if <code>fileSuffix</code> is
  902        * <code>null</code>.
  903        *
  904        * @see javax.imageio.spi.ImageWriterSpi#getFileSuffixes
  905        */
  906       public static Iterator<ImageWriter>
  907           getImageWritersBySuffix(String fileSuffix)
  908       {
  909           if (fileSuffix == null) {
  910               throw new IllegalArgumentException("fileSuffix == null!");
  911           }
  912           Iterator iter;
  913           // Ensure category is present
  914           try {
  915               iter = theRegistry.getServiceProviders(ImageWriterSpi.class,
  916                                      new ContainsFilter(writerFileSuffixesMethod,
  917                                                         fileSuffix),
  918                                               true);
  919           } catch (IllegalArgumentException e) {
  920               return Collections.emptyIterator();
  921           }
  922           return new ImageWriterIterator(iter);
  923       }
  924   
  925       /**
  926        * Returns an <code>Iterator</code> containing all currently
  927        * registered <code>ImageWriter</code>s that claim to be able to
  928        * encode files with the given MIME type.
  929        *
  930        * @param MIMEType a <code>String</code> containing a file
  931        * suffix (<i>e.g.</i>, "image/jpeg" or "image/x-bmp").
  932        *
  933        * @return an <code>Iterator</code> containing <code>ImageWriter</code>s.
  934        *
  935        * @exception IllegalArgumentException if <code>MIMEType</code> is
  936        * <code>null</code>.
  937        *
  938        * @see javax.imageio.spi.ImageWriterSpi#getMIMETypes
  939        */
  940       public static Iterator<ImageWriter>
  941           getImageWritersByMIMEType(String MIMEType)
  942       {
  943           if (MIMEType == null) {
  944               throw new IllegalArgumentException("MIMEType == null!");
  945           }
  946           Iterator iter;
  947           // Ensure category is present
  948           try {
  949               iter = theRegistry.getServiceProviders(ImageWriterSpi.class,
  950                                         new ContainsFilter(writerMIMETypesMethod,
  951                                                            MIMEType),
  952                                               true);
  953           } catch (IllegalArgumentException e) {
  954               return Collections.emptyIterator();
  955           }
  956           return new ImageWriterIterator(iter);
  957       }
  958   
  959       /**
  960        * Returns an <code>ImageWriter</code>corresponding to the given
  961        * <code>ImageReader</code>, if there is one, or <code>null</code>
  962        * if the plug-in for this <code>ImageReader</code> does not
  963        * specify a corresponding <code>ImageWriter</code>, or if the
  964        * given <code>ImageReader</code> is not registered.  This
  965        * mechanism may be used to obtain an <code>ImageWriter</code>
  966        * that will understand the internal structure of non-pixel
  967        * metadata (as encoded by <code>IIOMetadata</code> objects)
  968        * generated by the <code>ImageReader</code>.  By obtaining this
  969        * data from the <code>ImageReader</code> and passing it on to the
  970        * <code>ImageWriter</code> obtained with this method, a client
  971        * program can read an image, modify it in some way, and write it
  972        * back out preserving all metadata, without having to understand
  973        * anything about the structure of the metadata, or even about
  974        * the image format.  Note that this method returns the
  975        * "preferred" writer, which is the first in the list returned by
  976        * <code>javax.imageio.spi.ImageReaderSpi.getImageWriterSpiNames()</code>.
  977        *
  978        * @param reader an instance of a registered <code>ImageReader</code>.
  979        *
  980        * @return an <code>ImageWriter</code>, or null.
  981        *
  982        * @exception IllegalArgumentException if <code>reader</code> is
  983        * <code>null</code>.
  984        *
  985        * @see #getImageReader(ImageWriter)
  986        * @see javax.imageio.spi.ImageReaderSpi#getImageWriterSpiNames()
  987        */
  988       public static ImageWriter getImageWriter(ImageReader reader) {
  989           if (reader == null) {
  990               throw new IllegalArgumentException("reader == null!");
  991           }
  992   
  993           ImageReaderSpi readerSpi = reader.getOriginatingProvider();
  994           if (readerSpi == null) {
  995               Iterator readerSpiIter;
  996               // Ensure category is present
  997               try {
  998                   readerSpiIter =
  999                       theRegistry.getServiceProviders(ImageReaderSpi.class,
 1000                                                       false);
 1001               } catch (IllegalArgumentException e) {
 1002                   return null;
 1003               }
 1004   
 1005               while (readerSpiIter.hasNext()) {
 1006                   ImageReaderSpi temp = (ImageReaderSpi) readerSpiIter.next();
 1007                   if (temp.isOwnReader(reader)) {
 1008                       readerSpi = temp;
 1009                       break;
 1010                   }
 1011               }
 1012               if (readerSpi == null) {
 1013                   return null;
 1014               }
 1015           }
 1016   
 1017           String[] writerNames = readerSpi.getImageWriterSpiNames();
 1018           if (writerNames == null) {
 1019               return null;
 1020           }
 1021   
 1022           Class writerSpiClass = null;
 1023           try {
 1024               writerSpiClass = Class.forName(writerNames[0], true,
 1025                                              ClassLoader.getSystemClassLoader());
 1026           } catch (ClassNotFoundException e) {
 1027               return null;
 1028           }
 1029   
 1030           ImageWriterSpi writerSpi = (ImageWriterSpi)
 1031               theRegistry.getServiceProviderByClass(writerSpiClass);
 1032           if (writerSpi == null) {
 1033               return null;
 1034           }
 1035   
 1036           try {
 1037               return writerSpi.createWriterInstance();
 1038           } catch (IOException e) {
 1039               // Deregister the spi in this case, but only as a writerSpi
 1040               theRegistry.deregisterServiceProvider(writerSpi,
 1041                                                     ImageWriterSpi.class);
 1042               return null;
 1043           }
 1044       }
 1045   
 1046       /**
 1047        * Returns an <code>ImageReader</code>corresponding to the given
 1048        * <code>ImageWriter</code>, if there is one, or <code>null</code>
 1049        * if the plug-in for this <code>ImageWriter</code> does not
 1050        * specify a corresponding <code>ImageReader</code>, or if the
 1051        * given <code>ImageWriter</code> is not registered.  This method
 1052        * is provided principally for symmetry with
 1053        * <code>getImageWriter(ImageReader)</code>.  Note that this
 1054        * method returns the "preferred" reader, which is the first in
 1055        * the list returned by
 1056        * javax.imageio.spi.ImageWriterSpi.<code>getImageReaderSpiNames()</code>.
 1057        *
 1058        * @param writer an instance of a registered <code>ImageWriter</code>.
 1059        *
 1060        * @return an <code>ImageReader</code>, or null.
 1061        *
 1062        * @exception IllegalArgumentException if <code>writer</code> is
 1063        * <code>null</code>.
 1064        *
 1065        * @see #getImageWriter(ImageReader)
 1066        * @see javax.imageio.spi.ImageWriterSpi#getImageReaderSpiNames()
 1067        */
 1068       public static ImageReader getImageReader(ImageWriter writer) {
 1069           if (writer == null) {
 1070               throw new IllegalArgumentException("writer == null!");
 1071           }
 1072   
 1073           ImageWriterSpi writerSpi = writer.getOriginatingProvider();
 1074           if (writerSpi == null) {
 1075               Iterator writerSpiIter;
 1076               // Ensure category is present
 1077               try {
 1078                   writerSpiIter =
 1079                       theRegistry.getServiceProviders(ImageWriterSpi.class,
 1080                                                       false);
 1081               } catch (IllegalArgumentException e) {
 1082                   return null;
 1083               }
 1084   
 1085               while (writerSpiIter.hasNext()) {
 1086                   ImageWriterSpi temp = (ImageWriterSpi) writerSpiIter.next();
 1087                   if (temp.isOwnWriter(writer)) {
 1088                       writerSpi = temp;
 1089                       break;
 1090                   }
 1091               }
 1092               if (writerSpi == null) {
 1093                   return null;
 1094               }
 1095           }
 1096   
 1097           String[] readerNames = writerSpi.getImageReaderSpiNames();
 1098           if (readerNames == null) {
 1099               return null;
 1100           }
 1101   
 1102           Class readerSpiClass = null;
 1103           try {
 1104               readerSpiClass = Class.forName(readerNames[0], true,
 1105                                              ClassLoader.getSystemClassLoader());
 1106           } catch (ClassNotFoundException e) {
 1107               return null;
 1108           }
 1109   
 1110           ImageReaderSpi readerSpi = (ImageReaderSpi)
 1111               theRegistry.getServiceProviderByClass(readerSpiClass);
 1112           if (readerSpi == null) {
 1113               return null;
 1114           }
 1115   
 1116           try {
 1117               return readerSpi.createReaderInstance();
 1118           } catch (IOException e) {
 1119               // Deregister the spi in this case, but only as a readerSpi
 1120               theRegistry.deregisterServiceProvider(readerSpi,
 1121                                                     ImageReaderSpi.class);
 1122               return null;
 1123           }
 1124       }
 1125   
 1126       /**
 1127        * Returns an <code>Iterator</code> containing all currently
 1128        * registered <code>ImageWriter</code>s that claim to be able to
 1129        * encode images of the given layout (specified using an
 1130        * <code>ImageTypeSpecifier</code>) in the given format.
 1131        *
 1132        * @param type an <code>ImageTypeSpecifier</code> indicating the
 1133        * layout of the image to be written.
 1134        * @param formatName the informal name of the <code>format</code>.
 1135        *
 1136        * @return an <code>Iterator</code> containing <code>ImageWriter</code>s.
 1137        *
 1138        * @exception IllegalArgumentException if any parameter is
 1139        * <code>null</code>.
 1140        *
 1141        * @see javax.imageio.spi.ImageWriterSpi#canEncodeImage(ImageTypeSpecifier)
 1142        */
 1143       public static Iterator<ImageWriter>
 1144           getImageWriters(ImageTypeSpecifier type, String formatName)
 1145       {
 1146           if (type == null) {
 1147               throw new IllegalArgumentException("type == null!");
 1148           }
 1149           if (formatName == null) {
 1150               throw new IllegalArgumentException("formatName == null!");
 1151           }
 1152   
 1153           Iterator iter;
 1154           // Ensure category is present
 1155           try {
 1156               iter = theRegistry.getServiceProviders(ImageWriterSpi.class,
 1157                                    new CanEncodeImageAndFormatFilter(type,
 1158                                                                      formatName),
 1159                                               true);
 1160           } catch (IllegalArgumentException e) {
 1161               return Collections.emptyIterator();
 1162           }
 1163   
 1164           return new ImageWriterIterator(iter);
 1165       }
 1166   
 1167       static class ImageTranscoderIterator
 1168           implements Iterator<ImageTranscoder>
 1169       {
 1170           // Contains ImageTranscoderSpis
 1171           public Iterator iter;
 1172   
 1173           public ImageTranscoderIterator(Iterator iter) {
 1174               this.iter = iter;
 1175           }
 1176   
 1177           public boolean hasNext() {
 1178               return iter.hasNext();
 1179           }
 1180   
 1181           public ImageTranscoder next() {
 1182               ImageTranscoderSpi spi = null;
 1183               spi = (ImageTranscoderSpi)iter.next();
 1184               return spi.createTranscoderInstance();
 1185           }
 1186   
 1187           public void remove() {
 1188               throw new UnsupportedOperationException();
 1189           }
 1190       }
 1191   
 1192       static class TranscoderFilter
 1193           implements ServiceRegistry.Filter {
 1194   
 1195           String readerSpiName;
 1196           String writerSpiName;
 1197   
 1198           public TranscoderFilter(ImageReaderSpi readerSpi,
 1199                                   ImageWriterSpi writerSpi) {
 1200               this.readerSpiName = readerSpi.getClass().getName();
 1201               this.writerSpiName = writerSpi.getClass().getName();
 1202           }
 1203   
 1204           public boolean filter(Object elt) {
 1205               ImageTranscoderSpi spi = (ImageTranscoderSpi)elt;
 1206               String readerName = spi.getReaderServiceProviderName();
 1207               String writerName = spi.getWriterServiceProviderName();
 1208               return (readerName.equals(readerSpiName) &&
 1209                       writerName.equals(writerSpiName));
 1210           }
 1211       }
 1212   
 1213       /**
 1214        * Returns an <code>Iterator</code> containing all currently
 1215        * registered <code>ImageTranscoder</code>s that claim to be
 1216        * able to transcode between the metadata of the given
 1217        * <code>ImageReader</code> and <code>ImageWriter</code>.
 1218        *
 1219        * @param reader an <code>ImageReader</code>.
 1220        * @param writer an <code>ImageWriter</code>.
 1221        *
 1222        * @return an <code>Iterator</code> containing
 1223        * <code>ImageTranscoder</code>s.
 1224        *
 1225        * @exception IllegalArgumentException if <code>reader</code> or
 1226        * <code>writer</code> is <code>null</code>.
 1227        */
 1228       public static Iterator<ImageTranscoder>
 1229           getImageTranscoders(ImageReader reader, ImageWriter writer)
 1230       {
 1231           if (reader == null) {
 1232               throw new IllegalArgumentException("reader == null!");
 1233           }
 1234           if (writer == null) {
 1235               throw new IllegalArgumentException("writer == null!");
 1236           }
 1237           ImageReaderSpi readerSpi = reader.getOriginatingProvider();
 1238           ImageWriterSpi writerSpi = writer.getOriginatingProvider();
 1239           ServiceRegistry.Filter filter =
 1240               new TranscoderFilter(readerSpi, writerSpi);
 1241   
 1242           Iterator iter;
 1243           // Ensure category is present
 1244           try {
 1245               iter = theRegistry.getServiceProviders(ImageTranscoderSpi.class,
 1246                                               filter, true);
 1247           } catch (IllegalArgumentException e) {
 1248               return Collections.emptyIterator();
 1249           }
 1250           return new ImageTranscoderIterator(iter);
 1251       }
 1252   
 1253       // All-in-one methods
 1254   
 1255       /**
 1256        * Returns a <code>BufferedImage</code> as the result of decoding
 1257        * a supplied <code>File</code> with an <code>ImageReader</code>
 1258        * chosen automatically from among those currently registered.
 1259        * The <code>File</code> is wrapped in an
 1260        * <code>ImageInputStream</code>.  If no registered
 1261        * <code>ImageReader</code> claims to be able to read the
 1262        * resulting stream, <code>null</code> is returned.
 1263        *
 1264        * <p> The current cache settings from <code>getUseCache</code>and
 1265        * <code>getCacheDirectory</code> will be used to control caching in the
 1266        * <code>ImageInputStream</code> that is created.
 1267        *
 1268        * <p> Note that there is no <code>read</code> method that takes a
 1269        * filename as a <code>String</code>; use this method instead after
 1270        * creating a <code>File</code> from the filename.
 1271        *
 1272        * <p> This method does not attempt to locate
 1273        * <code>ImageReader</code>s that can read directly from a
 1274        * <code>File</code>; that may be accomplished using
 1275        * <code>IIORegistry</code> and <code>ImageReaderSpi</code>.
 1276        *
 1277        * @param input a <code>File</code> to read from.
 1278        *
 1279        * @return a <code>BufferedImage</code> containing the decoded
 1280        * contents of the input, or <code>null</code>.
 1281        *
 1282        * @exception IllegalArgumentException if <code>input</code> is
 1283        * <code>null</code>.
 1284        * @exception IOException if an error occurs during reading.
 1285        */
 1286       public static BufferedImage read(File input) throws IOException {
 1287           if (input == null) {
 1288               throw new IllegalArgumentException("input == null!");
 1289           }
 1290           if (!input.canRead()) {
 1291               throw new IIOException("Can't read input file!");
 1292           }
 1293   
 1294           ImageInputStream stream = createImageInputStream(input);
 1295           if (stream == null) {
 1296               throw new IIOException("Can't create an ImageInputStream!");
 1297           }
 1298           BufferedImage bi = read(stream);
 1299           if (bi == null) {
 1300               stream.close();
 1301           }
 1302           return bi;
 1303       }
 1304   
 1305       /**
 1306        * Returns a <code>BufferedImage</code> as the result of decoding
 1307        * a supplied <code>InputStream</code> with an <code>ImageReader</code>
 1308        * chosen automatically from among those currently registered.
 1309        * The <code>InputStream</code> is wrapped in an
 1310        * <code>ImageInputStream</code>.  If no registered
 1311        * <code>ImageReader</code> claims to be able to read the
 1312        * resulting stream, <code>null</code> is returned.
 1313        *
 1314        * <p> The current cache settings from <code>getUseCache</code>and
 1315        * <code>getCacheDirectory</code> will be used to control caching in the
 1316        * <code>ImageInputStream</code> that is created.
 1317        *
 1318        * <p> This method does not attempt to locate
 1319        * <code>ImageReader</code>s that can read directly from an
 1320        * <code>InputStream</code>; that may be accomplished using
 1321        * <code>IIORegistry</code> and <code>ImageReaderSpi</code>.
 1322        *
 1323        * <p> This method <em>does not</em> close the provided
 1324        * <code>InputStream</code> after the read operation has completed;
 1325        * it is the responsibility of the caller to close the stream, if desired.
 1326        *
 1327        * @param input an <code>InputStream</code> to read from.
 1328        *
 1329        * @return a <code>BufferedImage</code> containing the decoded
 1330        * contents of the input, or <code>null</code>.
 1331        *
 1332        * @exception IllegalArgumentException if <code>input</code> is
 1333        * <code>null</code>.
 1334        * @exception IOException if an error occurs during reading.
 1335        */
 1336       public static BufferedImage read(InputStream input) throws IOException {
 1337           if (input == null) {
 1338               throw new IllegalArgumentException("input == null!");
 1339           }
 1340   
 1341           ImageInputStream stream = createImageInputStream(input);
 1342           BufferedImage bi = read(stream);
 1343           if (bi == null) {
 1344               stream.close();
 1345           }
 1346           return bi;
 1347       }
 1348   
 1349       /**
 1350        * Returns a <code>BufferedImage</code> as the result of decoding
 1351        * a supplied <code>URL</code> with an <code>ImageReader</code>
 1352        * chosen automatically from among those currently registered.  An
 1353        * <code>InputStream</code> is obtained from the <code>URL</code>,
 1354        * which is wrapped in an <code>ImageInputStream</code>.  If no
 1355        * registered <code>ImageReader</code> claims to be able to read
 1356        * the resulting stream, <code>null</code> is returned.
 1357        *
 1358        * <p> The current cache settings from <code>getUseCache</code>and
 1359        * <code>getCacheDirectory</code> will be used to control caching in the
 1360        * <code>ImageInputStream</code> that is created.
 1361        *
 1362        * <p> This method does not attempt to locate
 1363        * <code>ImageReader</code>s that can read directly from a
 1364        * <code>URL</code>; that may be accomplished using
 1365        * <code>IIORegistry</code> and <code>ImageReaderSpi</code>.
 1366        *
 1367        * @param input a <code>URL</code> to read from.
 1368        *
 1369        * @return a <code>BufferedImage</code> containing the decoded
 1370        * contents of the input, or <code>null</code>.
 1371        *
 1372        * @exception IllegalArgumentException if <code>input</code> is
 1373        * <code>null</code>.
 1374        * @exception IOException if an error occurs during reading.
 1375        */
 1376       public static BufferedImage read(URL input) throws IOException {
 1377           if (input == null) {
 1378               throw new IllegalArgumentException("input == null!");
 1379           }
 1380   
 1381           InputStream istream = null;
 1382           try {
 1383               istream = input.openStream();
 1384           } catch (IOException e) {
 1385               throw new IIOException("Can't get input stream from URL!", e);
 1386           }
 1387           ImageInputStream stream = createImageInputStream(istream);
 1388           BufferedImage bi;
 1389           try {
 1390               bi = read(stream);
 1391               if (bi == null) {
 1392                   stream.close();
 1393               }
 1394           } finally {
 1395               istream.close();
 1396           }
 1397           return bi;
 1398       }
 1399   
 1400       /**
 1401        * Returns a <code>BufferedImage</code> as the result of decoding
 1402        * a supplied <code>ImageInputStream</code> with an
 1403        * <code>ImageReader</code> chosen automatically from among those
 1404        * currently registered.  If no registered
 1405        * <code>ImageReader</code> claims to be able to read the stream,
 1406        * <code>null</code> is returned.
 1407        *
 1408        * <p> Unlike most other methods in this class, this method <em>does</em>
 1409        * close the provided <code>ImageInputStream</code> after the read
 1410        * operation has completed, unless <code>null</code> is returned,
 1411        * in which case this method <em>does not</em> close the stream.
 1412        *
 1413        * @param stream an <code>ImageInputStream</code> to read from.
 1414        *
 1415        * @return a <code>BufferedImage</code> containing the decoded
 1416        * contents of the input, or <code>null</code>.
 1417        *
 1418        * @exception IllegalArgumentException if <code>stream</code> is
 1419        * <code>null</code>.
 1420        * @exception IOException if an error occurs during reading.
 1421        */
 1422       public static BufferedImage read(ImageInputStream stream)
 1423           throws IOException {
 1424           if (stream == null) {
 1425               throw new IllegalArgumentException("stream == null!");
 1426           }
 1427   
 1428           Iterator iter = getImageReaders(stream);
 1429           if (!iter.hasNext()) {
 1430               return null;
 1431           }
 1432   
 1433           ImageReader reader = (ImageReader)iter.next();
 1434           ImageReadParam param = reader.getDefaultReadParam();
 1435           reader.setInput(stream, true, true);
 1436           BufferedImage bi;
 1437           try {
 1438               bi = reader.read(0, param);
 1439           } finally {
 1440               reader.dispose();
 1441               stream.close();
 1442           }
 1443           return bi;
 1444       }
 1445   
 1446       /**
 1447        * Writes an image using the an arbitrary <code>ImageWriter</code>
 1448        * that supports the given format to an
 1449        * <code>ImageOutputStream</code>.  The image is written to the
 1450        * <code>ImageOutputStream</code> starting at the current stream
 1451        * pointer, overwriting existing stream data from that point
 1452        * forward, if present.
 1453        *
 1454        * <p> This method <em>does not</em> close the provided
 1455        * <code>ImageOutputStream</code> after the write operation has completed;
 1456        * it is the responsibility of the caller to close the stream, if desired.
 1457        *
 1458        * @param im a <code>RenderedImage</code> to be written.
 1459        * @param formatName a <code>String</code> containg the informal
 1460        * name of the format.
 1461        * @param output an <code>ImageOutputStream</code> to be written to.
 1462        *
 1463        * @return <code>false</code> if no appropriate writer is found.
 1464        *
 1465        * @exception IllegalArgumentException if any parameter is
 1466        * <code>null</code>.
 1467        * @exception IOException if an error occurs during writing.
 1468        */
 1469       public static boolean write(RenderedImage im,
 1470                                   String formatName,
 1471                                   ImageOutputStream output) throws IOException {
 1472           if (im == null) {
 1473               throw new IllegalArgumentException("im == null!");
 1474           }
 1475           if (formatName == null) {
 1476               throw new IllegalArgumentException("formatName == null!");
 1477           }
 1478           if (output == null) {
 1479               throw new IllegalArgumentException("output == null!");
 1480           }
 1481   
 1482           return doWrite(im, getWriter(im, formatName), output);
 1483       }
 1484   
 1485       /**
 1486        * Writes an image using an arbitrary <code>ImageWriter</code>
 1487        * that supports the given format to a <code>File</code>.  If
 1488        * there is already a <code>File</code> present, its contents are
 1489        * discarded.
 1490        *
 1491        * @param im a <code>RenderedImage</code> to be written.
 1492        * @param formatName a <code>String</code> containg the informal
 1493        * name of the format.
 1494        * @param output a <code>File</code> to be written to.
 1495        *
 1496        * @return <code>false</code> if no appropriate writer is found.
 1497        *
 1498        * @exception IllegalArgumentException if any parameter is
 1499        * <code>null</code>.
 1500        * @exception IOException if an error occurs during writing.
 1501        */
 1502       public static boolean write(RenderedImage im,
 1503                                   String formatName,
 1504                                   File output) throws IOException {
 1505           if (output == null) {
 1506               throw new IllegalArgumentException("output == null!");
 1507           }
 1508           ImageOutputStream stream = null;
 1509   
 1510           ImageWriter writer = getWriter(im, formatName);
 1511           if (writer == null) {
 1512               /* Do not make changes in the file system if we have
 1513                * no appropriate writer.
 1514                */
 1515               return false;
 1516           }
 1517   
 1518           try {
 1519               output.delete();
 1520               stream = createImageOutputStream(output);
 1521           } catch (IOException e) {
 1522               throw new IIOException("Can't create output stream!", e);
 1523           }
 1524   
 1525           try {
 1526               return doWrite(im, writer, stream);
 1527           } finally {
 1528               stream.close();
 1529           }
 1530       }
 1531   
 1532       /**
 1533        * Writes an image using an arbitrary <code>ImageWriter</code>
 1534        * that supports the given format to an <code>OutputStream</code>.
 1535        *
 1536        * <p> This method <em>does not</em> close the provided
 1537        * <code>OutputStream</code> after the write operation has completed;
 1538        * it is the responsibility of the caller to close the stream, if desired.
 1539        *
 1540        * <p> The current cache settings from <code>getUseCache</code>and
 1541        * <code>getCacheDirectory</code> will be used to control caching.
 1542        *
 1543        * @param im a <code>RenderedImage</code> to be written.
 1544        * @param formatName a <code>String</code> containg the informal
 1545        * name of the format.
 1546        * @param output an <code>OutputStream</code> to be written to.
 1547        *
 1548        * @return <code>false</code> if no appropriate writer is found.
 1549        *
 1550        * @exception IllegalArgumentException if any parameter is
 1551        * <code>null</code>.
 1552        * @exception IOException if an error occurs during writing.
 1553        */
 1554       public static boolean write(RenderedImage im,
 1555                                   String formatName,
 1556                                   OutputStream output) throws IOException {
 1557           if (output == null) {
 1558               throw new IllegalArgumentException("output == null!");
 1559           }
 1560           ImageOutputStream stream = null;
 1561           try {
 1562               stream = createImageOutputStream(output);
 1563           } catch (IOException e) {
 1564               throw new IIOException("Can't create output stream!", e);
 1565           }
 1566   
 1567           try {
 1568               return doWrite(im, getWriter(im, formatName), stream);
 1569           } finally {
 1570               stream.close();
 1571           }
 1572       }
 1573   
 1574       /**
 1575        * Returns <code>ImageWriter</code> instance according to given
 1576        * rendered image and image format or <code>null</code> if there
 1577        * is no appropriate writer.
 1578        */
 1579       private static ImageWriter getWriter(RenderedImage im,
 1580                                            String formatName) {
 1581           ImageTypeSpecifier type =
 1582               ImageTypeSpecifier.createFromRenderedImage(im);
 1583           Iterator<ImageWriter> iter = getImageWriters(type, formatName);
 1584   
 1585           if (iter.hasNext()) {
 1586               return iter.next();
 1587           } else {
 1588               return null;
 1589           }
 1590       }
 1591   
 1592       /**
 1593        * Writes image to output stream  using given image writer.
 1594        */
 1595       private static boolean doWrite(RenderedImage im, ImageWriter writer,
 1596                                    ImageOutputStream output) throws IOException {
 1597           if (writer == null) {
 1598               return false;
 1599           }
 1600           writer.setOutput(output);
 1601           try {
 1602               writer.write(im);
 1603           } finally {
 1604               writer.dispose();
 1605               output.flush();
 1606           }
 1607           return true;
 1608       }
 1609   }

Save This Page
Home » openjdk-7 » javax » imageio » [javadoc | source]