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