0001 /*
0002 * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package javax.imageio;
0027
0028 import java.awt.image.BufferedImage;
0029 import java.awt.image.RenderedImage;
0030 import java.io.File;
0031 import java.io.InputStream;
0032 import java.io.IOException;
0033 import java.io.OutputStream;
0034 import java.lang.reflect.Method;
0035 import java.net.URL;
0036 import java.security.AccessController;
0037 import java.util.Arrays;
0038 import java.util.Collections;
0039 import java.util.HashSet;
0040 import java.util.Iterator;
0041 import java.util.NoSuchElementException;
0042 import java.util.Set;
0043 import javax.imageio.spi.IIORegistry;
0044 import javax.imageio.spi.ImageReaderSpi;
0045 import javax.imageio.spi.ImageReaderWriterSpi;
0046 import javax.imageio.spi.ImageWriterSpi;
0047 import javax.imageio.spi.ImageInputStreamSpi;
0048 import javax.imageio.spi.ImageOutputStreamSpi;
0049 import javax.imageio.spi.ImageTranscoderSpi;
0050 import javax.imageio.spi.ServiceRegistry;
0051 import javax.imageio.stream.ImageInputStream;
0052 import javax.imageio.stream.ImageOutputStream;
0053 import sun.awt.AppContext;
0054 import sun.security.action.GetPropertyAction;
0055
0056 /**
0057 * A class containing static convenience methods for locating
0058 * <code>ImageReader</code>s and <code>ImageWriter</code>s, and
0059 * performing simple encoding and decoding.
0060 *
0061 * @version 0.5
0062 */
0063 public final class ImageIO {
0064
0065 private static final IIORegistry theRegistry = IIORegistry
0066 .getDefaultInstance();
0067
0068 /**
0069 * Constructor is private to prevent instantiation.
0070 */
0071 private ImageIO() {
0072 }
0073
0074 /**
0075 * Scans for plug-ins on the application class path,
0076 * loads their service provider classes, and registers a service
0077 * provider instance for each one found with the
0078 * <code>IIORegistry</code>.
0079 *
0080 * <p>This method is needed because the application class path can
0081 * theoretically change, or additional plug-ins may become available.
0082 * Rather than re-scanning the classpath on every invocation of the
0083 * API, the class path is scanned automatically only on the first
0084 * invocation. Clients can call this method to prompt a re-scan.
0085 * Thus this method need only be invoked by sophisticated applications
0086 * which dynamically make new plug-ins available at runtime.
0087 *
0088 * <p> The <code>getResources</code> method of the context
0089 * <code>ClassLoader</code> is used locate JAR files containing
0090 * files named
0091 * <code>META-INF/services/javax.imageio.spi.</code><i>classname</i>,
0092 * where <i>classname</i> is one of <code>ImageReaderSpi</code>,
0093 * <code>ImageWriterSpi</code>, <code>ImageTranscoderSpi</code>,
0094 * <code>ImageInputStreamSpi</code>, or
0095 * <code>ImageOutputStreamSpi</code>, along the application class
0096 * path.
0097 *
0098 * <p> The contents of the located files indicate the names of
0099 * actual implementation classes which implement the
0100 * aforementioned service provider interfaces; the default class
0101 * loader is then used to load each of these classes and to
0102 * instantiate an instance of each class, which is then placed
0103 * into the registry for later retrieval.
0104 *
0105 * <p> The exact set of locations searched depends on the
0106 * implementation of the Java runtime enviroment.
0107 *
0108 * @see ClassLoader#getResources
0109 */
0110 public static void scanForPlugins() {
0111 theRegistry.registerApplicationClasspathSpis();
0112 }
0113
0114 // ImageInputStreams
0115
0116 /**
0117 * A class to hold information about caching. Each
0118 * <code>ThreadGroup</code> will have its own copy
0119 * via the <code>AppContext</code> mechanism.
0120 */
0121 static class CacheInfo {
0122 boolean useCache = true;
0123 File cacheDirectory = null;
0124 Boolean hasPermission = null;
0125
0126 public CacheInfo() {
0127 }
0128
0129 public boolean getUseCache() {
0130 return useCache;
0131 }
0132
0133 public void setUseCache(boolean useCache) {
0134 this .useCache = useCache;
0135 }
0136
0137 public File getCacheDirectory() {
0138 return cacheDirectory;
0139 }
0140
0141 public void setCacheDirectory(File cacheDirectory) {
0142 this .cacheDirectory = cacheDirectory;
0143 }
0144
0145 public Boolean getHasPermission() {
0146 return hasPermission;
0147 }
0148
0149 public void setHasPermission(Boolean hasPermission) {
0150 this .hasPermission = hasPermission;
0151 }
0152 }
0153
0154 /**
0155 * Returns the <code>CacheInfo</code> object associated with this
0156 * <code>ThreadGroup</code>.
0157 */
0158 private static synchronized CacheInfo getCacheInfo() {
0159 AppContext context = AppContext.getAppContext();
0160 CacheInfo info = (CacheInfo) context.get(CacheInfo.class);
0161 if (info == null) {
0162 info = new CacheInfo();
0163 context.put(CacheInfo.class, info);
0164 }
0165 return info;
0166 }
0167
0168 /**
0169 * Returns the default temporary (cache) directory as defined by the
0170 * java.io.tmpdir system property.
0171 */
0172 private static String getTempDir() {
0173 GetPropertyAction a = new GetPropertyAction("java.io.tmpdir");
0174 return (String) AccessController.doPrivileged(a);
0175 }
0176
0177 /**
0178 * Determines whether the caller has write access to the cache
0179 * directory, stores the result in the <code>CacheInfo</code> object,
0180 * and returns the decision. This method helps to prevent mysterious
0181 * SecurityExceptions to be thrown when this convenience class is used
0182 * in an applet, for example.
0183 */
0184 private static boolean hasCachePermission() {
0185 Boolean hasPermission = getCacheInfo().getHasPermission();
0186
0187 if (hasPermission != null) {
0188 return hasPermission.booleanValue();
0189 } else {
0190 try {
0191 SecurityManager security = System.getSecurityManager();
0192 if (security != null) {
0193 File cachedir = getCacheDirectory();
0194 String cachepath;
0195
0196 if (cachedir != null) {
0197 cachepath = cachedir.getPath();
0198 } else {
0199 cachepath = getTempDir();
0200
0201 if (cachepath == null) {
0202 getCacheInfo().setHasPermission(
0203 Boolean.FALSE);
0204 return false;
0205 }
0206 }
0207
0208 security.checkWrite(cachepath);
0209 }
0210 } catch (SecurityException e) {
0211 getCacheInfo().setHasPermission(Boolean.FALSE);
0212 return false;
0213 }
0214
0215 getCacheInfo().setHasPermission(Boolean.TRUE);
0216 return true;
0217 }
0218 }
0219
0220 /**
0221 * Sets a flag indicating whether a disk-based cache file should
0222 * be used when creating <code>ImageInputStream</code>s and
0223 * <code>ImageOutputStream</code>s.
0224 *
0225 * <p> When reading from a standard <code>InputStream</code>>, it
0226 * may be necessary to save previously read information in a cache
0227 * since the underlying stream does not allow data to be re-read.
0228 * Similarly, when writing to a standard
0229 * <code>OutputStream</code>, a cache may be used to allow a
0230 * previously written value to be changed before flushing it to
0231 * the final destination.
0232 *
0233 * <p> The cache may reside in main memory or on disk. Setting
0234 * this flag to <code>false</code> disallows the use of disk for
0235 * future streams, which may be advantageous when working with
0236 * small images, as the overhead of creating and destroying files
0237 * is removed.
0238 *
0239 * <p> On startup, the value is set to <code>true</code>.
0240 *
0241 * @param useCache a <code>boolean</code> indicating whether a
0242 * cache file should be used, in cases where it is optional.
0243 *
0244 * @see #getUseCache
0245 */
0246 public static void setUseCache(boolean useCache) {
0247 getCacheInfo().setUseCache(useCache);
0248 }
0249
0250 /**
0251 * Returns the current value set by <code>setUseCache</code>, or
0252 * <code>true</code> if no explicit setting has been made.
0253 *
0254 * @return true if a disk-based cache may be used for
0255 * <code>ImageInputStream</code>s and
0256 * <code>ImageOutputStream</code>s.
0257 *
0258 * @see #setUseCache
0259 */
0260 public static boolean getUseCache() {
0261 return getCacheInfo().getUseCache();
0262 }
0263
0264 /**
0265 * Sets the directory where cache files are to be created. A
0266 * value of <code>null</code> indicates that the system-dependent
0267 * default temporary-file directory is to be used. If
0268 * <code>getUseCache</code> returns false, this value is ignored.
0269 *
0270 * @param cacheDirectory a <code>File</code> specifying a directory.
0271 *
0272 * @see File#createTempFile(String, String, File)
0273 *
0274 * @exception SecurityException if the security manager denies
0275 * access to the directory.
0276 * @exception IllegalArgumentException if <code>cacheDir</code> is
0277 * non-<code>null</code> but is not a directory.
0278 *
0279 * @see #getCacheDirectory
0280 */
0281 public static void setCacheDirectory(File cacheDirectory) {
0282 if ((cacheDirectory != null) && !(cacheDirectory.isDirectory())) {
0283 throw new IllegalArgumentException("Not a directory!");
0284 }
0285 getCacheInfo().setCacheDirectory(cacheDirectory);
0286 getCacheInfo().setHasPermission(null);
0287 }
0288
0289 /**
0290 * Returns the current value set by
0291 * <code>setCacheDirectory</code>, or <code>null</code> if no
0292 * explicit setting has been made.
0293 *
0294 * @return a <code>File</code> indicating the directory where
0295 * cache files will be created, or <code>null</code> to indicate
0296 * the system-dependent default temporary-file directory.
0297 *
0298 * @see #setCacheDirectory
0299 */
0300 public static File getCacheDirectory() {
0301 return getCacheInfo().getCacheDirectory();
0302 }
0303
0304 /**
0305 * Returns an <code>ImageInputStream</code> that will take its
0306 * input from the given <code>Object</code>. The set of
0307 * <code>ImageInputStreamSpi</code>s registered with the
0308 * <code>IIORegistry</code> class is queried and the first one
0309 * that is able to take input from the supplied object is used to
0310 * create the returned <code>ImageInputStream</code>. If no
0311 * suitable <code>ImageInputStreamSpi</code> exists,
0312 * <code>null</code> is returned.
0313 *
0314 * <p> The current cache settings from <code>getUseCache</code>and
0315 * <code>getCacheDirectory</code> will be used to control caching.
0316 *
0317 * @param input an <code>Object</code> to be used as an input
0318 * source, such as a <code>File</code>, readable
0319 * <code>RandomAccessFile</code>, or <code>InputStream</code>.
0320 *
0321 * @return an <code>ImageInputStream</code>, or <code>null</code>.
0322 *
0323 * @exception IllegalArgumentException if <code>input</code>
0324 * is <code>null</code>.
0325 * @exception IOException if a cache file is needed but cannot be
0326 * created.
0327 *
0328 * @see javax.imageio.spi.ImageInputStreamSpi
0329 */
0330 public static ImageInputStream createImageInputStream(Object input)
0331 throws IOException {
0332 if (input == null) {
0333 throw new IllegalArgumentException("input == null!");
0334 }
0335
0336 Iterator iter;
0337 // Ensure category is present
0338 try {
0339 iter = theRegistry.getServiceProviders(
0340 ImageInputStreamSpi.class, true);
0341 } catch (IllegalArgumentException e) {
0342 return null;
0343 }
0344
0345 boolean usecache = getUseCache() && hasCachePermission();
0346
0347 while (iter.hasNext()) {
0348 ImageInputStreamSpi spi = (ImageInputStreamSpi) iter.next();
0349 if (spi.getInputClass().isInstance(input)) {
0350 try {
0351 return spi.createInputStreamInstance(input,
0352 usecache, getCacheDirectory());
0353 } catch (IOException e) {
0354 throw new IIOException("Can't create cache file!",
0355 e);
0356 }
0357 }
0358 }
0359
0360 return null;
0361 }
0362
0363 // ImageOutputStreams
0364
0365 /**
0366 * Returns an <code>ImageOutputStream</code> that will send its
0367 * output to the given <code>Object</code>. The set of
0368 * <code>ImageOutputStreamSpi</code>s registered with the
0369 * <code>IIORegistry</code> class is queried and the first one
0370 * that is able to send output from the supplied object is used to
0371 * create the returned <code>ImageOutputStream</code>. If no
0372 * suitable <code>ImageOutputStreamSpi</code> exists,
0373 * <code>null</code> is returned.
0374 *
0375 * <p> The current cache settings from <code>getUseCache</code>and
0376 * <code>getCacheDirectory</code> will be used to control caching.
0377 *
0378 * @param output an <code>Object</code> to be used as an output
0379 * destination, such as a <code>File</code>, writable
0380 * <code>RandomAccessFile</code>, or <code>OutputStream</code>.
0381 *
0382 * @return an <code>ImageOutputStream</code>, or
0383 * <code>null</code>.
0384 *
0385 * @exception IllegalArgumentException if <code>output</code> is
0386 * <code>null</code>.
0387 * @exception IOException if a cache file is needed but cannot be
0388 * created.
0389 *
0390 * @see javax.imageio.spi.ImageOutputStreamSpi
0391 */
0392 public static ImageOutputStream createImageOutputStream(
0393 Object output) throws IOException {
0394 if (output == null) {
0395 throw new IllegalArgumentException("output == null!");
0396 }
0397
0398 Iterator iter;
0399 // Ensure category is present
0400 try {
0401 iter = theRegistry.getServiceProviders(
0402 ImageOutputStreamSpi.class, true);
0403 } catch (IllegalArgumentException e) {
0404 return null;
0405 }
0406
0407 boolean usecache = getUseCache() && hasCachePermission();
0408
0409 while (iter.hasNext()) {
0410 ImageOutputStreamSpi spi = (ImageOutputStreamSpi) iter
0411 .next();
0412 if (spi.getOutputClass().isInstance(output)) {
0413 try {
0414 return spi.createOutputStreamInstance(output,
0415 usecache, getCacheDirectory());
0416 } catch (IOException e) {
0417 throw new IIOException("Can't create cache file!",
0418 e);
0419 }
0420 }
0421 }
0422
0423 return null;
0424 }
0425
0426 private static enum SpiInfo {
0427 FORMAT_NAMES {
0428 @Override
0429 String[] info(ImageReaderWriterSpi spi) {
0430 return spi.getFormatNames();
0431 }
0432 },
0433 MIME_TYPES {
0434 @Override
0435 String[] info(ImageReaderWriterSpi spi) {
0436 return spi.getMIMETypes();
0437 }
0438 },
0439 FILE_SUFFIXES {
0440 @Override
0441 String[] info(ImageReaderWriterSpi spi) {
0442 return spi.getFileSuffixes();
0443 }
0444 };
0445
0446 abstract String[] info(ImageReaderWriterSpi spi);
0447 }
0448
0449 private static <S extends ImageReaderWriterSpi> String[] getReaderWriterInfo(
0450 Class<S> spiClass, SpiInfo spiInfo) {
0451 // Ensure category is present
0452 Iterator<S> iter;
0453 try {
0454 iter = theRegistry.getServiceProviders(spiClass, true);
0455 } catch (IllegalArgumentException e) {
0456 return new String[0];
0457 }
0458
0459 HashSet<String> s = new HashSet<String>();
0460 while (iter.hasNext()) {
0461 ImageReaderWriterSpi spi = iter.next();
0462 Collections.addAll(s, spiInfo.info(spi));
0463 }
0464
0465 return s.toArray(new String[s.size()]);
0466 }
0467
0468 // Readers
0469
0470 /**
0471 * Returns an array of <code>String</code>s listing all of the
0472 * informal format names understood by the current set of registered
0473 * readers.
0474 *
0475 * @return an array of <code>String</code>s.
0476 */
0477 public static String[] getReaderFormatNames() {
0478 return getReaderWriterInfo(ImageReaderSpi.class,
0479 SpiInfo.FORMAT_NAMES);
0480 }
0481
0482 /**
0483 * Returns an array of <code>String</code>s listing all of the
0484 * MIME types understood by the current set of registered
0485 * readers.
0486 *
0487 * @return an array of <code>String</code>s.
0488 */
0489 public static String[] getReaderMIMETypes() {
0490 return getReaderWriterInfo(ImageReaderSpi.class,
0491 SpiInfo.MIME_TYPES);
0492 }
0493
0494 /**
0495 * Returns an array of <code>String</code>s listing all of the
0496 * file suffixes associated with the formats understood
0497 * by the current set of registered readers.
0498 *
0499 * @return an array of <code>String</code>s.
0500 * @since 1.6
0501 */
0502 public static String[] getReaderFileSuffixes() {
0503 return getReaderWriterInfo(ImageReaderSpi.class,
0504 SpiInfo.FILE_SUFFIXES);
0505 }
0506
0507 static class ImageReaderIterator implements Iterator<ImageReader> {
0508 // Contains ImageReaderSpis
0509 public Iterator iter;
0510
0511 public ImageReaderIterator(Iterator iter) {
0512 this .iter = iter;
0513 }
0514
0515 public boolean hasNext() {
0516 return iter.hasNext();
0517 }
0518
0519 public ImageReader next() {
0520 ImageReaderSpi spi = null;
0521 try {
0522 spi = (ImageReaderSpi) iter.next();
0523 return spi.createReaderInstance();
0524 } catch (IOException e) {
0525 // Deregister the spi in this case, but only as
0526 // an ImageReaderSpi
0527 theRegistry.deregisterServiceProvider(spi,
0528 ImageReaderSpi.class);
0529 }
0530 return null;
0531 }
0532
0533 public void remove() {
0534 throw new UnsupportedOperationException();
0535 }
0536 }
0537
0538 static class CanDecodeInputFilter implements ServiceRegistry.Filter {
0539
0540 Object input;
0541
0542 public CanDecodeInputFilter(Object input) {
0543 this .input = input;
0544 }
0545
0546 public boolean filter(Object elt) {
0547 try {
0548 ImageReaderSpi spi = (ImageReaderSpi) elt;
0549 ImageInputStream stream = null;
0550 if (input instanceof ImageInputStream) {
0551 stream = (ImageInputStream) input;
0552 }
0553
0554 // Perform mark/reset as a defensive measure
0555 // even though plug-ins are supposed to take
0556 // care of it.
0557 boolean canDecode = false;
0558 if (stream != null) {
0559 stream.mark();
0560 }
0561 canDecode = spi.canDecodeInput(input);
0562 if (stream != null) {
0563 stream.reset();
0564 }
0565
0566 return canDecode;
0567 } catch (IOException e) {
0568 return false;
0569 }
0570 }
0571 }
0572
0573 static class CanEncodeImageAndFormatFilter implements
0574 ServiceRegistry.Filter {
0575
0576 ImageTypeSpecifier type;
0577 String formatName;
0578
0579 public CanEncodeImageAndFormatFilter(ImageTypeSpecifier type,
0580 String formatName) {
0581 this .type = type;
0582 this .formatName = formatName;
0583 }
0584
0585 public boolean filter(Object elt) {
0586 ImageWriterSpi spi = (ImageWriterSpi) elt;
0587 return Arrays.asList(spi.getFormatNames()).contains(
0588 formatName)
0589 && spi.canEncodeImage(type);
0590 }
0591 }
0592
0593 static class ContainsFilter implements ServiceRegistry.Filter {
0594
0595 Method method;
0596 String name;
0597
0598 // method returns an array of Strings
0599 public ContainsFilter(Method method, String name) {
0600 this .method = method;
0601 this .name = name;
0602 }
0603
0604 public boolean filter(Object elt) {
0605 try {
0606 return contains((String[]) method.invoke(elt), name);
0607 } catch (Exception e) {
0608 return false;
0609 }
0610 }
0611 }
0612
0613 /**
0614 * Returns an <code>Iterator</code> containing all currently
0615 * registered <code>ImageReader</code>s that claim to be able to
0616 * decode the supplied <code>Object</code>, typically an
0617 * <code>ImageInputStream</code>.
0618 *
0619 * <p> The stream position is left at its prior position upon
0620 * exit from this method.
0621 *
0622 * @param input an <code>ImageInputStream</code> or other
0623 * <code>Object</code> containing encoded image data.
0624 *
0625 * @return an <code>Iterator</code> containing <code>ImageReader</code>s.
0626 *
0627 * @exception IllegalArgumentException if <code>input</code> is
0628 * <code>null</code>.
0629 *
0630 * @see javax.imageio.spi.ImageReaderSpi#canDecodeInput
0631 */
0632 public static Iterator<ImageReader> getImageReaders(Object input) {
0633 if (input == null) {
0634 throw new IllegalArgumentException("input == null!");
0635 }
0636 Iterator iter;
0637 // Ensure category is present
0638 try {
0639 iter = theRegistry.getServiceProviders(
0640 ImageReaderSpi.class, new CanDecodeInputFilter(
0641 input), true);
0642 } catch (IllegalArgumentException e) {
0643 return Collections.emptyIterator();
0644 }
0645
0646 return new ImageReaderIterator(iter);
0647 }
0648
0649 private static Method readerFormatNamesMethod;
0650 private static Method readerFileSuffixesMethod;
0651 private static Method readerMIMETypesMethod;
0652 private static Method writerFormatNamesMethod;
0653 private static Method writerFileSuffixesMethod;
0654 private static Method writerMIMETypesMethod;
0655
0656 static {
0657 try {
0658 readerFormatNamesMethod = ImageReaderSpi.class
0659 .getMethod("getFormatNames");
0660 readerFileSuffixesMethod = ImageReaderSpi.class
0661 .getMethod("getFileSuffixes");
0662 readerMIMETypesMethod = ImageReaderSpi.class
0663 .getMethod("getMIMETypes");
0664
0665 writerFormatNamesMethod = ImageWriterSpi.class
0666 .getMethod("getFormatNames");
0667 writerFileSuffixesMethod = ImageWriterSpi.class
0668 .getMethod("getFileSuffixes");
0669 writerMIMETypesMethod = ImageWriterSpi.class
0670 .getMethod("getMIMETypes");
0671 } catch (NoSuchMethodException e) {
0672 e.printStackTrace();
0673 }
0674 }
0675
0676 /**
0677 * Returns an <code>Iterator</code> containing all currently
0678 * registered <code>ImageReader</code>s that claim to be able to
0679 * decode the named format.
0680 *
0681 * @param formatName a <code>String</code> containing the informal
0682 * name of a format (<i>e.g.</i>, "jpeg" or "tiff".
0683 *
0684 * @return an <code>Iterator</code> containing
0685 * <code>ImageReader</code>s.
0686 *
0687 * @exception IllegalArgumentException if <code>formatName</code>
0688 * is <code>null</code>.
0689 *
0690 * @see javax.imageio.spi.ImageReaderSpi#getFormatNames
0691 */
0692 public static Iterator<ImageReader> getImageReadersByFormatName(
0693 String formatName) {
0694 if (formatName == null) {
0695 throw new IllegalArgumentException("formatName == null!");
0696 }
0697 Iterator iter;
0698 // Ensure category is present
0699 try {
0700 iter = theRegistry.getServiceProviders(
0701 ImageReaderSpi.class, new ContainsFilter(
0702 readerFormatNamesMethod, formatName), true);
0703 } catch (IllegalArgumentException e) {
0704 return Collections.emptyIterator();
0705 }
0706 return new ImageReaderIterator(iter);
0707 }
0708
0709 /**
0710 * Returns an <code>Iterator</code> containing all currently
0711 * registered <code>ImageReader</code>s that claim to be able to
0712 * decode files with the given suffix.
0713 *
0714 * @param fileSuffix a <code>String</code> containing a file
0715 * suffix (<i>e.g.</i>, "jpg" or "tiff").
0716 *
0717 * @return an <code>Iterator</code> containing
0718 * <code>ImageReader</code>s.
0719 *
0720 * @exception IllegalArgumentException if <code>fileSuffix</code>
0721 * is <code>null</code>.
0722 *
0723 * @see javax.imageio.spi.ImageReaderSpi#getFileSuffixes
0724 */
0725 public static Iterator<ImageReader> getImageReadersBySuffix(
0726 String fileSuffix) {
0727 if (fileSuffix == null) {
0728 throw new IllegalArgumentException("fileSuffix == null!");
0729 }
0730 // Ensure category is present
0731 Iterator iter;
0732 try {
0733 iter = theRegistry
0734 .getServiceProviders(ImageReaderSpi.class,
0735 new ContainsFilter(
0736 readerFileSuffixesMethod,
0737 fileSuffix), true);
0738 } catch (IllegalArgumentException e) {
0739 return Collections.emptyIterator();
0740 }
0741 return new ImageReaderIterator(iter);
0742 }
0743
0744 /**
0745 * Returns an <code>Iterator</code> containing all currently
0746 * registered <code>ImageReader</code>s that claim to be able to
0747 * decode files with the given MIME type.
0748 *
0749 * @param MIMEType a <code>String</code> containing a file
0750 * suffix (<i>e.g.</i>, "image/jpeg" or "image/x-bmp").
0751 *
0752 * @return an <code>Iterator</code> containing
0753 * <code>ImageReader</code>s.
0754 *
0755 * @exception IllegalArgumentException if <code>MIMEType</code> is
0756 * <code>null</code>.
0757 *
0758 * @see javax.imageio.spi.ImageReaderSpi#getMIMETypes
0759 */
0760 public static Iterator<ImageReader> getImageReadersByMIMEType(
0761 String MIMEType) {
0762 if (MIMEType == null) {
0763 throw new IllegalArgumentException("MIMEType == null!");
0764 }
0765 // Ensure category is present
0766 Iterator iter;
0767 try {
0768 iter = theRegistry.getServiceProviders(
0769 ImageReaderSpi.class, new ContainsFilter(
0770 readerMIMETypesMethod, MIMEType), true);
0771 } catch (IllegalArgumentException e) {
0772 return Collections.emptyIterator();
0773 }
0774 return new ImageReaderIterator(iter);
0775 }
0776
0777 // Writers
0778
0779 /**
0780 * Returns an array of <code>String</code>s listing all of the
0781 * informal format names understood by the current set of registered
0782 * writers.
0783 *
0784 * @return an array of <code>String</code>s.
0785 */
0786 public static String[] getWriterFormatNames() {
0787 return getReaderWriterInfo(ImageWriterSpi.class,
0788 SpiInfo.FORMAT_NAMES);
0789 }
0790
0791 /**
0792 * Returns an array of <code>String</code>s listing all of the
0793 * MIME types understood by the current set of registered
0794 * writers.
0795 *
0796 * @return an array of <code>String</code>s.
0797 */
0798 public static String[] getWriterMIMETypes() {
0799 return getReaderWriterInfo(ImageWriterSpi.class,
0800 SpiInfo.MIME_TYPES);
0801 }
0802
0803 /**
0804 * Returns an array of <code>String</code>s listing all of the
0805 * file suffixes associated with the formats understood
0806 * by the current set of registered writers.
0807 *
0808 * @return an array of <code>String</code>s.
0809 * @since 1.6
0810 */
0811 public static String[] getWriterFileSuffixes() {
0812 return getReaderWriterInfo(ImageWriterSpi.class,
0813 SpiInfo.FILE_SUFFIXES);
0814 }
0815
0816 static class ImageWriterIterator implements Iterator<ImageWriter> {
0817 // Contains ImageWriterSpis
0818 public Iterator iter;
0819
0820 public ImageWriterIterator(Iterator iter) {
0821 this .iter = iter;
0822 }
0823
0824 public boolean hasNext() {
0825 return iter.hasNext();
0826 }
0827
0828 public ImageWriter next() {
0829 ImageWriterSpi spi = null;
0830 try {
0831 spi = (ImageWriterSpi) iter.next();
0832 return spi.createWriterInstance();
0833 } catch (IOException e) {
0834 // Deregister the spi in this case, but only as a writerSpi
0835 theRegistry.deregisterServiceProvider(spi,
0836 ImageWriterSpi.class);
0837 }
0838 return null;
0839 }
0840
0841 public void remove() {
0842 throw new UnsupportedOperationException();
0843 }
0844 }
0845
0846 private static boolean contains(String[] names, String name) {
0847 for (int i = 0; i < names.length; i++) {
0848 if (name.equalsIgnoreCase(names[i])) {
0849 return true;
0850 }
0851 }
0852
0853 return false;
0854 }
0855
0856 /**
0857 * Returns an <code>Iterator</code> containing all currently
0858 * registered <code>ImageWriter</code>s that claim to be able to
0859 * encode the named format.
0860 *
0861 * @param formatName a <code>String</code> containing the informal
0862 * name of a format (<i>e.g.</i>, "jpeg" or "tiff".
0863 *
0864 * @return an <code>Iterator</code> containing
0865 * <code>ImageWriter</code>s.
0866 *
0867 * @exception IllegalArgumentException if <code>formatName</code> is
0868 * <code>null</code>.
0869 *
0870 * @see javax.imageio.spi.ImageWriterSpi#getFormatNames
0871 */
0872 public static Iterator<ImageWriter> getImageWritersByFormatName(
0873 String formatName) {
0874 if (formatName == null) {
0875 throw new IllegalArgumentException("formatName == null!");
0876 }
0877 Iterator iter;
0878 // Ensure category is present
0879 try {
0880 iter = theRegistry.getServiceProviders(
0881 ImageWriterSpi.class, new ContainsFilter(
0882 writerFormatNamesMethod, formatName), true);
0883 } catch (IllegalArgumentException e) {
0884 return Collections.emptyIterator();
0885 }
0886 return new ImageWriterIterator(iter);
0887 }
0888
0889 /**
0890 * Returns an <code>Iterator</code> containing all currently
0891 * registered <code>ImageWriter</code>s that claim to be able to
0892 * encode files with the given suffix.
0893 *
0894 * @param fileSuffix a <code>String</code> containing a file
0895 * suffix (<i>e.g.</i>, "jpg" or "tiff").
0896 *
0897 * @return an <code>Iterator</code> containing <code>ImageWriter</code>s.
0898 *
0899 * @exception IllegalArgumentException if <code>fileSuffix</code> is
0900 * <code>null</code>.
0901 *
0902 * @see javax.imageio.spi.ImageWriterSpi#getFileSuffixes
0903 */
0904 public static Iterator<ImageWriter> getImageWritersBySuffix(
0905 String fileSuffix) {
0906 if (fileSuffix == null) {
0907 throw new IllegalArgumentException("fileSuffix == null!");
0908 }
0909 Iterator iter;
0910 // Ensure category is present
0911 try {
0912 iter = theRegistry
0913 .getServiceProviders(ImageWriterSpi.class,
0914 new ContainsFilter(
0915 writerFileSuffixesMethod,
0916 fileSuffix), true);
0917 } catch (IllegalArgumentException e) {
0918 return Collections.emptyIterator();
0919 }
0920 return new ImageWriterIterator(iter);
0921 }
0922
0923 /**
0924 * Returns an <code>Iterator</code> containing all currently
0925 * registered <code>ImageWriter</code>s that claim to be able to
0926 * encode files with the given MIME type.
0927 *
0928 * @param MIMEType a <code>String</code> containing a file
0929 * suffix (<i>e.g.</i>, "image/jpeg" or "image/x-bmp").
0930 *
0931 * @return an <code>Iterator</code> containing <code>ImageWriter</code>s.
0932 *
0933 * @exception IllegalArgumentException if <code>MIMEType</code> is
0934 * <code>null</code>.
0935 *
0936 * @see javax.imageio.spi.ImageWriterSpi#getMIMETypes
0937 */
0938 public static Iterator<ImageWriter> getImageWritersByMIMEType(
0939 String MIMEType) {
0940 if (MIMEType == null) {
0941 throw new IllegalArgumentException("MIMEType == null!");
0942 }
0943 Iterator iter;
0944 // Ensure category is present
0945 try {
0946 iter = theRegistry.getServiceProviders(
0947 ImageWriterSpi.class, new ContainsFilter(
0948 writerMIMETypesMethod, MIMEType), true);
0949 } catch (IllegalArgumentException e) {
0950 return Collections.emptyIterator();
0951 }
0952 return new ImageWriterIterator(iter);
0953 }
0954
0955 /**
0956 * Returns an <code>ImageWriter</code>corresponding to the given
0957 * <code>ImageReader</code>, if there is one, or <code>null</code>
0958 * if the plug-in for this <code>ImageReader</code> does not
0959 * specify a corresponding <code>ImageWriter</code>, or if the
0960 * given <code>ImageReader</code> is not registered. This
0961 * mechanism may be used to obtain an <code>ImageWriter</code>
0962 * that will understand the internal structure of non-pixel
0963 * metadata (as encoded by <code>IIOMetadata</code> objects)
0964 * generated by the <code>ImageReader</code>. By obtaining this
0965 * data from the <code>ImageReader</code> and passing it on to the
0966 * <code>ImageWriter</code> obtained with this method, a client
0967 * program can read an image, modify it in some way, and write it
0968 * back out preserving all metadata, without having to understand
0969 * anything about the structure of the metadata, or even about
0970 * the image format. Note that this method returns the
0971 * "preferred" writer, which is the first in the list returned by
0972 * <code>javax.imageio.spi.ImageReaderSpi.getImageWriterSpiNames()</code>.
0973 *
0974 * @param reader an instance of a registered <code>ImageReader</code>.
0975 *
0976 * @return an <code>ImageWriter</code>, or null.
0977 *
0978 * @exception IllegalArgumentException if <code>reader</code> is
0979 * <code>null</code>.
0980 *
0981 * @see #getImageReader(ImageWriter)
0982 * @see javax.imageio.spi.ImageReaderSpi#getImageWriterSpiNames()
0983 */
0984 public static ImageWriter getImageWriter(ImageReader reader) {
0985 if (reader == null) {
0986 throw new IllegalArgumentException("reader == null!");
0987 }
0988
0989 ImageReaderSpi readerSpi = reader.getOriginatingProvider();
0990 if (readerSpi == null) {
0991 Iterator readerSpiIter;
0992 // Ensure category is present
0993 try {
0994 readerSpiIter = theRegistry.getServiceProviders(
0995 ImageReaderSpi.class, false);
0996 } catch (IllegalArgumentException e) {
0997 return null;
0998 }
0999
1000 while (readerSpiIter.hasNext()) {
1001 ImageReaderSpi temp = (ImageReaderSpi) readerSpiIter
1002 .next();
1003 if (temp.isOwnReader(reader)) {
1004 readerSpi = temp;
1005 break;
1006 }
1007 }
1008 if (readerSpi == null) {
1009 return null;
1010 }
1011 }
1012
1013 String[] writerNames = readerSpi.getImageWriterSpiNames();
1014 if (writerNames == null) {
1015 return null;
1016 }
1017
1018 Class writerSpiClass = null;
1019 try {
1020 writerSpiClass = Class.forName(writerNames[0], true,
1021 ClassLoader.getSystemClassLoader());
1022 } catch (ClassNotFoundException e) {
1023 return null;
1024 }
1025
1026 ImageWriterSpi writerSpi = (ImageWriterSpi) theRegistry
1027 .getServiceProviderByClass(writerSpiClass);
1028 if (writerSpi == null) {
1029 return null;
1030 }
1031
1032 try {
1033 return writerSpi.createWriterInstance();
1034 } catch (IOException e) {
1035 // Deregister the spi in this case, but only as a writerSpi
1036 theRegistry.deregisterServiceProvider(writerSpi,
1037 ImageWriterSpi.class);
1038 return null;
1039 }
1040 }
1041
1042 /**
1043 * Returns an <code>ImageReader</code>corresponding to the given
1044 * <code>ImageWriter</code>, if there is one, or <code>null</code>
1045 * if the plug-in for this <code>ImageWriter</code> does not
1046 * specify a corresponding <code>ImageReader</code>, or if the
1047 * given <code>ImageWriter</code> is not registered. This method
1048 * is provided principally for symmetry with
1049 * <code>getImageWriter(ImageReader)</code>. Note that this
1050 * method returns the "preferred" reader, which is the first in
1051 * the list returned by
1052 * javax.imageio.spi.ImageWriterSpi.<code>getImageReaderSpiNames()</code>.
1053 *
1054 * @param writer an instance of a registered <code>ImageWriter</code>.
1055 *
1056 * @return an <code>ImageReader</code>, or null.
1057 *
1058 * @exception IllegalArgumentException if <code>writer</code> is
1059 * <code>null</code>.
1060 *
1061 * @see #getImageWriter(ImageReader)
1062 * @see javax.imageio.spi.ImageWriterSpi#getImageReaderSpiNames()
1063 */
1064 public static ImageReader getImageReader(ImageWriter writer) {
1065 if (writer == null) {
1066 throw new IllegalArgumentException("writer == null!");
1067 }
1068
1069 ImageWriterSpi writerSpi = writer.getOriginatingProvider();
1070 if (writerSpi == null) {
1071 Iterator writerSpiIter;
1072 // Ensure category is present
1073 try {
1074 writerSpiIter = theRegistry.getServiceProviders(
1075 ImageWriterSpi.class, false);
1076 } catch (IllegalArgumentException e) {
1077 return null;
1078 }
1079
1080 while (writerSpiIter.hasNext()) {
1081 ImageWriterSpi temp = (ImageWriterSpi) writerSpiIter
1082 .next();
1083 if (temp.isOwnWriter(writer)) {
1084 writerSpi = temp;
1085 break;
1086 }
1087 }
1088 if (writerSpi == null) {
1089 return null;
1090 }
1091 }
1092
1093 String[] readerNames = writerSpi.getImageReaderSpiNames();
1094 if (readerNames == null) {
1095 return null;
1096 }
1097
1098 Class readerSpiClass = null;
1099 try {
1100 readerSpiClass = Class.forName(readerNames[0], true,
1101 ClassLoader.getSystemClassLoader());
1102 } catch (ClassNotFoundException e) {
1103 return null;
1104 }
1105
1106 ImageReaderSpi readerSpi = (ImageReaderSpi) theRegistry
1107 .getServiceProviderByClass(readerSpiClass);
1108 if (readerSpi == null) {
1109 return null;
1110 }
1111
1112 try {
1113 return readerSpi.createReaderInstance();
1114 } catch (IOException e) {
1115 // Deregister the spi in this case, but only as a readerSpi
1116 theRegistry.deregisterServiceProvider(readerSpi,
1117 ImageReaderSpi.class);
1118 return null;
1119 }
1120 }
1121
1122 /**
1123 * Returns an <code>Iterator</code> containing all currently
1124 * registered <code>ImageWriter</code>s that claim to be able to
1125 * encode images of the given layout (specified using an
1126 * <code>ImageTypeSpecifier</code>) in the given format.
1127 *
1128 * @param type an <code>ImageTypeSpecifier</code> indicating the
1129 * layout of the image to be written.
1130 * @param formatName the informal name of the <code>format</code>.
1131 *
1132 * @return an <code>Iterator</code> containing <code>ImageWriter</code>s.
1133 *
1134 * @exception IllegalArgumentException if any parameter is
1135 * <code>null</code>.
1136 *
1137 * @see javax.imageio.spi.ImageWriterSpi#canEncodeImage(ImageTypeSpecifier)
1138 */
1139 public static Iterator<ImageWriter> getImageWriters(
1140 ImageTypeSpecifier type, String formatName) {
1141 if (type == null) {
1142 throw new IllegalArgumentException("type == null!");
1143 }
1144 if (formatName == null) {
1145 throw new IllegalArgumentException("formatName == null!");
1146 }
1147
1148 Iterator iter;
1149 // Ensure category is present
1150 try {
1151 iter = theRegistry
1152 .getServiceProviders(ImageWriterSpi.class,
1153 new CanEncodeImageAndFormatFilter(type,
1154 formatName), true);
1155 } catch (IllegalArgumentException e) {
1156 return Collections.emptyIterator();
1157 }
1158
1159 return new ImageWriterIterator(iter);
1160 }
1161
1162 static class ImageTranscoderIterator implements
1163 Iterator<ImageTranscoder> {
1164 // Contains ImageTranscoderSpis
1165 public Iterator iter;
1166
1167 public ImageTranscoderIterator(Iterator iter) {
1168 this .iter = iter;
1169 }
1170
1171 public boolean hasNext() {
1172 return iter.hasNext();
1173 }
1174
1175 public ImageTranscoder next() {
1176 ImageTranscoderSpi spi = null;
1177 spi = (ImageTranscoderSpi) iter.next();
1178 return spi.createTranscoderInstance();
1179 }
1180
1181 public void remove() {
1182 throw new UnsupportedOperationException();
1183 }
1184 }
1185
1186 static class TranscoderFilter implements ServiceRegistry.Filter {
1187
1188 String readerSpiName;
1189 String writerSpiName;
1190
1191 public TranscoderFilter(ImageReaderSpi readerSpi,
1192 ImageWriterSpi writerSpi) {
1193 this .readerSpiName = readerSpi.getClass().getName();
1194 this .writerSpiName = writerSpi.getClass().getName();
1195 }
1196
1197 public boolean filter(Object elt) {
1198 ImageTranscoderSpi spi = (ImageTranscoderSpi) elt;
1199 String readerName = spi.getReaderServiceProviderName();
1200 String writerName = spi.getWriterServiceProviderName();
1201 return (readerName.equals(readerSpiName) && writerName
1202 .equals(writerSpiName));
1203 }
1204 }
1205
1206 /**
1207 * Returns an <code>Iterator</code> containing all currently
1208 * registered <code>ImageTranscoder</code>s that claim to be
1209 * able to transcode between the metadata of the given
1210 * <code>ImageReader</code> and <code>ImageWriter</code>.
1211 *
1212 * @param reader an <code>ImageReader</code>.
1213 * @param writer an <code>ImageWriter</code>.
1214 *
1215 * @return an <code>Iterator</code> containing
1216 * <code>ImageTranscoder</code>s.
1217 *
1218 * @exception IllegalArgumentException if <code>reader</code> or
1219 * <code>writer</code> is <code>null</code>.
1220 */
1221 public static Iterator<ImageTranscoder> getImageTranscoders(
1222 ImageReader reader, ImageWriter writer) {
1223 if (reader == null) {
1224 throw new IllegalArgumentException("reader == null!");
1225 }
1226 if (writer == null) {
1227 throw new IllegalArgumentException("writer == null!");
1228 }
1229 ImageReaderSpi readerSpi = reader.getOriginatingProvider();
1230 ImageWriterSpi writerSpi = writer.getOriginatingProvider();
1231 ServiceRegistry.Filter filter = new TranscoderFilter(readerSpi,
1232 writerSpi);
1233
1234 Iterator iter;
1235 // Ensure category is present
1236 try {
1237 iter = theRegistry.getServiceProviders(
1238 ImageTranscoderSpi.class, filter, true);
1239 } catch (IllegalArgumentException e) {
1240 return Collections.emptyIterator();
1241 }
1242 return new ImageTranscoderIterator(iter);
1243 }
1244
1245 // All-in-one methods
1246
1247 /**
1248 * Returns a <code>BufferedImage</code> as the result of decoding
1249 * a supplied <code>File</code> with an <code>ImageReader</code>
1250 * chosen automatically from among those currently registered.
1251 * The <code>File</code> is wrapped in an
1252 * <code>ImageInputStream</code>. If no registered
1253 * <code>ImageReader</code> claims to be able to read the
1254 * resulting stream, <code>null</code> is returned.
1255 *
1256 * <p> The current cache settings from <code>getUseCache</code>and
1257 * <code>getCacheDirectory</code> will be used to control caching in the
1258 * <code>ImageInputStream</code> that is created.
1259 *
1260 * <p> Note that there is no <code>read</code> method that takes a
1261 * filename as a <code>String</code>; use this method instead after
1262 * creating a <code>File</code> from the filename.
1263 *
1264 * <p> This method does not attempt to locate
1265 * <code>ImageReader</code>s that can read directly from a
1266 * <code>File</code>; that may be accomplished using
1267 * <code>IIORegistry</code> and <code>ImageReaderSpi</code>.
1268 *
1269 * @param input a <code>File</code> to read from.
1270 *
1271 * @return a <code>BufferedImage</code> containing the decoded
1272 * contents of the input, or <code>null</code>.
1273 *
1274 * @exception IllegalArgumentException if <code>input</code> is
1275 * <code>null</code>.
1276 * @exception IOException if an error occurs during reading.
1277 */
1278 public static BufferedImage read(File input) throws IOException {
1279 if (input == null) {
1280 throw new IllegalArgumentException("input == null!");
1281 }
1282 if (!input.canRead()) {
1283 throw new IIOException("Can't read input file!");
1284 }
1285
1286 ImageInputStream stream = createImageInputStream(input);
1287 if (stream == null) {
1288 throw new IIOException("Can't create an ImageInputStream!");
1289 }
1290 BufferedImage bi = read(stream);
1291 if (bi == null) {
1292 stream.close();
1293 }
1294 return bi;
1295 }
1296
1297 /**
1298 * Returns a <code>BufferedImage</code> as the result of decoding
1299 * a supplied <code>InputStream</code> with an <code>ImageReader</code>
1300 * chosen automatically from among those currently registered.
1301 * The <code>InputStream</code> is wrapped in an
1302 * <code>ImageInputStream</code>. If no registered
1303 * <code>ImageReader</code> claims to be able to read the
1304 * resulting stream, <code>null</code> is returned.
1305 *
1306 * <p> The current cache settings from <code>getUseCache</code>and
1307 * <code>getCacheDirectory</code> will be used to control caching in the
1308 * <code>ImageInputStream</code> that is created.
1309 *
1310 * <p> This method does not attempt to locate
1311 * <code>ImageReader</code>s that can read directly from an
1312 * <code>InputStream</code>; that may be accomplished using
1313 * <code>IIORegistry</code> and <code>ImageReaderSpi</code>.
1314 *
1315 * <p> This method <em>does not</em> close the provided
1316 * <code>InputStream</code> after the read operation has completed;
1317 * it is the responsibility of the caller to close the stream, if desired.
1318 *
1319 * @param input an <code>InputStream</code> to read from.
1320 *
1321 * @return a <code>BufferedImage</code> containing the decoded
1322 * contents of the input, or <code>null</code>.
1323 *
1324 * @exception IllegalArgumentException if <code>input</code> is
1325 * <code>null</code>.
1326 * @exception IOException if an error occurs during reading.
1327 */
1328 public static BufferedImage read(InputStream input)
1329 throws IOException {
1330 if (input == null) {
1331 throw new IllegalArgumentException("input == null!");
1332 }
1333
1334 ImageInputStream stream = createImageInputStream(input);
1335 BufferedImage bi = read(stream);
1336 if (bi == null) {
1337 stream.close();
1338 }
1339 return bi;
1340 }
1341
1342 /**
1343 * Returns a <code>BufferedImage</code> as the result of decoding
1344 * a supplied <code>URL</code> with an <code>ImageReader</code>
1345 * chosen automatically from among those currently registered. An
1346 * <code>InputStream</code> is obtained from the <code>URL</code>,
1347 * which is wrapped in an <code>ImageInputStream</code>. If no
1348 * registered <code>ImageReader</code> claims to be able to read
1349 * the resulting stream, <code>null</code> is returned.
1350 *
1351 * <p> The current cache settings from <code>getUseCache</code>and
1352 * <code>getCacheDirectory</code> will be used to control caching in the
1353 * <code>ImageInputStream</code> that is created.
1354 *
1355 * <p> This method does not attempt to locate
1356 * <code>ImageReader</code>s that can read directly from a
1357 * <code>URL</code>; that may be accomplished using
1358 * <code>IIORegistry</code> and <code>ImageReaderSpi</code>.
1359 *
1360 * @param input a <code>URL</code> to read from.
1361 *
1362 * @return a <code>BufferedImage</code> containing the decoded
1363 * contents of the input, or <code>null</code>.
1364 *
1365 * @exception IllegalArgumentException if <code>input</code> is
1366 * <code>null</code>.
1367 * @exception IOException if an error occurs during reading.
1368 */
1369 public static BufferedImage read(URL input) throws IOException {
1370 if (input == null) {
1371 throw new IllegalArgumentException("input == null!");
1372 }
1373
1374 InputStream istream = null;
1375 try {
1376 istream = input.openStream();
1377 } catch (IOException e) {
1378 throw new IIOException("Can't get input stream from URL!",
1379 e);
1380 }
1381 ImageInputStream stream = createImageInputStream(istream);
1382 BufferedImage bi;
1383 try {
1384 bi = read(stream);
1385 if (bi == null) {
1386 stream.close();
1387 }
1388 } finally {
1389 istream.close();
1390 }
1391 return bi;
1392 }
1393
1394 /**
1395 * Returns a <code>BufferedImage</code> as the result of decoding
1396 * a supplied <code>ImageInputStream</code> with an
1397 * <code>ImageReader</code> chosen automatically from among those
1398 * currently registered. If no registered
1399 * <code>ImageReader</code> claims to be able to read the stream,
1400 * <code>null</code> is returned.
1401 *
1402 * <p> Unlike most other methods in this class, this method <em>does</em>
1403 * close the provided <code>ImageInputStream</code> after the read
1404 * operation has completed, unless <code>null</code> is returned,
1405 * in which case this method <em>does not</em> close the stream.
1406 *
1407 * @param stream an <code>ImageInputStream</code> to read from.
1408 *
1409 * @return a <code>BufferedImage</code> containing the decoded
1410 * contents of the input, or <code>null</code>.
1411 *
1412 * @exception IllegalArgumentException if <code>stream</code> is
1413 * <code>null</code>.
1414 * @exception IOException if an error occurs during reading.
1415 */
1416 public static BufferedImage read(ImageInputStream stream)
1417 throws IOException {
1418 if (stream == null) {
1419 throw new IllegalArgumentException("stream == null!");
1420 }
1421
1422 Iterator iter = getImageReaders(stream);
1423 if (!iter.hasNext()) {
1424 return null;
1425 }
1426
1427 ImageReader reader = (ImageReader) iter.next();
1428 ImageReadParam param = reader.getDefaultReadParam();
1429 reader.setInput(stream, true, true);
1430 BufferedImage bi;
1431 try {
1432 bi = reader.read(0, param);
1433 } finally {
1434 reader.dispose();
1435 stream.close();
1436 }
1437 return bi;
1438 }
1439
1440 /**
1441 * Writes an image using the an arbitrary <code>ImageWriter</code>
1442 * that supports the given format to an
1443 * <code>ImageOutputStream</code>. The image is written to the
1444 * <code>ImageOutputStream</code> starting at the current stream
1445 * pointer, overwriting existing stream data from that point
1446 * forward, if present.
1447 *
1448 * <p> This method <em>does not</em> close the provided
1449 * <code>ImageOutputStream</code> after the write operation has completed;
1450 * it is the responsibility of the caller to close the stream, if desired.
1451 *
1452 * @param im a <code>RenderedImage</code> to be written.
1453 * @param formatName a <code>String</code> containg the informal
1454 * name of the format.
1455 * @param output an <code>ImageOutputStream</code> to be written to.
1456 *
1457 * @return <code>false</code> if no appropriate writer is found.
1458 *
1459 * @exception IllegalArgumentException if any parameter is
1460 * <code>null</code>.
1461 * @exception IOException if an error occurs during writing.
1462 */
1463 public static boolean write(RenderedImage im, String formatName,
1464 ImageOutputStream output) throws IOException {
1465 if (im == null) {
1466 throw new IllegalArgumentException("im == null!");
1467 }
1468 if (formatName == null) {
1469 throw new IllegalArgumentException("formatName == null!");
1470 }
1471 if (output == null) {
1472 throw new IllegalArgumentException("output == null!");
1473 }
1474
1475 ImageWriter writer = null;
1476 ImageTypeSpecifier type = ImageTypeSpecifier
1477 .createFromRenderedImage(im);
1478 Iterator iter = getImageWriters(type, formatName);
1479 if (iter.hasNext()) {
1480 writer = (ImageWriter) iter.next();
1481 }
1482 if (writer == null) {
1483 return false;
1484 }
1485
1486 writer.setOutput(output);
1487 try {
1488 writer.write(im);
1489 } finally {
1490 writer.dispose();
1491 output.flush();
1492 }
1493
1494 return true;
1495 }
1496
1497 /**
1498 * Writes an image using an arbitrary <code>ImageWriter</code>
1499 * that supports the given format to a <code>File</code>. If
1500 * there is already a <code>File</code> present, its contents are
1501 * discarded.
1502 *
1503 * @param im a <code>RenderedImage</code> to be written.
1504 * @param formatName a <code>String</code> containg the informal
1505 * name of the format.
1506 * @param output a <code>File</code> to be written to.
1507 *
1508 * @return <code>false</code> if no appropriate writer is found.
1509 *
1510 * @exception IllegalArgumentException if any parameter is
1511 * <code>null</code>.
1512 * @exception IOException if an error occurs during writing.
1513 */
1514 public static boolean write(RenderedImage im, String formatName,
1515 File output) throws IOException {
1516 if (output == null) {
1517 throw new IllegalArgumentException("output == null!");
1518 }
1519 ImageOutputStream stream = null;
1520 try {
1521 output.delete();
1522 stream = createImageOutputStream(output);
1523 } catch (IOException e) {
1524 throw new IIOException("Can't create output stream!", e);
1525 }
1526
1527 boolean val;
1528 try {
1529 val = write(im, formatName, stream);
1530 } finally {
1531 stream.close();
1532 }
1533 return val;
1534 }
1535
1536 /**
1537 * Writes an image using an arbitrary <code>ImageWriter</code>
1538 * that supports the given format to an <code>OutputStream</code>.
1539 *
1540 * <p> This method <em>does not</em> close the provided
1541 * <code>OutputStream</code> after the write operation has completed;
1542 * it is the responsibility of the caller to close the stream, if desired.
1543 *
1544 * <p> The current cache settings from <code>getUseCache</code>and
1545 * <code>getCacheDirectory</code> will be used to control caching.
1546 *
1547 * @param im a <code>RenderedImage</code> to be written.
1548 * @param formatName a <code>String</code> containg the informal
1549 * name of the format.
1550 * @param output an <code>OutputStream</code> to be written to.
1551 *
1552 * @return <code>false</code> if no appropriate writer is found.
1553 *
1554 * @exception IllegalArgumentException if any parameter is
1555 * <code>null</code>.
1556 * @exception IOException if an error occurs during writing.
1557 */
1558 public static boolean write(RenderedImage im, String formatName,
1559 OutputStream output) throws IOException {
1560 if (output == null) {
1561 throw new IllegalArgumentException("output == null!");
1562 }
1563 ImageOutputStream stream = null;
1564 try {
1565 stream = createImageOutputStream(output);
1566 } catch (IOException e) {
1567 throw new IIOException("Can't create output stream!", e);
1568 }
1569
1570 boolean val;
1571 try {
1572 val = write(im, formatName, stream);
1573 } finally {
1574 stream.close();
1575 }
1576 return val;
1577 }
1578 }
|