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</code>.
  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</code> method of its
  39  * <code>ImageWriter</code> implementation.  For example, the built-in
  40  * JPEG writer plug-in will return instances of
  41  * <code>javax.imageio.plugins.jpeg.JPEGImageWriteParam</code>.
  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</code>, if any.  If the
  46  * resulting rectangle has a width or height of zero, the writer will
  47  * throw an <code>IIOException</code>. 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</code> disables the features;
  57  * <code>MODE_DEFAULT</code> enables the feature with
  58  * writer-controlled parameter values; <code>MODE_EXPLICIT</code>
  59  * enables the feature and allows the use of a <code>set</code> method
  60  * to provide additional parameters; and
  61  * <code>MODE_COPY_FROM_METADATA</code> 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</code>.  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</code> 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</code> 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</code>
  76  * instances via <code>getDefaultWriteParam</code>.
  77  *
  78  * <p> Note that unless a query method exists for a capability, it must
  79  * be supported by all <code>ImageWriter</code> 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>, <code>setProgressiveMode</code>,
  91      * and <code>setCompressionMode</code> 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</code>.
  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</code>,
 112      * <code>setProgressiveMode</code>, and
 113      * <code>setCompressionMode</code> 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</code>.
 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</code> or <code>setCompressionMode</code>
 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</code> methods in this class and retrievable from the
 139      * corresponding <code>get</code> 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>, <code>setProgressiveMode</code>, or
 157      * <code>setCompressionMode</code> 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</code>.
 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</code> that is <code>true</code> if this
 185      * <code>ImageWriteParam</code> allows tile width and tile height
 186      * parameters to be set.  By default, the value is
 187      * <code>false</code>.  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</code>.
 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_*</code> values.  The default
 197      * is <code>MODE_COPY_FROM_METADATA</code>.
 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</code>, which indicates that there are no
 213      * preferred sizes.  If the value is non-<code>null</code>, 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</code> that is <code>true</code> 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</code>.
 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</code> that is <code>true</code> if this
 251      * <code>ImageWriteParam</code> allows tiling grid offset
 252      * parameters to be set.  By default, the value is
 253      * <code>false</code>.  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</code>.
 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</code>.
 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</code>.
 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</code> that is <code>true</code> if this
 283      * <code>ImageWriteParam</code> allows images to be written as a
 284      * progressive sequence of increasing quality passes.  By default,
 285      * the value is <code>false</code>.  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</code>.
 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_*</code> values, except
 296      * <code>MODE_EXPLICIT</code>.  The default is
 297      * <code>MODE_COPY_FROM_METADATA</code>.
 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</code> that is <code>true</code> if this writer
 313      * can write images using compression. By default, the value is
 314      * <code>false</code>.  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</code>.
 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_*</code> values.  The default is
 324      * <code>MODE_COPY_FROM_METADATA</code>.
 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</code>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</code> containing the name of the current
 350      * compression type, or <code>null</code> 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</code> containing the current compression quality
 359      * setting.  The initial value is <code>1.0F</code>.
 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</code> to be used to localize compression type
 368      * names and quality descriptions, or <code>null</code> to use a
 369      * default <code>Locale</code>.  Subclasses must set the value
 370      * manually.
 371      */
 372     protected Locale locale = null;
 373 
 374     /**
 375      * Constructs an empty <code>ImageWriteParam</code>.  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</code> set to use a
 382      * given <code>Locale</code>.
 383      *
 384      * @param locale a <code>Locale</code> to be used to localize
 385      * compression type names and quality descriptions, or
 386      * <code>null</code>.
 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</code>, or
 406      * <code>null</code> if only a default <code>Locale</code> is
 407      * supported.
 408      *
 409      * @return the current <code>Locale</code>, or <code>null</code>.
 410      */
 411     public Locale getLocale() {
 412         return locale;
 413     }
 414 
 415     /**
 416      * Returns <code>true</code> if the writer can perform tiling
 417      * while writing.  If this method returns <code>false</code>, then
 418      * <code>setTiling</code> will throw an
 419      * <code>UnsupportedOperationException</code>.
 420      *
 421      * @return <code>true</code> 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</code> if the writer can perform tiling with
 432      * non-zero grid offsets while writing.  If this method returns
 433      * <code>false</code>, then <code>setTiling</code> will throw an
 434      * <code>UnsupportedOperationException</code> if the grid offset
 435      * arguments are not both zero.  If <code>canWriteTiles</code>
 436      * returns <code>false</code>, this method will return
 437      * <code>false</code> as well.
 438      *
 439      * @return <code>true</code> 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</code> - The image will not be tiled.
 457      * <code>setTiling</code> will throw an
 458      * <code>IllegalStateException</code>.
 459      *
 460      * <li><code>MODE_DEFAULT</code> - The image will be tiled using
 461      * default parameters.  <code>setTiling</code> will throw an
 462      * <code>IllegalStateException</code>.
 463      *
 464      * <li><code>MODE_EXPLICIT</code> - 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</code> - The image will
 469      * conform to the metadata object passed in to a write.
 470      * <code>setTiling</code> will throw an
 471      * <code>IllegalStateException</code>.
 472      *
 473      * </ul>
 474      *
 475      * @param mode The mode to use for tiling.
 476      *
 477      * @exception UnsupportedOperationException if
 478      * <code>canWriteTiles</code> returns <code>false</code>.
 479      * @exception IllegalArgumentException if <code>mode</code> 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</code>.
 501      *
 502      * @return the current tiling mode.
 503      *
 504      * @exception UnsupportedOperationException if
 505      * <code>canWriteTiles</code> returns <code>false</code>.
 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</code>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</code> is used in place of an actual array of
 528      * <code>Dimension</code>s.
 529      *
 530      * <p> If no array is specified on the constructor, but tiling is
 531      * allowed, then this method returns <code>null</code>.
 532      *
 533      * @exception UnsupportedOperationException if the plug-in does
 534      * not support tiling.
 535      *
 536      * @return an array of <code>Dimension</code>s with an even length
 537      * of at least two, or <code>null</code>.
 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</code> and <code>tileHeight</code>
 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</code> returns <code>false</code>,
 554      * then the <code>tileGridXOffset</code> and
 555      * <code>tileGridYOffset</code> 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</code>.
 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</code>.
 571      * @exception IllegalArgumentException if <code>tileWidth</code>
 572      * or <code>tileHeight</code> 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</code>.
 627      *
 628      * <p> The default implementation sets the instance variables
 629      * <code>tileWidth</code>, <code>tileHeight</code>,
 630      * <code>tileGridXOffset</code>, and
 631      * <code>tileGridYOffset</code> to <code>0</code>.
 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</code>.
 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</code> 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</code>.
 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</code> 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</code>.
 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</code> 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</code>.
 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</code> 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</code>.
 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</code> if the writer can write out images
 776      * as a series of passes of progressively increasing quality.
 777      *
 778      * @return <code>true</code> 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</code> 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</code>,
 798      * <code>MODE_COPY_FROM_METADATA</code>, or
 799      * <code>MODE_DEFAULT</code>.  Otherwise an
 800      * <code>IllegalArgumentException</code> is thrown.
 801      *
 802      * <p> The modes are interpreted as follows:
 803      *
 804      * <ul>
 805      *   <li><code>MODE_DISABLED</code> - No progression.  Use this to
 806      *   turn off progression.
 807      *
 808      *   <li><code>MODE_COPY_FROM_METADATA</code> - 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</code> - 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</code>.
 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</code> 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</code> if this writer supports compression.
 864      *
 865      * @return <code>true</code> 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</code>
 874      * argument must be one of the four modes, interpreted as follows:
 875      *
 876      * <ul>
 877      *   <li><code>MODE_DISABLED</code> - If the mode is set to
 878      *   <code>MODE_DISABLED</code>, methods that query or modify the
 879      *   compression type or parameters will throw an
 880      *   <code>IllegalStateException</code> (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</code> will throw an
 884      *   <code>UnsupportedOperationException</code> and the mode will not be
 885      *   changed.
 886      *
 887      *   <li><code>MODE_EXPLICIT</code> - Compress using the
 888      *   compression type and quality settings specified in this
 889      *   <code>ImageWriteParam</code>.  Any previously set compression
 890      *   parameters are discarded.
 891      *
 892      *   <li><code>MODE_COPY_FROM_METADATA</code> - Use whatever
 893      *   compression parameters are specified in metadata objects
 894      *   passed in to the writer.
 895      *
 896      *   <li><code>MODE_DEFAULT</code> - Use default compression
 897      *   parameters.
 898      * </ul>
 899      *
 900      * <p> The default is <code>MODE_COPY_FROM_METADATA</code>.
 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</code> 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</code>s, or <code>null</code> 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</code> if not.  Otherwise,
 960      * it returns a clone of the <code>compressionTypes</code>
 961      * instance variable if it is non-<code>null</code>, or else
 962      * returns <code>null</code>.
 963      *
 964      * @return an array of <code>String</code>s containing the
 965      * (non-localized) names of available compression types, or
 966      * <code>null</code>.
 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</code>.  If a value of
 985      * <code>null</code> 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</code>.  If so, it calls
 991      * <code>getCompressionTypes</code> and checks if
 992      * <code>compressionType</code> is one of the legal values.  If it
 993      * is, the <code>compressionType</code> instance variable is set.
 994      * If <code>compressionType</code> is <code>null</code>, the
 995      * instance variable is set without performing any checking.
 996      *
 997      * @param compressionType one of the <code>String</code>s returned
 998      * by <code>getCompressionTypes</code>, or <code>null</code> 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</code>.
1005      * @exception UnsupportedOperationException if there are no
1006      * settable compression types.
1007      * @exception IllegalArgumentException if
1008      * <code>compressionType</code> is non-<code>null</code> but is not
1009      * one of the values returned by <code>getCompressionTypes</code>.
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</code> if none has been set.  The type is returned
1049      * as a <code>String</code> from among those returned by
1050      * <code>getCompressionTypes</code>.
1051      * If no compression type has been set, <code>null</code> is
1052      * returned.
1053      *
1054      * <p> The default implementation checks whether compression is
1055      * supported and the compression mode is
1056      * <code>MODE_EXPLICIT</code>.  If so, it returns the value of the
1057      * <code>compressionType</code> instance variable.
1058      *
1059      * @return the current compression type as a <code>String</code>,
1060      * or <code>null</code> 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</code>.
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</code> to <code>null</code>, and the
1086      * instance variable <code>compressionQuality</code> to
1087      * <code>1.0F</code>.
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</code>.
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</code> returned by
1113      * <code>getLocale</code>.
1114      *
1115      * <p> The default implementation checks whether compression is
1116      * supported and the compression mode is
1117      * <code>MODE_EXPLICIT</code>.  If so, if
1118      * <code>compressionType</code> is <code>non-null</code> the value
1119      * of <code>getCompressionType</code> is returned as a
1120      * convenience.
1121      *
1122      * @return a <code>String</code> 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</code>.
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</code> 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</code> first.
1151      *
1152      * <p> If there are multiple compression types but none has
1153      * been set, an <code>IllegalStateException</code> is thrown.
1154      *
1155      * <p> The default implementation checks whether compression is
1156      * supported and the compression mode is
1157      * <code>MODE_EXPLICIT</code>.  If so, if
1158      * <code>getCompressionTypes()</code> is <code>null</code> or
1159      * <code>getCompressionType()</code> is non-<code>null</code>
1160      * <code>true</code> is returned as a convenience.
1161      *
1162      * @return <code>true</code> 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</code>.
1169      * @exception IllegalStateException if the set of legal
1170      * compression types is non-<code>null</code> and the current
1171      * compression type is <code>null</code>.
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</code>
1191      * and <code>1</code>.  Only a single compression quality setting
1192      * is supported by default; writers can provide extended versions
1193      * of <code>ImageWriteParam</code> 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</code> is thrown.
1210      *
1211      * <p> The default implementation checks that compression is
1212      * supported, and that the compression mode is
1213      * <code>MODE_EXPLICIT</code>.  If so, if
1214      * <code>getCompressionTypes()</code> returns <code>null</code> or
1215      * <code>compressionType</code> is non-<code>null</code> it sets
1216      * the <code>compressionQuality</code> instance variable.
1217      *
1218      * @param quality a <code>float</code> between <code>0</code>and
1219      * <code>1</code> 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</code>.
1225      * @exception IllegalStateException if the set of legal
1226      * compression types is non-<code>null</code> and the current
1227      * compression type is <code>null</code>.
1228      * @exception IllegalArgumentException if <code>quality</code> is
1229      * not between <code>0</code>and <code>1</code>, 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</code> is thrown.
1256      *
1257      * <p> The default implementation checks that compression is
1258      * supported and that the compression mode is
1259      * <code>MODE_EXPLICIT</code>.  If so, if
1260      * <code>getCompressionTypes()</code> is <code>null</code> or
1261      * <code>getCompressionType()</code> is non-<code>null</code>, it
1262      * returns the value of the <code>compressionQuality</code>
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</code>.
1271      * @exception IllegalStateException if the set of legal
1272      * compression types is non-<code>null</code> and the current
1273      * compression type is <code>null</code>.
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</code> 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</code> and <code>1</code>, with smaller values
1299      * indicating more compression.  A special value of
1300      * <code>-1.0F</code> 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</code> is thrown.
1305      *
1306      * <p> The default implementation checks that compression is
1307      * supported and the compression mode is
1308      * <code>MODE_EXPLICIT</code>.  If so, if
1309      * <code>getCompressionTypes()</code> is <code>null</code> or
1310      * <code>getCompressionType()</code> is non-<code>null</code>, and
1311      * <code>quality</code> is within bounds, it returns
1312      * <code>-1.0</code>.
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</code> 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</code>.
1324      * @exception IllegalStateException if the set of legal
1325      * compression types is non-<code>null</code> and the current
1326      * compression type is <code>null</code>.
1327      * @exception IllegalArgumentException if <code>quality</code> is
1328      * not between <code>0</code>and <code>1</code>, 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</code>s that may be used along
1351      * with <code>getCompressionQualityValues</code> as part of a user
1352      * interface for setting or displaying the compression quality
1353      * level.  The <code>String</code> with index <code>i</code>
1354      * provides a description of the range of quality levels between
1355      * <code>getCompressionQualityValues[i]</code> and
1356      * <code>getCompressionQualityValues[i + 1]</code>.  Note that the
1357      * length of the array returned from
1358      * <code>getCompressionQualityValues</code> will always be one
1359      * greater than that returned from
1360      * <code>getCompressionQualityDescriptions</code>.
1361      *
1362      * <p> As an example, the strings "Good", "Better", and "Best"
1363      * could be associated with the ranges <code>[0, .33)</code>,
1364      * <code>[.33, .66)</code>, and <code>[.66, 1.0]</code>.  In this
1365      * case, <code>getCompressionQualityDescriptions</code> would
1366      * return <code>{ "Good", "Better", "Best" }</code> and
1367      * <code>getCompressionQualityValues</code> would return
1368      * <code>{ 0.0F, .33F, .66F, 1.0F }</code>.
1369      *
1370      * <p> If no descriptions are available, <code>null</code> is
1371      * returned.  If <code>null</code> is returned from
1372      * <code>getCompressionQualityValues</code>, this method must also
1373      * return <code>null</code>.
1374      *
1375      * <p> The descriptions should be localized for the
1376      * <code>Locale</code> returned by <code>getLocale</code>, if it
1377      * is non-<code>null</code>.
1378      *
1379      * <p> If there are multiple compression types but none has been set,
1380      * an <code>IllegalStateException</code> is thrown.
1381      *
1382      * <p> The default implementation checks that compression is
1383      * supported and that the compression mode is
1384      * <code>MODE_EXPLICIT</code>.  If so, if
1385      * <code>getCompressionTypes()</code> is <code>null</code> or
1386      * <code>getCompressionType()</code> is non-<code>null</code>, it
1387      * returns <code>null</code>.
1388      *
1389      * @return an array of <code>String</code>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</code>.
1396      * @exception IllegalStateException if the set of legal
1397      * compression types is non-<code>null</code> and the current
1398      * compression type is <code>null</code>.
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</code>s that may be used along
1420      * with <code>getCompressionQualityDescriptions</code> 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</code> is
1426      * returned.  If <code>null</code> is returned from
1427      * <code>getCompressionQualityDescriptions</code>, this method
1428      * must also return <code>null</code>.
1429      *
1430      * <p> If there are multiple compression types but none has been set,
1431      * an <code>IllegalStateException</code> is thrown.
1432      *
1433      * <p> The default implementation checks that compression is
1434      * supported and that the compression mode is
1435      * <code>MODE_EXPLICIT</code>.  If so, if
1436      * <code>getCompressionTypes()</code> is <code>null</code> or
1437      * <code>getCompressionType()</code> is non-<code>null</code>, it
1438      * returns <code>null</code>.
1439      *
1440      * @return an array of <code>float</code>s indicating the
1441      * boundaries between the compression quality levels as described
1442      * by the <code>String</code>s from
1443      * <code>getCompressionQualityDescriptions</code>.
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</code>.
1449      * @exception IllegalStateException if the set of legal
1450      * compression types is non-<code>null</code> and the current
1451      * compression type is <code>null</code>.
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 }