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