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