src/java.desktop/share/classes/javax/imageio/ImageWriteParam.java
changeset 47216 71c04702a3d5
parent 35667 ed476aba94de
child 50095 bf2f27b92064
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2000, 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.util.Locale;
       
    30 
       
    31 /**
       
    32  * A class describing how a stream is to be encoded.  Instances of
       
    33  * this class or its subclasses are used to supply prescriptive
       
    34  * "how-to" information to instances of {@code ImageWriter}.
       
    35  *
       
    36  * <p> A plug-in for a specific image format may define a subclass of
       
    37  * this class, and return objects of that class from the
       
    38  * {@code getDefaultWriteParam} method of its
       
    39  * {@code ImageWriter} implementation.  For example, the built-in
       
    40  * JPEG writer plug-in will return instances of
       
    41  * {@code javax.imageio.plugins.jpeg.JPEGImageWriteParam}.
       
    42  *
       
    43  * <p> The region of the image to be written is determined by first
       
    44  * intersecting the actual bounds of the image with the rectangle
       
    45  * specified by {@code IIOParam.setSourceRegion}, if any.  If the
       
    46  * resulting rectangle has a width or height of zero, the writer will
       
    47  * throw an {@code IIOException}. If the intersection is
       
    48  * non-empty, writing will commence with the first subsampled pixel
       
    49  * and include additional pixels within the intersected bounds
       
    50  * according to the horizontal and vertical subsampling factors
       
    51  * specified by {@link IIOParam#setSourceSubsampling
       
    52  * IIOParam.setSourceSubsampling}.
       
    53  *
       
    54  * <p> Individual features such as tiling, progressive encoding, and
       
    55  * compression may be set in one of four modes.
       
    56  * {@code MODE_DISABLED} disables the features;
       
    57  * {@code MODE_DEFAULT} enables the feature with
       
    58  * writer-controlled parameter values; {@code MODE_EXPLICIT}
       
    59  * enables the feature and allows the use of a {@code set} method
       
    60  * to provide additional parameters; and
       
    61  * {@code MODE_COPY_FROM_METADATA} copies relevant parameter
       
    62  * values from the stream and image metadata objects passed to the
       
    63  * writer.  The default for all features is
       
    64  * {@code MODE_COPY_FROM_METADATA}.  Non-standard features
       
    65  * supplied in subclasses are encouraged, but not required to use a
       
    66  * similar scheme.
       
    67  *
       
    68  * <p> Plug-in writers may extend the functionality of
       
    69  * {@code ImageWriteParam} by providing a subclass that implements
       
    70  * additional, plug-in specific interfaces.  It is up to the plug-in
       
    71  * to document what interfaces are available and how they are to be
       
    72  * used.  Writers will silently ignore any extended features of an
       
    73  * {@code ImageWriteParam} subclass of which they are not aware.
       
    74  * Also, they may ignore any optional features that they normally
       
    75  * disable when creating their own {@code ImageWriteParam}
       
    76  * instances via {@code getDefaultWriteParam}.
       
    77  *
       
    78  * <p> Note that unless a query method exists for a capability, it must
       
    79  * be supported by all {@code ImageWriter} implementations
       
    80  * (<i>e.g.</i> progressive encoding is optional, but subsampling must be
       
    81  * supported).
       
    82  *
       
    83  *
       
    84  * @see ImageReadParam
       
    85  */
       
    86 public class ImageWriteParam extends IIOParam {
       
    87 
       
    88     /**
       
    89      * A constant value that may be passed into methods such as
       
    90      * {@code setTilingMode}, {@code setProgressiveMode},
       
    91      * and {@code setCompressionMode} to disable a feature for
       
    92      * future writes.  That is, when this mode is set the stream will
       
    93      * <b>not</b> be tiled, progressive, or compressed, and the
       
    94      * relevant accessor methods will throw an
       
    95      * {@code IllegalStateException}.
       
    96      *
       
    97      * @see #MODE_EXPLICIT
       
    98      * @see #MODE_COPY_FROM_METADATA
       
    99      * @see #MODE_DEFAULT
       
   100      * @see #setProgressiveMode
       
   101      * @see #getProgressiveMode
       
   102      * @see #setTilingMode
       
   103      * @see #getTilingMode
       
   104      * @see #setCompressionMode
       
   105      * @see #getCompressionMode
       
   106      */
       
   107     public static final int MODE_DISABLED = 0;
       
   108 
       
   109     /**
       
   110      * A constant value that may be passed into methods such as
       
   111      * {@code setTilingMode},
       
   112      * {@code setProgressiveMode}, and
       
   113      * {@code setCompressionMode} to enable that feature for
       
   114      * future writes.  That is, when this mode is enabled the stream
       
   115      * will be tiled, progressive, or compressed according to a
       
   116      * sensible default chosen internally by the writer in a plug-in
       
   117      * dependent way, and the relevant accessor methods will
       
   118      * throw an {@code IllegalStateException}.
       
   119      *
       
   120      * @see #MODE_DISABLED
       
   121      * @see #MODE_EXPLICIT
       
   122      * @see #MODE_COPY_FROM_METADATA
       
   123      * @see #setProgressiveMode
       
   124      * @see #getProgressiveMode
       
   125      * @see #setTilingMode
       
   126      * @see #getTilingMode
       
   127      * @see #setCompressionMode
       
   128      * @see #getCompressionMode
       
   129      */
       
   130     public static final int MODE_DEFAULT = 1;
       
   131 
       
   132     /**
       
   133      * A constant value that may be passed into methods such as
       
   134      * {@code setTilingMode} or {@code setCompressionMode}
       
   135      * to enable a feature for future writes. That is, when this mode
       
   136      * is set the stream will be tiled or compressed according to
       
   137      * additional information supplied to the corresponding
       
   138      * {@code set} methods in this class and retrievable from the
       
   139      * corresponding {@code get} methods.  Note that this mode is
       
   140      * not supported for progressive output.
       
   141      *
       
   142      * @see #MODE_DISABLED
       
   143      * @see #MODE_COPY_FROM_METADATA
       
   144      * @see #MODE_DEFAULT
       
   145      * @see #setProgressiveMode
       
   146      * @see #getProgressiveMode
       
   147      * @see #setTilingMode
       
   148      * @see #getTilingMode
       
   149      * @see #setCompressionMode
       
   150      * @see #getCompressionMode
       
   151      */
       
   152     public static final int MODE_EXPLICIT = 2;
       
   153 
       
   154     /**
       
   155      * A constant value that may be passed into methods such as
       
   156      * {@code setTilingMode}, {@code setProgressiveMode}, or
       
   157      * {@code setCompressionMode} to enable that feature for
       
   158      * future writes.  That is, when this mode is enabled the stream
       
   159      * will be tiled, progressive, or compressed based on the contents
       
   160      * of stream and/or image metadata passed into the write
       
   161      * operation, and any relevant accessor methods will throw an
       
   162      * {@code IllegalStateException}.
       
   163      *
       
   164      * <p> This is the default mode for all features, so that a read
       
   165      * including metadata followed by a write including metadata will
       
   166      * preserve as much information as possible.
       
   167      *
       
   168      * @see #MODE_DISABLED
       
   169      * @see #MODE_EXPLICIT
       
   170      * @see #MODE_DEFAULT
       
   171      * @see #setProgressiveMode
       
   172      * @see #getProgressiveMode
       
   173      * @see #setTilingMode
       
   174      * @see #getTilingMode
       
   175      * @see #setCompressionMode
       
   176      * @see #getCompressionMode
       
   177      */
       
   178     public static final int MODE_COPY_FROM_METADATA = 3;
       
   179 
       
   180     // If more modes are added, this should be updated.
       
   181     private static final int MAX_MODE = MODE_COPY_FROM_METADATA;
       
   182 
       
   183     /**
       
   184      * A {@code boolean} that is {@code true} if this
       
   185      * {@code ImageWriteParam} allows tile width and tile height
       
   186      * parameters to be set.  By default, the value is
       
   187      * {@code false}.  Subclasses must set the value manually.
       
   188      *
       
   189      * <p> Subclasses that do not support writing tiles should ensure
       
   190      * that this value is set to {@code false}.
       
   191      */
       
   192     protected boolean canWriteTiles = false;
       
   193 
       
   194     /**
       
   195      * The mode controlling tiling settings, which Must be
       
   196      * set to one of the four {@code MODE_*} values.  The default
       
   197      * is {@code MODE_COPY_FROM_METADATA}.
       
   198      *
       
   199      * <p> Subclasses that do not writing tiles may ignore this value.
       
   200      *
       
   201      * @see #MODE_DISABLED
       
   202      * @see #MODE_EXPLICIT
       
   203      * @see #MODE_COPY_FROM_METADATA
       
   204      * @see #MODE_DEFAULT
       
   205      * @see #setTilingMode
       
   206      * @see #getTilingMode
       
   207      */
       
   208     protected int tilingMode = MODE_COPY_FROM_METADATA;
       
   209 
       
   210     /**
       
   211      * An array of preferred tile size range pairs.  The default value
       
   212      * is {@code null}, which indicates that there are no
       
   213      * preferred sizes.  If the value is non-{@code null}, it
       
   214      * must have an even length of at least two.
       
   215      *
       
   216      * <p> Subclasses that do not support writing tiles may ignore
       
   217      * this value.
       
   218      *
       
   219      * @see #getPreferredTileSizes
       
   220      */
       
   221     protected Dimension[] preferredTileSizes = null;
       
   222 
       
   223     /**
       
   224      * A {@code boolean} that is {@code true} if tiling
       
   225      * parameters have been specified.
       
   226      *
       
   227      * <p> Subclasses that do not support writing tiles may ignore
       
   228      * this value.
       
   229      */
       
   230     protected boolean tilingSet = false;
       
   231 
       
   232     /**
       
   233      * The width of each tile if tiling has been set, or 0 otherwise.
       
   234      *
       
   235      * <p> Subclasses that do not support tiling may ignore this
       
   236      * value.
       
   237      */
       
   238     protected int tileWidth = 0;
       
   239 
       
   240     /**
       
   241      * The height of each tile if tiling has been set, or 0 otherwise.
       
   242      * The initial value is {@code 0}.
       
   243      *
       
   244      * <p> Subclasses that do not support tiling may ignore this
       
   245      * value.
       
   246      */
       
   247     protected int tileHeight = 0;
       
   248 
       
   249     /**
       
   250      * A {@code boolean} that is {@code true} if this
       
   251      * {@code ImageWriteParam} allows tiling grid offset
       
   252      * parameters to be set.  By default, the value is
       
   253      * {@code false}.  Subclasses must set the value manually.
       
   254      *
       
   255      * <p> Subclasses that do not support writing tiles, or that
       
   256      * support writing but not offsetting tiles must ensure that this
       
   257      * value is set to {@code false}.
       
   258      */
       
   259     protected boolean canOffsetTiles = false;
       
   260 
       
   261     /**
       
   262      * The amount by which the tile grid origin should be offset
       
   263      * horizontally from the image origin if tiling has been set,
       
   264      * or 0 otherwise.  The initial value is {@code 0}.
       
   265      *
       
   266      * <p> Subclasses that do not support offsetting tiles may ignore
       
   267      * this value.
       
   268      */
       
   269     protected int tileGridXOffset = 0;
       
   270 
       
   271     /**
       
   272      * The amount by which the tile grid origin should be offset
       
   273      * vertically from the image origin if tiling has been set,
       
   274      * or 0 otherwise.  The initial value is {@code 0}.
       
   275      *
       
   276      * <p> Subclasses that do not support offsetting tiles may ignore
       
   277      * this value.
       
   278      */
       
   279     protected int tileGridYOffset = 0;
       
   280 
       
   281     /**
       
   282      * A {@code boolean} that is {@code true} if this
       
   283      * {@code ImageWriteParam} allows images to be written as a
       
   284      * progressive sequence of increasing quality passes.  By default,
       
   285      * the value is {@code false}.  Subclasses must set the value
       
   286      * manually.
       
   287      *
       
   288      * <p> Subclasses that do not support progressive encoding must
       
   289      * ensure that this value is set to {@code false}.
       
   290      */
       
   291     protected boolean canWriteProgressive = false;
       
   292 
       
   293     /**
       
   294      * The mode controlling progressive encoding, which must be set to
       
   295      * one of the four {@code MODE_*} values, except
       
   296      * {@code MODE_EXPLICIT}.  The default is
       
   297      * {@code MODE_COPY_FROM_METADATA}.
       
   298      *
       
   299      * <p> Subclasses that do not support progressive encoding may
       
   300      * ignore this value.
       
   301      *
       
   302      * @see #MODE_DISABLED
       
   303      * @see #MODE_EXPLICIT
       
   304      * @see #MODE_COPY_FROM_METADATA
       
   305      * @see #MODE_DEFAULT
       
   306      * @see #setProgressiveMode
       
   307      * @see #getProgressiveMode
       
   308      */
       
   309     protected int progressiveMode = MODE_COPY_FROM_METADATA;
       
   310 
       
   311     /**
       
   312      * A {@code boolean} that is {@code true} if this writer
       
   313      * can write images using compression. By default, the value is
       
   314      * {@code false}.  Subclasses must set the value manually.
       
   315      *
       
   316      * <p> Subclasses that do not support compression must ensure that
       
   317      * this value is set to {@code false}.
       
   318      */
       
   319     protected boolean canWriteCompressed = false;
       
   320 
       
   321     /**
       
   322      * The mode controlling compression settings, which must be set to
       
   323      * one of the four {@code MODE_*} values.  The default is
       
   324      * {@code MODE_COPY_FROM_METADATA}.
       
   325      *
       
   326      * <p> Subclasses that do not support compression may ignore this
       
   327      * value.
       
   328      *
       
   329      * @see #MODE_DISABLED
       
   330      * @see #MODE_EXPLICIT
       
   331      * @see #MODE_COPY_FROM_METADATA
       
   332      * @see #MODE_DEFAULT
       
   333      * @see #setCompressionMode
       
   334      * @see #getCompressionMode
       
   335      */
       
   336     protected int compressionMode = MODE_COPY_FROM_METADATA;
       
   337 
       
   338     /**
       
   339      * An array of {@code String}s containing the names of the
       
   340      * available compression types.  Subclasses must set the value
       
   341      * manually.
       
   342      *
       
   343      * <p> Subclasses that do not support compression may ignore this
       
   344      * value.
       
   345      */
       
   346     protected String[] compressionTypes = null;
       
   347 
       
   348     /**
       
   349      * A {@code String} containing the name of the current
       
   350      * compression type, or {@code null} if none is set.
       
   351      *
       
   352      * <p> Subclasses that do not support compression may ignore this
       
   353      * value.
       
   354      */
       
   355     protected String compressionType = null;
       
   356 
       
   357     /**
       
   358      * A {@code float} containing the current compression quality
       
   359      * setting.  The initial value is {@code 1.0F}.
       
   360      *
       
   361      * <p> Subclasses that do not support compression may ignore this
       
   362      * value.
       
   363      */
       
   364     protected float compressionQuality = 1.0F;
       
   365 
       
   366     /**
       
   367      * A {@code Locale} to be used to localize compression type
       
   368      * names and quality descriptions, or {@code null} to use a
       
   369      * default {@code Locale}.  Subclasses must set the value
       
   370      * manually.
       
   371      */
       
   372     protected Locale locale = null;
       
   373 
       
   374     /**
       
   375      * Constructs an empty {@code ImageWriteParam}.  It is up to
       
   376      * the subclass to set up the instance variables properly.
       
   377      */
       
   378     protected ImageWriteParam() {}
       
   379 
       
   380     /**
       
   381      * Constructs an {@code ImageWriteParam} set to use a
       
   382      * given {@code Locale}.
       
   383      *
       
   384      * @param locale a {@code Locale} to be used to localize
       
   385      * compression type names and quality descriptions, or
       
   386      * {@code null}.
       
   387      */
       
   388     public ImageWriteParam(Locale locale) {
       
   389         this.locale = locale;
       
   390     }
       
   391 
       
   392     // Return a deep copy of the array
       
   393     private static Dimension[] clonePreferredTileSizes(Dimension[] sizes) {
       
   394         if (sizes == null) {
       
   395             return null;
       
   396         }
       
   397         Dimension[] temp = new Dimension[sizes.length];
       
   398         for (int i = 0; i < sizes.length; i++) {
       
   399             temp[i] = new Dimension(sizes[i]);
       
   400         }
       
   401         return temp;
       
   402     }
       
   403 
       
   404     /**
       
   405      * Returns the currently set {@code Locale}, or
       
   406      * {@code null} if only a default {@code Locale} is
       
   407      * supported.
       
   408      *
       
   409      * @return the current {@code Locale}, or {@code null}.
       
   410      */
       
   411     public Locale getLocale() {
       
   412         return locale;
       
   413     }
       
   414 
       
   415     /**
       
   416      * Returns {@code true} if the writer can perform tiling
       
   417      * while writing.  If this method returns {@code false}, then
       
   418      * {@code setTiling} will throw an
       
   419      * {@code UnsupportedOperationException}.
       
   420      *
       
   421      * @return {@code true} if the writer supports tiling.
       
   422      *
       
   423      * @see #canOffsetTiles()
       
   424      * @see #setTiling(int, int, int, int)
       
   425      */
       
   426     public boolean canWriteTiles() {
       
   427         return canWriteTiles;
       
   428     }
       
   429 
       
   430     /**
       
   431      * Returns {@code true} if the writer can perform tiling with
       
   432      * non-zero grid offsets while writing.  If this method returns
       
   433      * {@code false}, then {@code setTiling} will throw an
       
   434      * {@code UnsupportedOperationException} if the grid offset
       
   435      * arguments are not both zero.  If {@code canWriteTiles}
       
   436      * returns {@code false}, this method will return
       
   437      * {@code false} as well.
       
   438      *
       
   439      * @return {@code true} if the writer supports non-zero tile
       
   440      * offsets.
       
   441      *
       
   442      * @see #canWriteTiles()
       
   443      * @see #setTiling(int, int, int, int)
       
   444      */
       
   445     public boolean canOffsetTiles() {
       
   446         return canOffsetTiles;
       
   447     }
       
   448 
       
   449     /**
       
   450      * Determines whether the image will be tiled in the output
       
   451      * stream and, if it will, how the tiling parameters will be
       
   452      * determined.  The modes are interpreted as follows:
       
   453      *
       
   454      * <ul>
       
   455      *
       
   456      * <li>{@code MODE_DISABLED} - The image will not be tiled.
       
   457      * {@code setTiling} will throw an
       
   458      * {@code IllegalStateException}.
       
   459      *
       
   460      * <li>{@code MODE_DEFAULT} - The image will be tiled using
       
   461      * default parameters.  {@code setTiling} will throw an
       
   462      * {@code IllegalStateException}.
       
   463      *
       
   464      * <li>{@code MODE_EXPLICIT} - The image will be tiled
       
   465      * according to parameters given in the {@link #setTiling setTiling}
       
   466      * method.  Any previously set tiling parameters are discarded.
       
   467      *
       
   468      * <li>{@code MODE_COPY_FROM_METADATA} - The image will
       
   469      * conform to the metadata object passed in to a write.
       
   470      * {@code setTiling} will throw an
       
   471      * {@code IllegalStateException}.
       
   472      *
       
   473      * </ul>
       
   474      *
       
   475      * @param mode The mode to use for tiling.
       
   476      *
       
   477      * @exception UnsupportedOperationException if
       
   478      * {@code canWriteTiles} returns {@code false}.
       
   479      * @exception IllegalArgumentException if {@code mode} is not
       
   480      * one of the modes listed above.
       
   481      *
       
   482      * @see #setTiling
       
   483      * @see #getTilingMode
       
   484      */
       
   485     public void setTilingMode(int mode) {
       
   486         if (canWriteTiles() == false) {
       
   487             throw new UnsupportedOperationException("Tiling not supported!");
       
   488         }
       
   489         if (mode < MODE_DISABLED || mode > MAX_MODE) {
       
   490             throw new IllegalArgumentException("Illegal value for mode!");
       
   491         }
       
   492         this.tilingMode = mode;
       
   493         if (mode == MODE_EXPLICIT) {
       
   494             unsetTiling();
       
   495         }
       
   496     }
       
   497 
       
   498     /**
       
   499      * Returns the current tiling mode, if tiling is supported.
       
   500      * Otherwise throws an {@code UnsupportedOperationException}.
       
   501      *
       
   502      * @return the current tiling mode.
       
   503      *
       
   504      * @exception UnsupportedOperationException if
       
   505      * {@code canWriteTiles} returns {@code false}.
       
   506      *
       
   507      * @see #setTilingMode
       
   508      */
       
   509     public int getTilingMode() {
       
   510         if (!canWriteTiles()) {
       
   511             throw new UnsupportedOperationException("Tiling not supported");
       
   512         }
       
   513         return tilingMode;
       
   514     }
       
   515 
       
   516     /**
       
   517      * Returns an array of {@code Dimension}s indicating the
       
   518      * legal size ranges for tiles as they will be encoded in the
       
   519      * output file or stream.  The returned array is a copy.
       
   520      *
       
   521      * <p> The information is returned as a set of pairs; the first
       
   522      * element of a pair contains an (inclusive) minimum width and
       
   523      * height, and the second element contains an (inclusive) maximum
       
   524      * width and height.  Together, each pair defines a valid range of
       
   525      * sizes.  To specify a fixed size, use the same width and height
       
   526      * for both elements.  To specify an arbitrary range, a value of
       
   527      * {@code null} is used in place of an actual array of
       
   528      * {@code Dimension}s.
       
   529      *
       
   530      * <p> If no array is specified on the constructor, but tiling is
       
   531      * allowed, then this method returns {@code null}.
       
   532      *
       
   533      * @exception UnsupportedOperationException if the plug-in does
       
   534      * not support tiling.
       
   535      *
       
   536      * @return an array of {@code Dimension}s with an even length
       
   537      * of at least two, or {@code null}.
       
   538      */
       
   539     public Dimension[] getPreferredTileSizes() {
       
   540         if (!canWriteTiles()) {
       
   541             throw new UnsupportedOperationException("Tiling not supported");
       
   542         }
       
   543         return clonePreferredTileSizes(preferredTileSizes);
       
   544     }
       
   545 
       
   546     /**
       
   547      * Specifies that the image should be tiled in the output stream.
       
   548      * The {@code tileWidth} and {@code tileHeight}
       
   549      * parameters specify the width and height of the tiles in the
       
   550      * file.  If the tile width or height is greater than the width or
       
   551      * height of the image, the image is not tiled in that dimension.
       
   552      *
       
   553      * <p> If {@code canOffsetTiles} returns {@code false},
       
   554      * then the {@code tileGridXOffset} and
       
   555      * {@code tileGridYOffset} parameters must be zero.
       
   556      *
       
   557      * @param tileWidth the width of each tile.
       
   558      * @param tileHeight the height of each tile.
       
   559      * @param tileGridXOffset the horizontal offset of the tile grid.
       
   560      * @param tileGridYOffset the vertical offset of the tile grid.
       
   561      *
       
   562      * @exception UnsupportedOperationException if the plug-in does not
       
   563      * support tiling.
       
   564      * @exception IllegalStateException if the tiling mode is not
       
   565      * {@code MODE_EXPLICIT}.
       
   566      * @exception UnsupportedOperationException if the plug-in does not
       
   567      * support grid offsets, and the grid offsets are not both zero.
       
   568      * @exception IllegalArgumentException if the tile size is not
       
   569      * within one of the allowable ranges returned by
       
   570      * {@code getPreferredTileSizes}.
       
   571      * @exception IllegalArgumentException if {@code tileWidth}
       
   572      * or {@code tileHeight} is less than or equal to 0.
       
   573      *
       
   574      * @see #canWriteTiles
       
   575      * @see #canOffsetTiles
       
   576      * @see #getTileWidth()
       
   577      * @see #getTileHeight()
       
   578      * @see #getTileGridXOffset()
       
   579      * @see #getTileGridYOffset()
       
   580      */
       
   581     public void setTiling(int tileWidth,
       
   582                           int tileHeight,
       
   583                           int tileGridXOffset,
       
   584                           int tileGridYOffset) {
       
   585         if (!canWriteTiles()) {
       
   586             throw new UnsupportedOperationException("Tiling not supported!");
       
   587         }
       
   588         if (getTilingMode() != MODE_EXPLICIT) {
       
   589             throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
       
   590         }
       
   591         if (tileWidth <= 0 || tileHeight <= 0) {
       
   592             throw new IllegalArgumentException
       
   593                 ("tile dimensions are non-positive!");
       
   594         }
       
   595         boolean tilesOffset = (tileGridXOffset != 0) || (tileGridYOffset != 0);
       
   596         if (!canOffsetTiles() && tilesOffset) {
       
   597             throw new UnsupportedOperationException("Can't offset tiles!");
       
   598         }
       
   599         if (preferredTileSizes != null) {
       
   600             boolean ok = true;
       
   601             for (int i = 0; i < preferredTileSizes.length; i += 2) {
       
   602                 Dimension min = preferredTileSizes[i];
       
   603                 Dimension max = preferredTileSizes[i+1];
       
   604                 if ((tileWidth < min.width) ||
       
   605                     (tileWidth > max.width) ||
       
   606                     (tileHeight < min.height) ||
       
   607                     (tileHeight > max.height)) {
       
   608                     ok = false;
       
   609                     break;
       
   610                 }
       
   611             }
       
   612             if (!ok) {
       
   613                 throw new IllegalArgumentException("Illegal tile size!");
       
   614             }
       
   615         }
       
   616 
       
   617         this.tilingSet = true;
       
   618         this.tileWidth = tileWidth;
       
   619         this.tileHeight = tileHeight;
       
   620         this.tileGridXOffset = tileGridXOffset;
       
   621         this.tileGridYOffset = tileGridYOffset;
       
   622     }
       
   623 
       
   624     /**
       
   625      * Removes any previous tile grid parameters specified by calls to
       
   626      * {@code setTiling}.
       
   627      *
       
   628      * <p> The default implementation sets the instance variables
       
   629      * {@code tileWidth}, {@code tileHeight},
       
   630      * {@code tileGridXOffset}, and
       
   631      * {@code tileGridYOffset} to {@code 0}.
       
   632      *
       
   633      * @exception UnsupportedOperationException if the plug-in does not
       
   634      * support tiling.
       
   635      * @exception IllegalStateException if the tiling mode is not
       
   636      * {@code MODE_EXPLICIT}.
       
   637      *
       
   638      * @see #setTiling(int, int, int, int)
       
   639      */
       
   640     public void unsetTiling() {
       
   641         if (!canWriteTiles()) {
       
   642             throw new UnsupportedOperationException("Tiling not supported!");
       
   643         }
       
   644         if (getTilingMode() != MODE_EXPLICIT) {
       
   645             throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
       
   646         }
       
   647         this.tilingSet = false;
       
   648         this.tileWidth = 0;
       
   649         this.tileHeight = 0;
       
   650         this.tileGridXOffset = 0;
       
   651         this.tileGridYOffset = 0;
       
   652     }
       
   653 
       
   654     /**
       
   655      * Returns the width of each tile in an image as it will be
       
   656      * written to the output stream.  If tiling parameters have not
       
   657      * been set, an {@code IllegalStateException} is thrown.
       
   658      *
       
   659      * @return the tile width to be used for encoding.
       
   660      *
       
   661      * @exception UnsupportedOperationException if the plug-in does not
       
   662      * support tiling.
       
   663      * @exception IllegalStateException if the tiling mode is not
       
   664      * {@code MODE_EXPLICIT}.
       
   665      * @exception IllegalStateException if the tiling parameters have
       
   666      * not been set.
       
   667      *
       
   668      * @see #setTiling(int, int, int, int)
       
   669      * @see #getTileHeight()
       
   670      */
       
   671     public int getTileWidth() {
       
   672         if (!canWriteTiles()) {
       
   673             throw new UnsupportedOperationException("Tiling not supported!");
       
   674         }
       
   675         if (getTilingMode() != MODE_EXPLICIT) {
       
   676             throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
       
   677         }
       
   678         if (!tilingSet) {
       
   679             throw new IllegalStateException("Tiling parameters not set!");
       
   680         }
       
   681         return tileWidth;
       
   682     }
       
   683 
       
   684     /**
       
   685      * Returns the height of each tile in an image as it will be written to
       
   686      * the output stream.  If tiling parameters have not
       
   687      * been set, an {@code IllegalStateException} is thrown.
       
   688      *
       
   689      * @return the tile height to be used for encoding.
       
   690      *
       
   691      * @exception UnsupportedOperationException if the plug-in does not
       
   692      * support tiling.
       
   693      * @exception IllegalStateException if the tiling mode is not
       
   694      * {@code MODE_EXPLICIT}.
       
   695      * @exception IllegalStateException if the tiling parameters have
       
   696      * not been set.
       
   697      *
       
   698      * @see #setTiling(int, int, int, int)
       
   699      * @see #getTileWidth()
       
   700      */
       
   701     public int getTileHeight() {
       
   702         if (!canWriteTiles()) {
       
   703             throw new UnsupportedOperationException("Tiling not supported!");
       
   704         }
       
   705         if (getTilingMode() != MODE_EXPLICIT) {
       
   706             throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
       
   707         }
       
   708         if (!tilingSet) {
       
   709             throw new IllegalStateException("Tiling parameters not set!");
       
   710         }
       
   711         return tileHeight;
       
   712     }
       
   713 
       
   714     /**
       
   715      * Returns the horizontal tile grid offset of an image as it will
       
   716      * be written to the output stream.  If tiling parameters have not
       
   717      * been set, an {@code IllegalStateException} is thrown.
       
   718      *
       
   719      * @return the tile grid X offset to be used for encoding.
       
   720      *
       
   721      * @exception UnsupportedOperationException if the plug-in does not
       
   722      * support tiling.
       
   723      * @exception IllegalStateException if the tiling mode is not
       
   724      * {@code MODE_EXPLICIT}.
       
   725      * @exception IllegalStateException if the tiling parameters have
       
   726      * not been set.
       
   727      *
       
   728      * @see #setTiling(int, int, int, int)
       
   729      * @see #getTileGridYOffset()
       
   730      */
       
   731     public int getTileGridXOffset() {
       
   732         if (!canWriteTiles()) {
       
   733             throw new UnsupportedOperationException("Tiling not supported!");
       
   734         }
       
   735         if (getTilingMode() != MODE_EXPLICIT) {
       
   736             throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
       
   737         }
       
   738         if (!tilingSet) {
       
   739             throw new IllegalStateException("Tiling parameters not set!");
       
   740         }
       
   741         return tileGridXOffset;
       
   742     }
       
   743 
       
   744     /**
       
   745      * Returns the vertical tile grid offset of an image as it will
       
   746      * be written to the output stream.  If tiling parameters have not
       
   747      * been set, an {@code IllegalStateException} is thrown.
       
   748      *
       
   749      * @return the tile grid Y offset to be used for encoding.
       
   750      *
       
   751      * @exception UnsupportedOperationException if the plug-in does not
       
   752      * support tiling.
       
   753      * @exception IllegalStateException if the tiling mode is not
       
   754      * {@code MODE_EXPLICIT}.
       
   755      * @exception IllegalStateException if the tiling parameters have
       
   756      * not been set.
       
   757      *
       
   758      * @see #setTiling(int, int, int, int)
       
   759      * @see #getTileGridXOffset()
       
   760      */
       
   761     public int getTileGridYOffset() {
       
   762         if (!canWriteTiles()) {
       
   763             throw new UnsupportedOperationException("Tiling not supported!");
       
   764         }
       
   765         if (getTilingMode() != MODE_EXPLICIT) {
       
   766             throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
       
   767         }
       
   768         if (!tilingSet) {
       
   769             throw new IllegalStateException("Tiling parameters not set!");
       
   770         }
       
   771         return tileGridYOffset;
       
   772     }
       
   773 
       
   774     /**
       
   775      * Returns {@code true} if the writer can write out images
       
   776      * as a series of passes of progressively increasing quality.
       
   777      *
       
   778      * @return {@code true} if the writer supports progressive
       
   779      * encoding.
       
   780      *
       
   781      * @see #setProgressiveMode
       
   782      * @see #getProgressiveMode
       
   783      */
       
   784     public boolean canWriteProgressive() {
       
   785         return canWriteProgressive;
       
   786     }
       
   787 
       
   788     /**
       
   789      * Specifies that the writer is to write the image out in a
       
   790      * progressive mode such that the stream will contain a series of
       
   791      * scans of increasing quality.  If progressive encoding is not
       
   792      * supported, an {@code UnsupportedOperationException} will
       
   793      * be thrown.
       
   794      *
       
   795      * <p>  The mode argument determines how
       
   796      * the progression parameters are chosen, and must be either
       
   797      * {@code MODE_DISABLED},
       
   798      * {@code MODE_COPY_FROM_METADATA}, or
       
   799      * {@code MODE_DEFAULT}.  Otherwise an
       
   800      * {@code IllegalArgumentException} is thrown.
       
   801      *
       
   802      * <p> The modes are interpreted as follows:
       
   803      *
       
   804      * <ul>
       
   805      *   <li>{@code MODE_DISABLED} - No progression.  Use this to
       
   806      *   turn off progression.
       
   807      *
       
   808      *   <li>{@code MODE_COPY_FROM_METADATA} - The output image
       
   809      *   will use whatever progression parameters are found in the
       
   810      *   metadata objects passed into the writer.
       
   811      *
       
   812      *   <li>{@code MODE_DEFAULT} - The image will be written
       
   813      *   progressively, with parameters chosen by the writer.
       
   814      * </ul>
       
   815      *
       
   816      * <p> The default is {@code MODE_COPY_FROM_METADATA}.
       
   817      *
       
   818      * @param mode The mode for setting progression in the output
       
   819      * stream.
       
   820      *
       
   821      * @exception UnsupportedOperationException if the writer does not
       
   822      * support progressive encoding.
       
   823      * @exception IllegalArgumentException if {@code mode} is not
       
   824      * one of the modes listed above.
       
   825      *
       
   826      * @see #getProgressiveMode
       
   827      */
       
   828     public void setProgressiveMode(int mode) {
       
   829         if (!canWriteProgressive()) {
       
   830             throw new UnsupportedOperationException(
       
   831                 "Progressive output not supported");
       
   832         }
       
   833         if (mode < MODE_DISABLED || mode > MAX_MODE) {
       
   834             throw new IllegalArgumentException("Illegal value for mode!");
       
   835         }
       
   836         if (mode == MODE_EXPLICIT) {
       
   837             throw new IllegalArgumentException(
       
   838                 "MODE_EXPLICIT not supported for progressive output");
       
   839         }
       
   840         this.progressiveMode = mode;
       
   841     }
       
   842 
       
   843     /**
       
   844      * Returns the current mode for writing the stream in a
       
   845      * progressive manner.
       
   846      *
       
   847      * @return the current mode for progressive encoding.
       
   848      *
       
   849      * @exception UnsupportedOperationException if the writer does not
       
   850      * support progressive encoding.
       
   851      *
       
   852      * @see #setProgressiveMode
       
   853      */
       
   854     public int getProgressiveMode() {
       
   855         if (!canWriteProgressive()) {
       
   856             throw new UnsupportedOperationException
       
   857                 ("Progressive output not supported");
       
   858         }
       
   859         return progressiveMode;
       
   860     }
       
   861 
       
   862     /**
       
   863      * Returns {@code true} if this writer supports compression.
       
   864      *
       
   865      * @return {@code true} if the writer supports compression.
       
   866      */
       
   867     public boolean canWriteCompressed() {
       
   868         return canWriteCompressed;
       
   869     }
       
   870 
       
   871     /**
       
   872      * Specifies whether compression is to be performed, and if so how
       
   873      * compression parameters are to be determined.  The {@code mode}
       
   874      * argument must be one of the four modes, interpreted as follows:
       
   875      *
       
   876      * <ul>
       
   877      *   <li>{@code MODE_DISABLED} - If the mode is set to
       
   878      *   {@code MODE_DISABLED}, methods that query or modify the
       
   879      *   compression type or parameters will throw an
       
   880      *   {@code IllegalStateException} (if compression is
       
   881      *   normally supported by the plug-in). Some writers, such as JPEG,
       
   882      *   do not normally offer uncompressed output. In this case, attempting
       
   883      *   to set the mode to {@code MODE_DISABLED} will throw an
       
   884      *   {@code UnsupportedOperationException} and the mode will not be
       
   885      *   changed.
       
   886      *
       
   887      *   <li>{@code MODE_EXPLICIT} - Compress using the
       
   888      *   compression type and quality settings specified in this
       
   889      *   {@code ImageWriteParam}.  Any previously set compression
       
   890      *   parameters are discarded.
       
   891      *
       
   892      *   <li>{@code MODE_COPY_FROM_METADATA} - Use whatever
       
   893      *   compression parameters are specified in metadata objects
       
   894      *   passed in to the writer.
       
   895      *
       
   896      *   <li>{@code MODE_DEFAULT} - Use default compression
       
   897      *   parameters.
       
   898      * </ul>
       
   899      *
       
   900      * <p> The default is {@code MODE_COPY_FROM_METADATA}.
       
   901      *
       
   902      * @param mode The mode for setting compression in the output
       
   903      * stream.
       
   904      *
       
   905      * @exception UnsupportedOperationException if the writer does not
       
   906      * support compression, or does not support the requested mode.
       
   907      * @exception IllegalArgumentException if {@code mode} is not
       
   908      * one of the modes listed above.
       
   909      *
       
   910      * @see #getCompressionMode
       
   911      */
       
   912     public void setCompressionMode(int mode) {
       
   913         if (!canWriteCompressed()) {
       
   914             throw new UnsupportedOperationException(
       
   915                 "Compression not supported.");
       
   916         }
       
   917         if (mode < MODE_DISABLED || mode > MAX_MODE) {
       
   918             throw new IllegalArgumentException("Illegal value for mode!");
       
   919         }
       
   920         this.compressionMode = mode;
       
   921         if (mode == MODE_EXPLICIT) {
       
   922             unsetCompression();
       
   923         }
       
   924     }
       
   925 
       
   926     /**
       
   927      * Returns the current compression mode, if compression is
       
   928      * supported.
       
   929      *
       
   930      * @return the current compression mode.
       
   931      *
       
   932      * @exception UnsupportedOperationException if the writer does not
       
   933      * support compression.
       
   934      *
       
   935      * @see #setCompressionMode
       
   936      */
       
   937     public int getCompressionMode() {
       
   938         if (!canWriteCompressed()) {
       
   939             throw new UnsupportedOperationException(
       
   940                 "Compression not supported.");
       
   941         }
       
   942         return compressionMode;
       
   943     }
       
   944 
       
   945     /**
       
   946      * Returns a list of available compression types, as an array or
       
   947      * {@code String}s, or {@code null} if a compression
       
   948      * type may not be chosen using these interfaces.  The array
       
   949      * returned is a copy.
       
   950      *
       
   951      * <p> If the writer only offers a single, mandatory form of
       
   952      * compression, it is not necessary to provide any named
       
   953      * compression types.  Named compression types should only be
       
   954      * used where the user is able to make a meaningful choice
       
   955      * between different schemes.
       
   956      *
       
   957      * <p> The default implementation checks if compression is
       
   958      * supported and throws an
       
   959      * {@code UnsupportedOperationException} if not.  Otherwise,
       
   960      * it returns a clone of the {@code compressionTypes}
       
   961      * instance variable if it is non-{@code null}, or else
       
   962      * returns {@code null}.
       
   963      *
       
   964      * @return an array of {@code String}s containing the
       
   965      * (non-localized) names of available compression types, or
       
   966      * {@code null}.
       
   967      *
       
   968      * @exception UnsupportedOperationException if the writer does not
       
   969      * support compression.
       
   970      */
       
   971     public String[] getCompressionTypes() {
       
   972         if (!canWriteCompressed()) {
       
   973             throw new UnsupportedOperationException(
       
   974                 "Compression not supported");
       
   975         }
       
   976         if (compressionTypes == null) {
       
   977             return null;
       
   978         }
       
   979         return compressionTypes.clone();
       
   980     }
       
   981 
       
   982     /**
       
   983      * Sets the compression type to one of the values indicated by
       
   984      * {@code getCompressionTypes}.  If a value of
       
   985      * {@code null} is passed in, any previous setting is
       
   986      * removed.
       
   987      *
       
   988      * <p> The default implementation checks whether compression is
       
   989      * supported and the compression mode is
       
   990      * {@code MODE_EXPLICIT}.  If so, it calls
       
   991      * {@code getCompressionTypes} and checks if
       
   992      * {@code compressionType} is one of the legal values.  If it
       
   993      * is, the {@code compressionType} instance variable is set.
       
   994      * If {@code compressionType} is {@code null}, the
       
   995      * instance variable is set without performing any checking.
       
   996      *
       
   997      * @param compressionType one of the {@code String}s returned
       
   998      * by {@code getCompressionTypes}, or {@code null} to
       
   999      * remove any previous setting.
       
  1000      *
       
  1001      * @exception UnsupportedOperationException if the writer does not
       
  1002      * support compression.
       
  1003      * @exception IllegalStateException if the compression mode is not
       
  1004      * {@code MODE_EXPLICIT}.
       
  1005      * @exception UnsupportedOperationException if there are no
       
  1006      * settable compression types.
       
  1007      * @exception IllegalArgumentException if
       
  1008      * {@code compressionType} is non-{@code null} but is not
       
  1009      * one of the values returned by {@code getCompressionTypes}.
       
  1010      *
       
  1011      * @see #getCompressionTypes
       
  1012      * @see #getCompressionType
       
  1013      * @see #unsetCompression
       
  1014      */
       
  1015     public void setCompressionType(String compressionType) {
       
  1016         if (!canWriteCompressed()) {
       
  1017             throw new UnsupportedOperationException(
       
  1018                 "Compression not supported");
       
  1019         }
       
  1020         if (getCompressionMode() != MODE_EXPLICIT) {
       
  1021             throw new IllegalStateException
       
  1022                 ("Compression mode not MODE_EXPLICIT!");
       
  1023         }
       
  1024         String[] legalTypes = getCompressionTypes();
       
  1025         if (legalTypes == null) {
       
  1026             throw new UnsupportedOperationException(
       
  1027                 "No settable compression types");
       
  1028         }
       
  1029         if (compressionType != null) {
       
  1030             boolean found = false;
       
  1031             if (legalTypes != null) {
       
  1032                 for (int i = 0; i < legalTypes.length; i++) {
       
  1033                     if (compressionType.equals(legalTypes[i])) {
       
  1034                         found = true;
       
  1035                         break;
       
  1036                     }
       
  1037                 }
       
  1038             }
       
  1039             if (!found) {
       
  1040                 throw new IllegalArgumentException("Unknown compression type!");
       
  1041             }
       
  1042         }
       
  1043         this.compressionType = compressionType;
       
  1044     }
       
  1045 
       
  1046     /**
       
  1047      * Returns the currently set compression type, or
       
  1048      * {@code null} if none has been set.  The type is returned
       
  1049      * as a {@code String} from among those returned by
       
  1050      * {@code getCompressionTypes}.
       
  1051      * If no compression type has been set, {@code null} is
       
  1052      * returned.
       
  1053      *
       
  1054      * <p> The default implementation checks whether compression is
       
  1055      * supported and the compression mode is
       
  1056      * {@code MODE_EXPLICIT}.  If so, it returns the value of the
       
  1057      * {@code compressionType} instance variable.
       
  1058      *
       
  1059      * @return the current compression type as a {@code String},
       
  1060      * or {@code null} if no type is set.
       
  1061      *
       
  1062      * @exception UnsupportedOperationException if the writer does not
       
  1063      * support compression.
       
  1064      * @exception IllegalStateException if the compression mode is not
       
  1065      * {@code MODE_EXPLICIT}.
       
  1066      *
       
  1067      * @see #setCompressionType
       
  1068      */
       
  1069     public String getCompressionType() {
       
  1070         if (!canWriteCompressed()) {
       
  1071             throw new UnsupportedOperationException(
       
  1072                 "Compression not supported.");
       
  1073         }
       
  1074         if (getCompressionMode() != MODE_EXPLICIT) {
       
  1075             throw new IllegalStateException
       
  1076                 ("Compression mode not MODE_EXPLICIT!");
       
  1077         }
       
  1078         return compressionType;
       
  1079     }
       
  1080 
       
  1081     /**
       
  1082      * Removes any previous compression type and quality settings.
       
  1083      *
       
  1084      * <p> The default implementation sets the instance variable
       
  1085      * {@code compressionType} to {@code null}, and the
       
  1086      * instance variable {@code compressionQuality} to
       
  1087      * {@code 1.0F}.
       
  1088      *
       
  1089      * @exception UnsupportedOperationException if the plug-in does not
       
  1090      * support compression.
       
  1091      * @exception IllegalStateException if the compression mode is not
       
  1092      * {@code MODE_EXPLICIT}.
       
  1093      *
       
  1094      * @see #setCompressionType
       
  1095      * @see #setCompressionQuality
       
  1096      */
       
  1097     public void unsetCompression() {
       
  1098         if (!canWriteCompressed()) {
       
  1099             throw new UnsupportedOperationException(
       
  1100                 "Compression not supported");
       
  1101         }
       
  1102         if (getCompressionMode() != MODE_EXPLICIT) {
       
  1103             throw new IllegalStateException
       
  1104                 ("Compression mode not MODE_EXPLICIT!");
       
  1105         }
       
  1106         this.compressionType = null;
       
  1107         this.compressionQuality = 1.0F;
       
  1108     }
       
  1109 
       
  1110     /**
       
  1111      * Returns a localized version of the name of the current
       
  1112      * compression type, using the {@code Locale} returned by
       
  1113      * {@code getLocale}.
       
  1114      *
       
  1115      * <p> The default implementation checks whether compression is
       
  1116      * supported and the compression mode is
       
  1117      * {@code MODE_EXPLICIT}.  If so, if
       
  1118      * {@code compressionType} is {@code non-null} the value
       
  1119      * of {@code getCompressionType} is returned as a
       
  1120      * convenience.
       
  1121      *
       
  1122      * @return a {@code String} containing a localized version of
       
  1123      * the name of the current compression type.
       
  1124      *
       
  1125      * @exception UnsupportedOperationException if the writer does not
       
  1126      * support compression.
       
  1127      * @exception IllegalStateException if the compression mode is not
       
  1128      * {@code MODE_EXPLICIT}.
       
  1129      * @exception IllegalStateException if no compression type is set.
       
  1130      */
       
  1131     public String getLocalizedCompressionTypeName() {
       
  1132         if (!canWriteCompressed()) {
       
  1133             throw new UnsupportedOperationException(
       
  1134                 "Compression not supported.");
       
  1135         }
       
  1136         if (getCompressionMode() != MODE_EXPLICIT) {
       
  1137             throw new IllegalStateException
       
  1138                 ("Compression mode not MODE_EXPLICIT!");
       
  1139         }
       
  1140         if (getCompressionType() == null) {
       
  1141             throw new IllegalStateException("No compression type set!");
       
  1142         }
       
  1143         return getCompressionType();
       
  1144     }
       
  1145 
       
  1146     /**
       
  1147      * Returns {@code true} if the current compression type
       
  1148      * provides lossless compression.  If a plug-in provides only
       
  1149      * one mandatory compression type, then this method may be
       
  1150      * called without calling {@code setCompressionType} first.
       
  1151      *
       
  1152      * <p> If there are multiple compression types but none has
       
  1153      * been set, an {@code IllegalStateException} is thrown.
       
  1154      *
       
  1155      * <p> The default implementation checks whether compression is
       
  1156      * supported and the compression mode is
       
  1157      * {@code MODE_EXPLICIT}.  If so, if
       
  1158      * {@code getCompressionTypes()} is {@code null} or
       
  1159      * {@code getCompressionType()} is non-{@code null}
       
  1160      * {@code true} is returned as a convenience.
       
  1161      *
       
  1162      * @return {@code true} if the current compression type is
       
  1163      * lossless.
       
  1164      *
       
  1165      * @exception UnsupportedOperationException if the writer does not
       
  1166      * support compression.
       
  1167      * @exception IllegalStateException if the compression mode is not
       
  1168      * {@code MODE_EXPLICIT}.
       
  1169      * @exception IllegalStateException if the set of legal
       
  1170      * compression types is non-{@code null} and the current
       
  1171      * compression type is {@code null}.
       
  1172      */
       
  1173     public boolean isCompressionLossless() {
       
  1174         if (!canWriteCompressed()) {
       
  1175             throw new UnsupportedOperationException(
       
  1176                 "Compression not supported");
       
  1177         }
       
  1178         if (getCompressionMode() != MODE_EXPLICIT) {
       
  1179             throw new IllegalStateException
       
  1180                 ("Compression mode not MODE_EXPLICIT!");
       
  1181         }
       
  1182         if ((getCompressionTypes() != null) &&
       
  1183             (getCompressionType() == null)) {
       
  1184             throw new IllegalStateException("No compression type set!");
       
  1185         }
       
  1186         return true;
       
  1187     }
       
  1188 
       
  1189     /**
       
  1190      * Sets the compression quality to a value between {@code 0}
       
  1191      * and {@code 1}.  Only a single compression quality setting
       
  1192      * is supported by default; writers can provide extended versions
       
  1193      * of {@code ImageWriteParam} that offer more control.  For
       
  1194      * lossy compression schemes, the compression quality should
       
  1195      * control the tradeoff between file size and image quality (for
       
  1196      * example, by choosing quantization tables when writing JPEG
       
  1197      * images).  For lossless schemes, the compression quality may be
       
  1198      * used to control the tradeoff between file size and time taken
       
  1199      * to perform the compression (for example, by optimizing row
       
  1200      * filters and setting the ZLIB compression level when writing
       
  1201      * PNG images).
       
  1202      *
       
  1203      * <p> A compression quality setting of 0.0 is most generically
       
  1204      * interpreted as "high compression is important," while a setting of
       
  1205      * 1.0 is most generically interpreted as "high image quality is
       
  1206      * important."
       
  1207      *
       
  1208      * <p> If there are multiple compression types but none has been
       
  1209      * set, an {@code IllegalStateException} is thrown.
       
  1210      *
       
  1211      * <p> The default implementation checks that compression is
       
  1212      * supported, and that the compression mode is
       
  1213      * {@code MODE_EXPLICIT}.  If so, if
       
  1214      * {@code getCompressionTypes()} returns {@code null} or
       
  1215      * {@code compressionType} is non-{@code null} it sets
       
  1216      * the {@code compressionQuality} instance variable.
       
  1217      *
       
  1218      * @param quality a {@code float} between {@code 0} and
       
  1219      * {@code 1} indicating the desired quality level.
       
  1220      *
       
  1221      * @exception UnsupportedOperationException if the writer does not
       
  1222      * support compression.
       
  1223      * @exception IllegalStateException if the compression mode is not
       
  1224      * {@code MODE_EXPLICIT}.
       
  1225      * @exception IllegalStateException if the set of legal
       
  1226      * compression types is non-{@code null} and the current
       
  1227      * compression type is {@code null}.
       
  1228      * @exception IllegalArgumentException if {@code quality} is
       
  1229      * not between {@code 0} and {@code 1}, inclusive.
       
  1230      *
       
  1231      * @see #getCompressionQuality
       
  1232      */
       
  1233     public void setCompressionQuality(float quality) {
       
  1234         if (!canWriteCompressed()) {
       
  1235             throw new UnsupportedOperationException(
       
  1236                 "Compression not supported");
       
  1237         }
       
  1238         if (getCompressionMode() != MODE_EXPLICIT) {
       
  1239             throw new IllegalStateException
       
  1240                 ("Compression mode not MODE_EXPLICIT!");
       
  1241         }
       
  1242         if (getCompressionTypes() != null && getCompressionType() == null) {
       
  1243             throw new IllegalStateException("No compression type set!");
       
  1244         }
       
  1245         if (quality < 0.0F || quality > 1.0F) {
       
  1246             throw new IllegalArgumentException("Quality out-of-bounds!");
       
  1247         }
       
  1248         this.compressionQuality = quality;
       
  1249     }
       
  1250 
       
  1251     /**
       
  1252      * Returns the current compression quality setting.
       
  1253      *
       
  1254      * <p> If there are multiple compression types but none has been
       
  1255      * set, an {@code IllegalStateException} is thrown.
       
  1256      *
       
  1257      * <p> The default implementation checks that compression is
       
  1258      * supported and that the compression mode is
       
  1259      * {@code MODE_EXPLICIT}.  If so, if
       
  1260      * {@code getCompressionTypes()} is {@code null} or
       
  1261      * {@code getCompressionType()} is non-{@code null}, it
       
  1262      * returns the value of the {@code compressionQuality}
       
  1263      * instance variable.
       
  1264      *
       
  1265      * @return the current compression quality setting.
       
  1266      *
       
  1267      * @exception UnsupportedOperationException if the writer does not
       
  1268      * support compression.
       
  1269      * @exception IllegalStateException if the compression mode is not
       
  1270      * {@code MODE_EXPLICIT}.
       
  1271      * @exception IllegalStateException if the set of legal
       
  1272      * compression types is non-{@code null} and the current
       
  1273      * compression type is {@code null}.
       
  1274      *
       
  1275      * @see #setCompressionQuality
       
  1276      */
       
  1277     public float getCompressionQuality() {
       
  1278         if (!canWriteCompressed()) {
       
  1279             throw new UnsupportedOperationException(
       
  1280                 "Compression not supported.");
       
  1281         }
       
  1282         if (getCompressionMode() != MODE_EXPLICIT) {
       
  1283             throw new IllegalStateException
       
  1284                 ("Compression mode not MODE_EXPLICIT!");
       
  1285         }
       
  1286         if ((getCompressionTypes() != null) &&
       
  1287             (getCompressionType() == null)) {
       
  1288             throw new IllegalStateException("No compression type set!");
       
  1289         }
       
  1290         return compressionQuality;
       
  1291     }
       
  1292 
       
  1293 
       
  1294     /**
       
  1295      * Returns a {@code float} indicating an estimate of the
       
  1296      * number of bits of output data for each bit of input image data
       
  1297      * at the given quality level.  The value will typically lie
       
  1298      * between {@code 0} and {@code 1}, with smaller values
       
  1299      * indicating more compression.  A special value of
       
  1300      * {@code -1.0F} is used to indicate that no estimate is
       
  1301      * available.
       
  1302      *
       
  1303      * <p> If there are multiple compression types but none has been set,
       
  1304      * an {@code IllegalStateException} is thrown.
       
  1305      *
       
  1306      * <p> The default implementation checks that compression is
       
  1307      * supported and the compression mode is
       
  1308      * {@code MODE_EXPLICIT}.  If so, if
       
  1309      * {@code getCompressionTypes()} is {@code null} or
       
  1310      * {@code getCompressionType()} is non-{@code null}, and
       
  1311      * {@code quality} is within bounds, it returns
       
  1312      * {@code -1.0}.
       
  1313      *
       
  1314      * @param quality the quality setting whose bit rate is to be
       
  1315      * queried.
       
  1316      *
       
  1317      * @return an estimate of the compressed bit rate, or
       
  1318      * {@code -1.0F} if no estimate is available.
       
  1319      *
       
  1320      * @exception UnsupportedOperationException if the writer does not
       
  1321      * support compression.
       
  1322      * @exception IllegalStateException if the compression mode is not
       
  1323      * {@code MODE_EXPLICIT}.
       
  1324      * @exception IllegalStateException if the set of legal
       
  1325      * compression types is non-{@code null} and the current
       
  1326      * compression type is {@code null}.
       
  1327      * @exception IllegalArgumentException if {@code quality} is
       
  1328      * not between {@code 0} and {@code 1}, inclusive.
       
  1329      */
       
  1330     public float getBitRate(float quality) {
       
  1331         if (!canWriteCompressed()) {
       
  1332             throw new UnsupportedOperationException(
       
  1333                 "Compression not supported.");
       
  1334         }
       
  1335         if (getCompressionMode() != MODE_EXPLICIT) {
       
  1336             throw new IllegalStateException
       
  1337                 ("Compression mode not MODE_EXPLICIT!");
       
  1338         }
       
  1339         if ((getCompressionTypes() != null) &&
       
  1340             (getCompressionType() == null)) {
       
  1341             throw new IllegalStateException("No compression type set!");
       
  1342         }
       
  1343         if (quality < 0.0F || quality > 1.0F) {
       
  1344             throw new IllegalArgumentException("Quality out-of-bounds!");
       
  1345         }
       
  1346         return -1.0F;
       
  1347     }
       
  1348 
       
  1349     /**
       
  1350      * Returns an array of {@code String}s that may be used along
       
  1351      * with {@code getCompressionQualityValues} as part of a user
       
  1352      * interface for setting or displaying the compression quality
       
  1353      * level.  The {@code String} with index {@code i}
       
  1354      * provides a description of the range of quality levels between
       
  1355      * {@code getCompressionQualityValues[i]} and
       
  1356      * {@code getCompressionQualityValues[i + 1]}.  Note that the
       
  1357      * length of the array returned from
       
  1358      * {@code getCompressionQualityValues} will always be one
       
  1359      * greater than that returned from
       
  1360      * {@code getCompressionQualityDescriptions}.
       
  1361      *
       
  1362      * <p> As an example, the strings "Good", "Better", and "Best"
       
  1363      * could be associated with the ranges {@code [0, .33)},
       
  1364      * {@code [.33, .66)}, and {@code [.66, 1.0]}.  In this
       
  1365      * case, {@code getCompressionQualityDescriptions} would
       
  1366      * return {@code { "Good", "Better", "Best" }} and
       
  1367      * {@code getCompressionQualityValues} would return
       
  1368      * {@code { 0.0F, .33F, .66F, 1.0F }}.
       
  1369      *
       
  1370      * <p> If no descriptions are available, {@code null} is
       
  1371      * returned.  If {@code null} is returned from
       
  1372      * {@code getCompressionQualityValues}, this method must also
       
  1373      * return {@code null}.
       
  1374      *
       
  1375      * <p> The descriptions should be localized for the
       
  1376      * {@code Locale} returned by {@code getLocale}, if it
       
  1377      * is non-{@code null}.
       
  1378      *
       
  1379      * <p> If there are multiple compression types but none has been set,
       
  1380      * an {@code IllegalStateException} is thrown.
       
  1381      *
       
  1382      * <p> The default implementation checks that compression is
       
  1383      * supported and that the compression mode is
       
  1384      * {@code MODE_EXPLICIT}.  If so, if
       
  1385      * {@code getCompressionTypes()} is {@code null} or
       
  1386      * {@code getCompressionType()} is non-{@code null}, it
       
  1387      * returns {@code null}.
       
  1388      *
       
  1389      * @return an array of {@code String}s containing localized
       
  1390      * descriptions of the compression quality levels.
       
  1391      *
       
  1392      * @exception UnsupportedOperationException if the writer does not
       
  1393      * support compression.
       
  1394      * @exception IllegalStateException if the compression mode is not
       
  1395      * {@code MODE_EXPLICIT}.
       
  1396      * @exception IllegalStateException if the set of legal
       
  1397      * compression types is non-{@code null} and the current
       
  1398      * compression type is {@code null}.
       
  1399      *
       
  1400      * @see #getCompressionQualityValues
       
  1401      */
       
  1402     public String[] getCompressionQualityDescriptions() {
       
  1403         if (!canWriteCompressed()) {
       
  1404             throw new UnsupportedOperationException(
       
  1405                 "Compression not supported.");
       
  1406         }
       
  1407         if (getCompressionMode() != MODE_EXPLICIT) {
       
  1408             throw new IllegalStateException
       
  1409                 ("Compression mode not MODE_EXPLICIT!");
       
  1410         }
       
  1411         if ((getCompressionTypes() != null) &&
       
  1412             (getCompressionType() == null)) {
       
  1413             throw new IllegalStateException("No compression type set!");
       
  1414         }
       
  1415         return null;
       
  1416     }
       
  1417 
       
  1418     /**
       
  1419      * Returns an array of {@code float}s that may be used along
       
  1420      * with {@code getCompressionQualityDescriptions} as part of a user
       
  1421      * interface for setting or displaying the compression quality
       
  1422      * level.  See {@link #getCompressionQualityDescriptions
       
  1423      * getCompressionQualityDescriptions} for more information.
       
  1424      *
       
  1425      * <p> If no descriptions are available, {@code null} is
       
  1426      * returned.  If {@code null} is returned from
       
  1427      * {@code getCompressionQualityDescriptions}, this method
       
  1428      * must also return {@code null}.
       
  1429      *
       
  1430      * <p> If there are multiple compression types but none has been set,
       
  1431      * an {@code IllegalStateException} is thrown.
       
  1432      *
       
  1433      * <p> The default implementation checks that compression is
       
  1434      * supported and that the compression mode is
       
  1435      * {@code MODE_EXPLICIT}.  If so, if
       
  1436      * {@code getCompressionTypes()} is {@code null} or
       
  1437      * {@code getCompressionType()} is non-{@code null}, it
       
  1438      * returns {@code null}.
       
  1439      *
       
  1440      * @return an array of {@code float}s indicating the
       
  1441      * boundaries between the compression quality levels as described
       
  1442      * by the {@code String}s from
       
  1443      * {@code getCompressionQualityDescriptions}.
       
  1444      *
       
  1445      * @exception UnsupportedOperationException if the writer does not
       
  1446      * support compression.
       
  1447      * @exception IllegalStateException if the compression mode is not
       
  1448      * {@code MODE_EXPLICIT}.
       
  1449      * @exception IllegalStateException if the set of legal
       
  1450      * compression types is non-{@code null} and the current
       
  1451      * compression type is {@code null}.
       
  1452      *
       
  1453      * @see #getCompressionQualityDescriptions
       
  1454      */
       
  1455     public float[] getCompressionQualityValues() {
       
  1456         if (!canWriteCompressed()) {
       
  1457             throw new UnsupportedOperationException(
       
  1458                 "Compression not supported.");
       
  1459         }
       
  1460         if (getCompressionMode() != MODE_EXPLICIT) {
       
  1461             throw new IllegalStateException
       
  1462                 ("Compression mode not MODE_EXPLICIT!");
       
  1463         }
       
  1464         if ((getCompressionTypes() != null) &&
       
  1465             (getCompressionType() == null)) {
       
  1466             throw new IllegalStateException("No compression type set!");
       
  1467         }
       
  1468         return null;
       
  1469     }
       
  1470 }