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:         output.close();
 855:         return true;
 856:       }
 857:     return false;
 858:   }
 859: 
 860:   /**
 861:    * Create a buffered image from an image input stream.  An image
 862:    * reader that supports the given image data is automatically
 863:    * selected from the collection of registered readers.  If no
 864:    * registered reader can handle the input format, null is returned.
 865:    *
 866:    * @param stream the image input stream from which to read image
 867:    * data
 868:    *
 869:    * @return a new buffered image created from the given image data,
 870:    * or null
 871:    *
 872:    * @exception IllegalArgumentException if stream is null
 873:    * @exception IOException if a reading error occurs
 874:    */
 875:   public static BufferedImage read(ImageInputStream stream)
 876:     throws IOException
 877:   {
 878:     if (stream == null)
 879:       throw new IllegalArgumentException("null argument");
 880: 
 881:     Iterator providers = getRegistry().getServiceProviders(ImageReaderSpi.class, true);
 882:     while (providers.hasNext())
 883:       {
 884:         ImageReaderSpi spi = (ImageReaderSpi) providers.next();
 885:         if (spi.canDecodeInput(stream))
 886:           {
 887:             ImageReader reader = spi.createReaderInstance();
 888:             reader.setInput(stream);
 889:             return reader.read(0, null);
 890:           }
 891:       }
 892:     return null;
 893:   }
 894: 
 895:   /**
 896:    * Create a buffered image from a URL.  An image reader that
 897:    * supports the given image data is automatically selected from the
 898:    * collection of registered readers.  If no registered reader can
 899:    * handle the input format, null is returned.
 900:    *
 901:    * The image data will be cached in the current cache directory if
 902:    * caching is enabled.
 903:    *
 904:    * This method does not locate readers that read data directly from
 905:    * a URL.  To locate such readers manually, use IIORegistry and
 906:    * ImageReaderSpi.
 907:    *
 908:    * @param input the URL from which to retrieve the image file
 909:    *
 910:    * @return a new buffered image created from the given image URL, or
 911:    * null
 912:    *
 913:    * @exception IllegalArgumentException if input is null
 914:    * @exception IOException if a reading error occurs
 915:    */
 916:   public static BufferedImage read(URL input)
 917:     throws IOException
 918:   {
 919:     if (input == null)
 920:       throw new IllegalArgumentException("null argument");
 921: 
 922:     return read(input.openStream());
 923:   }
 924: 
 925:   /**
 926:    * Create a buffered image from an input stream.  An image reader
 927:    * that supports the given image data is automatically selected from
 928:    * the collection of registered readers.  If no registered reader
 929:    * can handle the input format, null is returned.
 930:    *
 931:    * The image data will be cached in the current cache directory if
 932:    * caching is enabled.
 933:    *
 934:    * This method does not locate readers that read data directly from
 935:    * an input stream.  To locate such readers manually, use
 936:    * IIORegistry and ImageReaderSpi.
 937:    *
 938:    * @param input the input stream from which to read the image data
 939:    *
 940:    * @return a new buffered image created from the given input stream,
 941:    * or null
 942:    *
 943:    * @exception IllegalArgumentException if input is null
 944:    * @exception IOException if a reading error occurs
 945:    */
 946:   public static BufferedImage read(InputStream input)
 947:     throws IOException
 948:   {
 949:     if (input == null)
 950:       throw new IllegalArgumentException("null argument");
 951: 
 952:     return read(new MemoryCacheImageInputStream(input));
 953:   }
 954: 
 955:   /**
 956:    * Create a buffered image from a file.  An image reader that
 957:    * supports the given image data is automatically selected from the
 958:    * collection of registered readers.  If no registered reader can
 959:    * handle the input format, null is returned.
 960:    *
 961:    * The image data will be cached in the current cache directory if
 962:    * caching is enabled.
 963:    *
 964:    * This method does not locate readers that read data directly from
 965:    * a file.  To locate such readers manually, use IIORegistry and
 966:    * ImageReaderSpi.
 967:    *
 968:    * @param input the file from which to read image data
 969:    *
 970:    * @return a new buffered image created from the given image file,
 971:    * or null
 972:    *
 973:    * @exception IllegalArgumentException if input is null
 974:    * @exception IOException if a reading error occurs
 975:    */
 976:   public static BufferedImage read(File input)
 977:     throws IOException
 978:   {
 979:     if (input == null)
 980:       throw new IllegalArgumentException("null argument");
 981: 
 982:     return read(new FileInputStream(input));
 983:   }
 984: 
 985:   /**
 986:    * Create an image input stream from the given object.  The
 987:    * collection of ImageInputStreamSpis registered with the
 988:    * IIORegistry is searched for an image input stream that can take
 989:    * input from the given object.  null is returned if no such SPI is
 990:    * registered.
 991:    *
 992:    * The image data will be cached in the current cache directory if
 993:    * caching is enabled.
 994:    *
 995:    * @param input an object from which to read image data
 996:    *
 997:    * @return an ImageInputStream that can read data from input, or
 998:    * null
 999:    *
1000:    * @exception IllegalArgumentException if input is null
1001:    * @exception IOException if caching is required but not enabled
1002:    */
1003:   public static ImageInputStream createImageInputStream (Object input)
1004:     throws IOException
1005:   {
1006:     if (input == null)
1007:       throw new IllegalArgumentException ("null argument");
1008: 
1009:     Iterator spis = getRegistry().getServiceProviders
1010:       (ImageInputStreamSpi.class, true);
1011: 
1012:     ImageInputStreamSpi foundSpi = null;
1013: 
1014:     while(spis.hasNext())
1015:       {
1016:     ImageInputStreamSpi spi = (ImageInputStreamSpi) spis.next();
1017: 
1018:     if (input.getClass().equals(spi.getInputClass()))
1019:       {
1020:         foundSpi = spi;
1021:         break;
1022:       }
1023:       }
1024: 
1025:     return foundSpi == null ? null :
1026:       foundSpi.createInputStreamInstance (input,
1027:                                           getUseCache(),
1028:                                           getCacheDirectory());
1029:   }
1030: 
1031:   /**
1032:    * Create an image output stream from the given object.  The
1033:    * collection of ImageOutputStreamSpis registered with the
1034:    * IIORegistry is searched for an image output stream that can send
1035:    * output to the given object.  null is returned if no such SPI is
1036:    * registered.
1037:    *
1038:    * The image data will be cached in the current cache directory if
1039:    * caching is enabled.
1040:    *
1041:    * @param output an object to which to write image data
1042:    *
1043:    * @return an ImageOutputStream that can send data to output, or
1044:    * null
1045:    *
1046:    * @exception IllegalArgumentException if output is null
1047:    * @exception IOException if caching is required but not enabled
1048:    */
1049:   public static ImageOutputStream createImageOutputStream (Object output)
1050:     throws IOException
1051:   {
1052:     if (output == null)
1053:       throw new IllegalArgumentException ("null argument");
1054: 
1055:     Iterator spis = getRegistry().getServiceProviders
1056:       (ImageOutputStreamSpi.class, true);
1057: 
1058:     ImageOutputStreamSpi foundSpi = null;
1059: 
1060:     while(spis.hasNext())
1061:       {
1062:     ImageOutputStreamSpi spi = (ImageOutputStreamSpi) spis.next();
1063: 
1064:     if (output.getClass().equals(spi.getOutputClass()))
1065:       {
1066:         foundSpi = spi;
1067:         break;
1068:       }
1069:       }
1070: 
1071:     return foundSpi == null ? null :
1072:       foundSpi.createOutputStreamInstance (output,
1073:                                            getUseCache(),
1074:                                            getCacheDirectory());
1075:   }
1076: 
1077:   /**
1078:    * Retrieve an image reader corresponding to an image writer, or
1079:    * null if writer is not registered or if no corresponding reader is
1080:    * registered.
1081:    *
1082:    * @param writer a registered image writer
1083:    *
1084:    * @return an image reader corresponding to writer, or null
1085:    *
1086:    * @exception IllegalArgumentException if writer is null
1087:    */
1088:   public static ImageReader getImageReader (ImageWriter writer)
1089:   {
1090:     if (writer == null)
1091:       throw new IllegalArgumentException ("null argument");
1092: 
1093:     ImageWriterSpi spi = writer.getOriginatingProvider();
1094: 
1095:     String[] readerSpiNames = spi.getImageReaderSpiNames();
1096: 
1097:     ImageReader r = null;
1098: 
1099:     if (readerSpiNames != null)
1100:       {
1101:         try
1102:           {
1103:             Class readerClass = Class.forName (readerSpiNames[0]);
1104:             r = (ImageReader) readerClass.newInstance ();
1105:           }
1106:         catch (Exception e)
1107:           {
1108:             return null;
1109:           }
1110:       }
1111:     return r;
1112:   }
1113: 
1114:   /**
1115:    * Retrieve an iterator over the collection of registered image
1116:    * readers that support reading data from the given object.
1117:    *
1118:    * @param input the object for which to retrieve image readers
1119:    *
1120:    * @return an iterator over a collection of image readers
1121:    */
1122:   public static Iterator<ImageReader> getImageReaders (Object input)
1123:   {
1124:     if (input == null)
1125:       throw new IllegalArgumentException ("null argument");
1126: 
1127:     Iterator<ImageReaderSpi> spiIterator
1128:       = getRegistry().getServiceProviders (ImageReaderSpi.class,
1129:                                            new ReaderObjectFilter(input),
1130:                                            true);
1131:     return new ImageReaderIterator(spiIterator);
1132:   }
1133: 
1134:   /**
1135:    * Retrieve an iterator over the collection of registered image
1136:    * writers that support writing images of the given type and in the
1137:    * given format.
1138:    *
1139:    * @param type the output image's colour and sample models
1140:    * @param formatName the output image format
1141:    *
1142:    * @return an iterator over a collection of image writers
1143:    */
1144:   public static Iterator<ImageWriter> getImageWriters (ImageTypeSpecifier type,
1145:                       String formatName)
1146:   {
1147:     if (type == null || formatName == null)
1148:       throw new IllegalArgumentException ("null argument");
1149: 
1150:     final Iterator<ImageWriterSpi> spiIterator
1151:       = getRegistry().getServiceProviders (ImageWriterSpi.class,
1152:                                            new WriterObjectFilter(type,
1153:                                                                   formatName),
1154:                                                                   true);
1155:     return new ImageWriterIterator(spiIterator);
1156:   }
1157: 
1158:   /**
1159:    * Retrieve an image writer corresponding to an image reader, or
1160:    * null if reader is not registered or if no corresponding writer is
1161:    * registered.  This method is useful for preserving metadata
1162:    * without needing to understand its format, since the returned
1163:    * writer will be able to write, unchanged, the metadata passed to
1164:    * it by the reader.
1165:    *
1166:    * @param reader a registered image reader
1167:    *
1168:    * @return an image writer corresponding to reader, or null
1169:    *
1170:    * @exception IllegalArgumentException if reader is null
1171:    */
1172:   public static ImageWriter getImageWriter (ImageReader reader)
1173:   {
1174:     if (reader == null)
1175:       throw new IllegalArgumentException ("null argument");
1176: 
1177:     ImageReaderSpi spi = reader.getOriginatingProvider();
1178: 
1179:     String[] writerSpiNames = spi.getImageWriterSpiNames();
1180: 
1181:     ImageWriter w = null;
1182: 
1183:     if (writerSpiNames != null)
1184:       {
1185:         try
1186:           {
1187:             Class writerClass = Class.forName (writerSpiNames[0]);
1188:             w = (ImageWriter) writerClass.newInstance ();
1189:           }
1190:         catch (Exception e)
1191:           {
1192:             return null;
1193:           }
1194:       }
1195:     return w;
1196:   }
1197: 
1198:   /**
1199:    * Retrieve an iterator over a collection of image transcoders that
1200:    * support transcoding from the given image reader's metadata format
1201:    * to the given writer's metadata format.
1202:    *
1203:    * @param reader an image reader
1204:    * @param writer an image writer
1205:    *
1206:    * @return an iterator over a collection of image transcoders
1207:    *
1208:    * @exception IllegalArgumentException if either reader or writer is
1209:    * null
1210:    */
1211:   public static Iterator<ImageTranscoder> getImageTranscoders (ImageReader reader,
1212:                                                                ImageWriter writer)
1213:   {
1214:     if (reader == null || writer == null)
1215:       throw new IllegalArgumentException ("null argument");
1216: 
1217:     final Iterator<ImageTranscoderSpi> spiIterator
1218:       = getRegistry().getServiceProviders (ImageTranscoderSpi.class,
1219:                                            new TranscoderFilter (reader,
1220:                                                                  writer),
1221:                                            true);
1222:     return new Iterator<ImageTranscoder>()
1223:     {
1224:       public boolean hasNext()
1225:       {
1226:         return spiIterator.hasNext();
1227:       }
1228:       
1229:       public ImageTranscoder next()
1230:       {
1231:         return spiIterator.next().createTranscoderInstance();
1232:       }
1233:       
1234:       public void remove()
1235:       {
1236:         throw new UnsupportedOperationException();
1237:       }
1238:     };
1239:   }
1240: }