1 /*
2 * Copyright 2000-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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 * <code>IIOParam.setSourceSubsampling</code>}.
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 * supprt 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
466 * <code>setTiling</code>} method. Any previously set tiling
467 * parameters are discarded.
468 *
469 * <li><code>MODE_COPY_FROM_METADATA</code> - The image will
470 * conform to the metadata object passed in to a write.
471 * <code>setTiling</code> will throw an
472 * <code>IllegalStateException</code>.
473 *
474 * </ul>
475 *
476 * @param mode The mode to use for tiling.
477 *
478 * @exception UnsupportedOperationException if
479 * <code>canWriteTiles</code> returns <code>false</code>.
480 * @exception IllegalArgumentException if <code>mode</code> is not
481 * one of the modes listed above.
482 *
483 * @see #setTiling
484 * @see #getTilingMode
485 */
486 public void setTilingMode(int mode) {
487 if (canWriteTiles() == false) {
488 throw new UnsupportedOperationException("Tiling not supported!");
489 }
490 if (mode < MODE_DISABLED || mode > MAX_MODE) {
491 throw new IllegalArgumentException("Illegal value for mode!");
492 }
493 this.tilingMode = mode;
494 if (mode == MODE_EXPLICIT) {
495 unsetTiling();
496 }
497 }
498
499 /**
500 * Returns the current tiling mode, if tiling is supported.
501 * Otherwise throws an <code>UnsupportedOperationException</code>.
502 *
503 * @return the current tiling mode.
504 *
505 * @exception UnsupportedOperationException if
506 * <code>canWriteTiles</code> returns <code>false</code>.
507 *
508 * @see #setTilingMode
509 */
510 public int getTilingMode() {
511 if (!canWriteTiles()) {
512 throw new UnsupportedOperationException("Tiling not supported");
513 }
514 return tilingMode;
515 }
516
517 /**
518 * Returns an array of <code>Dimension</code>s indicating the
519 * legal size ranges for tiles as they will be encoded in the
520 * output file or stream. The returned array is a copy.
521 *
522 * <p> The information is returned as a set of pairs; the first
523 * element of a pair contains an (inclusive) minimum width and
524 * height, and the second element contains an (inclusive) maximum
525 * width and height. Together, each pair defines a valid range of
526 * sizes. To specify a fixed size, use the same width and height
527 * for both elements. To specify an arbitrary range, a value of
528 * <code>null</code> is used in place of an actual array of
529 * <code>Dimension</code>s.
530 *
531 * <p> If no array is specified on the constructor, but tiling is
532 * allowed, then this method returns <code>null</code>.
533 *
534 * @exception UnsupportedOperationException if the plug-in does
535 * not support tiling.
536 *
537 * @return an array of <code>Dimension</code>s with an even length
538 * of at least two, or <code>null</code>.
539 */
540 public Dimension[] getPreferredTileSizes() {
541 if (!canWriteTiles()) {
542 throw new UnsupportedOperationException("Tiling not supported");
543 }
544 return clonePreferredTileSizes(preferredTileSizes);
545 }
546
547 /**
548 * Specifies that the image should be tiled in the output stream.
549 * The <code>tileWidth</code> and <code>tileHeight</code>
550 * parameters specify the width and height of the tiles in the
551 * file. If the tile width or height is greater than the width or
552 * height of the image, the image is not tiled in that dimension.
553 *
554 * <p> If <code>canOffsetTiles</code> returns <code>false</code>,
555 * then the <code>tileGridXOffset</code> and
556 * <code>tileGridYOffset</code> parameters must be zero.
557 *
558 * @param tileWidth the width of each tile.
559 * @param tileHeight the height of each tile.
560 * @param tileGridXOffset the horizontal offset of the tile grid.
561 * @param tileGridYOffset the vertical offset of the tile grid.
562 *
563 * @exception UnsupportedOperationException if the plug-in does not
564 * support tiling.
565 * @exception IllegalStateException if the tiling mode is not
566 * <code>MODE_EXPLICIT</code>.
567 * @exception UnsupportedOperationException if the plug-in does not
568 * support grid offsets, and the grid offsets are not both zero.
569 * @exception IllegalArgumentException if the tile size is not
570 * within one of the allowable ranges returned by
571 * <code>getPreferredTileSizes</code>.
572 * @exception IllegalArgumentException if <code>tileWidth</code>
573 * or <code>tileHeight</code> is less than or equal to 0.
574 *
575 * @see #canWriteTiles
576 * @see #canOffsetTiles
577 * @see #getTileWidth()
578 * @see #getTileHeight()
579 * @see #getTileGridXOffset()
580 * @see #getTileGridYOffset()
581 */
582 public void setTiling(int tileWidth,
583 int tileHeight,
584 int tileGridXOffset,
585 int tileGridYOffset) {
586 if (!canWriteTiles()) {
587 throw new UnsupportedOperationException("Tiling not supported!");
588 }
589 if (getTilingMode() != MODE_EXPLICIT) {
590 throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
591 }
592 if (tileWidth <= 0 || tileHeight <= 0) {
593 throw new IllegalArgumentException
594 ("tile dimensions are non-positive!");
595 }
596 boolean tilesOffset = (tileGridXOffset != 0) || (tileGridYOffset != 0);
597 if (!canOffsetTiles() && tilesOffset) {
598 throw new UnsupportedOperationException("Can't offset tiles!");
599 }
600 if (preferredTileSizes != null) {
601 boolean ok = true;
602 for (int i = 0; i < preferredTileSizes.length; i += 2) {
603 Dimension min = preferredTileSizes[i];
604 Dimension max = preferredTileSizes[i+1];
605 if ((tileWidth < min.width) ||
606 (tileWidth > max.width) ||
607 (tileHeight < min.height) ||
608 (tileHeight > max.height)) {
609 ok = false;
610 break;
611 }
612 }
613 if (!ok) {
614 throw new IllegalArgumentException("Illegal tile size!");
615 }
616 }
617
618 this.tilingSet = true;
619 this.tileWidth = tileWidth;
620 this.tileHeight = tileHeight;
621 this.tileGridXOffset = tileGridXOffset;
622 this.tileGridYOffset = tileGridYOffset;
623 }
624
625 /**
626 * Removes any previous tile grid parameters specified by calls to
627 * <code>setTiling</code>.
628 *
629 * <p> The default implementation sets the instance variables
630 * <code>tileWidth</code>, <code>tileHeight</code>,
631 * <code>tileGridXOffset</code>, and
632 * <code>tileGridYOffset</code> to <code>0</code>.
633 *
634 * @exception UnsupportedOperationException if the plug-in does not
635 * support tiling.
636 * @exception IllegalStateException if the tiling mode is not
637 * <code>MODE_EXPLICIT</code>.
638 *
639 * @see #setTiling(int, int, int, int)
640 */
641 public void unsetTiling() {
642 if (!canWriteTiles()) {
643 throw new UnsupportedOperationException("Tiling not supported!");
644 }
645 if (getTilingMode() != MODE_EXPLICIT) {
646 throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
647 }
648 this.tilingSet = false;
649 this.tileWidth = 0;
650 this.tileHeight = 0;
651 this.tileGridXOffset = 0;
652 this.tileGridYOffset = 0;
653 }
654
655 /**
656 * Returns the width of each tile in an image as it will be
657 * written to the output stream. If tiling parameters have not
658 * been set, an <code>IllegalStateException</code> is thrown.
659 *
660 * @return the tile width to be used for encoding.
661 *
662 * @exception UnsupportedOperationException if the plug-in does not
663 * support tiling.
664 * @exception IllegalStateException if the tiling mode is not
665 * <code>MODE_EXPLICIT</code>.
666 * @exception IllegalStateException if the tiling parameters have
667 * not been set.
668 *
669 * @see #setTiling(int, int, int, int)
670 * @see #getTileHeight()
671 */
672 public int getTileWidth() {
673 if (!canWriteTiles()) {
674 throw new UnsupportedOperationException("Tiling not supported!");
675 }
676 if (getTilingMode() != MODE_EXPLICIT) {
677 throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
678 }
679 if (!tilingSet) {
680 throw new IllegalStateException("Tiling parameters not set!");
681 }
682 return tileWidth;
683 }
684
685 /**
686 * Returns the height of each tile in an image as it will be written to
687 * the output stream. If tiling parameters have not
688 * been set, an <code>IllegalStateException</code> is thrown.
689 *
690 * @return the tile height to be used for encoding.
691 *
692 * @exception UnsupportedOperationException if the plug-in does not
693 * support tiling.
694 * @exception IllegalStateException if the tiling mode is not
695 * <code>MODE_EXPLICIT</code>.
696 * @exception IllegalStateException if the tiling parameters have
697 * not been set.
698 *
699 * @see #setTiling(int, int, int, int)
700 * @see #getTileWidth()
701 */
702 public int getTileHeight() {
703 if (!canWriteTiles()) {
704 throw new UnsupportedOperationException("Tiling not supported!");
705 }
706 if (getTilingMode() != MODE_EXPLICIT) {
707 throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
708 }
709 if (!tilingSet) {
710 throw new IllegalStateException("Tiling parameters not set!");
711 }
712 return tileHeight;
713 }
714
715 /**
716 * Returns the horizontal tile grid offset of an image as it will
717 * be written to the output stream. If tiling parameters have not
718 * been set, an <code>IllegalStateException</code> is thrown.
719 *
720 * @return the tile grid X offset to be used for encoding.
721 *
722 * @exception UnsupportedOperationException if the plug-in does not
723 * support tiling.
724 * @exception IllegalStateException if the tiling mode is not
725 * <code>MODE_EXPLICIT</code>.
726 * @exception IllegalStateException if the tiling parameters have
727 * not been set.
728 *
729 * @see #setTiling(int, int, int, int)
730 * @see #getTileGridYOffset()
731 */
732 public int getTileGridXOffset() {
733 if (!canWriteTiles()) {
734 throw new UnsupportedOperationException("Tiling not supported!");
735 }
736 if (getTilingMode() != MODE_EXPLICIT) {
737 throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
738 }
739 if (!tilingSet) {
740 throw new IllegalStateException("Tiling parameters not set!");
741 }
742 return tileGridXOffset;
743 }
744
745 /**
746 * Returns the vertical tile grid offset of an image as it will
747 * be written to the output stream. If tiling parameters have not
748 * been set, an <code>IllegalStateException</code> is thrown.
749 *
750 * @return the tile grid Y offset to be used for encoding.
751 *
752 * @exception UnsupportedOperationException if the plug-in does not
753 * support tiling.
754 * @exception IllegalStateException if the tiling mode is not
755 * <code>MODE_EXPLICIT</code>.
756 * @exception IllegalStateException if the tiling parameters have
757 * not been set.
758 *
759 * @see #setTiling(int, int, int, int)
760 * @see #getTileGridXOffset()
761 */
762 public int getTileGridYOffset() {
763 if (!canWriteTiles()) {
764 throw new UnsupportedOperationException("Tiling not supported!");
765 }
766 if (getTilingMode() != MODE_EXPLICIT) {
767 throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");
768 }
769 if (!tilingSet) {
770 throw new IllegalStateException("Tiling parameters not set!");
771 }
772 return tileGridYOffset;
773 }
774
775 /**
776 * Returns <code>true</code> if the writer can write out images
777 * as a series of passes of progressively increasing quality.
778 *
779 * @return <code>true</code> if the writer supports progressive
780 * encoding.
781 *
782 * @see #setProgressiveMode
783 * @see #getProgressiveMode
784 */
785 public boolean canWriteProgressive() {
786 return canWriteProgressive;
787 }
788
789 /**
790 * Specifies that the writer is to write the image out in a
791 * progressive mode such that the stream will contain a series of
792 * scans of increasing quality. If progressive encoding is not
793 * supported, an <code>UnsupportedOperationException</code> will
794 * be thrown.
795 *
796 * <p> The mode argument determines how
797 * the progression parameters are chosen, and must be either
798 * <code>MODE_DISABLED</code>,
799 * <code>MODE_COPY_FROM_METADATA</code>, or
800 * <code>MODE_DEFAULT</code>. Otherwise an
801 * <code>IllegalArgumentException</code> is thrown.
802 *
803 * <p> The modes are interpreted as follows:
804 *
805 * <ul>
806 * <li><code>MODE_DISABLED</code> - No progression. Use this to
807 * turn off progession.
808 *
809 * <li><code>MODE_COPY_FROM_METADATA</code> - The output image
810 * will use whatever progression parameters are found in the
811 * metadata objects passed into the writer.
812 *
813 * <li><code>MODE_DEFAULT</code> - The image will be written
814 * progressively, with parameters chosen by the writer.
815 * </ul>
816 *
817 * <p> The default is <code>MODE_COPY_FROM_METADATA</code>.
818 *
819 * @param mode The mode for setting progression in the output
820 * stream.
821 *
822 * @exception UnsupportedOperationException if the writer does not
823 * support progressive encoding.
824 * @exception IllegalArgumentException if <code>mode</code> is not
825 * one of the modes listed above.
826 *
827 * @see #getProgressiveMode
828 */
829 public void setProgressiveMode(int mode) {
830 if (!canWriteProgressive()) {
831 throw new UnsupportedOperationException(
832 "Progressive output not supported");
833 }
834 if (mode < MODE_DISABLED || mode > MAX_MODE) {
835 throw new IllegalArgumentException("Illegal value for mode!");
836 }
837 if (mode == MODE_EXPLICIT) {
838 throw new IllegalArgumentException(
839 "MODE_EXPLICIT not supported for progressive output");
840 }
841 this.progressiveMode = mode;
842 }
843
844 /**
845 * Returns the current mode for writing the stream in a
846 * progressive manner.
847 *
848 * @return the current mode for progressive encoding.
849 *
850 * @exception UnsupportedOperationException if the writer does not
851 * support progressive encoding.
852 *
853 * @see #setProgressiveMode
854 */
855 public int getProgressiveMode() {
856 if (!canWriteProgressive()) {
857 throw new UnsupportedOperationException
858 ("Progressive output not supported");
859 }
860 return progressiveMode;
861 }
862
863 /**
864 * Returns <code>true</code> if this writer supports compression.
865 *
866 * @return <code>true</code> if the writer supports compression.
867 */
868 public boolean canWriteCompressed() {
869 return canWriteCompressed;
870 }
871
872 /**
873 * Specifies whether compression is to be performed, and if so how
874 * compression parameters are to be determined. The <code>mode</code>
875 * argument must be one of the four modes, interpreted as follows:
876 *
877 * <ul>
878 * <li><code>MODE_DISABLED</code> - If the mode is set to
879 * <code>MODE_DISABLED</code>, methods that query or modify the
880 * compression type or parameters will throw an
881 * <code>IllegalStateException</code> (if compression is
882 * normally supported by the plug-in). Some writers, such as JPEG,
883 * do not normally offer uncompressed output. In this case, attempting
884 * to set the mode to <code>MODE_DISABLED</code> will throw an
885 * <code>UnsupportedOperationException</code> and the mode will not be
886 * changed.
887 *
888 * <li><code>MODE_EXPLICIT</code> - Compress using the
889 * compression type and quality settings specified in this
890 * <code>ImageWriteParam</code>. Any previously set compression
891 * parameters are discarded.
892 *
893 * <li><code>MODE_COPY_FROM_METADATA</code> - Use whatever
894 * compression parameters are specified in metadata objects
895 * passed in to the writer.
896 *
897 * <li><code>MODE_DEFAULT</code> - Use default compression
898 * parameters.
899 * </ul>
900 *
901 * <p> The default is <code>MODE_COPY_FROM_METADATA</code>.
902 *
903 * @param mode The mode for setting compression in the output
904 * stream.
905 *
906 * @exception UnsupportedOperationException if the writer does not
907 * support compression, or does not support the requested mode.
908 * @exception IllegalArgumentException if <code>mode</code> is not
909 * one of the modes listed above.
910 *
911 * @see #getCompressionMode
912 */
913 public void setCompressionMode(int mode) {
914 if (!canWriteCompressed()) {
915 throw new UnsupportedOperationException(
916 "Compression not supported.");
917 }
918 if (mode < MODE_DISABLED || mode > MAX_MODE) {
919 throw new IllegalArgumentException("Illegal value for mode!");
920 }
921 this.compressionMode = mode;
922 if (mode == MODE_EXPLICIT) {
923 unsetCompression();
924 }
925 }
926
927 /**
928 * Returns the current compression mode, if compression is
929 * supported.
930 *
931 * @return the current compression mode.
932 *
933 * @exception UnsupportedOperationException if the writer does not
934 * support compression.
935 *
936 * @see #setCompressionMode
937 */
938 public int getCompressionMode() {
939 if (!canWriteCompressed()) {
940 throw new UnsupportedOperationException(
941 "Compression not supported.");
942 }
943 return compressionMode;
944 }
945
946 /**
947 * Returns a list of available compression types, as an array or
948 * <code>String</code>s, or <code>null</code> if a compression
949 * type may not be chosen using these interfaces. The array
950 * returned is a copy.
951 *
952 * <p> If the writer only offers a single, mandatory form of
953 * compression, it is not necessary to provide any named
954 * compression types. Named compression types should only be
955 * used where the user is able to make a meaningful choice
956 * between different schemes.
957 *
958 * <p> The default implementation checks if compression is
959 * supported and throws an
960 * <code>UnsupportedOperationException</code> if not. Otherwise,
961 * it returns a clone of the <code>compressionTypes</code>
962 * instance variable if it is non-<code>null</code>, or else
963 * returns <code>null</code>.
964 *
965 * @return an array of <code>String</code>s containing the
966 * (non-localized) names of available compression types, or
967 * <code>null</code>.
968 *
969 * @exception UnsupportedOperationException if the writer does not
970 * support compression.
971 */
972 public String[] getCompressionTypes() {
973 if (!canWriteCompressed()) {
974 throw new UnsupportedOperationException(
975 "Compression not supported");
976 }
977 if (compressionTypes == null) {
978 return null;
979 }
980 return (String[])compressionTypes.clone();
981 }
982
983 /**
984 * Sets the compression type to one of the values indicated by
985 * <code>getCompressionTypes</code>. If a value of
986 * <code>null</code> is passed in, any previous setting is
987 * removed.
988 *
989 * <p> The default implementation checks whether compression is
990 * supported and the compression mode is
991 * <code>MODE_EXPLICIT</code>. If so, it calls
992 * <code>getCompressionTypes</code> and checks if
993 * <code>compressionType</code> is one of the legal values. If it
994 * is, the <code>compressionType</code> instance variable is set.
995 * If <code>compressionType</code> is <code>null</code>, the
996 * instance variable is set without performing any checking.
997 *
998 * @param compressionType one of the <code>String</code>s returned
999 * by <code>getCompressionTypes</code>, or <code>null</code> to
1000 * remove any previous setting.
1001 *
1002 * @exception UnsupportedOperationException if the writer does not
1003 * support compression.
1004 * @exception IllegalStateException if the compression mode is not
1005 * <code>MODE_EXPLICIT</code>.
1006 * @exception UnsupportedOperationException if there are no
1007 * settable compression types.
1008 * @exception IllegalArgumentException if
1009 * <code>compressionType</code> is non-<code>null</code> but is not
1010 * one of the values returned by <code>getCompressionTypes</code>.
1011 *
1012 * @see #getCompressionTypes
1013 * @see #getCompressionType
1014 * @see #unsetCompression
1015 */
1016 public void setCompressionType(String compressionType) {
1017 if (!canWriteCompressed()) {
1018 throw new UnsupportedOperationException(
1019 "Compression not supported");
1020 }
1021 if (getCompressionMode() != MODE_EXPLICIT) {
1022 throw new IllegalStateException
1023 ("Compression mode not MODE_EXPLICIT!");
1024 }
1025 String[] legalTypes = getCompressionTypes();
1026 if (legalTypes == null) {
1027 throw new UnsupportedOperationException(
1028 "No settable compression types");
1029 }
1030 if (compressionType != null) {
1031 boolean found = false;
1032 if (legalTypes != null) {
1033 for (int i = 0; i < legalTypes.length; i++) {
1034 if (compressionType.equals(legalTypes[i])) {
1035 found = true;
1036 break;
1037 }
1038 }
1039 }
1040 if (!found) {
1041 throw new IllegalArgumentException("Unknown compression type!");
1042 }
1043 }
1044 this.compressionType = compressionType;
1045 }
1046
1047 /**
1048 * Returns the currently set compression type, or
1049 * <code>null</code> if none has been set. The type is returned
1050 * as a <code>String</code> from among those returned by
1051 * <code>getCompressionTypes</code>.
1052 * If no compression type has been set, <code>null</code> is
1053 * returned.
1054 *
1055 * <p> The default implementation checks whether compression is
1056 * supported and the compression mode is
1057 * <code>MODE_EXPLICIT</code>. If so, it returns the value of the
1058 * <code>compressionType</code> instance variable.
1059 *
1060 * @return the current compression type as a <code>String</code>,
1061 * or <code>null</code> if no type is set.
1062 *
1063 * @exception UnsupportedOperationException if the writer does not
1064 * support compression.
1065 * @exception IllegalStateException if the compression mode is not
1066 * <code>MODE_EXPLICIT</code>.
1067 *
1068 * @see #setCompressionType
1069 */
1070 public String getCompressionType() {
1071 if (!canWriteCompressed()) {
1072 throw new UnsupportedOperationException(
1073 "Compression not supported.");
1074 }
1075 if (getCompressionMode() != MODE_EXPLICIT) {
1076 throw new IllegalStateException
1077 ("Compression mode not MODE_EXPLICIT!");
1078 }
1079 return compressionType;
1080 }
1081
1082 /**
1083 * Removes any previous compression type and quality settings.
1084 *
1085 * <p> The default implementation sets the instance variable
1086 * <code>compressionType</code> to <code>null</code>, and the
1087 * instance variable <code>compressionQuality</code> to
1088 * <code>1.0F</code>.
1089 *
1090 * @exception UnsupportedOperationException if the plug-in does not
1091 * support compression.
1092 * @exception IllegalStateException if the compression mode is not
1093 * <code>MODE_EXPLICIT</code>.
1094 *
1095 * @see #setCompressionType
1096 * @see #setCompressionQuality
1097 */
1098 public void unsetCompression() {
1099 if (!canWriteCompressed()) {
1100 throw new UnsupportedOperationException(
1101 "Compression not supported");
1102 }
1103 if (getCompressionMode() != MODE_EXPLICIT) {
1104 throw new IllegalStateException
1105 ("Compression mode not MODE_EXPLICIT!");
1106 }
1107 this.compressionType = null;
1108 this.compressionQuality = 1.0F;
1109 }
1110
1111 /**
1112 * Returns a localized version of the name of the current
1113 * compression type, using the <code>Locale</code> returned by
1114 * <code>getLocale</code>.
1115 *
1116 * <p> The default implementation checks whether compression is
1117 * supported and the compression mode is
1118 * <code>MODE_EXPLICIT</code>. If so, if
1119 * <code>compressionType</code> is <code>non-null</code> the value
1120 * of <code>getCompressionType</code> is returned as a
1121 * convenience.
1122 *
1123 * @return a <code>String</code> containing a localized version of
1124 * the name of the current compression type.
1125 *
1126 * @exception UnsupportedOperationException if the writer does not
1127 * support compression.
1128 * @exception IllegalStateException if the compression mode is not
1129 * <code>MODE_EXPLICIT</code>.
1130 * @exception IllegalStateException if no compression type is set.
1131 */
1132 public String getLocalizedCompressionTypeName() {
1133 if (!canWriteCompressed()) {
1134 throw new UnsupportedOperationException(
1135 "Compression not supported.");
1136 }
1137 if (getCompressionMode() != MODE_EXPLICIT) {
1138 throw new IllegalStateException
1139 ("Compression mode not MODE_EXPLICIT!");
1140 }
1141 if (getCompressionType() == null) {
1142 throw new IllegalStateException("No compression type set!");
1143 }
1144 return getCompressionType();
1145 }
1146
1147 /**
1148 * Returns <code>true</code> if the current compression type
1149 * provides lossless compression. If a plug-in provides only
1150 * one mandatory compression type, then this method may be
1151 * called without calling <code>setCompressionType</code> first.
1152 *
1153 * <p> If there are multiple compression types but none has
1154 * been set, an <code>IllegalStateException</code> is thrown.
1155 *
1156 * <p> The default implementation checks whether compression is
1157 * supported and the compression mode is
1158 * <code>MODE_EXPLICIT</code>. If so, if
1159 * <code>getCompressionTypes()</code> is <code>null</code> or
1160 * <code>getCompressionType()</code> is non-<code>null</code>
1161 * <code>true</code> is returned as a convenience.
1162 *
1163 * @return <code>true</code> if the current compression type is
1164 * lossless.
1165 *
1166 * @exception UnsupportedOperationException if the writer does not
1167 * support compression.
1168 * @exception IllegalStateException if the compression mode is not
1169 * <code>MODE_EXPLICIT</code>.
1170 * @exception IllegalStateException if the set of legal
1171 * compression types is non-<code>null</code> and the current
1172 * compression type is <code>null</code>.
1173 */
1174 public boolean isCompressionLossless() {
1175 if (!canWriteCompressed()) {
1176 throw new UnsupportedOperationException(
1177 "Compression not supported");
1178 }
1179 if (getCompressionMode() != MODE_EXPLICIT) {
1180 throw new IllegalStateException
1181 ("Compression mode not MODE_EXPLICIT!");
1182 }
1183 if ((getCompressionTypes() != null) &&
1184 (getCompressionType() == null)) {
1185 throw new IllegalStateException("No compression type set!");
1186 }
1187 return true;
1188 }
1189
1190 /**
1191 * Sets the compression quality to a value between <code>0</code>
1192 * and <code>1</code>. Only a single compression quality setting
1193 * is supported by default; writers can provide extended versions
1194 * of <code>ImageWriteParam</code> that offer more control. For
1195 * lossy compression schemes, the compression quality should
1196 * control the tradeoff between file size and image quality (for
1197 * example, by choosing quantization tables when writing JPEG
1198 * images). For lossless schemes, the compression quality may be
1199 * used to control the tradeoff between file size and time taken
1200 * to perform the compression (for example, by optimizing row
1201 * filters and setting the ZLIB compression level when writing
1202 * PNG images).
1203 *
1204 * <p> A compression quality setting of 0.0 is most generically
1205 * interpreted as "high compression is important," while a setting of
1206 * 1.0 is most generically interpreted as "high image quality is
1207 * important."
1208 *
1209 * <p> If there are multiple compression types but none has been
1210 * set, an <code>IllegalStateException</code> is thrown.
1211 *
1212 * <p> The default implementation checks that compression is
1213 * supported, and that the compression mode is
1214 * <code>MODE_EXPLICIT</code>. If so, if
1215 * <code>getCompressionTypes()</code> returns <code>null</code> or
1216 * <code>compressionType</code> is non-<code>null</code> it sets
1217 * the <code>compressionQuality</code> instance variable.
1218 *
1219 * @param quality a <code>float</code> between <code>0</code>and
1220 * <code>1</code> indicating the desired quality level.
1221 *
1222 * @exception UnsupportedOperationException if the writer does not
1223 * support compression.
1224 * @exception IllegalStateException if the compression mode is not
1225 * <code>MODE_EXPLICIT</code>.
1226 * @exception IllegalStateException if the set of legal
1227 * compression types is non-<code>null</code> and the current
1228 * compression type is <code>null</code>.
1229 * @exception IllegalArgumentException if <code>quality</code> is
1230 * not between <code>0</code>and <code>1</code>, inclusive.
1231 *
1232 * @see #getCompressionQuality
1233 */
1234 public void setCompressionQuality(float quality) {
1235 if (!canWriteCompressed()) {
1236 throw new UnsupportedOperationException(
1237 "Compression not supported");
1238 }
1239 if (getCompressionMode() != MODE_EXPLICIT) {
1240 throw new IllegalStateException
1241 ("Compression mode not MODE_EXPLICIT!");
1242 }
1243 if (getCompressionTypes() != null && getCompressionType() == null) {
1244 throw new IllegalStateException("No compression type set!");
1245 }
1246 if (quality < 0.0F || quality > 1.0F) {
1247 throw new IllegalArgumentException("Quality out-of-bounds!");
1248 }
1249 this.compressionQuality = quality;
1250 }
1251
1252 /**
1253 * Returns the current compression quality setting.
1254 *
1255 * <p> If there are multiple compression types but none has been
1256 * set, an <code>IllegalStateException</code> is thrown.
1257 *
1258 * <p> The default implementation checks that compression is
1259 * supported and that the compression mode is
1260 * <code>MODE_EXPLICIT</code>. If so, if
1261 * <code>getCompressionTypes()</code> is <code>null</code> or
1262 * <code>getCompressionType()</code> is non-<code>null</code>, it
1263 * returns the value of the <code>compressionQuality</code>
1264 * instance variable.
1265 *
1266 * @return the current compression quality setting.
1267 *
1268 * @exception UnsupportedOperationException if the writer does not
1269 * support compression.
1270 * @exception IllegalStateException if the compression mode is not
1271 * <code>MODE_EXPLICIT</code>.
1272 * @exception IllegalStateException if the set of legal
1273 * compression types is non-<code>null</code> and the current
1274 * compression type is <code>null</code>.
1275 *
1276 * @see #setCompressionQuality
1277 */
1278 public float getCompressionQuality() {
1279 if (!canWriteCompressed()) {
1280 throw new UnsupportedOperationException(
1281 "Compression not supported.");
1282 }
1283 if (getCompressionMode() != MODE_EXPLICIT) {
1284 throw new IllegalStateException
1285 ("Compression mode not MODE_EXPLICIT!");
1286 }
1287 if ((getCompressionTypes() != null) &&
1288 (getCompressionType() == null)) {
1289 throw new IllegalStateException("No compression type set!");
1290 }
1291 return compressionQuality;
1292 }
1293
1294
1295 /**
1296 * Returns a <code>float</code> indicating an estimate of the
1297 * number of bits of output data for each bit of input image data
1298 * at the given quality level. The value will typically lie
1299 * between <code>0</code> and <code>1</code>, with smaller values
1300 * indicating more compression. A special value of
1301 * <code>-1.0F</code> is used to indicate that no estimate is
1302 * available.
1303 *
1304 * <p> If there are multiple compression types but none has been set,
1305 * an <code>IllegalStateException</code> is thrown.
1306 *
1307 * <p> The default implementation checks that compression is
1308 * supported and the compression mode is
1309 * <code>MODE_EXPLICIT</code>. If so, if
1310 * <code>getCompressionTypes()</code> is <code>null</code> or
1311 * <code>getCompressionType()</code> is non-<code>null</code>, and
1312 * <code>quality</code> is within bounds, it returns
1313 * <code>-1.0</code>.
1314 *
1315 * @param quality the quality setting whose bit rate is to be
1316 * queried.
1317 *
1318 * @return an estimate of the compressed bit rate, or
1319 * <code>-1.0F</code> if no estimate is available.
1320 *
1321 * @exception UnsupportedOperationException if the writer does not
1322 * support compression.
1323 * @exception IllegalStateException if the compression mode is not
1324 * <code>MODE_EXPLICIT</code>.
1325 * @exception IllegalStateException if the set of legal
1326 * compression types is non-<code>null</code> and the current
1327 * compression type is <code>null</code>.
1328 * @exception IllegalArgumentException if <code>quality</code> is
1329 * not between <code>0</code>and <code>1</code>, inclusive.
1330 */
1331 public float getBitRate(float quality) {
1332 if (!canWriteCompressed()) {
1333 throw new UnsupportedOperationException(
1334 "Compression not supported.");
1335 }
1336 if (getCompressionMode() != MODE_EXPLICIT) {
1337 throw new IllegalStateException
1338 ("Compression mode not MODE_EXPLICIT!");
1339 }
1340 if ((getCompressionTypes() != null) &&
1341 (getCompressionType() == null)) {
1342 throw new IllegalStateException("No compression type set!");
1343 }
1344 if (quality < 0.0F || quality > 1.0F) {
1345 throw new IllegalArgumentException("Quality out-of-bounds!");
1346 }
1347 return -1.0F;
1348 }
1349
1350 /**
1351 * Returns an array of <code>String</code>s that may be used along
1352 * with <code>getCompressionQualityValues</code> as part of a user
1353 * interface for setting or displaying the compression quality
1354 * level. The <code>String</code> with index <code>i</code>
1355 * provides a description of the range of quality levels between
1356 * <code>getCompressionQualityValues[i]</code> and
1357 * <code>getCompressionQualityValues[i + 1]</code>. Note that the
1358 * length of the array returned from
1359 * <code>getCompressionQualityValues</code> will always be one
1360 * greater than that returned from
1361 * <code>getCompressionQualityDescriptions</code>.
1362 *
1363 * <p> As an example, the strings "Good", "Better", and "Best"
1364 * could be associated with the ranges <code>[0, .33)</code>,
1365 * <code>[.33, .66)</code>, and <code>[.66, 1.0]</code>. In this
1366 * case, <code>getCompressionQualityDescriptions</code> would
1367 * return <code>{ "Good", "Better", "Best" }</code> and
1368 * <code>getCompressionQualityValues</code> would return
1369 * <code>{ 0.0F, .33F, .66F, 1.0F }</code>.
1370 *
1371 * <p> If no descriptions are available, <code>null</code> is
1372 * returned. If <code>null</code> is returned from
1373 * <code>getCompressionQualityValues</code>, this method must also
1374 * return <code>null</code>.
1375 *
1376 * <p> The descriptions should be localized for the
1377 * <code>Locale</code> returned by <code>getLocale</code>, if it
1378 * is non-<code>null</code>.
1379 *
1380 * <p> If there are multiple compression types but none has been set,
1381 * an <code>IllegalStateException</code> is thrown.
1382 *
1383 * <p> The default implementation checks that compression is
1384 * supported and that the compression mode is
1385 * <code>MODE_EXPLICIT</code>. If so, if
1386 * <code>getCompressionTypes()</code> is <code>null</code> or
1387 * <code>getCompressionType()</code> is non-<code>null</code>, it
1388 * returns <code>null</code>.
1389 *
1390 * @return an array of <code>String</code>s containing localized
1391 * descriptions of the compression quality levels.
1392 *
1393 * @exception UnsupportedOperationException if the writer does not
1394 * support compression.
1395 * @exception IllegalStateException if the compression mode is not
1396 * <code>MODE_EXPLICIT</code>.
1397 * @exception IllegalStateException if the set of legal
1398 * compression types is non-<code>null</code> and the current
1399 * compression type is <code>null</code>.
1400 *
1401 * @see #getCompressionQualityValues
1402 */
1403 public String[] getCompressionQualityDescriptions() {
1404 if (!canWriteCompressed()) {
1405 throw new UnsupportedOperationException(
1406 "Compression not supported.");
1407 }
1408 if (getCompressionMode() != MODE_EXPLICIT) {
1409 throw new IllegalStateException
1410 ("Compression mode not MODE_EXPLICIT!");
1411 }
1412 if ((getCompressionTypes() != null) &&
1413 (getCompressionType() == null)) {
1414 throw new IllegalStateException("No compression type set!");
1415 }
1416 return null;
1417 }
1418
1419 /**
1420 * Returns an array of <code>float</code>s that may be used along
1421 * with <code>getCompressionQualityDescriptions</code> as part of a user
1422 * interface for setting or displaying the compression quality
1423 * level. See {@link #getCompressionQualityDescriptions
1424 * <code>getCompressionQualityDescriptions</code>} for more information.
1425 *
1426 * <p> If no descriptions are available, <code>null</code> is
1427 * returned. If <code>null</code> is returned from
1428 * <code>getCompressionQualityDescriptions</code>, this method
1429 * must also return <code>null</code>.
1430 *
1431 * <p> If there are multiple compression types but none has been set,
1432 * an <code>IllegalStateException</code> is thrown.
1433 *
1434 * <p> The default implementation checks that compression is
1435 * supported and that the compression mode is
1436 * <code>MODE_EXPLICIT</code>. If so, if
1437 * <code>getCompressionTypes()</code> is <code>null</code> or
1438 * <code>getCompressionType()</code> is non-<code>null</code>, it
1439 * returns <code>null</code>.
1440 *
1441 * @return an array of <code>float</code>s indicating the
1442 * boundaries between the compression quality levels as described
1443 * by the <code>String</code>s from
1444 * <code>getCompressionQualityDescriptions</code>.
1445 *
1446 * @exception UnsupportedOperationException if the writer does not
1447 * support compression.
1448 * @exception IllegalStateException if the compression mode is not
1449 * <code>MODE_EXPLICIT</code>.
1450 * @exception IllegalStateException if the set of legal
1451 * compression types is non-<code>null</code> and the current
1452 * compression type is <code>null</code>.
1453 *
1454 * @see #getCompressionQualityDescriptions
1455 */
1456 public float[] getCompressionQualityValues() {
1457 if (!canWriteCompressed()) {
1458 throw new UnsupportedOperationException(
1459 "Compression not supported.");
1460 }
1461 if (getCompressionMode() != MODE_EXPLICIT) {
1462 throw new IllegalStateException
1463 ("Compression mode not MODE_EXPLICIT!");
1464 }
1465 if ((getCompressionTypes() != null) &&
1466 (getCompressionType() == null)) {
1467 throw new IllegalStateException("No compression type set!");
1468 }
1469 return null;
1470 }
1471 }