Source for javax.imageio.ImageIO

   1: /* ImageIO.java --
   2:    Copyright (C) 2004, 2005  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.imageio;
  40: 
  41: import java.awt.image.BufferedImage;
  42: import java.awt.image.RenderedImage;
  43: import java.io.File;
  44: import java.io.FileInputStream;
  45: import java.io.FileOutputStream;
  46: import java.io.IOException;
  47: import java.io.InputStream;
  48: import java.io.OutputStream;
  49: import java.net.URL;
  50: import java.util.ArrayList;
  51: import java.util.Collections;
  52: import java.util.Iterator;
  53: 
  54: import javax.imageio.spi.IIORegistry;
  55: import javax.imageio.spi.ImageInputStreamSpi;
  56: import javax.imageio.spi.ImageOutputStreamSpi;
  57: import javax.imageio.spi.ImageReaderSpi;
  58: import javax.imageio.spi.ImageTranscoderSpi;
  59: import javax.imageio.spi.ImageWriterSpi;
  60: import javax.imageio.spi.ServiceRegistry;
  61: import javax.imageio.stream.ImageInputStream;
  62: import javax.imageio.stream.ImageOutputStream;
  63: import javax.imageio.stream.MemoryCacheImageInputStream;
  64: import javax.imageio.stream.MemoryCacheImageOutputStream;
  65: 
  66: /**
  67:  * An uninstantiable class that provides static methods for locating
  68:  * and using image readers and writers.
  69:  */
  70: public final class ImageIO
  71: {
  72:   /**
  73:    * Construct an ImageIO.  Private since ImageIO is not instantiable.
  74:    */
  75:   private ImageIO()
  76:   {
  77:   }
  78: 
  79:   private static final class ReaderFormatFilter implements ServiceRegistry.Filter
  80:   {
  81:     private String formatName;
  82: 
  83:     public ReaderFormatFilter(String formatName)
  84:     {
  85:       this.formatName = formatName;
  86:     }
  87: 
  88:     public boolean filter (Object provider)
  89:     {
  90:       if (provider instanceof ImageReaderSpi)
  91:         {
  92:           ImageReaderSpi spi = (ImageReaderSpi) provider;
  93:           String[] formatNames = spi.getFormatNames();
  94: 
  95:           for (int i = formatNames.length - 1; i >= 0; --i)
  96:             if (formatName.equals(formatNames[i]))
  97:               return true;
  98:         }
  99: 
 100:       return false;
 101:     }
 102:   }
 103: 
 104:   private static final class ReaderMIMETypeFilter implements ServiceRegistry.Filter
 105:   {
 106:     private String MIMEType;
 107: 
 108:     public ReaderMIMETypeFilter(String MIMEType)
 109:     {
 110:       this.MIMEType = MIMEType;
 111:     }
 112: 
 113:     public boolean filter(Object provider)
 114:     {
 115:       if (provider instanceof ImageReaderSpi)
 116:         {
 117:           ImageReaderSpi spi = (ImageReaderSpi) provider;
 118:           String[] mimetypes = spi.getMIMETypes();
 119: 
 120:           for (int i = mimetypes.length - 1; i >= 0; --i)
 121:             if (MIMEType.equals(mimetypes[i]))
 122:               return true;
 123:         }
 124: 
 125:       return false;
 126:     }
 127:   }
 128: 
 129:   private static final class ReaderObjectFilter implements ServiceRegistry.Filter
 130:   {
 131:     private Object object;
 132: 
 133:     public ReaderObjectFilter(Object object)
 134:     {
 135:       this.object = object;
 136:     }
 137: 
 138:     public boolean filter(Object provider)
 139:     {
 140:       if (provider instanceof ImageReaderSpi)
 141:         {
 142:           ImageReaderSpi spi = (ImageReaderSpi) provider;
 143: 
 144:           try
 145:             {
 146:               if (spi.canDecodeInput(object))
 147:                 return true;
 148:             }
 149:           catch (IOException e)
 150:             {
 151:               // Return false in this case
 152:             }
 153:         }
 154:       return false;
 155:     }
 156:   }
 157: 
 158:   private static final class ReaderSuffixFilter implements ServiceRegistry.Filter
 159:   {
 160:     private String fileSuffix;
 161: 
 162:     public ReaderSuffixFilter(String fileSuffix)
 163:     {
 164:       this.fileSuffix = fileSuffix;
 165:     }
 166: 
 167:     public boolean filter(Object provider)
 168:     {
 169:       if (provider instanceof ImageReaderSpi)
 170:         {
 171:           ImageReaderSpi spi = (ImageReaderSpi) provider;
 172:           String[] suffixes = spi.getFileSuffixes();
 173: 
 174:           for (int i = suffixes.length - 1; i >= 0; --i)
 175:             if (fileSuffix.equals(suffixes[i]))
 176:               return true;
 177:         }
 178: 
 179:       return false;
 180:     }
 181:   }
 182: 
 183:   private static final class WriterFormatFilter implements ServiceRegistry.Filter
 184:   {
 185:     private String formatName;
 186: 
 187:     public WriterFormatFilter(String formatName)
 188:     {
 189:       this.formatName = formatName;
 190:     }
 191: 
 192:     public boolean filter(Object provider)
 193:     {
 194:       if (provider instanceof ImageWriterSpi)
 195:         {
 196:           ImageWriterSpi spi = (ImageWriterSpi) provider;
 197:           String[] formatNames = spi.getFormatNames();
 198: 
 199:           for (int i = formatNames.length - 1; i >= 0; --i)
 200:             if (formatName.equals(formatNames[i]))
 201:               return true;
 202:         }
 203: 
 204:       return false;
 205:     }
 206:   }
 207: 
 208:   private static final class WriterMIMETypeFilter implements ServiceRegistry.Filter
 209:   {
 210:     private String MIMEType;
 211: 
 212:     public WriterMIMETypeFilter(String MIMEType)
 213:     {
 214:       this.MIMEType = MIMEType;
 215:     }
 216: 
 217:     public boolean filter(Object provider)
 218:     {
 219:       if (provider instanceof ImageWriterSpi)
 220:         {
 221:           ImageWriterSpi spi = (ImageWriterSpi) provider;
 222:           String[] mimetypes = spi.getMIMETypes();
 223: 
 224:           for (int i = mimetypes.length - 1; i >= 0; --i)
 225:             if (MIMEType.equals(mimetypes[i]))
 226:               return true;
 227:         }
 228: 
 229:       return false;
 230:     }
 231:   }
 232: 
 233:   private static final class WriterSuffixFilter implements ServiceRegistry.Filter
 234:   {
 235:     private String fileSuffix;
 236: 
 237:     public WriterSuffixFilter(String fileSuffix)
 238:     {
 239:       this.fileSuffix = fileSuffix;
 240:     }
 241: 
 242:     public boolean filter(Object provider)
 243:     {
 244:       if (provider instanceof ImageWriterSpi)
 245:         {
 246:           ImageWriterSpi spi = (ImageWriterSpi) provider;
 247:           String[] suffixes = spi.getFileSuffixes();
 248: 
 249:           for (int i = suffixes.length - 1; i >= 0; --i)
 250:             if (fileSuffix.equals(suffixes[i]))
 251:               return true;
 252:         }
 253: 
 254:       return false;
 255:     }
 256:   }
 257: 
 258:   private static final class WriterObjectFilter implements ServiceRegistry.Filter
 259:   {
 260:     private ImageTypeSpecifier type;
 261:     private String formatName;
 262: 
 263:     public WriterObjectFilter(ImageTypeSpecifier type,
 264:                               String formatName)
 265:     {
 266:       this.type = type;
 267:       this.formatName = formatName;
 268:     }
 269: 
 270:     public boolean filter(Object provider)
 271:     {
 272:       if (provider instanceof ImageWriterSpi)
 273:         {
 274:           ImageWriterSpi spi = (ImageWriterSpi) provider;
 275: 
 276:           if (spi.canEncodeImage(type))
 277:             {
 278:               String[] formatNames = spi.getFormatNames();
 279:               for (int i = formatNames.length - 1; i >= 0; --i)
 280:                 if (formatName.equals(formatNames[i]))
 281:                   return true;
 282:             }
 283:         }
 284: 
 285:       return false;
 286:     }
 287:   }
 288: 
 289:   private static final class TranscoderFilter implements ServiceRegistry.Filter
 290:   {
 291:     private ImageReader reader;
 292:     private ImageWriter writer;
 293: 
 294:     public TranscoderFilter(ImageReader reader,
 295:                             ImageWriter writer)
 296:     {
 297:       this.reader = reader;
 298:       this.writer = writer;
 299:     }
 300: 
 301:     public boolean filter(Object provider)
 302:     {
 303:       if (provider instanceof ImageTranscoderSpi)
 304:         {
 305:           ImageTranscoderSpi spi = (ImageTranscoderSpi) provider;
 306: 
 307:           if (spi.getReaderServiceProviderName().equals
 308:               (reader.getOriginatingProvider().getClass().getName())
 309:               && spi.getWriterServiceProviderName().equals
 310:               (writer.getOriginatingProvider().getClass().getName()))
 311:             return true;
 312:         }
 313: 
 314:       return false;
 315:     }
 316:   }
 317: 
 318:   private static final class ImageReaderIterator
 319:     implements Iterator<ImageReader>
 320:   {
 321:     Iterator<ImageReaderSpi> it;
 322:     Object readerExtension;
 323: 
 324:     public ImageReaderIterator(Iterator<ImageReaderSpi> it,
 325:                                Object readerExtension)
 326:     {
 327:       this.it = it;
 328:       this.readerExtension = readerExtension;
 329:     }
 330: 
 331:     public ImageReaderIterator(Iterator<ImageReaderSpi> it)
 332:     {
 333:       this.it = it;
 334:     }
 335: 
 336:     public boolean hasNext()
 337:     {
 338:       return it.hasNext();
 339:     }
 340: 
 341:     public ImageReader next()
 342:     {
 343:       try
 344:         {
 345:           ImageReaderSpi spi = it.next();
 346:           return (readerExtension == null
 347:               ? spi.createReaderInstance()
 348:               : spi.createReaderInstance(readerExtension));
 349:         }
 350:       catch (IOException e)
 351:         {
 352:           return null;
 353:         }
 354:     }
 355: 
 356:     public void remove()
 357:     {
 358:       throw new UnsupportedOperationException();
 359:     }
 360:   }
 361: 
 362:   private static final class ImageWriterIterator
 363:     implements Iterator<ImageWriter>
 364:   {
 365:     Iterator<ImageWriterSpi> it;
 366:     Object writerExtension;
 367: 
 368:     public ImageWriterIterator(Iterator<ImageWriterSpi> it,
 369:                                Object writerExtension)
 370:     {
 371:       this.it = it;
 372:       this.writerExtension = writerExtension;
 373:     }
 374: 
 375:     public ImageWriterIterator(Iterator<ImageWriterSpi> it)
 376:     {
 377:       this.it = it;
 378:     }
 379: 
 380:     public boolean hasNext()
 381:     {
 382:       return it.hasNext();
 383:     }
 384: 
 385:     public ImageWriter next()
 386:     {
 387:       try
 388:         {
 389:           ImageWriterSpi spi = it.next();
 390:           return (writerExtension == null
 391:               ? spi.createWriterInstance()
 392:               : spi.createWriterInstance(writerExtension));
 393:         }
 394:       catch (IOException e)
 395:         {
 396:           return null;
 397:         }
 398:     }
 399: 
 400:     public void remove()
 401:     {
 402:       throw new UnsupportedOperationException();
 403:     }
 404:   }
 405: 
 406:   private static File cacheDirectory;
 407:   private static boolean useCache = true;
 408: 
 409:   private static Iterator<ImageReader> getReadersByFilter(Class<ImageReaderSpi> type,
 410:                                                           ServiceRegistry.Filter filter,
 411:                                                           Object readerExtension)
 412:   {
 413:     try
 414:       {
 415:         Iterator<ImageReaderSpi> it
 416:           = getRegistry().getServiceProviders(type, filter, true);
 417:         return new ImageReaderIterator(it, readerExtension);
 418:       }
 419:     catch (IllegalArgumentException e)
 420:       {
 421:         return Collections.EMPTY_SET.iterator();
 422:       }
 423:   }
 424: 
 425:   private static Iterator<ImageWriter> getWritersByFilter(Class<ImageWriterSpi> type,
 426:                                                           ServiceRegistry.Filter filter,
 427:                                                           Object writerExtension)
 428:   {
 429:     try
 430:       {
 431:         Iterator<ImageWriterSpi> it
 432:           = getRegistry().getServiceProviders(type, filter, true);
 433:         return new ImageWriterIterator(it, writerExtension);
 434:       }
 435:     catch (IllegalArgumentException e)
 436:       {
 437:         return Collections.EMPTY_SET.iterator();
 438:       }
 439:   }
 440: 
 441:   /**
 442:    * Retrieve the current cache directory.
 443:    *
 444:    * @return the current cache directory or null if none is set.
 445:    */
 446:   public static File getCacheDirectory()
 447:   {
 448:     return cacheDirectory;
 449:   }
 450: 
 451:   /**
 452:    * Retrieve an iterator over all registered readers for the given
 453:    * format.
 454:    *
 455:    * @param formatName an infomal format name (e.g. "jpeg" or "bmp")
 456:    *
 457:    * @return an iterator over a collection of image readers
 458:    *
 459:    * @exception IllegalArgumentException if formatName is null
 460:    */
 461:   public static Iterator<ImageReader> getImageReadersByFormatName(String formatName)
 462:   {
 463:     if (formatName == null)
 464:       throw new IllegalArgumentException("formatName may not be null");
 465: 
 466:     return getReadersByFilter(ImageReaderSpi.class,
 467:                               new ReaderFormatFilter(formatName),
 468:                               formatName);
 469:   }
 470: 
 471:   /**
 472:    * Retrieve an iterator over all registered readers for the given
 473:    * MIME type.
 474:    *
 475:    * @param MIMEType a MIME specification for an image type
 476:    * (e.g. "image/jpeg" or "image/x-bmp")
 477:    *
 478:    * @return an iterator over a collection of image readers
 479:    *
 480:    * @exception IllegalArgumentException if MIMEType is null
 481:    */
 482:   public static Iterator<ImageReader> getImageReadersByMIMEType(String MIMEType)
 483:   {
 484:     if (MIMEType == null)
 485:       throw new IllegalArgumentException("MIMEType may not be null");
 486: 
 487:     return getReadersByFilter(ImageReaderSpi.class,
 488:                               new ReaderMIMETypeFilter(MIMEType),
 489:                               MIMEType);
 490:   }
 491: 
 492:   /**
 493:    * Retrieve an iterator over all registered readers for the given
 494:    * file suffix.
 495:    *
 496:    * @param fileSuffix an image file suffix (e.g. "jpg" or "bmp")
 497:    *
 498:    * @return an iterator over a collection of image readers
 499:    *
 500:    * @exception IllegalArgumentException if fileSuffix is null
 501:    */
 502:   public static Iterator<ImageReader> getImageReadersBySuffix(String fileSuffix)
 503:   {
 504:     if (fileSuffix == null)
 505:       throw new IllegalArgumentException("formatName may not be null");
 506: 
 507:     return getReadersByFilter(ImageReaderSpi.class,
 508:                               new ReaderSuffixFilter(fileSuffix),
 509:                               fileSuffix);
 510:   }
 511: 
 512:   /**
 513:    * Retrieve an iterator over all registered writers for the given
 514:    * format.
 515:    *
 516:    * @param formatName an infomal format name (e.g. "jpeg" or "bmp")
 517:    *
 518:    * @return an iterator over a collection of image writers
 519:    *
 520:    * @exception IllegalArgumentException if formatName is null
 521:    */
 522:   public static Iterator<ImageWriter> getImageWritersByFormatName(String formatName)
 523:   {
 524:     if (formatName == null)
 525:       throw new IllegalArgumentException("formatName may not be null");
 526: 
 527:     return getWritersByFilter(ImageWriterSpi.class,
 528:                               new WriterFormatFilter(formatName),
 529:                               formatName);
 530:   }
 531: 
 532:   /**
 533:    * Retrieve an iterator over all registered writers for the given
 534:    * MIME type.
 535:    *
 536:    * @param MIMEType a MIME specification for an image type
 537:    * (e.g. "image/jpeg" or "image/x-bmp")
 538:    *
 539:    * @return an iterator over a collection of image writers
 540:    *
 541:    * @exception IllegalArgumentException if MIMEType is null
 542:    */
 543:   public static Iterator<ImageWriter> getImageWritersByMIMEType(String MIMEType)
 544:   {
 545:     if (MIMEType == null)
 546:       throw new IllegalArgumentException("MIMEType may not be null");
 547: 
 548:     return getWritersByFilter(ImageWriterSpi.class,
 549:                               new WriterMIMETypeFilter(MIMEType),
 550:                               MIMEType);
 551:   }
 552: 
 553:   /**
 554:    * Retrieve an iterator over all registered writers for the given
 555:    * file suffix.
 556:    *
 557:    * @param fileSuffix an image file suffix (e.g. "jpg" or "bmp")
 558:    *
 559:    * @return an iterator over a collection of image writers
 560:    *
 561:    * @exception IllegalArgumentException if fileSuffix is null
 562:    */
 563:   public static Iterator<ImageWriter> getImageWritersBySuffix(String fileSuffix)
 564:   {
 565:     if (fileSuffix == null)
 566:       throw new IllegalArgumentException("fileSuffix may not be null");
 567: 
 568:     return getWritersByFilter(ImageWriterSpi.class,
 569:                               new WriterSuffixFilter(fileSuffix),
 570:                               fileSuffix);
 571:   }
 572: 
 573:   /**
 574:    * Retrieve all the informal format names supported by the
 575:    * collection of registered image readers.
 576:    *
 577:    * @return an array of format names
 578:    */
 579:   public static String[] getReaderFormatNames()
 580:   {
 581:     try
 582:       {
 583:         Iterator it =
 584:           getRegistry().getServiceProviders(ImageReaderSpi.class, true);
 585:         ArrayList result = new ArrayList();
 586: 
 587:         while (it.hasNext())
 588:           {
 589:             ImageReaderSpi spi = (ImageReaderSpi) it.next();
 590:             String[] names = spi.getFormatNames();
 591: 
 592:             for (int i = names.length - 1; i >= 0; --i)
 593:               result.add(names[i]);
 594:           }
 595: 
 596:         return (String[]) result.toArray(new String[result.size()]);
 597:       }
 598:     catch (IllegalArgumentException e)
 599:       {
 600:         return new String[0];
 601:       }
 602:   }
 603: 
 604:   /**
 605:    * Retrieve all the MIME types supported by the collection of
 606:    * registered image readers.
 607:    *
 608:    * @return an array of MIME types
 609:    */
 610:   public static String[] getReaderMIMETypes()
 611:   {
 612:     try
 613:       {
 614:         Iterator it =
 615:           getRegistry().getServiceProviders(ImageReaderSpi.class, true);
 616:         ArrayList result = new ArrayList();
 617: 
 618:         while (it.hasNext())
 619:           {
 620:             ImageReaderSpi spi = (ImageReaderSpi) it.next();
 621:             String[] names = spi.getMIMETypes();
 622: 
 623:             for (int i = names.length - 1; i >= 0; --i)
 624:               result.add(names[i]);
 625:           }
 626: 
 627:         return (String[]) result.toArray(new String[result.size()]);
 628:       }
 629:     catch (IllegalArgumentException e)
 630:       {
 631:         return new String[0];
 632:       }
 633:   }
 634: 
 635:   private static IIORegistry getRegistry()
 636:   {
 637:     return IIORegistry.getDefaultInstance();
 638:   }
 639: 
 640:   /**
 641:    * Check whether or not an on-disk cache is used for image input and
 642:    * output streams.
 643:    *
 644:    * @return true if an on-disk cache is available, false otherwise
 645:    */
 646:   public static boolean getUseCache()
 647:   {
 648:     return useCache;
 649:   }
 650: 
 651:   /**
 652:    * Retrieve all the informal format names supported by the
 653:    * collection of registered image writers.
 654:    *
 655:    * @return an array of format names
 656:    */
 657:   public static String[] getWriterFormatNames()
 658:   {
 659:     try
 660:       {
 661:         Iterator it =
 662:           getRegistry().getServiceProviders(ImageWriterSpi.class, true);
 663:         ArrayList result = new ArrayList();
 664: 
 665:         while (it.hasNext())
 666:           {
 667:             ImageWriterSpi spi = (ImageWriterSpi) it.next();
 668:             String[] names = spi.getFormatNames();
 669: 
 670:             for (int i = names.length - 1; i >= 0; --i)
 671:               result.add(names[i]);
 672:           }
 673: 
 674:         return (String[]) result.toArray(new String[result.size()]);
 675:       }
 676:     catch (IllegalArgumentException e)
 677:       {
 678:         return new String[0];
 679:       }
 680:   }
 681: 
 682:   /**
 683:    * Retrieve all the MIME types supported by the collection of
 684:    * registered image writers.
 685:    *
 686:    * @return an array of MIME types
 687:    */
 688:   public static String[] getWriterMIMETypes()
 689:   {
 690:     try
 691:       {
 692:         Iterator it =
 693:           getRegistry().getServiceProviders(ImageWriterSpi.class, true);
 694:         ArrayList result = new ArrayList();
 695: 
 696:         while (it.hasNext())
 697:           {
 698:             ImageWriterSpi spi = (ImageWriterSpi) it.next();
 699:             String[] names = spi.getMIMETypes();
 700: 
 701:             for (int i = names.length - 1; i >= 0; --i)
 702:               result.add(names[i]);
 703:           }
 704: 
 705:         return (String[]) result.toArray(new String[result.size()]);
 706:       }
 707:     catch (IllegalArgumentException e)
 708:       {
 709:         return new String[0];
 710:       }
 711:   }
 712: 
 713:   /**
 714:    * Rescans the application classpath for ImageIO service providers
 715:    * and registers them.
 716:    */
 717:   public static void scanForPlugins()
 718:   {
 719:     IIORegistry.getDefaultInstance().registerApplicationClasspathSpis();
 720:   }
 721: 
 722:   /**
 723:    * Set the directory to be used for caching image data.  A null
 724:    * argument means to use the default system temporary directory.
 725:    * This cache directory is only used if getUseCache returns true.
 726:    *
 727:    * @param cacheDirectory the directory where image data should be
 728:    * cached
 729:    *
 730:    * @exception IllegalArgumentException if cacheDirectory is not a
 731:    * directory
 732:    */
 733:   public static void setCacheDirectory(File cacheDirectory)
 734:   {
 735:     // FIXME: add SecurityManager call
 736:     if (cacheDirectory != null)
 737:       {
 738:         if (!cacheDirectory.isDirectory())
 739:           throw new IllegalArgumentException("cacheDirectory must be a directory");
 740: 
 741:         cacheDirectory.canWrite();
 742:       }
 743: 
 744:     ImageIO.cacheDirectory = cacheDirectory;
 745:   }
 746: 
 747:   /**
 748:    * Control whether or not an on-disk cache is used.  This cache is
 749:    * used to store input or output data from an image data stream when
 750:    * data in the stream needs to be re-processed.
 751:    *
 752:    * If useCache is false the cache will be stored in memory.  Doing
 753:    * so eliminates file creation and deletion overhead.  The default
 754:    * is to use an on-disk cache.
 755:    *
 756:    * @param useCache true to use an on-disk cache, false otherwise
 757:    */
 758:   public static void setUseCache(boolean useCache)
 759:   {
 760:     ImageIO.useCache = useCache;
 761:   }
 762: 
 763:   /**
 764:    * Write an image to a file using a registered writer that supports
 765:    * the given format, overwriting the file if it already exists.
 766:    *
 767:    * @param im the image data to write
 768:    * @param formatName an informal description of the output format
 769:    * @param output the file to which the image will be written
 770:    *
 771:    * @return false if no registered writer supports the given format,
 772:    * true otherwise
 773:    *
 774:    * @exception IllegalArgumentException if any argument is null
 775:    * @exception IOException if a writing error occurs
 776:    */
 777:   public static boolean write(RenderedImage im,
 778:                               String formatName,
 779:                               File output)
 780:     throws IOException
 781:   {
 782:     if (im == null || formatName == null || output == null)
 783:       throw new IllegalArgumentException ("null argument");
 784: 
 785:     return write(im, formatName, new FileOutputStream(output));
 786:   }
 787: 
 788:   /**
 789:    * Write an image to an output stream using a registered writer that
 790:    * supports the given format.
 791:    *
 792:    * @param im the image data to write
 793:    * @param formatName an informal description of the output format
 794:    * @param output the output stream to which the image will be
 795:    * written
 796:    *
 797:    * @return false if no registered writer supports the given format,
 798:    * true otherwise
 799:    *
 800:    * @exception IllegalArgumentException if any argument is null
 801:    * @exception IOException if a writing error occurs
 802:    */
 803:   public static boolean write(RenderedImage im,
 804:                               String formatName,
 805:                               OutputStream output)
 806:     throws IOException
 807:   {
 808:     if (im == null || formatName == null || output == null)
 809:       throw new IllegalArgumentException ("null argument");
 810: 
 811:     return write(im, formatName, new MemoryCacheImageOutputStream(output));
 812:   }
 813: 
 814:   /**
 815:    * Write an image to an ImageOutputStream using a registered writer
 816:    * that supports the given format.  Image data is written starting
 817:    * at the ImageOutputStream's current stream pointer, overwriting
 818:    * any existing data.
 819:    *
 820:    * @param im the image data to write
 821:    * @param formatName an informal description of the output format
 822:    * @param output the image output stream to which the image will be
 823:    * written
 824:    *
 825:    * @return false if no registered writer supports the given format,
 826:    * true otherwise
 827:    *
 828:    * @exception IllegalArgumentException if any argument is null
 829:    * @exception IOException if a writing error occurs
 830:    */
 831:   public static boolean write(RenderedImage im,
 832:                               String formatName,
 833:                               ImageOutputStream output)
 834:     throws IOException
 835:   {
 836:     if (im == null || formatName == null || output == null)
 837:       throw new IllegalArgumentException ("null argument");
 838: 
 839:     Iterator writers = getImageWritersByFormatName(formatName);
 840:     IIOImage img = new IIOImage(im, null, null);
 841:     while (writers.hasNext())
 842:       {
 843:         ImageWriter w = (ImageWriter) writers.next();
 844:         try
 845:           {
 846:             w.setOutput(output);
 847:           }
 848:         catch (IllegalArgumentException e)
 849:           {
 850:             continue;
 851:           }
 852: 
 853:         w.write(null, img, null);
 854:         w.dispose();
 855:         output.close();
 856:         return true;
 857:       }
 858:     return false;
 859:   }
 860: 
 861:   /**
 862:    * Create a buffered image from an image input stream.  An image
 863:    * reader that supports the given image data is automatically
 864:    * selected from the collection of registered readers.  If no
 865:    * registered reader can handle the input format, null is returned.
 866:    *
 867:    * @param stream the image input stream from which to read image
 868:    * data
 869:    *
 870:    * @return a new buffered image created from the given image data,
 871:    * or null
 872:    *
 873:    * @exception IllegalArgumentException if stream is null
 874:    * @exception IOException if a reading error occurs
 875:    */
 876:   public static BufferedImage read(ImageInputStream stream)
 877:     throws IOException
 878:   {
 879:     if (stream == null)
 880:       throw new IllegalArgumentException("null argument");
 881: 
 882:     Iterator providers = getRegistry().getServiceProviders(ImageReaderSpi.class, true);
 883:     while (providers.hasNext())
 884:       {
 885:         ImageReaderSpi spi = (ImageReaderSpi) providers.next();
 886:         if (spi.canDecodeInput(stream))
 887:           {
 888:             ImageReader reader = spi.createReaderInstance();
 889:             reader.setInput(stream);
 890:             return reader.read(0, null);
 891:           }
 892:       }
 893:     return null;
 894:   }
 895: 
 896:   /**
 897:    * Create a buffered image from a URL.  An image reader that
 898:    * supports the given image data is automatically selected from the
 899:    * collection of registered readers.  If no registered reader can
 900:    * handle the input format, null is returned.
 901:    *
 902:    * The image data will be cached in the current cache directory if
 903:    * caching is enabled.
 904:    *
 905:    * This method does not locate readers that read data directly from
 906:    * a URL.  To locate such readers manually, use IIORegistry and
 907:    * ImageReaderSpi.
 908:    *
 909:    * @param input the URL from which to retrieve the image file
 910:    *
 911:    * @return a new buffered image created from the given image URL, or
 912:    * null
 913:    *
 914:    * @exception IllegalArgumentException if input is null
 915:    * @exception IOException if a reading error occurs
 916:    */
 917:   public static BufferedImage read(URL input)
 918:     throws IOException
 919:   {
 920:     if (input == null)
 921:       throw new IllegalArgumentException("null argument");
 922: 
 923:     return read(input.openStream());
 924:   }
 925: 
 926:   /**
 927:    * Create a buffered image from an input stream.  An image reader
 928:    * that supports the given image data is automatically selected from
 929:    * the collection of registered readers.  If no registered reader
 930:    * can handle the input format, null is returned.
 931:    *
 932:    * The image data will be cached in the current cache directory if
 933:    * caching is enabled.
 934:    *
 935:    * This method does not locate readers that read data directly from
 936:    * an input stream.  To locate such readers manually, use
 937:    * IIORegistry and ImageReaderSpi.
 938:    *
 939:    * @param input the input stream from which to read the image data
 940:    *
 941:    * @return a new buffered image created from the given input stream,
 942:    * or null
 943:    *
 944:    * @exception IllegalArgumentException if input is null
 945:    * @exception IOException if a reading error occurs
 946:    */
 947:   public static BufferedImage read(InputStream input)
 948:     throws IOException
 949:   {
 950:     if (input == null)
 951:       throw new IllegalArgumentException("null argument");
 952: 
 953:     return read(new MemoryCacheImageInputStream(input));
 954:   }
 955: 
 956:   /**
 957:    * Create a buffered image from a file.  An image reader that
 958:    * supports the given image data is automatically selected from the
 959:    * collection of registered readers.  If no registered reader can
 960:    * handle the input format, null is returned.
 961:    *
 962:    * The image data will be cached in the current cache directory if
 963:    * caching is enabled.
 964:    *
 965:    * This method does not locate readers that read data directly from
 966:    * a file.  To locate such readers manually, use IIORegistry and
 967:    * ImageReaderSpi.
 968:    *
 969:    * @param input the file from which to read image data
 970:    *
 971:    * @return a new buffered image created from the given image file,
 972:    * or null
 973:    *
 974:    * @exception IllegalArgumentException if input is null
 975:    * @exception IOException if a reading error occurs
 976:    */
 977:   public static BufferedImage read(File input)
 978:     throws IOException
 979:   {
 980:     if (input == null)
 981:       throw new IllegalArgumentException("null argument");
 982: 
 983:     return read(new FileInputStream(input));
 984:   }
 985: 
 986:   /**
 987:    * Create an image input stream from the given object.  The
 988:    * collection of ImageInputStreamSpis registered with the
 989:    * IIORegistry is searched for an image input stream that can take
 990:    * input from the given object.  null is returned if no such SPI is
 991:    * registered.
 992:    *
 993:    * The image data will be cached in the current cache directory if
 994:    * caching is enabled.
 995:    *
 996:    * @param input an object from which to read image data
 997:    *
 998:    * @return an ImageInputStream that can read data from input, or
 999:    * null
1000:    *
1001:    * @exception IllegalArgumentException if input is null
1002:    * @exception IOException if caching is required but not enabled
1003:    */
1004:   public static ImageInputStream createImageInputStream (Object input)
1005:     throws IOException
1006:   {
1007:     if (input == null)
1008:       throw new IllegalArgumentException ("null argument");
1009: 
1010:     Iterator spis = getRegistry().getServiceProviders
1011:       (ImageInputStreamSpi.class, true);
1012: 
1013:     ImageInputStreamSpi foundSpi = null;
1014: 
1015:     while(spis.hasNext())
1016:       {
1017:         ImageInputStreamSpi spi = (ImageInputStreamSpi) spis.next();
1018: 
1019:         if (input.getClass().equals(spi.getInputClass()))
1020:           {
1021:             foundSpi = spi;
1022:             break;
1023:           }
1024:       }
1025: 
1026:     return foundSpi == null ? null :
1027:       foundSpi.createInputStreamInstance (input,
1028:                                           getUseCache(),
1029:                                           getCacheDirectory());
1030:   }
1031: 
1032:   /**
1033:    * Create an image output stream from the given object.  The
1034:    * collection of ImageOutputStreamSpis registered with the
1035:    * IIORegistry is searched for an image output stream that can send
1036:    * output to the given object.  null is returned if no such SPI is
1037:    * registered.
1038:    *
1039:    * The image data will be cached in the current cache directory if
1040:    * caching is enabled.
1041:    *
1042:    * @param output an object to which to write image data
1043:    *
1044:    * @return an ImageOutputStream that can send data to output, or
1045:    * null
1046:    *
1047:    * @exception IllegalArgumentException if output is null
1048:    * @exception IOException if caching is required but not enabled
1049:    */
1050:   public static ImageOutputStream createImageOutputStream (Object output)
1051:     throws IOException
1052:   {
1053:     if (output == null)
1054:       throw new IllegalArgumentException ("null argument");
1055: 
1056:     Iterator spis = getRegistry().getServiceProviders
1057:       (ImageOutputStreamSpi.class, true);
1058: 
1059:     ImageOutputStreamSpi foundSpi = null;
1060: 
1061:     while(spis.hasNext())
1062:       {
1063:         ImageOutputStreamSpi spi = (ImageOutputStreamSpi) spis.next();
1064: 
1065:         if (output.getClass().equals(spi.getOutputClass()))
1066:           {
1067:             foundSpi = spi;
1068:             break;
1069:           }
1070:       }
1071: 
1072:     return foundSpi == null ? null :
1073:       foundSpi.createOutputStreamInstance (output,
1074:                                            getUseCache(),
1075:                                            getCacheDirectory());
1076:   }
1077: 
1078:   /**
1079:    * Retrieve an image reader corresponding to an image writer, or
1080:    * null if writer is not registered or if no corresponding reader is
1081:    * registered.
1082:    *
1083:    * @param writer a registered image writer
1084:    *
1085:    * @return an image reader corresponding to writer, or null
1086:    *
1087:    * @exception IllegalArgumentException if writer is null
1088:    */
1089:   public static ImageReader getImageReader (ImageWriter writer)
1090:   {
1091:     if (writer == null)
1092:       throw new IllegalArgumentException ("null argument");
1093: 
1094:     ImageWriterSpi spi = writer.getOriginatingProvider();
1095: 
1096:     String[] readerSpiNames = spi.getImageReaderSpiNames();
1097: 
1098:     ImageReader r = null;
1099: 
1100:     if (readerSpiNames != null)
1101:       {
1102:         try
1103:           {
1104:             Class readerClass = Class.forName (readerSpiNames[0]);
1105:             r = (ImageReader) readerClass.newInstance ();
1106:           }
1107:         catch (Exception e)
1108:           {
1109:             return null;
1110:           }
1111:       }
1112:     return r;
1113:   }
1114: 
1115:   /**
1116:    * Retrieve an iterator over the collection of registered image
1117:    * readers that support reading data from the given object.
1118:    *
1119:    * @param input the object for which to retrieve image readers
1120:    *
1121:    * @return an iterator over a collection of image readers
1122:    */
1123:   public static Iterator<ImageReader> getImageReaders (Object input)
1124:   {
1125:     if (input == null)
1126:       throw new IllegalArgumentException ("null argument");
1127: 
1128:     Iterator<ImageReaderSpi> spiIterator
1129:       = getRegistry().getServiceProviders (ImageReaderSpi.class,
1130:                                            new ReaderObjectFilter(input),
1131:                                            true);
1132:     return new ImageReaderIterator(spiIterator);
1133:   }
1134: 
1135:   /**
1136:    * Retrieve an iterator over the collection of registered image
1137:    * writers that support writing images of the given type and in the
1138:    * given format.
1139:    *
1140:    * @param type the output image's colour and sample models
1141:    * @param formatName the output image format
1142:    *
1143:    * @return an iterator over a collection of image writers
1144:    */
1145:   public static Iterator<ImageWriter> getImageWriters (ImageTypeSpecifier type,
1146:                                           String formatName)
1147:   {
1148:     if (type == null || formatName == null)
1149:       throw new IllegalArgumentException ("null argument");
1150: 
1151:     final Iterator<ImageWriterSpi> spiIterator
1152:       = getRegistry().getServiceProviders (ImageWriterSpi.class,
1153:                                            new WriterObjectFilter(type,
1154:                                                                   formatName),
1155:                                                                   true);
1156:     return new ImageWriterIterator(spiIterator);
1157:   }
1158: 
1159:   /**
1160:    * Retrieve an image writer corresponding to an image reader, or
1161:    * null if reader is not registered or if no corresponding writer is
1162:    * registered.  This method is useful for preserving metadata
1163:    * without needing to understand its format, since the returned
1164:    * writer will be able to write, unchanged, the metadata passed to
1165:    * it by the reader.
1166:    *
1167:    * @param reader a registered image reader
1168:    *
1169:    * @return an image writer corresponding to reader, or null
1170:    *
1171:    * @exception IllegalArgumentException if reader is null
1172:    */
1173:   public static ImageWriter getImageWriter (ImageReader reader)
1174:   {
1175:     if (reader == null)
1176:       throw new IllegalArgumentException ("null argument");
1177: 
1178:     ImageReaderSpi spi = reader.getOriginatingProvider();
1179: 
1180:     String[] writerSpiNames = spi.getImageWriterSpiNames();
1181: 
1182:     ImageWriter w = null;
1183: 
1184:     if (writerSpiNames != null)
1185:       {
1186:         try
1187:           {
1188:             Class writerClass = Class.forName (writerSpiNames[0]);
1189:             w = (ImageWriter) writerClass.newInstance ();
1190:           }
1191:         catch (Exception e)
1192:           {
1193:             return null;
1194:           }
1195:       }
1196:     return w;
1197:   }
1198: 
1199:   /**
1200:    * Retrieve an iterator over a collection of image transcoders that
1201:    * support transcoding from the given image reader's metadata format
1202:    * to the given writer's metadata format.
1203:    *
1204:    * @param reader an image reader
1205:    * @param writer an image writer
1206:    *
1207:    * @return an iterator over a collection of image transcoders
1208:    *
1209:    * @exception IllegalArgumentException if either reader or writer is
1210:    * null
1211:    */
1212:   public static Iterator<ImageTranscoder> getImageTranscoders (ImageReader reader,
1213:                                                                ImageWriter writer)
1214:   {
1215:     if (reader == null || writer == null)
1216:       throw new IllegalArgumentException ("null argument");
1217: 
1218:     final Iterator<ImageTranscoderSpi> spiIterator
1219:       = getRegistry().getServiceProviders (ImageTranscoderSpi.class,
1220:                                            new TranscoderFilter (reader,
1221:                                                                  writer),
1222:                                            true);
1223:     return new Iterator<ImageTranscoder>()
1224:     {
1225:       public boolean hasNext()
1226:       {
1227:         return spiIterator.hasNext();
1228:       }
1229: 
1230:       public ImageTranscoder next()
1231:       {
1232:         return spiIterator.next().createTranscoderInstance();
1233:       }
1234: 
1235:       public void remove()
1236:       {
1237:         throw new UnsupportedOperationException();
1238:       }
1239:     };
1240:   }
1241: }