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

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

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