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