1 /*
2  * Copyright (c) 1999, 2014, 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.Dimension;
29 import java.awt.Rectangle;
30 import java.awt.image.BufferedImage;
31 import java.awt.image.RenderedImage;
32 import java.awt.image.Raster;
33 import java.io.IOException;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Locale;
37 import java.util.MissingResourceException;
38 import java.util.ResourceBundle;
39 import javax.imageio.event.IIOWriteWarningListener;
40 import javax.imageio.event.IIOWriteProgressListener;
41 import javax.imageio.metadata.IIOMetadata;
42 import javax.imageio.stream.ImageOutputStream;
43 import javax.imageio.spi.ImageWriterSpi;
44 
45 /**
46  * An abstract superclass for encoding and writing images.  This class
47  * must be subclassed by classes that write out images in the context
48  * of the Java Image I/O framework.
49  *
50  * <p> {@code ImageWriter} objects are normally instantiated by
51  * the service provider class for the specific format.  Service
52  * provider classes are registered with the {@code IIORegistry},
53  * which uses them for format recognition and presentation of
54  * available format readers and writers.
55  *
56  * @see ImageReader
57  * @see ImageWriteParam
58  * @see javax.imageio.spi.IIORegistry
59  * @see javax.imageio.spi.ImageWriterSpi
60  *
61  */
62 public abstract class ImageWriter implements ImageTranscoder {
63 
64     /**
65      * The {@code ImageWriterSpi} that instantiated this object,
66      * or {@code null} if its identity is not known or none
67      * exists.  By default it is initialized to {@code null}.
68      */
69     protected ImageWriterSpi originatingProvider = null;
70 
71     /**
72      * The {@code ImageOutputStream} or other {@code Object}
73      * set by {@code setOutput} and retrieved by
74      * {@code getOutput}.  By default it is initialized to
75      * {@code null}.
76      */
77     protected Object output = null;
78 
79     /**
80      * An array of {@code Locale}s that may be used to localize
81      * warning messages and compression setting values, or
82      * {@code null} if localization is not supported.  By default
83      * it is initialized to {@code null}.
84      */
85     protected Locale[] availableLocales = null;
86 
87     /**
88      * The current {@code Locale} to be used for localization, or
89      * {@code null} if none has been set.  By default it is
90      * initialized to {@code null}.
91      */
92     protected Locale locale = null;
93 
94     /**
95      * A {@code List} of currently registered
96      * {@code IIOWriteWarningListener}s, initialized by default to
97      * {@code null}, which is synonymous with an empty
98      * {@code List}.
99      */
100     protected List<IIOWriteWarningListener> warningListeners = null;
101 
102     /**
103      * A {@code List} of {@code Locale}s, one for each
104      * element of {@code warningListeners}, initialized by default
105      * {@code null}, which is synonymous with an empty
106      * {@code List}.
107      */
108     protected List<Locale> warningLocales = null;
109 
110     /**
111      * A {@code List} of currently registered
112      * {@code IIOWriteProgressListener}s, initialized by default
113      * {@code null}, which is synonymous with an empty
114      * {@code List}.
115      */
116     protected List<IIOWriteProgressListener> progressListeners = null;
117 
118     /**
119      * If {@code true}, the current write operation should be
120      * aborted.
121      */
122     private boolean abortFlag = false;
123 
124     /**
125      * Constructs an {@code ImageWriter} and sets its
126      * {@code originatingProvider} instance variable to the
127      * supplied value.
128      *
129      * <p> Subclasses that make use of extensions should provide a
130      * constructor with signature {@code (ImageWriterSpi, Object)}
131      * in order to retrieve the extension object.  If
132      * the extension object is unsuitable, an
133      * {@code IllegalArgumentException} should be thrown.
134      *
135      * @param originatingProvider the {@code ImageWriterSpi} that
136      * is constructing this object, or {@code null}.
137      */
ImageWriter(ImageWriterSpi originatingProvider)138     protected ImageWriter(ImageWriterSpi originatingProvider) {
139         this.originatingProvider = originatingProvider;
140     }
141 
142     /**
143      * Returns the {@code ImageWriterSpi} object that created
144      * this {@code ImageWriter}, or {@code null} if this
145      * object was not created through the {@code IIORegistry}.
146      *
147      * <p> The default implementation returns the value of the
148      * {@code originatingProvider} instance variable.
149      *
150      * @return an {@code ImageWriterSpi}, or {@code null}.
151      *
152      * @see ImageWriterSpi
153      */
getOriginatingProvider()154     public ImageWriterSpi getOriginatingProvider() {
155         return originatingProvider;
156     }
157 
158     /**
159      * Sets the destination to the given
160      * {@code ImageOutputStream} or other {@code Object}.
161      * The destination is assumed to be ready to accept data, and will
162      * not be closed at the end of each write. This allows distributed
163      * imaging applications to transmit a series of images over a
164      * single network connection.  If {@code output} is
165      * {@code null}, any currently set output will be removed.
166      *
167      * <p> If {@code output} is an
168      * {@code ImageOutputStream}, calls to the
169      * {@code write}, {@code writeToSequence}, and
170      * {@code prepareWriteEmpty}/{@code endWriteEmpty}
171      * methods will preserve the existing contents of the stream.
172      * Other write methods, such as {@code writeInsert},
173      * {@code replaceStreamMetadata},
174      * {@code replaceImageMetadata}, {@code replacePixels},
175      * {@code prepareInsertEmpty}/{@code endInsertEmpty},
176      * and {@code endWriteSequence}, require the full contents
177      * of the stream to be readable and writable, and may alter any
178      * portion of the stream.
179      *
180      * <p> Use of a general {@code Object} other than an
181      * {@code ImageOutputStream} is intended for writers that
182      * interact directly with an output device or imaging protocol.
183      * The set of legal classes is advertised by the writer's service
184      * provider's {@code getOutputTypes} method; most writers
185      * will return a single-element array containing only
186      * {@code ImageOutputStream.class} to indicate that they
187      * accept only an {@code ImageOutputStream}.
188      *
189      * <p> The default implementation sets the {@code output}
190      * instance variable to the value of {@code output} after
191      * checking {@code output} against the set of classes
192      * advertised by the originating provider, if there is one.
193      *
194      * @param output the {@code ImageOutputStream} or other
195      * {@code Object} to use for future writing.
196      *
197      * @exception IllegalArgumentException if {@code output} is
198      * not an instance of one of the classes returned by the
199      * originating service provider's {@code getOutputTypes}
200      * method.
201      *
202      * @see #getOutput
203      */
setOutput(Object output)204     public void setOutput(Object output) {
205         if (output != null) {
206             ImageWriterSpi provider = getOriginatingProvider();
207             if (provider != null) {
208                 Class<?>[] classes = provider.getOutputTypes();
209                 boolean found = false;
210                 for (int i = 0; i < classes.length; i++) {
211                     if (classes[i].isInstance(output)) {
212                         found = true;
213                         break;
214                     }
215                 }
216                 if (!found) {
217                     throw new IllegalArgumentException("Illegal output type!");
218                 }
219             }
220         }
221 
222         this.output = output;
223     }
224 
225     /**
226      * Returns the {@code ImageOutputStream} or other
227      * {@code Object} set by the most recent call to the
228      * {@code setOutput} method.  If no destination has been
229      * set, {@code null} is returned.
230      *
231      * <p> The default implementation returns the value of the
232      * {@code output} instance variable.
233      *
234      * @return the {@code Object} that was specified using
235      * {@code setOutput}, or {@code null}.
236      *
237      * @see #setOutput
238      */
getOutput()239     public Object getOutput() {
240         return output;
241     }
242 
243     // Localization
244 
245     /**
246      * Returns an array of {@code Locale}s that may be used to
247      * localize warning listeners and compression settings.  A return
248      * value of {@code null} indicates that localization is not
249      * supported.
250      *
251      * <p> The default implementation returns a clone of the
252      * {@code availableLocales} instance variable if it is
253      * non-{@code null}, or else returns {@code null}.
254      *
255      * @return an array of {@code Locale}s that may be used as
256      * arguments to {@code setLocale}, or {@code null}.
257      */
getAvailableLocales()258     public Locale[] getAvailableLocales() {
259         return (availableLocales == null) ?
260             null : availableLocales.clone();
261     }
262 
263     /**
264      * Sets the current {@code Locale} of this
265      * {@code ImageWriter} to the given value.  A value of
266      * {@code null} removes any previous setting, and indicates
267      * that the writer should localize as it sees fit.
268      *
269      * <p> The default implementation checks {@code locale}
270      * against the values returned by
271      * {@code getAvailableLocales}, and sets the
272      * {@code locale} instance variable if it is found.  If
273      * {@code locale} is {@code null}, the instance variable
274      * is set to {@code null} without any checking.
275      *
276      * @param locale the desired {@code Locale}, or
277      * {@code null}.
278      *
279      * @exception IllegalArgumentException if {@code locale} is
280      * non-{@code null} but is not one of the values returned by
281      * {@code getAvailableLocales}.
282      *
283      * @see #getLocale
284      */
setLocale(Locale locale)285     public void setLocale(Locale locale) {
286         if (locale != null) {
287             Locale[] locales = getAvailableLocales();
288             boolean found = false;
289             if (locales != null) {
290                 for (int i = 0; i < locales.length; i++) {
291                     if (locale.equals(locales[i])) {
292                         found = true;
293                         break;
294                     }
295                 }
296             }
297             if (!found) {
298                 throw new IllegalArgumentException("Invalid locale!");
299             }
300         }
301         this.locale = locale;
302     }
303 
304     /**
305      * Returns the currently set {@code Locale}, or
306      * {@code null} if none has been set.
307      *
308      * <p> The default implementation returns the value of the
309      * {@code locale} instance variable.
310      *
311      * @return the current {@code Locale}, or {@code null}.
312      *
313      * @see #setLocale
314      */
getLocale()315     public Locale getLocale() {
316         return locale;
317     }
318 
319     // Write params
320 
321     /**
322      * Returns a new {@code ImageWriteParam} object of the
323      * appropriate type for this file format containing default
324      * values, that is, those values that would be used
325      * if no {@code ImageWriteParam} object were specified.  This
326      * is useful as a starting point for tweaking just a few parameters
327      * and otherwise leaving the default settings alone.
328      *
329      * <p> The default implementation constructs and returns a new
330      * {@code ImageWriteParam} object that does not allow tiling,
331      * progressive encoding, or compression, and that will be
332      * localized for the current {@code Locale} (<i>i.e.</i>,
333      * what you would get by calling
334      * {@code new ImageWriteParam(getLocale())}.
335      *
336      * <p> Individual plug-ins may return an instance of
337      * {@code ImageWriteParam} with additional optional features
338      * enabled, or they may return an instance of a plug-in specific
339      * subclass of {@code ImageWriteParam}.
340      *
341      * @return a new {@code ImageWriteParam} object containing
342      * default values.
343      */
getDefaultWriteParam()344     public ImageWriteParam getDefaultWriteParam() {
345         return new ImageWriteParam(getLocale());
346     }
347 
348     // Metadata
349 
350     /**
351      * Returns an {@code IIOMetadata} object containing default
352      * values for encoding a stream of images.  The contents of the
353      * object may be manipulated using either the XML tree structure
354      * returned by the {@code IIOMetadata.getAsTree} method, an
355      * {@code IIOMetadataController} object, or via plug-in
356      * specific interfaces, and the resulting data supplied to one of
357      * the {@code write} methods that take a stream metadata
358      * parameter.
359      *
360      * <p> An optional {@code ImageWriteParam} may be supplied
361      * for cases where it may affect the structure of the stream
362      * metadata.
363      *
364      * <p> If the supplied {@code ImageWriteParam} contains
365      * optional setting values not supported by this writer (<i>e.g.</i>
366      * progressive encoding or any format-specific settings), they
367      * will be ignored.
368      *
369      * <p> Writers that do not make use of stream metadata
370      * (<i>e.g.</i>, writers for single-image formats) should return
371      * {@code null}.
372      *
373      * @param param an {@code ImageWriteParam} that will be used to
374      * encode the image, or {@code null}.
375      *
376      * @return an {@code IIOMetadata} object.
377      */
378     public abstract IIOMetadata
getDefaultStreamMetadata(ImageWriteParam param)379         getDefaultStreamMetadata(ImageWriteParam param);
380 
381     /**
382      * Returns an {@code IIOMetadata} object containing default
383      * values for encoding an image of the given type.  The contents
384      * of the object may be manipulated using either the XML tree
385      * structure returned by the {@code IIOMetadata.getAsTree}
386      * method, an {@code IIOMetadataController} object, or via
387      * plug-in specific interfaces, and the resulting data supplied to
388      * one of the {@code write} methods that take a stream
389      * metadata parameter.
390      *
391      * <p> An optional {@code ImageWriteParam} may be supplied
392      * for cases where it may affect the structure of the image
393      * metadata.
394      *
395      * <p> If the supplied {@code ImageWriteParam} contains
396      * optional setting values not supported by this writer (<i>e.g.</i>
397      * progressive encoding or any format-specific settings), they
398      * will be ignored.
399      *
400      * @param imageType an {@code ImageTypeSpecifier} indicating the
401      * format of the image to be written later.
402      * @param param an {@code ImageWriteParam} that will be used to
403      * encode the image, or {@code null}.
404      *
405      * @return an {@code IIOMetadata} object.
406      */
407     public abstract IIOMetadata
getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param)408         getDefaultImageMetadata(ImageTypeSpecifier imageType,
409                                 ImageWriteParam param);
410 
411     // comment inherited
convertStreamMetadata(IIOMetadata inData, ImageWriteParam param)412     public abstract IIOMetadata convertStreamMetadata(IIOMetadata inData,
413                                                       ImageWriteParam param);
414 
415     // comment inherited
416     public abstract IIOMetadata
convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param)417         convertImageMetadata(IIOMetadata inData,
418                              ImageTypeSpecifier imageType,
419                              ImageWriteParam param);
420 
421     // Thumbnails
422 
423     /**
424      * Returns the number of thumbnails supported by the format being
425      * written, given the image type and any additional write
426      * parameters and metadata objects that will be used during
427      * encoding.  A return value of {@code -1} indicates that
428      * insufficient information is available.
429      *
430      * <p> An {@code ImageWriteParam} may optionally be supplied
431      * for cases where it may affect thumbnail handling.
432      *
433      * <p> If the supplied {@code ImageWriteParam} contains
434      * optional setting values not supported by this writer (<i>e.g.</i>
435      * progressive encoding or any format-specific settings), they
436      * will be ignored.
437      *
438      * <p> The default implementation returns 0.
439      *
440      * @param imageType an {@code ImageTypeSpecifier} indicating
441      * the type of image to be written, or {@code null}.
442      * @param param the {@code ImageWriteParam} that will be used for
443      * writing, or {@code null}.
444      * @param streamMetadata an {@code IIOMetadata} object that will
445      * be used for writing, or {@code null}.
446      * @param imageMetadata an {@code IIOMetadata} object that will
447      * be used for writing, or {@code null}.
448      *
449      * @return the number of thumbnails that may be written given the
450      * supplied parameters, or {@code -1} if insufficient
451      * information is available.
452      */
getNumThumbnailsSupported(ImageTypeSpecifier imageType, ImageWriteParam param, IIOMetadata streamMetadata, IIOMetadata imageMetadata)453     public int getNumThumbnailsSupported(ImageTypeSpecifier imageType,
454                                          ImageWriteParam param,
455                                          IIOMetadata streamMetadata,
456                                          IIOMetadata imageMetadata) {
457         return 0;
458     }
459 
460     /**
461      * Returns an array of {@code Dimension}s indicating the
462      * legal size ranges for thumbnail images as they will be encoded
463      * in the output file or stream.  This information is merely
464      * advisory; the writer will resize any supplied thumbnails as
465      * necessary.
466      *
467      * <p> The information is returned as a set of pairs; the first
468      * element of a pair contains an (inclusive) minimum width and
469      * height, and the second element contains an (inclusive) maximum
470      * width and height.  Together, each pair defines a valid range of
471      * sizes.  To specify a fixed size, the same width and height will
472      * appear for both elements.  A return value of {@code null}
473      * indicates that the size is arbitrary or unknown.
474      *
475      * <p> An {@code ImageWriteParam} may optionally be supplied
476      * for cases where it may affect thumbnail handling.
477      *
478      * <p> If the supplied {@code ImageWriteParam} contains
479      * optional setting values not supported by this writer (<i>e.g.</i>
480      * progressive encoding or any format-specific settings), they
481      * will be ignored.
482      *
483      * <p> The default implementation returns {@code null}.
484      *
485      * @param imageType an {@code ImageTypeSpecifier} indicating the
486      * type of image to be written, or {@code null}.
487      * @param param the {@code ImageWriteParam} that will be used for
488      * writing, or {@code null}.
489      * @param streamMetadata an {@code IIOMetadata} object that will
490      * be used for writing, or {@code null}.
491      * @param imageMetadata an {@code IIOMetadata} object that will
492      * be used for writing, or {@code null}.
493      *
494      * @return an array of {@code Dimension}s with an even length
495      * of at least two, or {@code null}.
496      */
getPreferredThumbnailSizes(ImageTypeSpecifier imageType, ImageWriteParam param, IIOMetadata streamMetadata, IIOMetadata imageMetadata)497     public Dimension[] getPreferredThumbnailSizes(ImageTypeSpecifier imageType,
498                                                   ImageWriteParam param,
499                                                   IIOMetadata streamMetadata,
500                                                   IIOMetadata imageMetadata) {
501         return null;
502     }
503 
504     /**
505      * Returns {@code true} if the methods that take an
506      * {@code IIOImage} parameter are capable of dealing with a
507      * {@code Raster} (as opposed to {@code RenderedImage})
508      * source image.  If this method returns {@code false}, then
509      * those methods will throw an
510      * {@code UnsupportedOperationException} if supplied with an
511      * {@code IIOImage} containing a {@code Raster}.
512      *
513      * <p> The default implementation returns {@code false}.
514      *
515      * @return {@code true} if {@code Raster} sources are
516      * supported.
517      */
canWriteRasters()518     public boolean canWriteRasters() {
519         return false;
520     }
521 
522     /**
523      * Appends a complete image stream containing a single image and
524      * associated stream and image metadata and thumbnails to the
525      * output.  Any necessary header information is included.  If the
526      * output is an {@code ImageOutputStream}, its existing
527      * contents prior to the current seek position are not affected,
528      * and need not be readable or writable.
529      *
530      * <p> The output must have been set beforehand using the
531      * {@code setOutput} method.
532      *
533      * <p> Stream metadata may optionally be supplied; if it is
534      * {@code null}, default stream metadata will be used.
535      *
536      * <p> If {@code canWriteRasters} returns {@code true},
537      * the {@code IIOImage} may contain a {@code Raster}
538      * source.  Otherwise, it must contain a
539      * {@code RenderedImage} source.
540      *
541      * <p> The supplied thumbnails will be resized if needed, and any
542      * thumbnails in excess of the supported number will be ignored.
543      * If the format requires additional thumbnails that are not
544      * provided, the writer should generate them internally.
545      *
546      * <p>  An {@code ImageWriteParam} may
547      * optionally be supplied to control the writing process.  If
548      * {@code param} is {@code null}, a default write param
549      * will be used.
550      *
551      * <p> If the supplied {@code ImageWriteParam} contains
552      * optional setting values not supported by this writer (<i>e.g.</i>
553      * progressive encoding or any format-specific settings), they
554      * will be ignored.
555      *
556      * @param streamMetadata an {@code IIOMetadata} object representing
557      * stream metadata, or {@code null} to use default values.
558      * @param image an {@code IIOImage} object containing an
559      * image, thumbnails, and metadata to be written.
560      * @param param an {@code ImageWriteParam}, or
561      * {@code null} to use a default
562      * {@code ImageWriteParam}.
563      *
564      * @exception IllegalStateException if the output has not
565      * been set.
566      * @exception UnsupportedOperationException if {@code image}
567      * contains a {@code Raster} and {@code canWriteRasters}
568      * returns {@code false}.
569      * @exception IllegalArgumentException if {@code image} is
570      * {@code null}.
571      * @exception IOException if an error occurs during writing.
572      */
write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param)573     public abstract void write(IIOMetadata streamMetadata,
574                                IIOImage image,
575                                ImageWriteParam param) throws IOException;
576 
577     /**
578      * Appends a complete image stream containing a single image with
579      * default metadata and thumbnails to the output.  This method is
580      * a shorthand for {@code write(null, image, null)}.
581      *
582      * @param image an {@code IIOImage} object containing an
583      * image, thumbnails, and metadata to be written.
584      *
585      * @exception IllegalStateException if the output has not
586      * been set.
587      * @exception IllegalArgumentException if {@code image} is
588      * {@code null}.
589      * @exception UnsupportedOperationException if {@code image}
590      * contains a {@code Raster} and {@code canWriteRasters}
591      * returns {@code false}.
592      * @exception IOException if an error occurs during writing.
593      */
write(IIOImage image)594     public void write(IIOImage image) throws IOException {
595         write(null, image, null);
596     }
597 
598     /**
599      * Appends a complete image stream consisting of a single image
600      * with default metadata and thumbnails to the output.  This
601      * method is a shorthand for
602      * {@code write(null, new IIOImage(image, null, null), null)}.
603      *
604      * @param image a {@code RenderedImage} to be written.
605      *
606      * @exception IllegalStateException if the output has not
607      * been set.
608      * @exception IllegalArgumentException if {@code image} is
609      * {@code null}.
610      * @exception IOException if an error occurs during writing.
611      */
write(RenderedImage image)612     public void write(RenderedImage image) throws IOException {
613         write(null, new IIOImage(image, null, null), null);
614     }
615 
616     // Check that the output has been set, then throw an
617     // UnsupportedOperationException.
unsupported()618     private void unsupported() {
619         if (getOutput() == null) {
620             throw new IllegalStateException("getOutput() == null!");
621         }
622         throw new UnsupportedOperationException("Unsupported write variant!");
623     }
624 
625     // Sequence writes
626 
627     /**
628      * Returns {@code true} if the writer is able to append an
629      * image to an image stream that already contains header
630      * information and possibly prior images.
631      *
632      * <p> If {@code canWriteSequence} returns {@code false},
633      * {@code writeToSequence} and {@code endWriteSequence}
634      * will throw an {@code UnsupportedOperationException}.
635      *
636      * <p> The default implementation returns {@code false}.
637      *
638      * @return {@code true} if images may be appended sequentially.
639      */
canWriteSequence()640     public boolean canWriteSequence() {
641         return false;
642     }
643 
644     /**
645      * Prepares a stream to accept a series of subsequent
646      * {@code writeToSequence} calls, using the provided stream
647      * metadata object.  The metadata will be written to the stream if
648      * it should precede the image data.  If the argument is {@code null},
649      * default stream metadata is used.
650      *
651      * <p> If the output is an {@code ImageOutputStream}, the existing
652      * contents of the output prior to the current seek position are
653      * flushed, and need not be readable or writable.  If the format
654      * requires that {@code endWriteSequence} be able to rewind to
655      * patch up the header information, such as for a sequence of images
656      * in a single TIFF file, then the metadata written by this method
657      * must remain in a writable portion of the stream.  Other formats
658      * may flush the stream after this method and after each image.
659      *
660      * <p> If {@code canWriteSequence} returns {@code false},
661      * this method will throw an
662      * {@code UnsupportedOperationException}.
663      *
664      * <p> The output must have been set beforehand using either
665      * the {@code setOutput} method.
666      *
667      * <p> The default implementation throws an
668      * {@code IllegalStateException} if the output is
669      * {@code null}, and otherwise throws an
670      * {@code UnsupportedOperationException}.
671      *
672      * @param streamMetadata A stream metadata object, or {@code null}.
673      *
674      * @exception IllegalStateException if the output has not
675      * been set.
676      * @exception UnsupportedOperationException if
677      * {@code canWriteSequence} returns {@code false}.
678      * @exception IOException if an error occurs writing the stream
679      * metadata.
680      */
prepareWriteSequence(IIOMetadata streamMetadata)681     public void prepareWriteSequence(IIOMetadata streamMetadata)
682         throws IOException {
683         unsupported();
684     }
685 
686     /**
687      * Appends a single image and possibly associated metadata and
688      * thumbnails, to the output.  If the output is an
689      * {@code ImageOutputStream}, the existing contents of the
690      * output prior to the current seek position may be flushed, and
691      * need not be readable or writable, unless the plug-in needs to
692      * be able to patch up the header information when
693      * {@code endWriteSequence} is called (<i>e.g.</i> TIFF).
694      *
695      * <p> If {@code canWriteSequence} returns {@code false},
696      * this method will throw an
697      * {@code UnsupportedOperationException}.
698      *
699      * <p> The output must have been set beforehand using
700      * the {@code setOutput} method.
701      *
702      * <p> {@code prepareWriteSequence} must have been called
703      * beforehand, or an {@code IllegalStateException} is thrown.
704      *
705      * <p> If {@code canWriteRasters} returns {@code true},
706      * the {@code IIOImage} may contain a {@code Raster}
707      * source.  Otherwise, it must contain a
708      * {@code RenderedImage} source.
709      *
710      * <p> The supplied thumbnails will be resized if needed, and any
711      * thumbnails in excess of the supported number will be ignored.
712      * If the format requires additional thumbnails that are not
713      * provided, the writer will generate them internally.
714      *
715      * <p> An {@code ImageWriteParam} may optionally be supplied
716      * to control the writing process.  If {@code param} is
717      * {@code null}, a default write param will be used.
718      *
719      * <p> If the supplied {@code ImageWriteParam} contains
720      * optional setting values not supported by this writer (<i>e.g.</i>
721      * progressive encoding or any format-specific settings), they
722      * will be ignored.
723      *
724      * <p> The default implementation throws an
725      * {@code IllegalStateException} if the output is
726      * {@code null}, and otherwise throws an
727      * {@code UnsupportedOperationException}.
728      *
729      * @param image an {@code IIOImage} object containing an
730      * image, thumbnails, and metadata to be written.
731      * @param param an {@code ImageWriteParam}, or
732      * {@code null} to use a default
733      * {@code ImageWriteParam}.
734      *
735      * @exception IllegalStateException if the output has not
736      * been set, or {@code prepareWriteSequence} has not been called.
737      * @exception UnsupportedOperationException if
738      * {@code canWriteSequence} returns {@code false}.
739      * @exception IllegalArgumentException if {@code image} is
740      * {@code null}.
741      * @exception UnsupportedOperationException if {@code image}
742      * contains a {@code Raster} and {@code canWriteRasters}
743      * returns {@code false}.
744      * @exception IOException if an error occurs during writing.
745      */
writeToSequence(IIOImage image, ImageWriteParam param)746     public void writeToSequence(IIOImage image, ImageWriteParam param)
747         throws IOException {
748         unsupported();
749     }
750 
751     /**
752      * Completes the writing of a sequence of images begun with
753      * {@code prepareWriteSequence}.  Any stream metadata that
754      * should come at the end of the sequence of images is written out,
755      * and any header information at the beginning of the sequence is
756      * patched up if necessary.  If the output is an
757      * {@code ImageOutputStream}, data through the stream metadata
758      * at the end of the sequence are flushed and need not be readable
759      * or writable.
760      *
761      * <p> If {@code canWriteSequence} returns {@code false},
762      * this method will throw an
763      * {@code UnsupportedOperationException}.
764      *
765      * <p> The default implementation throws an
766      * {@code IllegalStateException} if the output is
767      * {@code null}, and otherwise throws an
768      * {@code UnsupportedOperationException}.
769      *
770      * @exception IllegalStateException if the output has not
771      * been set, or {@code prepareWriteSequence} has not been called.
772      * @exception UnsupportedOperationException if
773      * {@code canWriteSequence} returns {@code false}.
774      * @exception IOException if an error occurs during writing.
775      */
endWriteSequence()776     public void endWriteSequence() throws IOException {
777         unsupported();
778     }
779 
780     // Metadata replacement
781 
782     /**
783      * Returns {@code true} if it is possible to replace the
784      * stream metadata already present in the output.
785      *
786      * <p> The default implementation throws an
787      * {@code IllegalStateException} if the output is
788      * {@code null}, and otherwise returns {@code false}.
789      *
790      * @return {@code true} if replacement of stream metadata is
791      * allowed.
792      *
793      * @exception IllegalStateException if the output has not
794      * been set.
795      * @exception IOException if an I/O error occurs during the query.
796      */
canReplaceStreamMetadata()797     public boolean canReplaceStreamMetadata() throws IOException {
798         if (getOutput() == null) {
799             throw new IllegalStateException("getOutput() == null!");
800         }
801         return false;
802     }
803 
804     /**
805      * Replaces the stream metadata in the output with new
806      * information.  If the output is an
807      * {@code ImageOutputStream}, the prior contents of the
808      * stream are examined and possibly edited to make room for the
809      * new data.  All of the prior contents of the output must be
810      * available for reading and writing.
811      *
812      * <p> If {@code canReplaceStreamMetadata} returns
813      * {@code false}, an
814      * {@code UnsupportedOperationException} will be thrown.
815      *
816      * <p> The default implementation throws an
817      * {@code IllegalStateException} if the output is
818      * {@code null}, and otherwise throws an
819      * {@code UnsupportedOperationException}.
820      *
821      * @param streamMetadata an {@code IIOMetadata} object representing
822      * stream metadata, or {@code null} to use default values.
823      *
824      * @exception IllegalStateException if the output has not
825      * been set.
826      * @exception UnsupportedOperationException if the
827      * {@code canReplaceStreamMetadata} returns
828      * {@code false}.  modes do not include
829      * @exception IOException if an error occurs during writing.
830      */
replaceStreamMetadata(IIOMetadata streamMetadata)831     public void replaceStreamMetadata(IIOMetadata streamMetadata)
832         throws IOException {
833         unsupported();
834     }
835 
836     /**
837      * Returns {@code true} if it is possible to replace the
838      * image metadata associated with an existing image with index
839      * {@code imageIndex}.  If this method returns
840      * {@code false}, a call to
841      * {@code replaceImageMetadata(imageIndex)} will throw an
842      * {@code UnsupportedOperationException}.
843      *
844      * <p> A writer that does not support any image metadata
845      * replacement may return {@code false} without performing
846      * bounds checking on the index.
847      *
848      * <p> The default implementation throws an
849      * {@code IllegalStateException} if the output is
850      * {@code null}, and otherwise returns {@code false}
851      * without checking the value of {@code imageIndex}.
852      *
853      * @param imageIndex the index of the image whose metadata is to
854      * be replaced.
855      *
856      * @return {@code true} if the image metadata of the given
857      * image can be replaced.
858      *
859      * @exception IllegalStateException if the output has not
860      * been set.
861      * @exception IndexOutOfBoundsException if the writer supports
862      * image metadata replacement in general, but
863      * {@code imageIndex} is less than 0 or greater than the
864      * largest available index.
865      * @exception IOException if an I/O error occurs during the query.
866      */
canReplaceImageMetadata(int imageIndex)867     public boolean canReplaceImageMetadata(int imageIndex)
868         throws IOException {
869         if (getOutput() == null) {
870             throw new IllegalStateException("getOutput() == null!");
871         }
872         return false;
873     }
874 
875     /**
876      * Replaces the image metadata associated with an existing image.
877      *
878      * <p> If {@code canReplaceImageMetadata(imageIndex)} returns
879      * {@code false}, an
880      * {@code UnsupportedOperationException} will be thrown.
881      *
882      * <p> The default implementation throws an
883      * {@code IllegalStateException} if the output is
884      * {@code null}, and otherwise throws an
885      * {@code UnsupportedOperationException}.
886      *
887      * @param imageIndex the index of the image whose metadata is to
888      * be replaced.
889      * @param imageMetadata an {@code IIOMetadata} object
890      * representing image metadata, or {@code null}.
891      *
892      * @exception IllegalStateException if the output has not been
893      * set.
894      * @exception UnsupportedOperationException if
895      * {@code canReplaceImageMetadata} returns
896      * {@code false}.
897      * @exception IndexOutOfBoundsException if {@code imageIndex}
898      * is less than 0 or greater than the largest available index.
899      * @exception IOException if an error occurs during writing.
900      */
replaceImageMetadata(int imageIndex, IIOMetadata imageMetadata)901     public void replaceImageMetadata(int imageIndex,
902                                      IIOMetadata imageMetadata)
903         throws IOException {
904         unsupported();
905     }
906 
907     // Image insertion
908 
909     /**
910      * Returns {@code true} if the writer supports the insertion
911      * of a new image at the given index.  Existing images with
912      * indices greater than or equal to the insertion index will have
913      * their indices increased by 1.  A value for
914      * {@code imageIndex} of {@code -1} may be used to
915      * signify an index one larger than the current largest index.
916      *
917      * <p> A writer that does not support any image insertion may
918      * return {@code false} without performing bounds checking on
919      * the index.
920      *
921      * <p> The default implementation throws an
922      * {@code IllegalStateException} if the output is
923      * {@code null}, and otherwise returns {@code false}
924      * without checking the value of {@code imageIndex}.
925      *
926      * @param imageIndex the index at which the image is to be
927      * inserted.
928      *
929      * @return {@code true} if an image may be inserted at the
930      * given index.
931      *
932      * @exception IllegalStateException if the output has not
933      * been set.
934      * @exception IndexOutOfBoundsException if the writer supports
935      * image insertion in general, but {@code imageIndex} is less
936      * than -1 or greater than the largest available index.
937      * @exception IOException if an I/O error occurs during the query.
938      */
canInsertImage(int imageIndex)939     public boolean canInsertImage(int imageIndex) throws IOException {
940         if (getOutput() == null) {
941             throw new IllegalStateException("getOutput() == null!");
942         }
943         return false;
944     }
945 
946     /**
947      * Inserts a new image into an existing image stream.  Existing
948      * images with an index greater than {@code imageIndex} are
949      * preserved, and their indices are each increased by 1.  A value
950      * for {@code imageIndex} of -1 may be used to signify an
951      * index one larger than the previous largest index; that is, it
952      * will cause the image to be logically appended to the end of the
953      * sequence.  If the output is an {@code ImageOutputStream},
954      * the entirety of the stream must be both readable and writeable.
955      *
956      * <p> If {@code canInsertImage(imageIndex)} returns
957      * {@code false}, an
958      * {@code UnsupportedOperationException} will be thrown.
959      *
960      * <p> An {@code ImageWriteParam} may optionally be supplied
961      * to control the writing process.  If {@code param} is
962      * {@code null}, a default write param will be used.
963      *
964      * <p> If the supplied {@code ImageWriteParam} contains
965      * optional setting values not supported by this writer (<i>e.g.</i>
966      * progressive encoding or any format-specific settings), they
967      * will be ignored.
968      *
969      * <p> The default implementation throws an
970      * {@code IllegalStateException} if the output is
971      * {@code null}, and otherwise throws an
972      * {@code UnsupportedOperationException}.
973      *
974      * @param imageIndex the index at which to write the image.
975      * @param image an {@code IIOImage} object containing an
976      * image, thumbnails, and metadata to be written.
977      * @param param an {@code ImageWriteParam}, or
978      * {@code null} to use a default
979      * {@code ImageWriteParam}.
980      *
981      * @exception IllegalStateException if the output has not
982      * been set.
983      * @exception UnsupportedOperationException if
984      * {@code canInsertImage(imageIndex)} returns {@code false}.
985      * @exception IllegalArgumentException if {@code image} is
986      * {@code null}.
987      * @exception IndexOutOfBoundsException if {@code imageIndex}
988      * is less than -1 or greater than the largest available index.
989      * @exception UnsupportedOperationException if {@code image}
990      * contains a {@code Raster} and {@code canWriteRasters}
991      * returns {@code false}.
992      * @exception IOException if an error occurs during writing.
993      */
writeInsert(int imageIndex, IIOImage image, ImageWriteParam param)994     public void writeInsert(int imageIndex,
995                             IIOImage image,
996                             ImageWriteParam param) throws IOException {
997         unsupported();
998     }
999 
1000     // Image removal
1001 
1002     /**
1003      * Returns {@code true} if the writer supports the removal
1004      * of an existing image at the given index.  Existing images with
1005      * indices greater than the insertion index will have
1006      * their indices decreased by 1.
1007      *
1008      * <p> A writer that does not support any image removal may
1009      * return {@code false} without performing bounds checking on
1010      * the index.
1011      *
1012      * <p> The default implementation throws an
1013      * {@code IllegalStateException} if the output is
1014      * {@code null}, and otherwise returns {@code false}
1015      * without checking the value of {@code imageIndex}.
1016      *
1017      * @param imageIndex the index of the image to be removed.
1018      *
1019      * @return {@code true} if it is possible to remove the given
1020      * image.
1021      *
1022      * @exception IllegalStateException if the output has not
1023      * been set.
1024      * @exception IndexOutOfBoundsException if the writer supports
1025      * image removal in general, but {@code imageIndex} is less
1026      * than 0 or greater than the largest available index.
1027      * @exception IOException if an I/O error occurs during the
1028      * query.
1029      */
canRemoveImage(int imageIndex)1030     public boolean canRemoveImage(int imageIndex) throws IOException {
1031         if (getOutput() == null) {
1032             throw new IllegalStateException("getOutput() == null!");
1033         }
1034         return false;
1035     }
1036 
1037     /**
1038      * Removes an image from the stream.
1039      *
1040      * <p> If {@code canRemoveImage(imageIndex)} returns false,
1041      * an {@code UnsupportedOperationException} will be thrown.
1042      *
1043      * <p> The removal may or may not cause a reduction in the actual
1044      * file size.
1045      *
1046      * <p> The default implementation throws an
1047      * {@code IllegalStateException} if the output is
1048      * {@code null}, and otherwise throws an
1049      * {@code UnsupportedOperationException}.
1050      *
1051      * @param imageIndex the index of the image to be removed.
1052      *
1053      * @exception IllegalStateException if the output has not
1054      * been set.
1055      * @exception UnsupportedOperationException if
1056      * {@code canRemoveImage(imageIndex)} returns {@code false}.
1057      * @exception IndexOutOfBoundsException if {@code imageIndex}
1058      * is less than 0 or greater than the largest available index.
1059      * @exception IOException if an I/O error occurs during the
1060      * removal.
1061      */
removeImage(int imageIndex)1062     public void removeImage(int imageIndex) throws IOException {
1063         unsupported();
1064     }
1065 
1066     // Empty images
1067 
1068     /**
1069      * Returns {@code true} if the writer supports the writing of
1070      * a complete image stream consisting of a single image with
1071      * undefined pixel values and associated metadata and thumbnails
1072      * to the output.  The pixel values may be defined by future
1073      * calls to the {@code replacePixels} methods.  If the output
1074      * is an {@code ImageOutputStream}, its existing contents
1075      * prior to the current seek position are not affected, and need
1076      * not be readable or writable.
1077      *
1078      * <p> The default implementation throws an
1079      * {@code IllegalStateException} if the output is
1080      * {@code null}, and otherwise returns {@code false}.
1081      *
1082      * @return {@code true} if the writing of complete image
1083      * stream with contents to be defined later is supported.
1084      *
1085      * @exception IllegalStateException if the output has not been
1086      * set.
1087      * @exception IOException if an I/O error occurs during the
1088      * query.
1089      */
canWriteEmpty()1090     public boolean canWriteEmpty() throws IOException {
1091         if (getOutput() == null) {
1092             throw new IllegalStateException("getOutput() == null!");
1093         }
1094         return false;
1095     }
1096 
1097     /**
1098      * Begins the writing of a complete image stream, consisting of a
1099      * single image with undefined pixel values and associated
1100      * metadata and thumbnails, to the output.  The pixel values will
1101      * be defined by future calls to the {@code replacePixels}
1102      * methods.  If the output is an {@code ImageOutputStream},
1103      * its existing contents prior to the current seek position are
1104      * not affected, and need not be readable or writable.
1105      *
1106      * <p> The writing is not complete until a call to
1107      * {@code endWriteEmpty} occurs.  Calls to
1108      * {@code prepareReplacePixels}, {@code replacePixels},
1109      * and {@code endReplacePixels} may occur between calls to
1110      * {@code prepareWriteEmpty} and {@code endWriteEmpty}.
1111      * However, calls to {@code prepareWriteEmpty} cannot be
1112      * nested, and calls to {@code prepareWriteEmpty} and
1113      * {@code prepareInsertEmpty} may not be interspersed.
1114      *
1115      * <p> If {@code canWriteEmpty} returns {@code false},
1116      * an {@code UnsupportedOperationException} will be thrown.
1117      *
1118      * <p> An {@code ImageWriteParam} may optionally be supplied
1119      * to control the writing process.  If {@code param} is
1120      * {@code null}, a default write param will be used.
1121      *
1122      * <p> If the supplied {@code ImageWriteParam} contains
1123      * optional setting values not supported by this writer (<i>e.g.</i>
1124      * progressive encoding or any format-specific settings), they
1125      * will be ignored.
1126      *
1127      * <p> The default implementation throws an
1128      * {@code IllegalStateException} if the output is
1129      * {@code null}, and otherwise throws an
1130      * {@code UnsupportedOperationException}.
1131      *
1132      * @param streamMetadata an {@code IIOMetadata} object representing
1133      * stream metadata, or {@code null} to use default values.
1134      * @param imageType an {@code ImageTypeSpecifier} describing
1135      * the layout of the image.
1136      * @param width the width of the image.
1137      * @param height the height of the image.
1138      * @param imageMetadata an {@code IIOMetadata} object
1139      * representing image metadata, or {@code null}.
1140      * @param thumbnails a {@code List} of
1141      * {@code BufferedImage} thumbnails for this image, or
1142      * {@code null}.
1143      * @param param an {@code ImageWriteParam}, or
1144      * {@code null} to use a default
1145      * {@code ImageWriteParam}.
1146      *
1147      * @exception IllegalStateException if the output has not
1148      * been set.
1149      * @exception UnsupportedOperationException if
1150      * {@code canWriteEmpty} returns {@code false}.
1151      * @exception IllegalStateException if a previous call to
1152      * {@code prepareWriteEmpty} has been made without a
1153      * corresponding call to {@code endWriteEmpty}.
1154      * @exception IllegalStateException if a previous call to
1155      * {@code prepareInsertEmpty} has been made without a
1156      * corresponding call to {@code endInsertEmpty}.
1157      * @exception IllegalArgumentException if {@code imageType}
1158      * is {@code null} or {@code thumbnails} contains
1159      * {@code null} references or objects other than
1160      * {@code BufferedImage}s.
1161      * @exception IllegalArgumentException if width or height are less
1162      * than 1.
1163      * @exception IOException if an I/O error occurs during writing.
1164      */
prepareWriteEmpty(IIOMetadata streamMetadata, ImageTypeSpecifier imageType, int width, int height, IIOMetadata imageMetadata, List<? extends BufferedImage> thumbnails, ImageWriteParam param)1165     public void prepareWriteEmpty(IIOMetadata streamMetadata,
1166                                   ImageTypeSpecifier imageType,
1167                                   int width, int height,
1168                                   IIOMetadata imageMetadata,
1169                                   List<? extends BufferedImage> thumbnails,
1170                                   ImageWriteParam param) throws IOException {
1171         unsupported();
1172     }
1173 
1174     /**
1175      * Completes the writing of a new image that was begun with a
1176      * prior call to {@code prepareWriteEmpty}.
1177      *
1178      * <p> If {@code canWriteEmpty()} returns {@code false},
1179      * an {@code UnsupportedOperationException} will be thrown.
1180      *
1181      * <p> The default implementation throws an
1182      * {@code IllegalStateException} if the output is
1183      * {@code null}, and otherwise throws an
1184      * {@code UnsupportedOperationException}.
1185      *
1186      * @exception IllegalStateException if the output has not
1187      * been set.
1188      * @exception UnsupportedOperationException if
1189      * {@code canWriteEmpty(imageIndex)} returns
1190      * {@code false}.
1191      * @exception IllegalStateException if a previous call to
1192      * {@code prepareWriteEmpty} without a corresponding call to
1193      * {@code endWriteEmpty} has not been made.
1194      * @exception IllegalStateException if a previous call to
1195      * {@code prepareInsertEmpty} without a corresponding call to
1196      * {@code endInsertEmpty} has been made.
1197      * @exception IllegalStateException if a call to
1198      * {@code prepareReiplacePixels} has been made without a
1199      * matching call to {@code endReplacePixels}.
1200      * @exception IOException if an I/O error occurs during writing.
1201      */
endWriteEmpty()1202     public void endWriteEmpty() throws IOException {
1203         if (getOutput() == null) {
1204             throw new IllegalStateException("getOutput() == null!");
1205         }
1206         throw new IllegalStateException("No call to prepareWriteEmpty!");
1207     }
1208 
1209     /**
1210      * Returns {@code true} if the writer supports the insertion
1211      * of a new, empty image at the given index.  The pixel values of
1212      * the image are undefined, and may be specified in pieces using
1213      * the {@code replacePixels} methods.  Existing images with
1214      * indices greater than or equal to the insertion index will have
1215      * their indices increased by 1.  A value for
1216      * {@code imageIndex} of {@code -1} may be used to
1217      * signify an index one larger than the current largest index.
1218      *
1219      * <p> A writer that does not support insertion of empty images
1220      * may return {@code false} without performing bounds
1221      * checking on the index.
1222      *
1223      * <p> The default implementation throws an
1224      * {@code IllegalStateException} if the output is
1225      * {@code null}, and otherwise returns {@code false}
1226      * without checking the value of {@code imageIndex}.
1227      *
1228      * @param imageIndex the index at which the image is to be
1229      * inserted.
1230      *
1231      * @return {@code true} if an empty image may be inserted at
1232      * the given index.
1233      *
1234      * @exception IllegalStateException if the output has not been
1235      * set.
1236      * @exception IndexOutOfBoundsException if the writer supports
1237      * empty image insertion in general, but {@code imageIndex}
1238      * is less than -1 or greater than the largest available index.
1239      * @exception IOException if an I/O error occurs during the
1240      * query.
1241      */
canInsertEmpty(int imageIndex)1242     public boolean canInsertEmpty(int imageIndex) throws IOException {
1243         if (getOutput() == null) {
1244             throw new IllegalStateException("getOutput() == null!");
1245         }
1246         return false;
1247     }
1248 
1249     /**
1250      * Begins the insertion of a new image with undefined pixel values
1251      * into an existing image stream.  Existing images with an index
1252      * greater than {@code imageIndex} are preserved, and their
1253      * indices are each increased by 1.  A value for
1254      * {@code imageIndex} of -1 may be used to signify an index
1255      * one larger than the previous largest index; that is, it will
1256      * cause the image to be logically appended to the end of the
1257      * sequence.  If the output is an {@code ImageOutputStream},
1258      * the entirety of the stream must be both readable and writeable.
1259      *
1260      * <p> The image contents may be
1261      * supplied later using the {@code replacePixels} method.
1262      * The insertion is not complete until a call to
1263      * {@code endInsertEmpty} occurs.  Calls to
1264      * {@code prepareReplacePixels}, {@code replacePixels},
1265      * and {@code endReplacePixels} may occur between calls to
1266      * {@code prepareInsertEmpty} and
1267      * {@code endInsertEmpty}.  However, calls to
1268      * {@code prepareInsertEmpty} cannot be nested, and calls to
1269      * {@code prepareWriteEmpty} and
1270      * {@code prepareInsertEmpty} may not be interspersed.
1271      *
1272      * <p> If {@code canInsertEmpty(imageIndex)} returns
1273      * {@code false}, an
1274      * {@code UnsupportedOperationException} will be thrown.
1275      *
1276      * <p> An {@code ImageWriteParam} may optionally be supplied
1277      * to control the writing process.  If {@code param} is
1278      * {@code null}, a default write param will be used.
1279      *
1280      * <p> If the supplied {@code ImageWriteParam} contains
1281      * optional setting values not supported by this writer (<i>e.g.</i>
1282      * progressive encoding or any format-specific settings), they
1283      * will be ignored.
1284      *
1285      * <p> The default implementation throws an
1286      * {@code IllegalStateException} if the output is
1287      * {@code null}, and otherwise throws an
1288      * {@code UnsupportedOperationException}.
1289      *
1290      * @param imageIndex the index at which to write the image.
1291      * @param imageType an {@code ImageTypeSpecifier} describing
1292      * the layout of the image.
1293      * @param width the width of the image.
1294      * @param height the height of the image.
1295      * @param imageMetadata an {@code IIOMetadata} object
1296      * representing image metadata, or {@code null}.
1297      * @param thumbnails a {@code List} of
1298      * {@code BufferedImage} thumbnails for this image, or
1299      * {@code null}.
1300      * @param param an {@code ImageWriteParam}, or
1301      * {@code null} to use a default
1302      * {@code ImageWriteParam}.
1303      *
1304      * @exception IllegalStateException if the output has not
1305      * been set.
1306      * @exception UnsupportedOperationException if
1307      * {@code canInsertEmpty(imageIndex)} returns
1308      * {@code false}.
1309      * @exception IndexOutOfBoundsException if {@code imageIndex}
1310      * is less than -1 or greater than the largest available index.
1311      * @exception IllegalStateException if a previous call to
1312      * {@code prepareInsertEmpty} has been made without a
1313      * corresponding call to {@code endInsertEmpty}.
1314      * @exception IllegalStateException if a previous call to
1315      * {@code prepareWriteEmpty} has been made without a
1316      * corresponding call to {@code endWriteEmpty}.
1317      * @exception IllegalArgumentException if {@code imageType}
1318      * is {@code null} or {@code thumbnails} contains
1319      * {@code null} references or objects other than
1320      * {@code BufferedImage}s.
1321      * @exception IllegalArgumentException if width or height are less
1322      * than 1.
1323      * @exception IOException if an I/O error occurs during writing.
1324      */
prepareInsertEmpty(int imageIndex, ImageTypeSpecifier imageType, int width, int height, IIOMetadata imageMetadata, List<? extends BufferedImage> thumbnails, ImageWriteParam param)1325     public void prepareInsertEmpty(int imageIndex,
1326                                    ImageTypeSpecifier imageType,
1327                                    int width, int height,
1328                                    IIOMetadata imageMetadata,
1329                                    List<? extends BufferedImage> thumbnails,
1330                                    ImageWriteParam param) throws IOException {
1331         unsupported();
1332     }
1333 
1334     /**
1335      * Completes the insertion of a new image that was begun with a
1336      * prior call to {@code prepareInsertEmpty}.
1337      *
1338      * <p> The default implementation throws an
1339      * {@code IllegalStateException} if the output is
1340      * {@code null}, and otherwise throws an
1341      * {@code UnsupportedOperationException}.
1342      *
1343      * @exception IllegalStateException if the output has not
1344      * been set.
1345      * @exception UnsupportedOperationException if
1346      * {@code canInsertEmpty(imageIndex)} returns
1347      * {@code false}.
1348      * @exception IllegalStateException if a previous call to
1349      * {@code prepareInsertEmpty} without a corresponding call to
1350      * {@code endInsertEmpty} has not been made.
1351      * @exception IllegalStateException if a previous call to
1352      * {@code prepareWriteEmpty} without a corresponding call to
1353      * {@code endWriteEmpty} has been made.
1354      * @exception IllegalStateException if a call to
1355      * {@code prepareReplacePixels} has been made without a
1356      * matching call to {@code endReplacePixels}.
1357      * @exception IOException if an I/O error occurs during writing.
1358      */
endInsertEmpty()1359     public void endInsertEmpty() throws IOException {
1360         unsupported();
1361     }
1362 
1363     // Pixel replacement
1364 
1365     /**
1366      * Returns {@code true} if the writer allows pixels of the
1367      * given image to be replaced using the {@code replacePixels}
1368      * methods.
1369      *
1370      * <p> A writer that does not support any pixel replacement may
1371      * return {@code false} without performing bounds checking on
1372      * the index.
1373      *
1374      * <p> The default implementation throws an
1375      * {@code IllegalStateException} if the output is
1376      * {@code null}, and otherwise returns {@code false}
1377      * without checking the value of {@code imageIndex}.
1378      *
1379      * @param imageIndex the index of the image whose pixels are to be
1380      * replaced.
1381      *
1382      * @return {@code true} if the pixels of the given
1383      * image can be replaced.
1384      *
1385      * @exception IllegalStateException if the output has not been
1386      * set.
1387      * @exception IndexOutOfBoundsException if the writer supports
1388      * pixel replacement in general, but {@code imageIndex} is
1389      * less than 0 or greater than the largest available index.
1390      * @exception IOException if an I/O error occurs during the query.
1391      */
canReplacePixels(int imageIndex)1392     public boolean canReplacePixels(int imageIndex) throws IOException {
1393         if (getOutput() == null) {
1394             throw new IllegalStateException("getOutput() == null!");
1395         }
1396         return false;
1397     }
1398 
1399     /**
1400      * Prepares the writer to handle a series of calls to the
1401      * {@code replacePixels} methods.  The affected pixel area
1402      * will be clipped against the supplied
1403      *
1404      * <p> If {@code canReplacePixels} returns
1405      * {@code false}, and
1406      * {@code UnsupportedOperationException} will be thrown.
1407      *
1408      * <p> The default implementation throws an
1409      * {@code IllegalStateException} if the output is
1410      * {@code null}, and otherwise throws an
1411      * {@code UnsupportedOperationException}.
1412      *
1413      * @param imageIndex the index of the image whose pixels are to be
1414      * replaced.
1415      * @param region a {@code Rectangle} that will be used to clip
1416      * future pixel regions.
1417      *
1418      * @exception IllegalStateException if the output has not
1419      * been set.
1420      * @exception UnsupportedOperationException if
1421      * {@code canReplacePixels(imageIndex)} returns
1422      * {@code false}.
1423      * @exception IndexOutOfBoundsException if {@code imageIndex}
1424      * is less than 0 or greater than the largest available index.
1425      * @exception IllegalStateException if there is a previous call to
1426      * {@code prepareReplacePixels} without a matching call to
1427      * {@code endReplacePixels} (<i>i.e.</i>, nesting is not
1428      * allowed).
1429      * @exception IllegalArgumentException if {@code region} is
1430      * {@code null} or has a width or height less than 1.
1431      * @exception IOException if an I/O error occurs during the
1432      * preparation.
1433      */
prepareReplacePixels(int imageIndex, Rectangle region)1434     public void prepareReplacePixels(int imageIndex,
1435                                      Rectangle region)  throws IOException {
1436         unsupported();
1437     }
1438 
1439     /**
1440      * Replaces a portion of an image already present in the output
1441      * with a portion of the given image.  The image data must match,
1442      * or be convertible to, the image layout of the existing image.
1443      *
1444      * <p> The destination region is specified in the
1445      * {@code param} argument, and will be clipped to the image
1446      * boundaries and the region supplied to
1447      * {@code prepareReplacePixels}.  At least one pixel of the
1448      * source must not be clipped, or an exception is thrown.
1449      *
1450      * <p> An {@code ImageWriteParam} may optionally be supplied
1451      * to control the writing process.  If {@code param} is
1452      * {@code null}, a default write param will be used.
1453      *
1454      * <p> If the supplied {@code ImageWriteParam} contains
1455      * optional setting values not supported by this writer (<i>e.g.</i>
1456      * progressive encoding or any format-specific settings), they
1457      * will be ignored.
1458      *
1459      * <p> This method may only be called after a call to
1460      * {@code prepareReplacePixels}, or else an
1461      * {@code IllegalStateException} will be thrown.
1462      *
1463      * <p> The default implementation throws an
1464      * {@code IllegalStateException} if the output is
1465      * {@code null}, and otherwise throws an
1466      * {@code UnsupportedOperationException}.
1467      *
1468      * @param image a {@code RenderedImage} containing source
1469      * pixels.
1470      * @param param an {@code ImageWriteParam}, or
1471      * {@code null} to use a default
1472      * {@code ImageWriteParam}.
1473      *
1474      * @exception IllegalStateException if the output has not
1475      * been set.
1476      * @exception UnsupportedOperationException if
1477      * {@code canReplacePixels(imageIndex)} returns
1478      * {@code false}.
1479      * @exception IllegalStateException if there is no previous call to
1480      * {@code prepareReplacePixels} without a matching call to
1481      * {@code endReplacePixels}.
1482      * @exception IllegalArgumentException if any of the following are true:
1483      * <ul>
1484      * <li> {@code image} is {@code null}.
1485      * <li> the intersected region does not contain at least one pixel.
1486      * <li> the layout of {@code image} does not match, or this
1487      * writer cannot convert it to, the existing image layout.
1488      * </ul>
1489      * @exception IOException if an I/O error occurs during writing.
1490      */
replacePixels(RenderedImage image, ImageWriteParam param)1491     public void replacePixels(RenderedImage image, ImageWriteParam param)
1492         throws IOException {
1493         unsupported();
1494     }
1495 
1496     /**
1497      * Replaces a portion of an image already present in the output
1498      * with a portion of the given {@code Raster}.  The image
1499      * data must match, or be convertible to, the image layout of the
1500      * existing image.
1501      *
1502      * <p> An {@code ImageWriteParam} may optionally be supplied
1503      * to control the writing process.  If {@code param} is
1504      * {@code null}, a default write param will be used.
1505      *
1506      * <p> The destination region is specified in the
1507      * {@code param} argument, and will be clipped to the image
1508      * boundaries and the region supplied to
1509      * {@code prepareReplacePixels}.  At least one pixel of the
1510      * source must not be clipped, or an exception is thrown.
1511      *
1512      * <p> If the supplied {@code ImageWriteParam} contains
1513      * optional setting values not supported by this writer (<i>e.g.</i>
1514      * progressive encoding or any format-specific settings), they
1515      * will be ignored.
1516      *
1517      * <p> This method may only be called after a call to
1518      * {@code prepareReplacePixels}, or else an
1519      * {@code IllegalStateException} will be thrown.
1520      *
1521      * <p> The default implementation throws an
1522      * {@code IllegalStateException} if the output is
1523      * {@code null}, and otherwise throws an
1524      * {@code UnsupportedOperationException}.
1525      *
1526      * @param raster a {@code Raster} containing source
1527      * pixels.
1528      * @param param an {@code ImageWriteParam}, or
1529      * {@code null} to use a default
1530      * {@code ImageWriteParam}.
1531      *
1532      * @exception IllegalStateException if the output has not
1533      * been set.
1534      * @exception UnsupportedOperationException if
1535      * {@code canReplacePixels(imageIndex)} returns
1536      * {@code false}.
1537      * @exception IllegalStateException if there is no previous call to
1538      * {@code prepareReplacePixels} without a matching call to
1539      * {@code endReplacePixels}.
1540      * @exception UnsupportedOperationException if
1541      * {@code canWriteRasters} returns {@code false}.
1542      * @exception IllegalArgumentException if any of the following are true:
1543      * <ul>
1544      * <li> {@code raster} is {@code null}.
1545      * <li> the intersected region does not contain at least one pixel.
1546      * <li> the layout of {@code raster} does not match, or this
1547      * writer cannot convert it to, the existing image layout.
1548      * </ul>
1549      * @exception IOException if an I/O error occurs during writing.
1550      */
replacePixels(Raster raster, ImageWriteParam param)1551     public void replacePixels(Raster raster, ImageWriteParam param)
1552         throws IOException {
1553         unsupported();
1554     }
1555 
1556     /**
1557      * Terminates a sequence of calls to {@code replacePixels}.
1558      *
1559      * <p> If {@code canReplacePixels} returns
1560      * {@code false}, and
1561      * {@code UnsupportedOperationException} will be thrown.
1562      *
1563      * <p> The default implementation throws an
1564      * {@code IllegalStateException} if the output is
1565      * {@code null}, and otherwise throws an
1566      * {@code UnsupportedOperationException}.
1567      *
1568      * @exception IllegalStateException if the output has not
1569      * been set.
1570      * @exception UnsupportedOperationException if
1571      * {@code canReplacePixels(imageIndex)} returns
1572      * {@code false}.
1573      * @exception IllegalStateException if there is no previous call
1574      * to {@code prepareReplacePixels} without a matching call to
1575      * {@code endReplacePixels}.
1576      * @exception IOException if an I/O error occurs during writing.
1577      */
endReplacePixels()1578     public void endReplacePixels() throws IOException {
1579         unsupported();
1580     }
1581 
1582     // Abort
1583 
1584     /**
1585      * Requests that any current write operation be aborted.  The
1586      * contents of the output following the abort will be undefined.
1587      *
1588      * <p> Writers should call {@code clearAbortRequest} at the
1589      * beginning of each write operation, and poll the value of
1590      * {@code abortRequested} regularly during the write.
1591      */
abort()1592     public synchronized void abort() {
1593         this.abortFlag = true;
1594     }
1595 
1596     /**
1597      * Returns {@code true} if a request to abort the current
1598      * write operation has been made since the writer was instantiated or
1599      * {@code clearAbortRequest} was called.
1600      *
1601      * @return {@code true} if the current write operation should
1602      * be aborted.
1603      *
1604      * @see #abort
1605      * @see #clearAbortRequest
1606      */
abortRequested()1607     protected synchronized boolean abortRequested() {
1608         return this.abortFlag;
1609     }
1610 
1611     /**
1612      * Clears any previous abort request.  After this method has been
1613      * called, {@code abortRequested} will return
1614      * {@code false}.
1615      *
1616      * @see #abort
1617      * @see #abortRequested
1618      */
clearAbortRequest()1619     protected synchronized void clearAbortRequest() {
1620         this.abortFlag = false;
1621     }
1622 
1623     // Listeners
1624 
1625     /**
1626      * Adds an {@code IIOWriteWarningListener} to the list of
1627      * registered warning listeners.  If {@code listener} is
1628      * {@code null}, no exception will be thrown and no action
1629      * will be taken.  Messages sent to the given listener will be
1630      * localized, if possible, to match the current
1631      * {@code Locale}.  If no {@code Locale} has been set,
1632      * warning messages may be localized as the writer sees fit.
1633      *
1634      * @param listener an {@code IIOWriteWarningListener} to be
1635      * registered.
1636      *
1637      * @see #removeIIOWriteWarningListener
1638      */
addIIOWriteWarningListener(IIOWriteWarningListener listener)1639     public void addIIOWriteWarningListener(IIOWriteWarningListener listener) {
1640         if (listener == null) {
1641             return;
1642         }
1643         warningListeners = ImageReader.addToList(warningListeners, listener);
1644         warningLocales = ImageReader.addToList(warningLocales, getLocale());
1645     }
1646 
1647     /**
1648      * Removes an {@code IIOWriteWarningListener} from the list
1649      * of registered warning listeners.  If the listener was not
1650      * previously registered, or if {@code listener} is
1651      * {@code null}, no exception will be thrown and no action
1652      * will be taken.
1653      *
1654      * @param listener an {@code IIOWriteWarningListener} to be
1655      * deregistered.
1656      *
1657      * @see #addIIOWriteWarningListener
1658      */
1659     public
removeIIOWriteWarningListener(IIOWriteWarningListener listener)1660         void removeIIOWriteWarningListener(IIOWriteWarningListener listener) {
1661         if (listener == null || warningListeners == null) {
1662             return;
1663         }
1664         int index = warningListeners.indexOf(listener);
1665         if (index != -1) {
1666             warningListeners.remove(index);
1667             warningLocales.remove(index);
1668             if (warningListeners.size() == 0) {
1669                 warningListeners = null;
1670                 warningLocales = null;
1671             }
1672         }
1673     }
1674 
1675     /**
1676      * Removes all currently registered
1677      * {@code IIOWriteWarningListener} objects.
1678      *
1679      * <p> The default implementation sets the
1680      * {@code warningListeners} and {@code warningLocales}
1681      * instance variables to {@code null}.
1682      */
removeAllIIOWriteWarningListeners()1683     public void removeAllIIOWriteWarningListeners() {
1684         this.warningListeners = null;
1685         this.warningLocales = null;
1686     }
1687 
1688     /**
1689      * Adds an {@code IIOWriteProgressListener} to the list of
1690      * registered progress listeners.  If {@code listener} is
1691      * {@code null}, no exception will be thrown and no action
1692      * will be taken.
1693      *
1694      * @param listener an {@code IIOWriteProgressListener} to be
1695      * registered.
1696      *
1697      * @see #removeIIOWriteProgressListener
1698      */
1699     public void
addIIOWriteProgressListener(IIOWriteProgressListener listener)1700         addIIOWriteProgressListener(IIOWriteProgressListener listener) {
1701         if (listener == null) {
1702             return;
1703         }
1704         progressListeners = ImageReader.addToList(progressListeners, listener);
1705     }
1706 
1707     /**
1708      * Removes an {@code IIOWriteProgressListener} from the list
1709      * of registered progress listeners.  If the listener was not
1710      * previously registered, or if {@code listener} is
1711      * {@code null}, no exception will be thrown and no action
1712      * will be taken.
1713      *
1714      * @param listener an {@code IIOWriteProgressListener} to be
1715      * deregistered.
1716      *
1717      * @see #addIIOWriteProgressListener
1718      */
1719     public void
removeIIOWriteProgressListener(IIOWriteProgressListener listener)1720         removeIIOWriteProgressListener(IIOWriteProgressListener listener) {
1721         if (listener == null || progressListeners == null) {
1722             return;
1723         }
1724         progressListeners =
1725             ImageReader.removeFromList(progressListeners, listener);
1726     }
1727 
1728     /**
1729      * Removes all currently registered
1730      * {@code IIOWriteProgressListener} objects.
1731      *
1732      * <p> The default implementation sets the
1733      * {@code progressListeners} instance variable to
1734      * {@code null}.
1735      */
removeAllIIOWriteProgressListeners()1736     public void removeAllIIOWriteProgressListeners() {
1737         this.progressListeners = null;
1738     }
1739 
1740     /**
1741      * Broadcasts the start of an image write to all registered
1742      * {@code IIOWriteProgressListener}s by calling their
1743      * {@code imageStarted} method.  Subclasses may use this
1744      * method as a convenience.
1745      *
1746      * @param imageIndex the index of the image about to be written.
1747      */
processImageStarted(int imageIndex)1748     protected void processImageStarted(int imageIndex) {
1749         if (progressListeners == null) {
1750             return;
1751         }
1752         int numListeners = progressListeners.size();
1753         for (int i = 0; i < numListeners; i++) {
1754             IIOWriteProgressListener listener =
1755                 progressListeners.get(i);
1756             listener.imageStarted(this, imageIndex);
1757         }
1758     }
1759 
1760     /**
1761      * Broadcasts the current percentage of image completion to all
1762      * registered {@code IIOWriteProgressListener}s by calling
1763      * their {@code imageProgress} method.  Subclasses may use
1764      * this method as a convenience.
1765      *
1766      * @param percentageDone the current percentage of completion,
1767      * as a {@code float}.
1768      */
processImageProgress(float percentageDone)1769     protected void processImageProgress(float percentageDone) {
1770         if (progressListeners == null) {
1771             return;
1772         }
1773         int numListeners = progressListeners.size();
1774         for (int i = 0; i < numListeners; i++) {
1775             IIOWriteProgressListener listener =
1776                 progressListeners.get(i);
1777             listener.imageProgress(this, percentageDone);
1778         }
1779     }
1780 
1781     /**
1782      * Broadcasts the completion of an image write to all registered
1783      * {@code IIOWriteProgressListener}s by calling their
1784      * {@code imageComplete} method.  Subclasses may use this
1785      * method as a convenience.
1786      */
processImageComplete()1787     protected void processImageComplete() {
1788         if (progressListeners == null) {
1789             return;
1790         }
1791         int numListeners = progressListeners.size();
1792         for (int i = 0; i < numListeners; i++) {
1793             IIOWriteProgressListener listener =
1794                 progressListeners.get(i);
1795             listener.imageComplete(this);
1796         }
1797     }
1798 
1799     /**
1800      * Broadcasts the start of a thumbnail write to all registered
1801      * {@code IIOWriteProgressListener}s by calling their
1802      * {@code thumbnailStarted} method.  Subclasses may use this
1803      * method as a convenience.
1804      *
1805      * @param imageIndex the index of the image associated with the
1806      * thumbnail.
1807      * @param thumbnailIndex the index of the thumbnail.
1808      */
processThumbnailStarted(int imageIndex, int thumbnailIndex)1809     protected void processThumbnailStarted(int imageIndex,
1810                                            int thumbnailIndex) {
1811         if (progressListeners == null) {
1812             return;
1813         }
1814         int numListeners = progressListeners.size();
1815         for (int i = 0; i < numListeners; i++) {
1816             IIOWriteProgressListener listener =
1817                 progressListeners.get(i);
1818             listener.thumbnailStarted(this, imageIndex, thumbnailIndex);
1819         }
1820     }
1821 
1822     /**
1823      * Broadcasts the current percentage of thumbnail completion to
1824      * all registered {@code IIOWriteProgressListener}s by calling
1825      * their {@code thumbnailProgress} method.  Subclasses may
1826      * use this method as a convenience.
1827      *
1828      * @param percentageDone the current percentage of completion,
1829      * as a {@code float}.
1830      */
processThumbnailProgress(float percentageDone)1831     protected void processThumbnailProgress(float percentageDone) {
1832         if (progressListeners == null) {
1833             return;
1834         }
1835         int numListeners = progressListeners.size();
1836         for (int i = 0; i < numListeners; i++) {
1837             IIOWriteProgressListener listener =
1838                 progressListeners.get(i);
1839             listener.thumbnailProgress(this, percentageDone);
1840         }
1841     }
1842 
1843     /**
1844      * Broadcasts the completion of a thumbnail write to all registered
1845      * {@code IIOWriteProgressListener}s by calling their
1846      * {@code thumbnailComplete} method.  Subclasses may use this
1847      * method as a convenience.
1848      */
processThumbnailComplete()1849     protected void processThumbnailComplete() {
1850         if (progressListeners == null) {
1851             return;
1852         }
1853         int numListeners = progressListeners.size();
1854         for (int i = 0; i < numListeners; i++) {
1855             IIOWriteProgressListener listener =
1856                 progressListeners.get(i);
1857             listener.thumbnailComplete(this);
1858         }
1859     }
1860 
1861     /**
1862      * Broadcasts that the write has been aborted to all registered
1863      * {@code IIOWriteProgressListener}s by calling their
1864      * {@code writeAborted} method.  Subclasses may use this
1865      * method as a convenience.
1866      */
processWriteAborted()1867     protected void processWriteAborted() {
1868         if (progressListeners == null) {
1869             return;
1870         }
1871         int numListeners = progressListeners.size();
1872         for (int i = 0; i < numListeners; i++) {
1873             IIOWriteProgressListener listener =
1874                 progressListeners.get(i);
1875             listener.writeAborted(this);
1876         }
1877     }
1878 
1879     /**
1880      * Broadcasts a warning message to all registered
1881      * {@code IIOWriteWarningListener}s by calling their
1882      * {@code warningOccurred} method.  Subclasses may use this
1883      * method as a convenience.
1884      *
1885      * @param imageIndex the index of the image on which the warning
1886      * occurred.
1887      * @param warning the warning message.
1888      *
1889      * @exception IllegalArgumentException if {@code warning}
1890      * is {@code null}.
1891      */
processWarningOccurred(int imageIndex, String warning)1892     protected void processWarningOccurred(int imageIndex,
1893                                           String warning) {
1894         if (warningListeners == null) {
1895             return;
1896         }
1897         if (warning == null) {
1898             throw new IllegalArgumentException("warning == null!");
1899         }
1900         int numListeners = warningListeners.size();
1901         for (int i = 0; i < numListeners; i++) {
1902             IIOWriteWarningListener listener =
1903                 warningListeners.get(i);
1904 
1905             listener.warningOccurred(this, imageIndex, warning);
1906         }
1907     }
1908 
1909     /**
1910      * Broadcasts a localized warning message to all registered
1911      * {@code IIOWriteWarningListener}s by calling their
1912      * {@code warningOccurred} method with a string taken
1913      * from a {@code ResourceBundle}.  Subclasses may use this
1914      * method as a convenience.
1915      *
1916      * @param imageIndex the index of the image on which the warning
1917      * occurred.
1918      * @param baseName the base name of a set of
1919      * {@code ResourceBundle}s containing localized warning
1920      * messages.
1921      * @param keyword the keyword used to index the warning message
1922      * within the set of {@code ResourceBundle}s.
1923      *
1924      * @exception IllegalArgumentException if {@code baseName}
1925      * is {@code null}.
1926      * @exception IllegalArgumentException if {@code keyword}
1927      * is {@code null}.
1928      * @exception IllegalArgumentException if no appropriate
1929      * {@code ResourceBundle} may be located.
1930      * @exception IllegalArgumentException if the named resource is
1931      * not found in the located {@code ResourceBundle}.
1932      * @exception IllegalArgumentException if the object retrieved
1933      * from the {@code ResourceBundle} is not a
1934      * {@code String}.
1935      */
processWarningOccurred(int imageIndex, String baseName, String keyword)1936     protected void processWarningOccurred(int imageIndex,
1937                                           String baseName,
1938                                           String keyword) {
1939         if (warningListeners == null) {
1940             return;
1941         }
1942         if (baseName == null) {
1943             throw new IllegalArgumentException("baseName == null!");
1944         }
1945         if (keyword == null) {
1946             throw new IllegalArgumentException("keyword == null!");
1947         }
1948         int numListeners = warningListeners.size();
1949         for (int i = 0; i < numListeners; i++) {
1950             IIOWriteWarningListener listener =
1951                 warningListeners.get(i);
1952             Locale locale = warningLocales.get(i);
1953             if (locale == null) {
1954                 locale = Locale.getDefault();
1955             }
1956 
1957             /*
1958              * Only the plugin knows the messages that are provided, so we
1959              * can always locate the resource bundles from the same loader
1960              * as that for the plugin code itself.
1961              */
1962             ResourceBundle bundle = null;
1963             try {
1964                 bundle = ResourceBundle.getBundle(baseName, locale, this.getClass().getModule());
1965             } catch (MissingResourceException mre) {
1966                 throw new IllegalArgumentException("Bundle not found!", mre);
1967             }
1968 
1969             String warning = null;
1970             try {
1971                 warning = bundle.getString(keyword);
1972             } catch (ClassCastException cce) {
1973                 throw new IllegalArgumentException("Resource is not a String!", cce);
1974             } catch (MissingResourceException mre) {
1975                 throw new IllegalArgumentException("Resource is missing!", mre);
1976             }
1977 
1978             listener.warningOccurred(this, imageIndex, warning);
1979         }
1980     }
1981 
1982     // State management
1983 
1984     /**
1985      * Restores the {@code ImageWriter} to its initial state.
1986      *
1987      * <p> The default implementation calls
1988      * {@code setOutput(null)}, {@code setLocale(null)},
1989      * {@code removeAllIIOWriteWarningListeners()},
1990      * {@code removeAllIIOWriteProgressListeners()}, and
1991      * {@code clearAbortRequest}.
1992      */
reset()1993     public void reset() {
1994         setOutput(null);
1995         setLocale(null);
1996         removeAllIIOWriteWarningListeners();
1997         removeAllIIOWriteProgressListeners();
1998         clearAbortRequest();
1999     }
2000 
2001     /**
2002      * Allows any resources held by this object to be released.  The
2003      * result of calling any other method (other than
2004      * {@code finalize}) subsequent to a call to this method
2005      * is undefined.
2006      *
2007      * <p>It is important for applications to call this method when they
2008      * know they will no longer be using this {@code ImageWriter}.
2009      * Otherwise, the writer may continue to hold on to resources
2010      * indefinitely.
2011      *
2012      * <p>The default implementation of this method in the superclass does
2013      * nothing.  Subclass implementations should ensure that all resources,
2014      * especially native resources, are released.
2015      */
dispose()2016     public void dispose() {
2017     }
2018 }
2019