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