1. /*
  2. * @(#)ImageIO.java 1.85 04/05/05
  3. *
  4. * Copyright 2004 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<ImageReader> {
  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 ImageReader 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<ImageReader> 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<ImageReader>
  587. getImageReadersByFormatName(String formatName)
  588. {
  589. if (formatName == null) {
  590. throw new IllegalArgumentException("formatName == null!");
  591. }
  592. Iterator iter;
  593. // Ensure category is present
  594. try {
  595. iter = theRegistry.getServiceProviders(ImageReaderSpi.class,
  596. new ContainsFilter(readerFormatNamesMethod,
  597. formatName),
  598. true);
  599. } catch (IllegalArgumentException e) {
  600. return new HashSet().iterator();
  601. }
  602. return new ImageReaderIterator(iter);
  603. }
  604. /**
  605. * Returns an <code>Iterator</code> containing all currently
  606. * registered <code>ImageReader</code>s that claim to be able to
  607. * decode files with the given suffix.
  608. *
  609. * @param fileSuffix a <code>String</code> containing a file
  610. * suffix (<i>e.g.</i>, "jpg" or "tiff").
  611. *
  612. * @return an <code>Iterator</code> containing
  613. * <code>ImageReader</code>s.
  614. *
  615. * @exception IllegalArgumentException if <code>fileSuffix</code>
  616. * is <code>null</code>.
  617. *
  618. * @see javax.imageio.spi.ImageReaderSpi#getFileSuffixes
  619. */
  620. public static Iterator<ImageReader>
  621. getImageReadersBySuffix(String fileSuffix)
  622. {
  623. if (fileSuffix == null) {
  624. throw new IllegalArgumentException("fileSuffix == null!");
  625. }
  626. // Ensure category is present
  627. Iterator iter;
  628. try {
  629. iter = theRegistry.getServiceProviders(ImageReaderSpi.class,
  630. new ContainsFilter(readerFileSuffixesMethod,
  631. fileSuffix),
  632. true);
  633. } catch (IllegalArgumentException e) {
  634. return new HashSet().iterator();
  635. }
  636. return new ImageReaderIterator(iter);
  637. }
  638. /**
  639. * Returns an <code>Iterator</code> containing all currently
  640. * registered <code>ImageReader</code>s that claim to be able to
  641. * decode files with the given MIME type.
  642. *
  643. * @param MIMEType a <code>String</code> containing a file
  644. * suffix (<i>e.g.</i>, "image/jpeg" or "image/x-bmp").
  645. *
  646. * @return an <code>Iterator</code> containing
  647. * <code>ImageReader</code>s.
  648. *
  649. * @exception IllegalArgumentException if <code>MIMEType</code> is
  650. * <code>null</code>.
  651. *
  652. * @see javax.imageio.spi.ImageReaderSpi#getMIMETypes
  653. */
  654. public static Iterator<ImageReader>
  655. getImageReadersByMIMEType(String MIMEType)
  656. {
  657. if (MIMEType == null) {
  658. throw new IllegalArgumentException("MIMEType == null!");
  659. }
  660. // Ensure category is present
  661. Iterator iter;
  662. try {
  663. iter = theRegistry.getServiceProviders(ImageReaderSpi.class,
  664. new ContainsFilter(readerMIMETypesMethod,
  665. MIMEType),
  666. true);
  667. } catch (IllegalArgumentException e) {
  668. return new HashSet().iterator();
  669. }
  670. return new ImageReaderIterator(iter);
  671. }
  672. // Writers
  673. /**
  674. * Returns an array of <code>String</code>s listing all of the
  675. * informal format names understood by the current set of registered
  676. * writers.
  677. *
  678. * @return an array of <code>String</code>s.
  679. */
  680. public static String[] getWriterFormatNames() {
  681. Iterator iter;
  682. // Ensure category is present
  683. try {
  684. iter = theRegistry.getServiceProviders(ImageWriterSpi.class, true);
  685. } catch (IllegalArgumentException e) {
  686. return new String[0];
  687. }
  688. Set s = new HashSet();
  689. while (iter.hasNext()) {
  690. ImageWriterSpi spi = (ImageWriterSpi)iter.next();
  691. String[] names = spi.getFormatNames();
  692. for (int i = 0; i < names.length; i++) {
  693. s.add(names[i]);
  694. }
  695. }
  696. return toStringArray(s);
  697. }
  698. /**
  699. * Returns an array of <code>String</code>s listing all of the
  700. * MIME types understood by the current set of registered
  701. * writers.
  702. *
  703. * @return an array of <code>String</code>s.
  704. */
  705. public static String[] getWriterMIMETypes() {
  706. Iterator iter;
  707. // Ensure category is present
  708. try {
  709. iter = theRegistry.getServiceProviders(ImageWriterSpi.class, true);
  710. } catch (IllegalArgumentException e) {
  711. return new String[0];
  712. }
  713. Set s = new HashSet();
  714. while (iter.hasNext()) {
  715. ImageWriterSpi spi = (ImageWriterSpi)iter.next();
  716. String[] names = spi.getMIMETypes();
  717. for (int i = 0; i < names.length; i++) {
  718. s.add(names[i]);
  719. }
  720. }
  721. return toStringArray(s);
  722. }
  723. static class ImageWriterIterator implements Iterator<ImageWriter> {
  724. // Contains ImageWriterSpis
  725. public Iterator iter;
  726. public ImageWriterIterator(Iterator iter) {
  727. this.iter = iter;
  728. }
  729. public boolean hasNext() {
  730. return iter.hasNext();
  731. }
  732. public ImageWriter next() {
  733. ImageWriterSpi spi = null;
  734. try {
  735. spi = (ImageWriterSpi)iter.next();
  736. return spi.createWriterInstance();
  737. } catch (IOException e) {
  738. // Deregister the spi in this case, but only as a writerSpi
  739. theRegistry.deregisterServiceProvider(spi, ImageWriterSpi.class);
  740. }
  741. return null;
  742. }
  743. public void remove() {
  744. throw new UnsupportedOperationException();
  745. }
  746. }
  747. private static boolean contains(String[] names, String name) {
  748. for (int i = 0; i < names.length; i++) {
  749. if (name.equalsIgnoreCase(names[i])) {
  750. return true;
  751. }
  752. }
  753. return false;
  754. }
  755. /**
  756. * Returns an <code>Iterator</code> containing all currently
  757. * registered <code>ImageWriter</code>s that claim to be able to
  758. * encode the named format.
  759. *
  760. * @param formatName a <code>String</code> containing the informal
  761. * name of a format (<i>e.g.</i>, "jpeg" or "tiff".
  762. *
  763. * @return an <code>Iterator</code> containing
  764. * <code>ImageWriter</code>s.
  765. *
  766. * @exception IllegalArgumentException if <code>formatName</code> is
  767. * <code>null</code>.
  768. *
  769. * @see javax.imageio.spi.ImageWriterSpi#getFormatNames
  770. */
  771. public static Iterator<ImageWriter>
  772. getImageWritersByFormatName(String formatName)
  773. {
  774. if (formatName == null) {
  775. throw new IllegalArgumentException("formatName == null!");
  776. }
  777. Iterator iter;
  778. // Ensure category is present
  779. try {
  780. iter = theRegistry.getServiceProviders(ImageWriterSpi.class,
  781. new ContainsFilter(writerFormatNamesMethod,
  782. formatName),
  783. true);
  784. } catch (IllegalArgumentException e) {
  785. return new HashSet().iterator();
  786. }
  787. return new ImageWriterIterator(iter);
  788. }
  789. /**
  790. * Returns an <code>Iterator</code> containing all currently
  791. * registered <code>ImageWriter</code>s that claim to be able to
  792. * encode files with the given suffix.
  793. *
  794. * @param fileSuffix a <code>String</code> containing a file
  795. * suffix (<i>e.g.</i>, "jpg" or "tiff").
  796. *
  797. * @return an <code>Iterator</code> containing <code>ImageWriter</code>s.
  798. *
  799. * @exception IllegalArgumentException if <code>fileSuffix</code> is
  800. * <code>null</code>.
  801. *
  802. * @see javax.imageio.spi.ImageWriterSpi#getFileSuffixes
  803. */
  804. public static Iterator<ImageWriter>
  805. getImageWritersBySuffix(String fileSuffix)
  806. {
  807. if (fileSuffix == null) {
  808. throw new IllegalArgumentException("fileSuffix == null!");
  809. }
  810. Iterator iter;
  811. // Ensure category is present
  812. try {
  813. iter = theRegistry.getServiceProviders(ImageWriterSpi.class,
  814. new ContainsFilter(writerFileSuffixesMethod,
  815. fileSuffix),
  816. true);
  817. } catch (IllegalArgumentException e) {
  818. return new HashSet().iterator();
  819. }
  820. return new ImageWriterIterator(iter);
  821. }
  822. /**
  823. * Returns an <code>Iterator</code> containing all currently
  824. * registered <code>ImageWriter</code>s that claim to be able to
  825. * encode files with the given MIME type.
  826. *
  827. * @param MIMEType a <code>String</code> containing a file
  828. * suffix (<i>e.g.</i>, "image/jpeg" or "image/x-bmp").
  829. *
  830. * @return an <code>Iterator</code> containing <code>ImageWriter</code>s.
  831. *
  832. * @exception IllegalArgumentException if <code>MIMEType</code> is
  833. * <code>null</code>.
  834. *
  835. * @see javax.imageio.spi.ImageWriterSpi#getMIMETypes
  836. */
  837. public static Iterator<ImageWriter>
  838. getImageWritersByMIMEType(String MIMEType)
  839. {
  840. if (MIMEType == null) {
  841. throw new IllegalArgumentException("MIMEType == null!");
  842. }
  843. Iterator iter;
  844. // Ensure category is present
  845. try {
  846. iter = theRegistry.getServiceProviders(ImageWriterSpi.class,
  847. new ContainsFilter(writerMIMETypesMethod,
  848. MIMEType),
  849. true);
  850. } catch (IllegalArgumentException e) {
  851. return new HashSet().iterator();
  852. }
  853. return new ImageWriterIterator(iter);
  854. }
  855. /**
  856. * Returns an <code>ImageWriter</code>corresponding to the given
  857. * <code>ImageReader</code>, if there is one, or <code>null</code>
  858. * if the plug-in for this <code>ImageReader</code> does not
  859. * specify a corresponding <code>ImageWriter</code>, or if the
  860. * given <code>ImageReader</code> is not registered. This
  861. * mechanism may be used to obtain an <code>ImageWriter</code>
  862. * that will understand the internal structure of non-pixel
  863. * metadata (as encoded by <code>IIOMetadata</code> objects)
  864. * generated by the <code>ImageReader</code>. By obtaining this
  865. * data from the <code>ImageReader</code> and passing it on to the
  866. * <code>ImageWriter</code> obtained with this method, a client
  867. * program can read an image, modify it in some way, and write it
  868. * back out preserving all metadata, without having to understand
  869. * anything about the structure of the metadata, or even about
  870. * the image format. Note that this method returns the
  871. * "preferred" writer, which is the first in the list returned by
  872. * <code>javax.imageio.spi.ImageReaderSpi.getImageWriterSpiNames()</code>.
  873. *
  874. * @param reader an instance of a registered <code>ImageReader</code>.
  875. *
  876. * @return an <code>ImageWriter</code>, or null.
  877. *
  878. * @exception IllegalArgumentException if <code>reader</code> is
  879. * <code>null</code>.
  880. *
  881. * @see #getImageReader(ImageWriter)
  882. * @see javax.imageio.spi.ImageReaderSpi#getImageWriterSpiNames()
  883. */
  884. public static ImageWriter getImageWriter(ImageReader reader) {
  885. if (reader == null) {
  886. throw new IllegalArgumentException("reader == null!");
  887. }
  888. ImageReaderSpi readerSpi = reader.getOriginatingProvider();
  889. if (readerSpi == null) {
  890. Iterator readerSpiIter;
  891. // Ensure category is present
  892. try {
  893. readerSpiIter =
  894. theRegistry.getServiceProviders(ImageReaderSpi.class,
  895. false);
  896. } catch (IllegalArgumentException e) {
  897. return null;
  898. }
  899. while (readerSpiIter.hasNext()) {
  900. ImageReaderSpi temp = (ImageReaderSpi) readerSpiIter.next();
  901. if (temp.isOwnReader(reader)) {
  902. readerSpi = temp;
  903. break;
  904. }
  905. }
  906. if (readerSpi == null) {
  907. return null;
  908. }
  909. }
  910. String[] writerNames = readerSpi.getImageWriterSpiNames();
  911. if (writerNames == null) {
  912. return null;
  913. }
  914. Class writerSpiClass = null;
  915. try {
  916. writerSpiClass = Class.forName(writerNames[0], true,
  917. ClassLoader.getSystemClassLoader());
  918. } catch (ClassNotFoundException e) {
  919. return null;
  920. }
  921. ImageWriterSpi writerSpi = (ImageWriterSpi)
  922. theRegistry.getServiceProviderByClass(writerSpiClass);
  923. if (writerSpi == null) {
  924. return null;
  925. }
  926. try {
  927. return writerSpi.createWriterInstance();
  928. } catch (IOException e) {
  929. // Deregister the spi in this case, but only as a writerSpi
  930. theRegistry.deregisterServiceProvider(writerSpi,
  931. ImageWriterSpi.class);
  932. return null;
  933. }
  934. }
  935. /**
  936. * Returns an <code>ImageReader</code>corresponding to the given
  937. * <code>ImageWriter</code>, if there is one, or <code>null</code>
  938. * if the plug-in for this <code>ImageWriter</code> does not
  939. * specify a corresponding <code>ImageReader</code>, or if the
  940. * given <code>ImageWriter</code> is not registered. This method
  941. * is provided principally for symmetry with
  942. * <code>getImageWriter(ImageReader)</code>. Note that this
  943. * method returns the "preferred" reader, which is the first in
  944. * the list returned by
  945. * javax.imageio.spi.ImageWriterSpi.<code>getImageReaderSpiNames()</code>.
  946. *
  947. * @param writer an instance of a registered <code>ImageWriter</code>.
  948. *
  949. * @return an <code>ImageReader</code>, or null.
  950. *
  951. * @exception IllegalArgumentException if <code>writer</code> is
  952. * <code>null</code>.
  953. *
  954. * @see #getImageWriter(ImageReader)
  955. * @see javax.imageio.spi.ImageWriterSpi#getImageReaderSpiNames()
  956. */
  957. public static ImageReader getImageReader(ImageWriter writer) {
  958. if (writer == null) {
  959. throw new IllegalArgumentException("writer == null!");
  960. }
  961. ImageWriterSpi writerSpi = writer.getOriginatingProvider();
  962. if (writerSpi == null) {
  963. Iterator writerSpiIter;
  964. // Ensure category is present
  965. try {
  966. writerSpiIter =
  967. theRegistry.getServiceProviders(ImageWriterSpi.class,
  968. false);
  969. } catch (IllegalArgumentException e) {
  970. return null;
  971. }
  972. while (writerSpiIter.hasNext()) {
  973. ImageWriterSpi temp = (ImageWriterSpi) writerSpiIter.next();
  974. if (temp.isOwnWriter(writer)) {
  975. writerSpi = temp;
  976. break;
  977. }
  978. }
  979. if (writerSpi == null) {
  980. return null;
  981. }
  982. }
  983. String[] readerNames = writerSpi.getImageReaderSpiNames();
  984. if (readerNames == null) {
  985. return null;
  986. }
  987. Class readerSpiClass = null;
  988. try {
  989. readerSpiClass = Class.forName(readerNames[0], true,
  990. ClassLoader.getSystemClassLoader());
  991. } catch (ClassNotFoundException e) {
  992. return null;
  993. }
  994. ImageReaderSpi readerSpi = (ImageReaderSpi)
  995. theRegistry.getServiceProviderByClass(readerSpiClass);
  996. if (readerSpi == null) {
  997. return null;
  998. }
  999. try {
  1000. return readerSpi.createReaderInstance();
  1001. } catch (IOException e) {
  1002. // Deregister the spi in this case, but only as a readerSpi
  1003. theRegistry.deregisterServiceProvider(readerSpi,
  1004. ImageReaderSpi.class);
  1005. return null;
  1006. }
  1007. }
  1008. /**
  1009. * Returns an <code>Iterator</code> containing all currently
  1010. * registered <code>ImageWriter</code>s that claim to be able to
  1011. * encode images of the given layout (specified using an
  1012. * <code>ImageTypeSpecifier</code>) in the given format.
  1013. *
  1014. * @param type an <code>ImageTypeSpecifier</code> indicating the
  1015. * layout of the image to be written.
  1016. * @param formatName the informal name of the <code>format</code>.
  1017. *
  1018. * @return an <code>Iterator</code> containing <code>ImageWriter</code>s.
  1019. *
  1020. * @exception IllegalArgumentException if any parameter is
  1021. * <code>null</code>.
  1022. *
  1023. * @see javax.imageio.spi.ImageWriterSpi#canEncodeImage(ImageTypeSpecifier)
  1024. */
  1025. public static Iterator<ImageWriter>
  1026. getImageWriters(ImageTypeSpecifier type, String formatName)
  1027. {
  1028. if (type == null) {
  1029. throw new IllegalArgumentException("type == null!");
  1030. }
  1031. if (formatName == null) {
  1032. throw new IllegalArgumentException("formatName == null!");
  1033. }
  1034. Iterator iter;
  1035. // Ensure category is present
  1036. try {
  1037. iter = theRegistry.getServiceProviders(ImageWriterSpi.class,
  1038. new CanEncodeImageAndFormatFilter(type,
  1039. formatName),
  1040. true);
  1041. } catch (IllegalArgumentException e) {
  1042. return new HashSet().iterator();
  1043. }
  1044. return new ImageWriterIterator(iter);
  1045. }
  1046. static class ImageTranscoderIterator
  1047. implements Iterator<ImageTranscoder>
  1048. {
  1049. // Contains ImageTranscoderSpis
  1050. public Iterator iter;
  1051. public ImageTranscoderIterator(Iterator iter) {
  1052. this.iter = iter;
  1053. }
  1054. public boolean hasNext() {
  1055. return iter.hasNext();
  1056. }
  1057. public ImageTranscoder next() {
  1058. ImageTranscoderSpi spi = null;
  1059. spi = (ImageTranscoderSpi)iter.next();
  1060. return spi.createTranscoderInstance();
  1061. }
  1062. public void remove() {
  1063. throw new UnsupportedOperationException();
  1064. }
  1065. }
  1066. static class TranscoderFilter
  1067. implements ServiceRegistry.Filter {
  1068. String readerSpiName;
  1069. String writerSpiName;
  1070. public TranscoderFilter(ImageReaderSpi readerSpi,
  1071. ImageWriterSpi writerSpi) {
  1072. this.readerSpiName = readerSpi.getClass().getName();
  1073. this.writerSpiName = writerSpi.getClass().getName();
  1074. }
  1075. public boolean filter(Object elt) {
  1076. ImageTranscoderSpi spi = (ImageTranscoderSpi)elt;
  1077. String readerName = spi.getReaderServiceProviderName();
  1078. String writerName = spi.getWriterServiceProviderName();
  1079. return (readerName.equals(readerSpiName) &&
  1080. writerName.equals(writerSpiName));
  1081. }
  1082. }
  1083. /**
  1084. * Returns an <code>Iterator</code> containing all currently
  1085. * registered <code>ImageTranscoder</code>s that claim to be
  1086. * able to transcode between the metadata of the given
  1087. * <code>ImageReader</code> and <code>ImageWriter</code>.
  1088. *
  1089. * @param reader an <code>ImageReader</code>.
  1090. * @param writer an <code>ImageWriter</code>.
  1091. *
  1092. * @return an <code>Iterator</code> containing
  1093. * <code>ImageTranscoder</code>s.
  1094. *
  1095. * @exception IllegalArgumentException if <code>reader</code> or
  1096. * <code>writer</code> is <code>null</code>.
  1097. */
  1098. public static Iterator<ImageTranscoder>
  1099. getImageTranscoders(ImageReader reader, ImageWriter writer)
  1100. {
  1101. if (reader == null) {
  1102. throw new IllegalArgumentException("reader == null!");
  1103. }
  1104. if (writer == null) {
  1105. throw new IllegalArgumentException("writer == null!");
  1106. }
  1107. ImageReaderSpi readerSpi = reader.getOriginatingProvider();
  1108. ImageWriterSpi writerSpi = writer.getOriginatingProvider();
  1109. ServiceRegistry.Filter filter =
  1110. new TranscoderFilter(readerSpi, writerSpi);
  1111. Iterator iter;
  1112. // Ensure category is present
  1113. try {
  1114. iter = theRegistry.getServiceProviders(ImageTranscoderSpi.class,
  1115. filter, true);
  1116. } catch (IllegalArgumentException e) {
  1117. return new HashSet().iterator();
  1118. }
  1119. return new ImageTranscoderIterator(iter);
  1120. }
  1121. // All-in-one methods
  1122. /**
  1123. * Returns a <code>BufferedImage</code> as the result of decoding
  1124. * a supplied <code>File</code> with an <code>ImageReader</code>
  1125. * chosen automatically from among those currently registered.
  1126. * The <code>File</code> is wrapped in an
  1127. * <code>ImageInputStream</code>. If no registered
  1128. * <code>ImageReader</code> claims to be able to read the
  1129. * resulting stream, <code>null</code> is returned.
  1130. *
  1131. * <p> The current cache settings from <code>getUseCache</code>and
  1132. * <code>getCacheDirectory</code> will be used to control caching in the
  1133. * <code>ImageInputStream</code> that is created.
  1134. *
  1135. * <p> Note that there is no <code>read</code> method that takes a
  1136. * filename as a <code>String</code> use this method instead after
  1137. * creating a <code>File</code> from the filename.
  1138. *
  1139. * <p> This methods does not attempt to locate
  1140. * <code>ImageReader</code>s that can read directly from a
  1141. * <code>File</code> that may be accomplished using
  1142. * <code>IIORegistry</code> and <code>ImageReaderSpi</code>.
  1143. *
  1144. * @param input a <code>File</code> to read from.
  1145. *
  1146. * @return a <code>BufferedImage</code> containing the decoded
  1147. * contents of the input, or <code>null</code>.
  1148. *
  1149. * @exception IllegalArgumentException if <code>input</code> is
  1150. * <code>null</code>.
  1151. * @exception IOException if an error occurs during reading.
  1152. */
  1153. public static BufferedImage read(File input) throws IOException {
  1154. if (input == null) {
  1155. throw new IllegalArgumentException("input == null!");
  1156. }
  1157. if (!input.canRead()) {
  1158. throw new IIOException("Can't read input file!");
  1159. }
  1160. ImageInputStream stream = createImageInputStream(input);
  1161. if (stream == null) {
  1162. throw new IIOException("Can't create an ImageInputStream!");
  1163. }
  1164. return read(stream);
  1165. }
  1166. /**
  1167. * Returns a <code>BufferedImage</code> as the result of decoding
  1168. * a supplied <code>InputStream</code> with an <code>ImageReader</code>
  1169. * chosen automatically from among those currently registered.
  1170. * The <code>InputStream</code> is wrapped in an
  1171. * <code>ImageInputStream</code>. If no registered
  1172. * <code>ImageReader</code> claims to be able to read the
  1173. * resulting stream, <code>null</code> is returned.
  1174. *
  1175. * <p> The current cache settings from <code>getUseCache</code>and
  1176. * <code>getCacheDirectory</code> will be used to control caching in the
  1177. * <code>ImageInputStream</code> that is created.
  1178. *
  1179. * <p> This methods does not attempt to locate
  1180. * <code>ImageReader</code>s that can read directly from an
  1181. * <code>InputStream</code> that may be accomplished using
  1182. * <code>IIORegistry</code> and <code>ImageReaderSpi</code>.
  1183. *
  1184. * @param input an <code>InputStream</code> to read from.
  1185. *
  1186. * @return a <code>BufferedImage</code> containing the decoded
  1187. * contents of the input, or <code>null</code>.
  1188. *
  1189. * @exception IllegalArgumentException if <code>input</code> is
  1190. * <code>null</code>.
  1191. * @exception IOException if an error occurs during reading.
  1192. */
  1193. public static BufferedImage read(InputStream input) throws IOException {
  1194. if (input == null) {
  1195. throw new IllegalArgumentException("input == null!");
  1196. }
  1197. ImageInputStream stream = createImageInputStream(input);
  1198. return read(stream);
  1199. }
  1200. /**
  1201. * Returns a <code>BufferedImage</code> as the result of decoding
  1202. * a supplied <code>URL</code> with an <code>ImageReader</code>
  1203. * chosen automatically from among those currently registered. An
  1204. * <code>InputStream</code> is obtained from the <code>URL</code>,
  1205. * which is wrapped in an <code>ImageInputStream</code>. If no
  1206. * registered <code>ImageReader</code> claims to be able to read
  1207. * the resulting stream, <code>null</code> is returned.
  1208. *
  1209. * <p> The current cache settings from <code>getUseCache</code>and
  1210. * <code>getCacheDirectory</code> will be used to control caching in the
  1211. * <code>ImageInputStream</code> that is created.
  1212. *
  1213. * <p> This methods does not attempt to locate
  1214. * <code>ImageReader</code>s that can read directly from a
  1215. * <code>URL</code> that may be accomplished using
  1216. * <code>IIORegistry</code> and <code>ImageReaderSpi</code>.
  1217. *
  1218. * @param input a <code>URL</code> to read from.
  1219. *
  1220. * @return a <code>BufferedImage</code> containing the decoded
  1221. * contents of the input, or <code>null</code>.
  1222. *
  1223. * @exception IllegalArgumentException if <code>input</code> is
  1224. * <code>null</code>.
  1225. * @exception IOException if an error occurs during reading.
  1226. */
  1227. public static BufferedImage read(URL input) throws IOException {
  1228. if (input == null) {
  1229. throw new IllegalArgumentException("input == null!");
  1230. }
  1231. InputStream istream = null;
  1232. try {
  1233. istream = input.openStream();
  1234. } catch (IOException e) {
  1235. throw new IIOException("Can't get input stream from URL!", e);
  1236. }
  1237. ImageInputStream stream = createImageInputStream(istream);
  1238. BufferedImage bi = read(stream);
  1239. istream.close();
  1240. return bi;
  1241. }
  1242. /**
  1243. * Returns a <code>BufferedImage</code> as the result of decoding
  1244. * a supplied <code>ImageInputStream</code> with an
  1245. * <code>ImageReader</code> chosen automatically from among those
  1246. * currently registered. If no registered
  1247. * <code>ImageReader</code> claims to be able to read the stream,
  1248. * <code>null</code> is returned.
  1249. *
  1250. * @param stream an <code>ImageInputStream</code> to read from.
  1251. *
  1252. * @return a <code>BufferedImage</code> containing the decoded
  1253. * contents of the input, or <code>null</code>.
  1254. *
  1255. * @exception IllegalArgumentException if <code>stream</code> is
  1256. * <code>null</code>.
  1257. * @exception IOException if an error occurs during reading.
  1258. */
  1259. public static BufferedImage read(ImageInputStream stream)
  1260. throws IOException {
  1261. if (stream == null) {
  1262. throw new IllegalArgumentException("stream == null!");
  1263. }
  1264. Iterator iter = getImageReaders(stream);
  1265. if (!iter.hasNext()) {
  1266. return null;
  1267. }
  1268. ImageReader reader = (ImageReader)iter.next();
  1269. ImageReadParam param = reader.getDefaultReadParam();
  1270. reader.setInput(stream, true, true);
  1271. BufferedImage bi = reader.read(0, param);
  1272. stream.close();
  1273. reader.dispose();
  1274. return bi;
  1275. }
  1276. /**
  1277. * Writes an image using the an arbitrary <code>ImageWriter</code>
  1278. * that supports the given format to an
  1279. * <code>ImageOutputStream</code>. The image is written to the
  1280. * <code>ImageOutputStream</code> starting at the current stream
  1281. * pointer, overwriting existing stream data from that point
  1282. * forward, if present.
  1283. *
  1284. * @param im a <code>RenderedImage</code> to be written.
  1285. * @param formatName a <code>String</code> containg the informal
  1286. * name of the format.
  1287. * @param output an <code>ImageOutputStream</code> to be written to.
  1288. *
  1289. * @return <code>false</code> if no appropriate writer is found.
  1290. *
  1291. * @exception IllegalArgumentException if any parameter is
  1292. * <code>null</code>.
  1293. * @exception IOException if an error occurs during writing.
  1294. */
  1295. public static boolean write(RenderedImage im,
  1296. String formatName,
  1297. ImageOutputStream output) throws IOException {
  1298. if (im == null) {
  1299. throw new IllegalArgumentException("im == null!");
  1300. }
  1301. if (formatName == null) {
  1302. throw new IllegalArgumentException("formatName == null!");
  1303. }
  1304. if (output == null) {
  1305. throw new IllegalArgumentException("output == null!");
  1306. }
  1307. ImageWriter writer = null;
  1308. ImageTypeSpecifier type =
  1309. ImageTypeSpecifier.createFromRenderedImage(im);
  1310. Iterator iter = getImageWriters(type, formatName);
  1311. if (iter.hasNext()) {
  1312. writer = (ImageWriter)iter.next();
  1313. }
  1314. if (writer == null) {
  1315. return false;
  1316. }
  1317. writer.setOutput(output);
  1318. writer.write(im);
  1319. output.flush();
  1320. writer.dispose();
  1321. return true;
  1322. }
  1323. /**
  1324. * Writes an image using an arbitrary <code>ImageWriter</code>
  1325. * that supports the given format to a <code>File</code>. If
  1326. * there is already a <code>File</code> present, its contents are
  1327. * discarded.
  1328. *
  1329. * @param im a <code>RenderedImage</code> to be written.
  1330. * @param formatName a <code>String</code> containg the informal
  1331. * name of the format.
  1332. * @param output a <code>File</code> to be written to.
  1333. *
  1334. * @return <code>false</code> if no appropriate writer is found.
  1335. *
  1336. * @exception IllegalArgumentException if any parameter is
  1337. * <code>null</code>.
  1338. * @exception IOException if an error occurs during writing.
  1339. */
  1340. public static boolean write(RenderedImage im,
  1341. String formatName,
  1342. File output) throws IOException {
  1343. if (output == null) {
  1344. throw new IllegalArgumentException("output == null!");
  1345. }
  1346. ImageOutputStream stream = null;
  1347. try {
  1348. output.delete();
  1349. stream = createImageOutputStream(output);
  1350. } catch (IOException e) {
  1351. throw new IIOException("Can't create output stream!", e);
  1352. }
  1353. boolean val = write(im, formatName, stream);
  1354. stream.close();
  1355. return val;
  1356. }
  1357. /**
  1358. * Writes an image using an arbitrary <code>ImageWriter</code>
  1359. * that supports the given format to an <code>OutputStream</code>.
  1360. *
  1361. * <p> The current cache settings from <code>getUseCache</code>and
  1362. * <code>getCacheDirectory</code> will be used to control caching.
  1363. *
  1364. * @param im a <code>RenderedImage</code> to be written.
  1365. * @param formatName a <code>String</code> containg the informal
  1366. * name of the format.
  1367. * @param output an <code>OutputStream</code> to be written to.
  1368. *
  1369. * @return <code>false</code> if no appropriate writer is found.
  1370. *
  1371. * @exception IllegalArgumentException if any parameter is
  1372. * <code>null</code>.
  1373. * @exception IOException if an error occurs during writing.
  1374. */
  1375. public static boolean write(RenderedImage im,
  1376. String formatName,
  1377. OutputStream output) throws IOException {
  1378. if (output == null) {
  1379. throw new IllegalArgumentException("output == null!");
  1380. }
  1381. ImageOutputStream stream = null;
  1382. try {
  1383. stream = createImageOutputStream(output);
  1384. } catch (IOException e) {
  1385. throw new IIOException("Can't create output stream!", e);
  1386. }
  1387. boolean val = write(im, formatName, stream);
  1388. stream.close();
  1389. return val;
  1390. }
  1391. }