History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/imageio/ImageIO.java (1 of 18352 files). Show all

Unified · Split

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