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 implements Iterator
 319:   {
 320:     Iterator it;
 321:     Object readerExtension;
 322:     
 323:     public ImageReaderIterator(Iterator it, Object readerExtension)
 324:     {
 325:       this.it = it;
 326:       this.readerExtension = readerExtension;
 327:     }
 328: 
 329:     public boolean hasNext()
 330:     {
 331:       return it.hasNext();
 332:     }
 333: 
 334:     public Object next()
 335:     {
 336:       try
 337:         {
 338:           return ((ImageReaderSpi) it.next()).createReaderInstance(readerExtension);
 339:         }
 340:       catch (IOException e)
 341:         {
 342:           return null;
 343:         }
 344:     }
 345: 
 346:     public void remove()
 347:     {
 348:       throw new UnsupportedOperationException();
 349:     }
 350:   }
 351: 
 352:   private static final class ImageWriterIterator implements Iterator
 353:   {
 354:     Iterator it;
 355:     Object writerExtension;
 356:     
 357:     public ImageWriterIterator(Iterator it, Object writerExtension)
 358:     {
 359:       this.it = it;
 360:       this.writerExtension = writerExtension;
 361:     }
 362: 
 363:     public boolean hasNext()
 364:     {
 365:       return it.hasNext();
 366:     }
 367: 
 368:     public Object next()
 369:     {
 370:       try
 371:         {
 372:           return ((ImageWriterSpi) it.next()).createWriterInstance(writerExtension);
 373:         }
 374:       catch (IOException e)
 375:         {
 376:           return null;
 377:         }
 378:     }
 379: 
 380:     public void remove()
 381:     {
 382:       throw new UnsupportedOperationException();
 383:     }
 384:   }
 385:   
 386:   private static File cacheDirectory;
 387:   private static boolean useCache = true;
 388: 
 389:   private static Iterator getReadersByFilter(Class type,
 390:                                              ServiceRegistry.Filter filter,
 391:                                              Object readerExtension)
 392:   {
 393:     try
 394:       {
 395:         Iterator it = getRegistry().getServiceProviders(type, filter, true);
 396:         return new ImageReaderIterator(it, readerExtension);
 397:       }
 398:     catch (IllegalArgumentException e)
 399:       {
 400:         return Collections.EMPTY_SET.iterator();
 401:       }
 402:   }
 403:   
 404:   private static Iterator getWritersByFilter(Class type,
 405:                          ServiceRegistry.Filter filter,
 406:                                              Object writerExtension)
 407:   {
 408:     try
 409:       {
 410:         Iterator it = getRegistry().getServiceProviders(type, filter, true);
 411:         return new ImageWriterIterator(it, writerExtension);
 412:       }
 413:     catch (IllegalArgumentException e)
 414:       {
 415:         return Collections.EMPTY_SET.iterator();
 416:       }
 417:   }
 418: 
 419:   /**
 420:    * Retrieve the current cache directory.
 421:    *
 422:    * @return the current cache directory or null if none is set.
 423:    */
 424:   public static File getCacheDirectory()
 425:   {
 426:     return cacheDirectory;
 427:   }
 428: 
 429:   /**
 430:    * Retrieve an iterator over all registered readers for the given
 431:    * format.
 432:    *
 433:    * @param formatName an infomal format name (e.g. "jpeg" or "bmp")
 434:    *
 435:    * @return an iterator over a collection of image readers
 436:    *
 437:    * @exception IllegalArgumentException if formatName is null
 438:    */
 439:   public static Iterator getImageReadersByFormatName(String formatName)
 440:   {
 441:     if (formatName == null)
 442:       throw new IllegalArgumentException("formatName may not be null");
 443: 
 444:     return getReadersByFilter(ImageReaderSpi.class,
 445:                               new ReaderFormatFilter(formatName),
 446:                               formatName);
 447:   }
 448: 
 449:   /**
 450:    * Retrieve an iterator over all registered readers for the given
 451:    * MIME type.
 452:    *
 453:    * @param MIMEType a MIME specification for an image type
 454:    * (e.g. "image/jpeg" or "image/x-bmp")
 455:    *
 456:    * @return an iterator over a collection of image readers
 457:    *
 458:    * @exception IllegalArgumentException if MIMEType is null
 459:    */
 460:   public static Iterator getImageReadersByMIMEType(String MIMEType)
 461:   {
 462:     if (MIMEType == null)
 463:       throw new IllegalArgumentException("MIMEType may not be null");
 464: 
 465:     return getReadersByFilter(ImageReaderSpi.class,
 466:                               new ReaderMIMETypeFilter(MIMEType),
 467:                               MIMEType);
 468:   }
 469: 
 470:   /**
 471:    * Retrieve an iterator over all registered readers for the given
 472:    * file suffix.
 473:    *
 474:    * @param fileSuffix an image file suffix (e.g. "jpg" or "bmp")
 475:    *
 476:    * @return an iterator over a collection of image readers
 477:    *
 478:    * @exception IllegalArgumentException if fileSuffix is null
 479:    */
 480:   public static Iterator getImageReadersBySuffix(String fileSuffix)
 481:   {
 482:     if (fileSuffix == null)
 483:       throw new IllegalArgumentException("formatName may not be null");
 484:     
 485:     return getReadersByFilter(ImageReaderSpi.class,
 486:                               new ReaderSuffixFilter(fileSuffix),
 487:                               fileSuffix);
 488:   }
 489: 
 490:   /**
 491:    * Retrieve an iterator over all registered writers for the given
 492:    * format.
 493:    *
 494:    * @param formatName an infomal format name (e.g. "jpeg" or "bmp")
 495:    *
 496:    * @return an iterator over a collection of image writers
 497:    *
 498:    * @exception IllegalArgumentException if formatName is null
 499:    */
 500:   public static Iterator getImageWritersByFormatName(String formatName)
 501:   {
 502:     if (formatName == null)
 503:       throw new IllegalArgumentException("formatName may not be null");
 504:     
 505:     return getWritersByFilter(ImageWriterSpi.class,
 506:                               new WriterFormatFilter(formatName),
 507:                               formatName);
 508:   }
 509: 
 510:   /**
 511:    * Retrieve an iterator over all registered writers for the given
 512:    * MIME type.
 513:    *
 514:    * @param MIMEType a MIME specification for an image type
 515:    * (e.g. "image/jpeg" or "image/x-bmp")
 516:    *
 517:    * @return an iterator over a collection of image writers
 518:    *
 519:    * @exception IllegalArgumentException if MIMEType is null
 520:    */
 521:   public static Iterator getImageWritersByMIMEType(String MIMEType)
 522:   {
 523:     if (MIMEType == null)
 524:       throw new IllegalArgumentException("MIMEType may not be null");
 525:     
 526:     return getWritersByFilter(ImageWriterSpi.class,
 527:                               new WriterMIMETypeFilter(MIMEType),
 528:                               MIMEType);
 529:   }
 530: 
 531:   /**
 532:    * Retrieve an iterator over all registered writers for the given
 533:    * file suffix.
 534:    *
 535:    * @param fileSuffix an image file suffix (e.g. "jpg" or "bmp")
 536:    *
 537:    * @return an iterator over a collection of image writers
 538:    *
 539:    * @exception IllegalArgumentException if fileSuffix is null
 540:    */
 541:   public static Iterator getImageWritersBySuffix(String fileSuffix)
 542:   {
 543:     if (fileSuffix == null)
 544:       throw new IllegalArgumentException("fileSuffix may not be null");
 545:     
 546:     return getWritersByFilter(ImageWriterSpi.class,
 547:                               new WriterSuffixFilter(fileSuffix),
 548:                               fileSuffix);
 549:   }
 550: 
 551:   /**
 552:    * Retrieve all the informal format names supported by the
 553:    * collection of registered image readers.
 554:    *
 555:    * @return an array of format names
 556:    */
 557:   public static String[] getReaderFormatNames()
 558:   {
 559:     try
 560:       {
 561:         Iterator it =
 562:       getRegistry().getServiceProviders(ImageReaderSpi.class, true);
 563:     ArrayList result = new ArrayList();
 564: 
 565:     while (it.hasNext())
 566:       {
 567:         ImageReaderSpi spi = (ImageReaderSpi) it.next();
 568:         String[] names = spi.getFormatNames();
 569: 
 570:         for (int i = names.length - 1; i >= 0; --i)
 571:           result.add(names[i]);
 572:       }
 573: 
 574:     return (String[]) result.toArray(new String[result.size()]);
 575:       }
 576:     catch (IllegalArgumentException e)
 577:       {
 578:         return new String[0];
 579:       }
 580:   }
 581: 
 582:   /**
 583:    * Retrieve all the MIME types supported by the collection of
 584:    * registered image readers.
 585:    *
 586:    * @return an array of MIME types
 587:    */
 588:   public static String[] getReaderMIMETypes()
 589:   {
 590:     try
 591:       {
 592:         Iterator it =
 593:       getRegistry().getServiceProviders(ImageReaderSpi.class, true);
 594:     ArrayList result = new ArrayList();
 595: 
 596:     while (it.hasNext())
 597:       {
 598:         ImageReaderSpi spi = (ImageReaderSpi) it.next();
 599:         String[] names = spi.getMIMETypes();
 600: 
 601:         for (int i = names.length - 1; i >= 0; --i)
 602:           result.add(names[i]);
 603:       }
 604: 
 605:     return (String[]) result.toArray(new String[result.size()]);
 606:       }
 607:     catch (IllegalArgumentException e)
 608:       {
 609:         return new String[0];
 610:       }
 611:   }
 612: 
 613:   private static IIORegistry getRegistry()
 614:   {
 615:     return IIORegistry.getDefaultInstance();
 616:   }
 617: 
 618:   /**
 619:    * Check whether or not an on-disk cache is used for image input and
 620:    * output streams.
 621:    *
 622:    * @return true if an on-disk cache is available, false otherwise
 623:    */
 624:   public static boolean getUseCache()
 625:   {
 626:     return useCache;
 627:   }
 628: 
 629:   /**
 630:    * Retrieve all the informal format names supported by the
 631:    * collection of registered image writers.
 632:    *
 633:    * @return an array of format names
 634:    */
 635:   public static String[] getWriterFormatNames()
 636:   {
 637:     try
 638:       {
 639:         Iterator it =
 640:       getRegistry().getServiceProviders(ImageWriterSpi.class, true);
 641:     ArrayList result = new ArrayList();
 642: 
 643:     while (it.hasNext())
 644:       {
 645:         ImageWriterSpi spi = (ImageWriterSpi) it.next();
 646:         String[] names = spi.getFormatNames();
 647: 
 648:         for (int i = names.length - 1; i >= 0; --i)
 649:           result.add(names[i]);
 650:       }
 651: 
 652:     return (String[]) result.toArray(new String[result.size()]);
 653:       }
 654:     catch (IllegalArgumentException e)
 655:       {
 656:         return new String[0];
 657:       }
 658:   }
 659: 
 660:   /**
 661:    * Retrieve all the MIME types supported by the collection of
 662:    * registered image writers.
 663:    *
 664:    * @return an array of MIME types
 665:    */
 666:   public static String[] getWriterMIMETypes()
 667:   {
 668:     try
 669:       {
 670:         Iterator it =
 671:       getRegistry().getServiceProviders(ImageWriterSpi.class, true);
 672:     ArrayList result = new ArrayList();
 673: 
 674:     while (it.hasNext())
 675:       {
 676:         ImageWriterSpi spi = (ImageWriterSpi) it.next();
 677:         String[] names = spi.getMIMETypes();
 678: 
 679:         for (int i = names.length - 1; i >= 0; --i)
 680:           result.add(names[i]);
 681:       }
 682: 
 683:     return (String[]) result.toArray(new String[result.size()]);
 684:       }
 685:     catch (IllegalArgumentException e)
 686:       {
 687:         return new String[0];
 688:       }
 689:   }
 690:   
 691:   /**
 692:    * Rescans the application classpath for ImageIO service providers
 693:    * and registers them.
 694:    */
 695:   public static void scanForPlugins()
 696:   {
 697:     IIORegistry.getDefaultInstance().registerApplicationClasspathSpis();
 698:   }
 699: 
 700:   /**
 701:    * Set the directory to be used for caching image data.  A null
 702:    * argument means to use the default system temporary directory.
 703:    * This cache directory is only used if getUseCache returns true.
 704:    *
 705:    * @param cacheDirectory the directory where image data should be
 706:    * cached
 707:    *
 708:    * @exception IllegalArgumentException if cacheDirectory is not a
 709:    * directory
 710:    */
 711:   public static void setCacheDirectory(File cacheDirectory)
 712:   {
 713:     // FIXME: add SecurityManager call
 714:     if (cacheDirectory != null)
 715:       {
 716:         if (!cacheDirectory.isDirectory())
 717:           throw new IllegalArgumentException("cacheDirectory must be a directory");
 718: 
 719:         cacheDirectory.canWrite();
 720:       }
 721:     
 722:     ImageIO.cacheDirectory = cacheDirectory;
 723:   }
 724: 
 725:   /**
 726:    * Control whether or not an on-disk cache is used.  This cache is
 727:    * used to store input or output data from an image data stream when
 728:    * data in the stream needs to be re-processed.
 729:    *
 730:    * If useCache is false the cache will be stored in memory.  Doing
 731:    * so eliminates file creation and deletion overhead.  The default
 732:    * is to use an on-disk cache.
 733:    *
 734:    * @param useCache true to use an on-disk cache, false otherwise
 735:    */
 736:   public static void setUseCache(boolean useCache)
 737:   {
 738:     ImageIO.useCache = useCache;
 739:   }
 740: 
 741:   /**
 742:    * Write an image to a file using a registered writer that supports
 743:    * the given format, overwriting the file if it already exists.
 744:    *
 745:    * @param im the image data to write
 746:    * @param formatName an informal description of the output format
 747:    * @param output the file to which the image will be written
 748:    *
 749:    * @return false if no registered writer supports the given format,
 750:    * true otherwise
 751:    *
 752:    * @exception IllegalArgumentException if any argument is null
 753:    * @exception IOException if a writing error occurs
 754:    */
 755:   public static boolean write(RenderedImage im,
 756:                               String formatName,
 757:                               File output)
 758:     throws IOException
 759:   {
 760:     if (im == null || formatName == null || output == null)
 761:       throw new IllegalArgumentException ("null argument");
 762: 
 763:     return write(im, formatName, new FileOutputStream(output));
 764:   }
 765: 
 766:   /**
 767:    * Write an image to an output stream using a registered writer that
 768:    * supports the given format.
 769:    *
 770:    * @param im the image data to write
 771:    * @param formatName an informal description of the output format
 772:    * @param output the output stream to which the image will be
 773:    * written
 774:    *
 775:    * @return false if no registered writer supports the given format,
 776:    * true otherwise
 777:    *
 778:    * @exception IllegalArgumentException if any argument is null
 779:    * @exception IOException if a writing error occurs
 780:    */
 781:   public static boolean write(RenderedImage im,
 782:                               String formatName,
 783:                               OutputStream output)
 784:     throws IOException
 785:   {
 786:     if (im == null || formatName == null || output == null)
 787:       throw new IllegalArgumentException ("null argument");
 788: 
 789:     return write(im, formatName, new MemoryCacheImageOutputStream(output));
 790:   }
 791: 
 792:   /**
 793:    * Write an image to an ImageOutputStream using a registered writer
 794:    * that supports the given format.  Image data is written starting
 795:    * at the ImageOutputStream's current stream pointer, overwriting
 796:    * any existing data.
 797:    *
 798:    * @param im the image data to write
 799:    * @param formatName an informal description of the output format
 800:    * @param output the image output stream to which the image will be
 801:    * written
 802:    *
 803:    * @return false if no registered writer supports the given format,
 804:    * true otherwise
 805:    *
 806:    * @exception IllegalArgumentException if any argument is null
 807:    * @exception IOException if a writing error occurs
 808:    */
 809:   public static boolean write(RenderedImage im,
 810:                               String formatName,
 811:                               ImageOutputStream output)
 812:     throws IOException
 813:   {
 814:     if (im == null || formatName == null || output == null)
 815:       throw new IllegalArgumentException ("null argument");
 816: 
 817:     Iterator writers = getImageWritersByFormatName(formatName);
 818:     IIOImage img = new IIOImage(im, null, null);
 819:     while (writers.hasNext())
 820:       {
 821:         ImageWriter w = (ImageWriter) writers.next();
 822:         try 
 823:           {
 824:             w.setOutput(output);
 825:           }
 826:         catch (IllegalArgumentException e)
 827:           {
 828:             continue;
 829:           }
 830:         
 831:         w.write(null, img, null);
 832:         output.close();
 833:         return true;
 834:       }
 835:     return false;
 836:   }
 837: 
 838:   /**
 839:    * Create a buffered image from an image input stream.  An image
 840:    * reader that supports the given image data is automatically
 841:    * selected from the collection of registered readers.  If no
 842:    * registered reader can handle the input format, null is returned.
 843:    *
 844:    * @param stream the image input stream from which to read image
 845:    * data
 846:    *
 847:    * @return a new buffered image created from the given image data,
 848:    * or null
 849:    *
 850:    * @exception IllegalArgumentException if stream is null
 851:    * @exception IOException if a reading error occurs
 852:    */
 853:   public static BufferedImage read(ImageInputStream stream)
 854:     throws IOException
 855:   {
 856:     if (stream == null)
 857:       throw new IllegalArgumentException("null argument");
 858: 
 859:     Iterator providers = getRegistry().getServiceProviders(ImageReaderSpi.class, true);
 860:     while (providers.hasNext())
 861:       {
 862:         ImageReaderSpi spi = (ImageReaderSpi) providers.next();
 863:         if (spi.canDecodeInput(stream))
 864:           {
 865:             ImageReader reader = spi.createReaderInstance();
 866:             reader.setInput(stream);
 867:             return reader.read(0, null);
 868:           }
 869:       }
 870:     return null;
 871:   }
 872: 
 873:   /**
 874:    * Create a buffered image from a URL.  An image reader that
 875:    * supports the given image data is automatically selected from the
 876:    * collection of registered readers.  If no registered reader can
 877:    * handle the input format, null is returned.
 878:    *
 879:    * The image data will be cached in the current cache directory if
 880:    * caching is enabled.
 881:    *
 882:    * This method does not locate readers that read data directly from
 883:    * a URL.  To locate such readers manually, use IIORegistry and
 884:    * ImageReaderSpi.
 885:    *
 886:    * @param input the URL from which to retrieve the image file
 887:    *
 888:    * @return a new buffered image created from the given image URL, or
 889:    * null
 890:    *
 891:    * @exception IllegalArgumentException if input is null
 892:    * @exception IOException if a reading error occurs
 893:    */
 894:   public static BufferedImage read(URL input)
 895:     throws IOException
 896:   {
 897:     if (input == null)
 898:       throw new IllegalArgumentException("null argument");
 899: 
 900:     return read(input.openStream());
 901:   }
 902: 
 903:   /**
 904:    * Create a buffered image from an input stream.  An image reader
 905:    * that supports the given image data is automatically selected from
 906:    * the collection of registered readers.  If no registered reader
 907:    * can handle the input format, null is returned.
 908:    *
 909:    * The image data will be cached in the current cache directory if
 910:    * caching is enabled.
 911:    *
 912:    * This method does not locate readers that read data directly from
 913:    * an input stream.  To locate such readers manually, use
 914:    * IIORegistry and ImageReaderSpi.
 915:    *
 916:    * @param input the input stream from which to read the image data
 917:    *
 918:    * @return a new buffered image created from the given input stream,
 919:    * or null
 920:    *
 921:    * @exception IllegalArgumentException if input is null
 922:    * @exception IOException if a reading error occurs
 923:    */
 924:   public static BufferedImage read(InputStream input)
 925:     throws IOException
 926:   {
 927:     if (input == null)
 928:       throw new IllegalArgumentException("null argument");
 929: 
 930:     return read(new MemoryCacheImageInputStream(input));
 931:   }
 932: 
 933:   /**
 934:    * Create a buffered image from a file.  An image reader that
 935:    * supports the given image data is automatically selected from the
 936:    * collection of registered readers.  If no registered reader can
 937:    * handle the input format, null is returned.
 938:    *
 939:    * The image data will be cached in the current cache directory if
 940:    * caching is enabled.
 941:    *
 942:    * This method does not locate readers that read data directly from
 943:    * a file.  To locate such readers manually, use IIORegistry and
 944:    * ImageReaderSpi.
 945:    *
 946:    * @param input the file from which to read image data
 947:    *
 948:    * @return a new buffered image created from the given image file,
 949:    * or null
 950:    *
 951:    * @exception IllegalArgumentException if input is null
 952:    * @exception IOException if a reading error occurs
 953:    */
 954:   public static BufferedImage read(File input)
 955:     throws IOException
 956:   {
 957:     if (input == null)
 958:       throw new IllegalArgumentException("null argument");
 959: 
 960:     return read(new FileInputStream(input));
 961:   }
 962: 
 963:   /**
 964:    * Create an image input stream from the given object.  The
 965:    * collection of ImageInputStreamSpis registered with the
 966:    * IIORegistry is searched for an image input stream that can take
 967:    * input from the given object.  null is returned if no such SPI is
 968:    * registered.
 969:    *
 970:    * The image data will be cached in the current cache directory if
 971:    * caching is enabled.
 972:    *
 973:    * @param input an object from which to read image data
 974:    *
 975:    * @return an ImageInputStream that can read data from input, or
 976:    * null
 977:    *
 978:    * @exception IllegalArgumentException if input is null
 979:    * @exception IOException if caching is required but not enabled
 980:    */
 981:   public static ImageInputStream createImageInputStream (Object input)
 982:     throws IOException
 983:   {
 984:     if (input == null)
 985:       throw new IllegalArgumentException ("null argument");
 986: 
 987:     Iterator spis = getRegistry().getServiceProviders
 988:       (ImageInputStreamSpi.class, true);
 989: 
 990:     ImageInputStreamSpi foundSpi = null;
 991: 
 992:     while(spis.hasNext())
 993:       {
 994:     ImageInputStreamSpi spi = (ImageInputStreamSpi) spis.next();
 995: 
 996:     if (input.getClass().equals(spi.getInputClass()))
 997:       {
 998:         foundSpi = spi;
 999:         break;
1000:       }
1001:       }
1002: 
1003:     return foundSpi == null ? null :
1004:       foundSpi.createInputStreamInstance (input,
1005:                                           getUseCache(),
1006:                                           getCacheDirectory());
1007:   }
1008: 
1009:   /**
1010:    * Create an image output stream from the given object.  The
1011:    * collection of ImageOutputStreamSpis registered with the
1012:    * IIORegistry is searched for an image output stream that can send
1013:    * output to the given object.  null is returned if no such SPI is
1014:    * registered.
1015:    *
1016:    * The image data will be cached in the current cache directory if
1017:    * caching is enabled.
1018:    *
1019:    * @param input an object to which to write image data
1020:    *
1021:    * @return an ImageOutputStream that can send data to output, or
1022:    * null
1023:    *
1024:    * @exception IllegalArgumentException if output is null
1025:    * @exception IOException if caching is required but not enabled
1026:    */
1027:   public static ImageOutputStream createImageOutputStream (Object output)
1028:     throws IOException
1029:   {
1030:     if (output == null)
1031:       throw new IllegalArgumentException ("null argument");
1032: 
1033:     Iterator spis = getRegistry().getServiceProviders
1034:       (ImageOutputStreamSpi.class, true);
1035: 
1036:     ImageOutputStreamSpi foundSpi = null;
1037: 
1038:     while(spis.hasNext())
1039:       {
1040:     ImageOutputStreamSpi spi = (ImageOutputStreamSpi) spis.next();
1041: 
1042:     if (output.getClass().equals(spi.getOutputClass()))
1043:       {
1044:         foundSpi = spi;
1045:         break;
1046:       }
1047:       }
1048: 
1049:     return foundSpi == null ? null :
1050:       foundSpi.createOutputStreamInstance (output,
1051:                                            getUseCache(),
1052:                                            getCacheDirectory());
1053:   }
1054: 
1055:   /**
1056:    * Retrieve an image reader corresponding to an image writer, or
1057:    * null if writer is not registered or if no corresponding reader is
1058:    * registered.
1059:    *
1060:    * @param writer a registered image writer
1061:    *
1062:    * @return an image reader corresponding to writer, or null
1063:    *
1064:    * @exception IllegalArgumentException if writer is null
1065:    */
1066:   public static ImageReader getImageReader (ImageWriter writer)
1067:   {
1068:     if (writer == null)
1069:       throw new IllegalArgumentException ("null argument");
1070: 
1071:     ImageWriterSpi spi = (ImageWriterSpi) getRegistry()
1072:       .getServiceProviderByClass(writer.getClass());
1073: 
1074:     String[] readerSpiNames = spi.getImageReaderSpiNames();
1075: 
1076:     ImageReader r = null;
1077: 
1078:     if (readerSpiNames != null)
1079:       {
1080:         try
1081:           {
1082:             Class readerClass = Class.forName (readerSpiNames[0]);
1083:             r = (ImageReader) readerClass.newInstance ();
1084:           }
1085:         catch (Exception e)
1086:           {
1087:             return null;
1088:           }
1089:       }
1090:     return r;
1091:   }
1092: 
1093:   /**
1094:    * Retrieve an iterator over the collection of registered image
1095:    * readers that support reading data from the given object.
1096:    *
1097:    * @param input the object for which to retrieve image readers
1098:    *
1099:    * @return an iterator over a collection of image readers
1100:    */
1101:   public static Iterator getImageReaders (Object input)
1102:   {
1103:     if (input == null)
1104:       throw new IllegalArgumentException ("null argument");
1105: 
1106:     return getRegistry().getServiceProviders (ImageReaderSpi.class,
1107:                           new ReaderObjectFilter(input),
1108:                           true);
1109:   }
1110: 
1111:   /**
1112:    * Retrieve an iterator over the collection of registered image
1113:    * writers that support writing images of the given type and in the
1114:    * given format.
1115:    *
1116:    * @param type the output image's colour and sample models
1117:    * @param formatName the output image format
1118:    *
1119:    * @return an iterator over a collection of image writers
1120:    */
1121:   public static Iterator getImageWriters (ImageTypeSpecifier type,
1122:                       String formatName)
1123:   {
1124:     if (type == null || formatName == null)
1125:       throw new IllegalArgumentException ("null argument");
1126: 
1127:     return getRegistry().getServiceProviders (ImageWriterSpi.class,
1128:                           new WriterObjectFilter(type,
1129:                                                                      formatName),
1130:                           true);
1131:   }
1132: 
1133:   /**
1134:    * Retrieve an image writer corresponding to an image reader, or
1135:    * null if reader is not registered or if no corresponding writer is
1136:    * registered.  This method is useful for preserving metadata
1137:    * without needing to understand its format, since the returned
1138:    * writer will be able to write, unchanged, the metadata passed to
1139:    * it by the reader.
1140:    *
1141:    * @param reader a registered image reader
1142:    *
1143:    * @return an image writer corresponding to reader, or null
1144:    *
1145:    * @exception IllegalArgumentException if reader is null
1146:    */
1147:   public static ImageWriter getImageWriter (ImageReader reader)
1148:   {
1149:     if (reader == null)
1150:       throw new IllegalArgumentException ("null argument");
1151: 
1152:     ImageReaderSpi spi = (ImageReaderSpi) getRegistry()
1153:       .getServiceProviderByClass(reader.getClass());
1154: 
1155:     String[] writerSpiNames = spi.getImageWriterSpiNames();
1156: 
1157:     ImageWriter w = null;
1158: 
1159:     if (writerSpiNames != null)
1160:       {
1161:         try
1162:           {
1163:             Class writerClass = Class.forName (writerSpiNames[0]);
1164:             w = (ImageWriter) writerClass.newInstance ();
1165:           }
1166:         catch (Exception e)
1167:           {
1168:             return null;
1169:           }
1170:       }
1171:     return w;
1172:   }
1173: 
1174:   /**
1175:    * Retrieve an iterator over a collection of image transcoders that
1176:    * support transcoding from the given image reader's metadata format
1177:    * to the given writer's metadata format.
1178:    *
1179:    * @param reader an image reader
1180:    * @param writer an image writer
1181:    *
1182:    * @return an iterator over a collection of image transcoders
1183:    *
1184:    * @exception IllegalArgumentException if either reader or writer is
1185:    * null
1186:    */
1187:   public static Iterator getImageTranscoders (ImageReader reader,
1188:                           ImageWriter writer)
1189:   {
1190:     if (reader == null || writer == null)
1191:       throw new IllegalArgumentException ("null argument");
1192: 
1193:     return getRegistry().getServiceProviders (ImageTranscoderSpi.class,
1194:                           new TranscoderFilter (reader,
1195:                                                                     writer),
1196:                           true);
1197:   }
1198: }