Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/imageio/ImageIO.java
38829 views
1
/*
2
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package javax.imageio;
27
28
import java.awt.image.BufferedImage;
29
import java.awt.image.RenderedImage;
30
import java.io.File;
31
import java.io.FilePermission;
32
import java.io.InputStream;
33
import java.io.IOException;
34
import java.io.OutputStream;
35
import java.lang.reflect.Method;
36
import java.net.URL;
37
import java.security.AccessController;
38
import java.util.Arrays;
39
import java.util.Collections;
40
import java.util.HashSet;
41
import java.util.Iterator;
42
import java.util.NoSuchElementException;
43
import java.util.Set;
44
import javax.imageio.spi.IIORegistry;
45
import javax.imageio.spi.ImageReaderSpi;
46
import javax.imageio.spi.ImageReaderWriterSpi;
47
import javax.imageio.spi.ImageWriterSpi;
48
import javax.imageio.spi.ImageInputStreamSpi;
49
import javax.imageio.spi.ImageOutputStreamSpi;
50
import javax.imageio.spi.ImageTranscoderSpi;
51
import javax.imageio.spi.ServiceRegistry;
52
import javax.imageio.stream.ImageInputStream;
53
import javax.imageio.stream.ImageOutputStream;
54
import sun.awt.AppContext;
55
import sun.security.action.GetPropertyAction;
56
57
/**
58
* A class containing static convenience methods for locating
59
* <code>ImageReader</code>s and <code>ImageWriter</code>s, and
60
* performing simple encoding and decoding.
61
*
62
*/
63
public final class ImageIO {
64
65
private static final IIORegistry theRegistry =
66
IIORegistry.getDefaultInstance();
67
68
/**
69
* Constructor is private to prevent instantiation.
70
*/
71
private ImageIO() {}
72
73
/**
74
* Scans for plug-ins on the application class path,
75
* loads their service provider classes, and registers a service
76
* provider instance for each one found with the
77
* <code>IIORegistry</code>.
78
*
79
* <p>This method is needed because the application class path can
80
* theoretically change, or additional plug-ins may become available.
81
* Rather than re-scanning the classpath on every invocation of the
82
* API, the class path is scanned automatically only on the first
83
* invocation. Clients can call this method to prompt a re-scan.
84
* Thus this method need only be invoked by sophisticated applications
85
* which dynamically make new plug-ins available at runtime.
86
*
87
* <p> The <code>getResources</code> method of the context
88
* <code>ClassLoader</code> is used locate JAR files containing
89
* files named
90
* <code>META-INF/services/javax.imageio.spi.</code><i>classname</i>,
91
* where <i>classname</i> is one of <code>ImageReaderSpi</code>,
92
* <code>ImageWriterSpi</code>, <code>ImageTranscoderSpi</code>,
93
* <code>ImageInputStreamSpi</code>, or
94
* <code>ImageOutputStreamSpi</code>, along the application class
95
* path.
96
*
97
* <p> The contents of the located files indicate the names of
98
* actual implementation classes which implement the
99
* aforementioned service provider interfaces; the default class
100
* loader is then used to load each of these classes and to
101
* instantiate an instance of each class, which is then placed
102
* into the registry for later retrieval.
103
*
104
* <p> The exact set of locations searched depends on the
105
* implementation of the Java runtime environment.
106
*
107
* @see ClassLoader#getResources
108
*/
109
public static void scanForPlugins() {
110
theRegistry.registerApplicationClasspathSpis();
111
}
112
113
// ImageInputStreams
114
115
/**
116
* A class to hold information about caching. Each
117
* <code>ThreadGroup</code> will have its own copy
118
* via the <code>AppContext</code> mechanism.
119
*/
120
static class CacheInfo {
121
boolean useCache = true;
122
File cacheDirectory = null;
123
Boolean hasPermission = null;
124
125
public CacheInfo() {}
126
127
public boolean getUseCache() {
128
return useCache;
129
}
130
131
public void setUseCache(boolean useCache) {
132
this.useCache = useCache;
133
}
134
135
public File getCacheDirectory() {
136
return cacheDirectory;
137
}
138
139
public void setCacheDirectory(File cacheDirectory) {
140
this.cacheDirectory = cacheDirectory;
141
}
142
143
public Boolean getHasPermission() {
144
return hasPermission;
145
}
146
147
public void setHasPermission(Boolean hasPermission) {
148
this.hasPermission = hasPermission;
149
}
150
}
151
152
/**
153
* Returns the <code>CacheInfo</code> object associated with this
154
* <code>ThreadGroup</code>.
155
*/
156
private static synchronized CacheInfo getCacheInfo() {
157
AppContext context = AppContext.getAppContext();
158
CacheInfo info = (CacheInfo)context.get(CacheInfo.class);
159
if (info == null) {
160
info = new CacheInfo();
161
context.put(CacheInfo.class, info);
162
}
163
return info;
164
}
165
166
/**
167
* Returns the default temporary (cache) directory as defined by the
168
* java.io.tmpdir system property.
169
*/
170
private static String getTempDir() {
171
GetPropertyAction a = new GetPropertyAction("java.io.tmpdir");
172
return (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 or when not
1295
* able to create required ImageInputStream.
1296
*/
1297
public static BufferedImage read(File input) throws IOException {
1298
if (input == null) {
1299
throw new IllegalArgumentException("input == null!");
1300
}
1301
if (!input.canRead()) {
1302
throw new IIOException("Can't read input file!");
1303
}
1304
1305
ImageInputStream stream = createImageInputStream(input);
1306
if (stream == null) {
1307
throw new IIOException("Can't create an ImageInputStream!");
1308
}
1309
BufferedImage bi = read(stream);
1310
if (bi == null) {
1311
stream.close();
1312
}
1313
return bi;
1314
}
1315
1316
/**
1317
* Returns a <code>BufferedImage</code> as the result of decoding
1318
* a supplied <code>InputStream</code> with an <code>ImageReader</code>
1319
* chosen automatically from among those currently registered.
1320
* The <code>InputStream</code> is wrapped in an
1321
* <code>ImageInputStream</code>. If no registered
1322
* <code>ImageReader</code> claims to be able to read the
1323
* resulting stream, <code>null</code> is returned.
1324
*
1325
* <p> The current cache settings from <code>getUseCache</code>and
1326
* <code>getCacheDirectory</code> will be used to control caching in the
1327
* <code>ImageInputStream</code> that is created.
1328
*
1329
* <p> This method does not attempt to locate
1330
* <code>ImageReader</code>s that can read directly from an
1331
* <code>InputStream</code>; that may be accomplished using
1332
* <code>IIORegistry</code> and <code>ImageReaderSpi</code>.
1333
*
1334
* <p> This method <em>does not</em> close the provided
1335
* <code>InputStream</code> after the read operation has completed;
1336
* it is the responsibility of the caller to close the stream, if desired.
1337
*
1338
* @param input an <code>InputStream</code> to read from.
1339
*
1340
* @return a <code>BufferedImage</code> containing the decoded
1341
* contents of the input, or <code>null</code>.
1342
*
1343
* @exception IllegalArgumentException if <code>input</code> is
1344
* <code>null</code>.
1345
* @exception IOException if an error occurs during reading or when not
1346
* able to create required ImageInputStream.
1347
*/
1348
public static BufferedImage read(InputStream input) throws IOException {
1349
if (input == null) {
1350
throw new IllegalArgumentException("input == null!");
1351
}
1352
1353
ImageInputStream stream = createImageInputStream(input);
1354
if (stream == null) {
1355
throw new IIOException("Can't create an ImageInputStream!");
1356
}
1357
BufferedImage bi = read(stream);
1358
if (bi == null) {
1359
stream.close();
1360
}
1361
return bi;
1362
}
1363
1364
/**
1365
* Returns a <code>BufferedImage</code> as the result of decoding
1366
* a supplied <code>URL</code> with an <code>ImageReader</code>
1367
* chosen automatically from among those currently registered. An
1368
* <code>InputStream</code> is obtained from the <code>URL</code>,
1369
* which is wrapped in an <code>ImageInputStream</code>. If no
1370
* registered <code>ImageReader</code> claims to be able to read
1371
* the resulting stream, <code>null</code> is returned.
1372
*
1373
* <p> The current cache settings from <code>getUseCache</code>and
1374
* <code>getCacheDirectory</code> will be used to control caching in the
1375
* <code>ImageInputStream</code> that is created.
1376
*
1377
* <p> This method does not attempt to locate
1378
* <code>ImageReader</code>s that can read directly from a
1379
* <code>URL</code>; that may be accomplished using
1380
* <code>IIORegistry</code> and <code>ImageReaderSpi</code>.
1381
*
1382
* @param input a <code>URL</code> to read from.
1383
*
1384
* @return a <code>BufferedImage</code> containing the decoded
1385
* contents of the input, or <code>null</code>.
1386
*
1387
* @exception IllegalArgumentException if <code>input</code> is
1388
* <code>null</code>.
1389
* @exception IOException if an error occurs during reading or when not
1390
* able to create required ImageInputStream.
1391
*/
1392
public static BufferedImage read(URL input) throws IOException {
1393
if (input == null) {
1394
throw new IllegalArgumentException("input == null!");
1395
}
1396
1397
InputStream istream = null;
1398
try {
1399
istream = input.openStream();
1400
} catch (IOException e) {
1401
throw new IIOException("Can't get input stream from URL!", e);
1402
}
1403
ImageInputStream stream = createImageInputStream(istream);
1404
if (stream == null) {
1405
/* close the istream when stream is null so that if user has
1406
* given filepath as URL he can delete it, otherwise stream will
1407
* be open to that file and he will not be able to delete it.
1408
*/
1409
istream.close();
1410
throw new IIOException("Can't create an ImageInputStream!");
1411
}
1412
BufferedImage bi;
1413
try {
1414
bi = read(stream);
1415
if (bi == null) {
1416
stream.close();
1417
}
1418
} finally {
1419
istream.close();
1420
}
1421
return bi;
1422
}
1423
1424
/**
1425
* Returns a <code>BufferedImage</code> as the result of decoding
1426
* a supplied <code>ImageInputStream</code> with an
1427
* <code>ImageReader</code> chosen automatically from among those
1428
* currently registered. If no registered
1429
* <code>ImageReader</code> claims to be able to read the stream,
1430
* <code>null</code> is returned.
1431
*
1432
* <p> Unlike most other methods in this class, this method <em>does</em>
1433
* close the provided <code>ImageInputStream</code> after the read
1434
* operation has completed, unless <code>null</code> is returned,
1435
* in which case this method <em>does not</em> close the stream.
1436
*
1437
* @param stream an <code>ImageInputStream</code> to read from.
1438
*
1439
* @return a <code>BufferedImage</code> containing the decoded
1440
* contents of the input, or <code>null</code>.
1441
*
1442
* @exception IllegalArgumentException if <code>stream</code> is
1443
* <code>null</code>.
1444
* @exception IOException if an error occurs during reading.
1445
*/
1446
public static BufferedImage read(ImageInputStream stream)
1447
throws IOException {
1448
if (stream == null) {
1449
throw new IllegalArgumentException("stream == null!");
1450
}
1451
1452
Iterator iter = getImageReaders(stream);
1453
if (!iter.hasNext()) {
1454
return null;
1455
}
1456
1457
ImageReader reader = (ImageReader)iter.next();
1458
ImageReadParam param = reader.getDefaultReadParam();
1459
reader.setInput(stream, true, true);
1460
BufferedImage bi;
1461
try {
1462
bi = reader.read(0, param);
1463
} finally {
1464
reader.dispose();
1465
stream.close();
1466
}
1467
return bi;
1468
}
1469
1470
/**
1471
* Writes an image using the an arbitrary <code>ImageWriter</code>
1472
* that supports the given format to an
1473
* <code>ImageOutputStream</code>. The image is written to the
1474
* <code>ImageOutputStream</code> starting at the current stream
1475
* pointer, overwriting existing stream data from that point
1476
* forward, if present.
1477
*
1478
* <p> This method <em>does not</em> close the provided
1479
* <code>ImageOutputStream</code> after the write operation has completed;
1480
* it is the responsibility of the caller to close the stream, if desired.
1481
*
1482
* @param im a <code>RenderedImage</code> to be written.
1483
* @param formatName a <code>String</code> containing the informal
1484
* name of the format.
1485
* @param output an <code>ImageOutputStream</code> to be written to.
1486
*
1487
* @return <code>false</code> if no appropriate writer is found.
1488
*
1489
* @exception IllegalArgumentException if any parameter is
1490
* <code>null</code>.
1491
* @exception IOException if an error occurs during writing.
1492
*/
1493
public static boolean write(RenderedImage im,
1494
String formatName,
1495
ImageOutputStream output) throws IOException {
1496
if (im == null) {
1497
throw new IllegalArgumentException("im == null!");
1498
}
1499
if (formatName == null) {
1500
throw new IllegalArgumentException("formatName == null!");
1501
}
1502
if (output == null) {
1503
throw new IllegalArgumentException("output == null!");
1504
}
1505
1506
return doWrite(im, getWriter(im, formatName), output);
1507
}
1508
1509
/**
1510
* Writes an image using an arbitrary <code>ImageWriter</code>
1511
* that supports the given format to a <code>File</code>. If
1512
* there is already a <code>File</code> present, its contents are
1513
* discarded.
1514
*
1515
* @param im a <code>RenderedImage</code> to be written.
1516
* @param formatName a <code>String</code> containing the informal
1517
* name of the format.
1518
* @param output a <code>File</code> to be written to.
1519
*
1520
* @return <code>false</code> if no appropriate writer is found.
1521
*
1522
* @exception IllegalArgumentException if any parameter is
1523
* <code>null</code>.
1524
* @exception IOException if an error occurs during writing or when not
1525
* able to create required ImageOutputStream.
1526
*/
1527
public static boolean write(RenderedImage im,
1528
String formatName,
1529
File output) throws IOException {
1530
if (output == null) {
1531
throw new IllegalArgumentException("output == null!");
1532
}
1533
1534
ImageWriter writer = getWriter(im, formatName);
1535
if (writer == null) {
1536
/* Do not make changes in the file system if we have
1537
* no appropriate writer.
1538
*/
1539
return false;
1540
}
1541
1542
output.delete();
1543
ImageOutputStream stream = createImageOutputStream(output);
1544
if (stream == null) {
1545
throw new IIOException("Can't create an ImageOutputStream!");
1546
}
1547
try {
1548
return doWrite(im, writer, stream);
1549
} finally {
1550
stream.close();
1551
}
1552
}
1553
1554
/**
1555
* Writes an image using an arbitrary <code>ImageWriter</code>
1556
* that supports the given format to an <code>OutputStream</code>.
1557
*
1558
* <p> This method <em>does not</em> close the provided
1559
* <code>OutputStream</code> after the write operation has completed;
1560
* it is the responsibility of the caller to close the stream, if desired.
1561
*
1562
* <p> The current cache settings from <code>getUseCache</code>and
1563
* <code>getCacheDirectory</code> will be used to control caching.
1564
*
1565
* @param im a <code>RenderedImage</code> to be written.
1566
* @param formatName a <code>String</code> containing the informal
1567
* name of the format.
1568
* @param output an <code>OutputStream</code> to be written to.
1569
*
1570
* @return <code>false</code> if no appropriate writer is found.
1571
*
1572
* @exception IllegalArgumentException if any parameter is
1573
* <code>null</code>.
1574
* @exception IOException if an error occurs during writing or when not
1575
* able to create required ImageOutputStream.
1576
*/
1577
public static boolean write(RenderedImage im,
1578
String formatName,
1579
OutputStream output) throws IOException {
1580
if (output == null) {
1581
throw new IllegalArgumentException("output == null!");
1582
}
1583
ImageOutputStream stream = createImageOutputStream(output);
1584
if (stream == null) {
1585
throw new IIOException("Can't create an ImageOutputStream!");
1586
}
1587
try {
1588
return doWrite(im, getWriter(im, formatName), stream);
1589
} finally {
1590
stream.close();
1591
}
1592
}
1593
1594
/**
1595
* Returns <code>ImageWriter</code> instance according to given
1596
* rendered image and image format or <code>null</code> if there
1597
* is no appropriate writer.
1598
*/
1599
private static ImageWriter getWriter(RenderedImage im,
1600
String formatName) {
1601
ImageTypeSpecifier type =
1602
ImageTypeSpecifier.createFromRenderedImage(im);
1603
Iterator<ImageWriter> iter = getImageWriters(type, formatName);
1604
1605
if (iter.hasNext()) {
1606
return iter.next();
1607
} else {
1608
return null;
1609
}
1610
}
1611
1612
/**
1613
* Writes image to output stream using given image writer.
1614
*/
1615
private static boolean doWrite(RenderedImage im, ImageWriter writer,
1616
ImageOutputStream output) throws IOException {
1617
if (writer == null) {
1618
return false;
1619
}
1620
writer.setOutput(output);
1621
try {
1622
writer.write(im);
1623
} finally {
1624
writer.dispose();
1625
output.flush();
1626
}
1627
return true;
1628
}
1629
}
1630
1631