Path: blob/master/src/java.desktop/share/classes/javax/imageio/ImageWriteParam.java
41152 views
/*1* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.imageio;2627import java.awt.Dimension;28import java.util.Locale;2930/**31* A class describing how a stream is to be encoded. Instances of32* this class or its subclasses are used to supply prescriptive33* "how-to" information to instances of {@code ImageWriter}.34*35* <p> A plug-in for a specific image format may define a subclass of36* this class, and return objects of that class from the37* {@code getDefaultWriteParam} method of its38* {@code ImageWriter} implementation. For example, the built-in39* JPEG writer plug-in will return instances of40* {@code javax.imageio.plugins.jpeg.JPEGImageWriteParam}.41*42* <p> The region of the image to be written is determined by first43* intersecting the actual bounds of the image with the rectangle44* specified by {@code IIOParam.setSourceRegion}, if any. If the45* resulting rectangle has a width or height of zero, the writer will46* throw an {@code IIOException}. If the intersection is47* non-empty, writing will commence with the first subsampled pixel48* and include additional pixels within the intersected bounds49* according to the horizontal and vertical subsampling factors50* specified by {@link IIOParam#setSourceSubsampling51* IIOParam.setSourceSubsampling}.52*53* <p> Individual features such as tiling, progressive encoding, and54* compression may be set in one of four modes.55* {@code MODE_DISABLED} disables the features;56* {@code MODE_DEFAULT} enables the feature with57* writer-controlled parameter values; {@code MODE_EXPLICIT}58* enables the feature and allows the use of a {@code set} method59* to provide additional parameters; and60* {@code MODE_COPY_FROM_METADATA} copies relevant parameter61* values from the stream and image metadata objects passed to the62* writer. The default for all features is63* {@code MODE_COPY_FROM_METADATA}. Non-standard features64* supplied in subclasses are encouraged, but not required to use a65* similar scheme.66*67* <p> Plug-in writers may extend the functionality of68* {@code ImageWriteParam} by providing a subclass that implements69* additional, plug-in specific interfaces. It is up to the plug-in70* to document what interfaces are available and how they are to be71* used. Writers will silently ignore any extended features of an72* {@code ImageWriteParam} subclass of which they are not aware.73* Also, they may ignore any optional features that they normally74* disable when creating their own {@code ImageWriteParam}75* instances via {@code getDefaultWriteParam}.76*77* <p> Note that unless a query method exists for a capability, it must78* be supported by all {@code ImageWriter} implementations79* (<i>e.g.</i> progressive encoding is optional, but subsampling must be80* supported).81*82*83* @see ImageReadParam84*/85public class ImageWriteParam extends IIOParam {8687/**88* A constant value that may be passed into methods such as89* {@code setTilingMode}, {@code setProgressiveMode},90* and {@code setCompressionMode} to disable a feature for91* future writes. That is, when this mode is set the stream will92* <b>not</b> be tiled, progressive, or compressed, and the93* relevant accessor methods will throw an94* {@code IllegalStateException}.95*96* @see #MODE_EXPLICIT97* @see #MODE_COPY_FROM_METADATA98* @see #MODE_DEFAULT99* @see #setProgressiveMode100* @see #getProgressiveMode101* @see #setTilingMode102* @see #getTilingMode103* @see #setCompressionMode104* @see #getCompressionMode105*/106public static final int MODE_DISABLED = 0;107108/**109* A constant value that may be passed into methods such as110* {@code setTilingMode},111* {@code setProgressiveMode}, and112* {@code setCompressionMode} to enable that feature for113* future writes. That is, when this mode is enabled the stream114* will be tiled, progressive, or compressed according to a115* sensible default chosen internally by the writer in a plug-in116* dependent way, and the relevant accessor methods will117* throw an {@code IllegalStateException}.118*119* @see #MODE_DISABLED120* @see #MODE_EXPLICIT121* @see #MODE_COPY_FROM_METADATA122* @see #setProgressiveMode123* @see #getProgressiveMode124* @see #setTilingMode125* @see #getTilingMode126* @see #setCompressionMode127* @see #getCompressionMode128*/129public static final int MODE_DEFAULT = 1;130131/**132* A constant value that may be passed into methods such as133* {@code setTilingMode} or {@code setCompressionMode}134* to enable a feature for future writes. That is, when this mode135* is set the stream will be tiled or compressed according to136* additional information supplied to the corresponding137* {@code set} methods in this class and retrievable from the138* corresponding {@code get} methods. Note that this mode is139* not supported for progressive output.140*141* @see #MODE_DISABLED142* @see #MODE_COPY_FROM_METADATA143* @see #MODE_DEFAULT144* @see #setProgressiveMode145* @see #getProgressiveMode146* @see #setTilingMode147* @see #getTilingMode148* @see #setCompressionMode149* @see #getCompressionMode150*/151public static final int MODE_EXPLICIT = 2;152153/**154* A constant value that may be passed into methods such as155* {@code setTilingMode}, {@code setProgressiveMode}, or156* {@code setCompressionMode} to enable that feature for157* future writes. That is, when this mode is enabled the stream158* will be tiled, progressive, or compressed based on the contents159* of stream and/or image metadata passed into the write160* operation, and any relevant accessor methods will throw an161* {@code IllegalStateException}.162*163* <p> This is the default mode for all features, so that a read164* including metadata followed by a write including metadata will165* preserve as much information as possible.166*167* @see #MODE_DISABLED168* @see #MODE_EXPLICIT169* @see #MODE_DEFAULT170* @see #setProgressiveMode171* @see #getProgressiveMode172* @see #setTilingMode173* @see #getTilingMode174* @see #setCompressionMode175* @see #getCompressionMode176*/177public static final int MODE_COPY_FROM_METADATA = 3;178179// If more modes are added, this should be updated.180private static final int MAX_MODE = MODE_COPY_FROM_METADATA;181182/**183* A {@code boolean} that is {@code true} if this184* {@code ImageWriteParam} allows tile width and tile height185* parameters to be set. By default, the value is186* {@code false}. Subclasses must set the value manually.187*188* <p> Subclasses that do not support writing tiles should ensure189* that this value is set to {@code false}.190*/191protected boolean canWriteTiles = false;192193/**194* The mode controlling tiling settings, which Must be195* set to one of the four {@code MODE_*} values. The default196* is {@code MODE_COPY_FROM_METADATA}.197*198* <p> Subclasses that do not writing tiles may ignore this value.199*200* @see #MODE_DISABLED201* @see #MODE_EXPLICIT202* @see #MODE_COPY_FROM_METADATA203* @see #MODE_DEFAULT204* @see #setTilingMode205* @see #getTilingMode206*/207protected int tilingMode = MODE_COPY_FROM_METADATA;208209/**210* An array of preferred tile size range pairs. The default value211* is {@code null}, which indicates that there are no212* preferred sizes. If the value is non-{@code null}, it213* must have an even length of at least two.214*215* <p> Subclasses that do not support writing tiles may ignore216* this value.217*218* @see #getPreferredTileSizes219*/220protected Dimension[] preferredTileSizes = null;221222/**223* A {@code boolean} that is {@code true} if tiling224* parameters have been specified.225*226* <p> Subclasses that do not support writing tiles may ignore227* this value.228*/229protected boolean tilingSet = false;230231/**232* The width of each tile if tiling has been set, or 0 otherwise.233*234* <p> Subclasses that do not support tiling may ignore this235* value.236*/237protected int tileWidth = 0;238239/**240* The height of each tile if tiling has been set, or 0 otherwise.241* The initial value is {@code 0}.242*243* <p> Subclasses that do not support tiling may ignore this244* value.245*/246protected int tileHeight = 0;247248/**249* A {@code boolean} that is {@code true} if this250* {@code ImageWriteParam} allows tiling grid offset251* parameters to be set. By default, the value is252* {@code false}. Subclasses must set the value manually.253*254* <p> Subclasses that do not support writing tiles, or that255* support writing but not offsetting tiles must ensure that this256* value is set to {@code false}.257*/258protected boolean canOffsetTiles = false;259260/**261* The amount by which the tile grid origin should be offset262* horizontally from the image origin if tiling has been set,263* or 0 otherwise. The initial value is {@code 0}.264*265* <p> Subclasses that do not support offsetting tiles may ignore266* this value.267*/268protected int tileGridXOffset = 0;269270/**271* The amount by which the tile grid origin should be offset272* vertically from the image origin if tiling has been set,273* or 0 otherwise. The initial value is {@code 0}.274*275* <p> Subclasses that do not support offsetting tiles may ignore276* this value.277*/278protected int tileGridYOffset = 0;279280/**281* A {@code boolean} that is {@code true} if this282* {@code ImageWriteParam} allows images to be written as a283* progressive sequence of increasing quality passes. By default,284* the value is {@code false}. Subclasses must set the value285* manually.286*287* <p> Subclasses that do not support progressive encoding must288* ensure that this value is set to {@code false}.289*/290protected boolean canWriteProgressive = false;291292/**293* The mode controlling progressive encoding, which must be set to294* one of the four {@code MODE_*} values, except295* {@code MODE_EXPLICIT}. The default is296* {@code MODE_COPY_FROM_METADATA}.297*298* <p> Subclasses that do not support progressive encoding may299* ignore this value.300*301* @see #MODE_DISABLED302* @see #MODE_EXPLICIT303* @see #MODE_COPY_FROM_METADATA304* @see #MODE_DEFAULT305* @see #setProgressiveMode306* @see #getProgressiveMode307*/308protected int progressiveMode = MODE_COPY_FROM_METADATA;309310/**311* A {@code boolean} that is {@code true} if this writer312* can write images using compression. By default, the value is313* {@code false}. Subclasses must set the value manually.314*315* <p> Subclasses that do not support compression must ensure that316* this value is set to {@code false}.317*/318protected boolean canWriteCompressed = false;319320/**321* The mode controlling compression settings, which must be set to322* one of the four {@code MODE_*} values. The default is323* {@code MODE_COPY_FROM_METADATA}.324*325* <p> Subclasses that do not support compression may ignore this326* value.327*328* @see #MODE_DISABLED329* @see #MODE_EXPLICIT330* @see #MODE_COPY_FROM_METADATA331* @see #MODE_DEFAULT332* @see #setCompressionMode333* @see #getCompressionMode334*/335protected int compressionMode = MODE_COPY_FROM_METADATA;336337/**338* An array of {@code String}s containing the names of the339* available compression types. Subclasses must set the value340* manually.341*342* <p> Subclasses that do not support compression may ignore this343* value.344*/345protected String[] compressionTypes = null;346347/**348* A {@code String} containing the name of the current349* compression type, or {@code null} if none is set.350*351* <p> Subclasses that do not support compression may ignore this352* value.353*/354protected String compressionType = null;355356/**357* A {@code float} containing the current compression quality358* setting. The initial value is {@code 1.0F}.359*360* <p> Subclasses that do not support compression may ignore this361* value.362*/363protected float compressionQuality = 1.0F;364365/**366* A {@code Locale} to be used to localize compression type367* names and quality descriptions, or {@code null} to use a368* default {@code Locale}. Subclasses must set the value369* manually.370*/371protected Locale locale = null;372373/**374* Constructs an empty {@code ImageWriteParam}. It is up to375* the subclass to set up the instance variables properly.376*/377protected ImageWriteParam() {}378379/**380* Constructs an {@code ImageWriteParam} set to use a381* given {@code Locale}.382*383* @param locale a {@code Locale} to be used to localize384* compression type names and quality descriptions, or385* {@code null}.386*/387public ImageWriteParam(Locale locale) {388this.locale = locale;389}390391// Return a deep copy of the array392private static Dimension[] clonePreferredTileSizes(Dimension[] sizes) {393if (sizes == null) {394return null;395}396Dimension[] temp = new Dimension[sizes.length];397for (int i = 0; i < sizes.length; i++) {398temp[i] = new Dimension(sizes[i]);399}400return temp;401}402403/**404* Returns the currently set {@code Locale}, or405* {@code null} if only a default {@code Locale} is406* supported.407*408* @return the current {@code Locale}, or {@code null}.409*/410public Locale getLocale() {411return locale;412}413414/**415* Returns {@code true} if the writer can perform tiling416* while writing. If this method returns {@code false}, then417* {@code setTiling} will throw an418* {@code UnsupportedOperationException}.419*420* @return {@code true} if the writer supports tiling.421*422* @see #canOffsetTiles()423* @see #setTiling(int, int, int, int)424*/425public boolean canWriteTiles() {426return canWriteTiles;427}428429/**430* Returns {@code true} if the writer can perform tiling with431* non-zero grid offsets while writing. If this method returns432* {@code false}, then {@code setTiling} will throw an433* {@code UnsupportedOperationException} if the grid offset434* arguments are not both zero. If {@code canWriteTiles}435* returns {@code false}, this method will return436* {@code false} as well.437*438* @return {@code true} if the writer supports non-zero tile439* offsets.440*441* @see #canWriteTiles()442* @see #setTiling(int, int, int, int)443*/444public boolean canOffsetTiles() {445return canOffsetTiles;446}447448/**449* Determines whether the image will be tiled in the output450* stream and, if it will, how the tiling parameters will be451* determined. The modes are interpreted as follows:452*453* <ul>454*455* <li>{@code MODE_DISABLED} - The image will not be tiled.456* {@code setTiling} will throw an457* {@code IllegalStateException}.458*459* <li>{@code MODE_DEFAULT} - The image will be tiled using460* default parameters. {@code setTiling} will throw an461* {@code IllegalStateException}.462*463* <li>{@code MODE_EXPLICIT} - The image will be tiled464* according to parameters given in the {@link #setTiling setTiling}465* method. Any previously set tiling parameters are discarded.466*467* <li>{@code MODE_COPY_FROM_METADATA} - The image will468* conform to the metadata object passed in to a write.469* {@code setTiling} will throw an470* {@code IllegalStateException}.471*472* </ul>473*474* @param mode The mode to use for tiling.475*476* @exception UnsupportedOperationException if477* {@code canWriteTiles} returns {@code false}.478* @exception IllegalArgumentException if {@code mode} is not479* one of the modes listed above.480*481* @see #setTiling482* @see #getTilingMode483*/484public void setTilingMode(int mode) {485if (canWriteTiles() == false) {486throw new UnsupportedOperationException("Tiling not supported!");487}488if (mode < MODE_DISABLED || mode > MAX_MODE) {489throw new IllegalArgumentException("Illegal value for mode!");490}491this.tilingMode = mode;492if (mode == MODE_EXPLICIT) {493unsetTiling();494}495}496497/**498* Returns the current tiling mode, if tiling is supported.499* Otherwise throws an {@code UnsupportedOperationException}.500*501* @return the current tiling mode.502*503* @exception UnsupportedOperationException if504* {@code canWriteTiles} returns {@code false}.505*506* @see #setTilingMode507*/508public int getTilingMode() {509if (!canWriteTiles()) {510throw new UnsupportedOperationException("Tiling not supported");511}512return tilingMode;513}514515/**516* Returns an array of {@code Dimension}s indicating the517* legal size ranges for tiles as they will be encoded in the518* output file or stream. The returned array is a copy.519*520* <p> The information is returned as a set of pairs; the first521* element of a pair contains an (inclusive) minimum width and522* height, and the second element contains an (inclusive) maximum523* width and height. Together, each pair defines a valid range of524* sizes. To specify a fixed size, use the same width and height525* for both elements. To specify an arbitrary range, a value of526* {@code null} is used in place of an actual array of527* {@code Dimension}s.528*529* <p> If no array is specified on the constructor, but tiling is530* allowed, then this method returns {@code null}.531*532* @exception UnsupportedOperationException if the plug-in does533* not support tiling.534*535* @return an array of {@code Dimension}s with an even length536* of at least two, or {@code null}.537*/538public Dimension[] getPreferredTileSizes() {539if (!canWriteTiles()) {540throw new UnsupportedOperationException("Tiling not supported");541}542return clonePreferredTileSizes(preferredTileSizes);543}544545/**546* Specifies that the image should be tiled in the output stream.547* The {@code tileWidth} and {@code tileHeight}548* parameters specify the width and height of the tiles in the549* file. If the tile width or height is greater than the width or550* height of the image, the image is not tiled in that dimension.551*552* <p> If {@code canOffsetTiles} returns {@code false},553* then the {@code tileGridXOffset} and554* {@code tileGridYOffset} parameters must be zero.555*556* @param tileWidth the width of each tile.557* @param tileHeight the height of each tile.558* @param tileGridXOffset the horizontal offset of the tile grid.559* @param tileGridYOffset the vertical offset of the tile grid.560*561* @exception UnsupportedOperationException if the plug-in does not562* support tiling.563* @exception IllegalStateException if the tiling mode is not564* {@code MODE_EXPLICIT}.565* @exception UnsupportedOperationException if the plug-in does not566* support grid offsets, and the grid offsets are not both zero.567* @exception IllegalArgumentException if the tile size is not568* within one of the allowable ranges returned by569* {@code getPreferredTileSizes}.570* @exception IllegalArgumentException if {@code tileWidth}571* or {@code tileHeight} is less than or equal to 0.572*573* @see #canWriteTiles574* @see #canOffsetTiles575* @see #getTileWidth()576* @see #getTileHeight()577* @see #getTileGridXOffset()578* @see #getTileGridYOffset()579*/580public void setTiling(int tileWidth,581int tileHeight,582int tileGridXOffset,583int tileGridYOffset) {584if (!canWriteTiles()) {585throw new UnsupportedOperationException("Tiling not supported!");586}587if (getTilingMode() != MODE_EXPLICIT) {588throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");589}590if (tileWidth <= 0 || tileHeight <= 0) {591throw new IllegalArgumentException592("tile dimensions are non-positive!");593}594boolean tilesOffset = (tileGridXOffset != 0) || (tileGridYOffset != 0);595if (!canOffsetTiles() && tilesOffset) {596throw new UnsupportedOperationException("Can't offset tiles!");597}598if (preferredTileSizes != null) {599boolean ok = true;600for (int i = 0; i < preferredTileSizes.length; i += 2) {601Dimension min = preferredTileSizes[i];602Dimension max = preferredTileSizes[i+1];603if ((tileWidth < min.width) ||604(tileWidth > max.width) ||605(tileHeight < min.height) ||606(tileHeight > max.height)) {607ok = false;608break;609}610}611if (!ok) {612throw new IllegalArgumentException("Illegal tile size!");613}614}615616this.tilingSet = true;617this.tileWidth = tileWidth;618this.tileHeight = tileHeight;619this.tileGridXOffset = tileGridXOffset;620this.tileGridYOffset = tileGridYOffset;621}622623/**624* Removes any previous tile grid parameters specified by calls to625* {@code setTiling}.626*627* <p> The default implementation sets the instance variables628* {@code tileWidth}, {@code tileHeight},629* {@code tileGridXOffset}, and630* {@code tileGridYOffset} to {@code 0}.631*632* @exception UnsupportedOperationException if the plug-in does not633* support tiling.634* @exception IllegalStateException if the tiling mode is not635* {@code MODE_EXPLICIT}.636*637* @see #setTiling(int, int, int, int)638*/639public void unsetTiling() {640if (!canWriteTiles()) {641throw new UnsupportedOperationException("Tiling not supported!");642}643if (getTilingMode() != MODE_EXPLICIT) {644throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");645}646this.tilingSet = false;647this.tileWidth = 0;648this.tileHeight = 0;649this.tileGridXOffset = 0;650this.tileGridYOffset = 0;651}652653/**654* Returns the width of each tile in an image as it will be655* written to the output stream. If tiling parameters have not656* been set, an {@code IllegalStateException} is thrown.657*658* @return the tile width to be used for encoding.659*660* @exception UnsupportedOperationException if the plug-in does not661* support tiling.662* @exception IllegalStateException if the tiling mode is not663* {@code MODE_EXPLICIT}.664* @exception IllegalStateException if the tiling parameters have665* not been set.666*667* @see #setTiling(int, int, int, int)668* @see #getTileHeight()669*/670public int getTileWidth() {671if (!canWriteTiles()) {672throw new UnsupportedOperationException("Tiling not supported!");673}674if (getTilingMode() != MODE_EXPLICIT) {675throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");676}677if (!tilingSet) {678throw new IllegalStateException("Tiling parameters not set!");679}680return tileWidth;681}682683/**684* Returns the height of each tile in an image as it will be written to685* the output stream. If tiling parameters have not686* been set, an {@code IllegalStateException} is thrown.687*688* @return the tile height to be used for encoding.689*690* @exception UnsupportedOperationException if the plug-in does not691* support tiling.692* @exception IllegalStateException if the tiling mode is not693* {@code MODE_EXPLICIT}.694* @exception IllegalStateException if the tiling parameters have695* not been set.696*697* @see #setTiling(int, int, int, int)698* @see #getTileWidth()699*/700public int getTileHeight() {701if (!canWriteTiles()) {702throw new UnsupportedOperationException("Tiling not supported!");703}704if (getTilingMode() != MODE_EXPLICIT) {705throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");706}707if (!tilingSet) {708throw new IllegalStateException("Tiling parameters not set!");709}710return tileHeight;711}712713/**714* Returns the horizontal tile grid offset of an image as it will715* be written to the output stream. If tiling parameters have not716* been set, an {@code IllegalStateException} is thrown.717*718* @return the tile grid X offset to be used for encoding.719*720* @exception UnsupportedOperationException if the plug-in does not721* support tiling.722* @exception IllegalStateException if the tiling mode is not723* {@code MODE_EXPLICIT}.724* @exception IllegalStateException if the tiling parameters have725* not been set.726*727* @see #setTiling(int, int, int, int)728* @see #getTileGridYOffset()729*/730public int getTileGridXOffset() {731if (!canWriteTiles()) {732throw new UnsupportedOperationException("Tiling not supported!");733}734if (getTilingMode() != MODE_EXPLICIT) {735throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");736}737if (!tilingSet) {738throw new IllegalStateException("Tiling parameters not set!");739}740return tileGridXOffset;741}742743/**744* Returns the vertical tile grid offset of an image as it will745* be written to the output stream. If tiling parameters have not746* been set, an {@code IllegalStateException} is thrown.747*748* @return the tile grid Y offset to be used for encoding.749*750* @exception UnsupportedOperationException if the plug-in does not751* support tiling.752* @exception IllegalStateException if the tiling mode is not753* {@code MODE_EXPLICIT}.754* @exception IllegalStateException if the tiling parameters have755* not been set.756*757* @see #setTiling(int, int, int, int)758* @see #getTileGridXOffset()759*/760public int getTileGridYOffset() {761if (!canWriteTiles()) {762throw new UnsupportedOperationException("Tiling not supported!");763}764if (getTilingMode() != MODE_EXPLICIT) {765throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!");766}767if (!tilingSet) {768throw new IllegalStateException("Tiling parameters not set!");769}770return tileGridYOffset;771}772773/**774* Returns {@code true} if the writer can write out images775* as a series of passes of progressively increasing quality.776*777* @return {@code true} if the writer supports progressive778* encoding.779*780* @see #setProgressiveMode781* @see #getProgressiveMode782*/783public boolean canWriteProgressive() {784return canWriteProgressive;785}786787/**788* Specifies that the writer is to write the image out in a789* progressive mode such that the stream will contain a series of790* scans of increasing quality. If progressive encoding is not791* supported, an {@code UnsupportedOperationException} will792* be thrown.793*794* <p> The mode argument determines how795* the progression parameters are chosen, and must be either796* {@code MODE_DISABLED},797* {@code MODE_COPY_FROM_METADATA}, or798* {@code MODE_DEFAULT}. Otherwise an799* {@code IllegalArgumentException} is thrown.800*801* <p> The modes are interpreted as follows:802*803* <ul>804* <li>{@code MODE_DISABLED} - No progression. Use this to805* turn off progression.806*807* <li>{@code MODE_COPY_FROM_METADATA} - The output image808* will use whatever progression parameters are found in the809* metadata objects passed into the writer.810*811* <li>{@code MODE_DEFAULT} - The image will be written812* progressively, with parameters chosen by the writer.813* </ul>814*815* <p> The default is {@code MODE_COPY_FROM_METADATA}.816*817* @param mode The mode for setting progression in the output818* stream.819*820* @exception UnsupportedOperationException if the writer does not821* support progressive encoding.822* @exception IllegalArgumentException if {@code mode} is not823* one of the modes listed above.824*825* @see #getProgressiveMode826*/827public void setProgressiveMode(int mode) {828if (!canWriteProgressive()) {829throw new UnsupportedOperationException(830"Progressive output not supported");831}832if (mode < MODE_DISABLED || mode > MAX_MODE) {833throw new IllegalArgumentException("Illegal value for mode!");834}835if (mode == MODE_EXPLICIT) {836throw new IllegalArgumentException(837"MODE_EXPLICIT not supported for progressive output");838}839this.progressiveMode = mode;840}841842/**843* Returns the current mode for writing the stream in a844* progressive manner.845*846* @return the current mode for progressive encoding.847*848* @exception UnsupportedOperationException if the writer does not849* support progressive encoding.850*851* @see #setProgressiveMode852*/853public int getProgressiveMode() {854if (!canWriteProgressive()) {855throw new UnsupportedOperationException856("Progressive output not supported");857}858return progressiveMode;859}860861/**862* Returns {@code true} if this writer supports compression.863*864* @return {@code true} if the writer supports compression.865*/866public boolean canWriteCompressed() {867return canWriteCompressed;868}869870/**871* Specifies whether compression is to be performed, and if so how872* compression parameters are to be determined. The {@code mode}873* argument must be one of the four modes, interpreted as follows:874*875* <ul>876* <li>{@code MODE_DISABLED} - If the mode is set to877* {@code MODE_DISABLED}, methods that query or modify the878* compression type or parameters will throw an879* {@code IllegalStateException} (if compression is880* normally supported by the plug-in). Some writers, such as JPEG,881* do not normally offer uncompressed output. In this case, attempting882* to set the mode to {@code MODE_DISABLED} will throw an883* {@code UnsupportedOperationException} and the mode will not be884* changed.885*886* <li>{@code MODE_EXPLICIT} - Compress using the887* compression type and quality settings specified in this888* {@code ImageWriteParam}. Any previously set compression889* parameters are discarded.890*891* <li>{@code MODE_COPY_FROM_METADATA} - Use whatever892* compression parameters are specified in metadata objects893* passed in to the writer.894*895* <li>{@code MODE_DEFAULT} - Use default compression896* parameters.897* </ul>898*899* <p> The default is {@code MODE_COPY_FROM_METADATA}.900*901* @param mode The mode for setting compression in the output902* stream.903*904* @exception UnsupportedOperationException if the writer does not905* support compression, or does not support the requested mode.906* @exception IllegalArgumentException if {@code mode} is not907* one of the modes listed above.908*909* @see #getCompressionMode910*/911public void setCompressionMode(int mode) {912if (!canWriteCompressed()) {913throw new UnsupportedOperationException(914"Compression not supported.");915}916if (mode < MODE_DISABLED || mode > MAX_MODE) {917throw new IllegalArgumentException("Illegal value for mode!");918}919this.compressionMode = mode;920if (mode == MODE_EXPLICIT) {921unsetCompression();922}923}924925/**926* Returns the current compression mode, if compression is927* supported.928*929* @return the current compression mode.930*931* @exception UnsupportedOperationException if the writer does not932* support compression.933*934* @see #setCompressionMode935*/936public int getCompressionMode() {937if (!canWriteCompressed()) {938throw new UnsupportedOperationException(939"Compression not supported.");940}941return compressionMode;942}943944/**945* Returns a list of available compression types, as an array or946* {@code String}s, or {@code null} if a compression947* type may not be chosen using these interfaces. The array948* returned is a copy.949*950* <p> If the writer only offers a single, mandatory form of951* compression, it is not necessary to provide any named952* compression types. Named compression types should only be953* used where the user is able to make a meaningful choice954* between different schemes.955*956* <p> The default implementation checks if compression is957* supported and throws an958* {@code UnsupportedOperationException} if not. Otherwise,959* it returns a clone of the {@code compressionTypes}960* instance variable if it is non-{@code null}, or else961* returns {@code null}.962*963* @return an array of {@code String}s containing the964* (non-localized) names of available compression types, or965* {@code null}.966*967* @exception UnsupportedOperationException if the writer does not968* support compression.969*/970public String[] getCompressionTypes() {971if (!canWriteCompressed()) {972throw new UnsupportedOperationException(973"Compression not supported");974}975if (compressionTypes == null) {976return null;977}978return compressionTypes.clone();979}980981/**982* Sets the compression type to one of the values indicated by983* {@code getCompressionTypes}. If a value of984* {@code null} is passed in, any previous setting is985* removed.986*987* <p> The default implementation checks whether compression is988* supported and the compression mode is989* {@code MODE_EXPLICIT}. If so, it calls990* {@code getCompressionTypes} and checks if991* {@code compressionType} is one of the legal values. If it992* is, the {@code compressionType} instance variable is set.993* If {@code compressionType} is {@code null}, the994* instance variable is set without performing any checking.995*996* @param compressionType one of the {@code String}s returned997* by {@code getCompressionTypes}, or {@code null} to998* remove any previous setting.999*1000* @exception UnsupportedOperationException if the writer does not1001* support compression.1002* @exception IllegalStateException if the compression mode is not1003* {@code MODE_EXPLICIT}.1004* @exception UnsupportedOperationException if there are no1005* settable compression types.1006* @exception IllegalArgumentException if1007* {@code compressionType} is non-{@code null} but is not1008* one of the values returned by {@code getCompressionTypes}.1009*1010* @see #getCompressionTypes1011* @see #getCompressionType1012* @see #unsetCompression1013*/1014public void setCompressionType(String compressionType) {1015if (!canWriteCompressed()) {1016throw new UnsupportedOperationException(1017"Compression not supported");1018}1019if (getCompressionMode() != MODE_EXPLICIT) {1020throw new IllegalStateException1021("Compression mode not MODE_EXPLICIT!");1022}1023String[] legalTypes = getCompressionTypes();1024if (legalTypes == null) {1025throw new UnsupportedOperationException(1026"No settable compression types");1027}1028if (compressionType != null) {1029boolean found = false;1030if (legalTypes != null) {1031for (int i = 0; i < legalTypes.length; i++) {1032if (compressionType.equals(legalTypes[i])) {1033found = true;1034break;1035}1036}1037}1038if (!found) {1039throw new IllegalArgumentException("Unknown compression type!");1040}1041}1042this.compressionType = compressionType;1043}10441045/**1046* Returns the currently set compression type, or1047* {@code null} if none has been set. The type is returned1048* as a {@code String} from among those returned by1049* {@code getCompressionTypes}.1050* If no compression type has been set, {@code null} is1051* returned.1052*1053* <p> The default implementation checks whether compression is1054* supported and the compression mode is1055* {@code MODE_EXPLICIT}. If so, it returns the value of the1056* {@code compressionType} instance variable.1057*1058* @return the current compression type as a {@code String},1059* or {@code null} if no type is set.1060*1061* @exception UnsupportedOperationException if the writer does not1062* support compression.1063* @exception IllegalStateException if the compression mode is not1064* {@code MODE_EXPLICIT}.1065*1066* @see #setCompressionType1067*/1068public String getCompressionType() {1069if (!canWriteCompressed()) {1070throw new UnsupportedOperationException(1071"Compression not supported.");1072}1073if (getCompressionMode() != MODE_EXPLICIT) {1074throw new IllegalStateException1075("Compression mode not MODE_EXPLICIT!");1076}1077return compressionType;1078}10791080/**1081* Removes any previous compression type and quality settings.1082*1083* <p> The default implementation sets the instance variable1084* {@code compressionType} to {@code null}, and the1085* instance variable {@code compressionQuality} to1086* {@code 1.0F}.1087*1088* @exception UnsupportedOperationException if the plug-in does not1089* support compression.1090* @exception IllegalStateException if the compression mode is not1091* {@code MODE_EXPLICIT}.1092*1093* @see #setCompressionType1094* @see #setCompressionQuality1095*/1096public void unsetCompression() {1097if (!canWriteCompressed()) {1098throw new UnsupportedOperationException(1099"Compression not supported");1100}1101if (getCompressionMode() != MODE_EXPLICIT) {1102throw new IllegalStateException1103("Compression mode not MODE_EXPLICIT!");1104}1105this.compressionType = null;1106this.compressionQuality = 1.0F;1107}11081109/**1110* Returns a localized version of the name of the current1111* compression type, using the {@code Locale} returned by1112* {@code getLocale}.1113*1114* <p> The default implementation checks whether compression is1115* supported and the compression mode is1116* {@code MODE_EXPLICIT}. If so, if1117* {@code compressionType} is {@code non-null} the value1118* of {@code getCompressionType} is returned as a1119* convenience.1120*1121* @return a {@code String} containing a localized version of1122* the name of the current compression type.1123*1124* @exception UnsupportedOperationException if the writer does not1125* support compression.1126* @exception IllegalStateException if the compression mode is not1127* {@code MODE_EXPLICIT}.1128* @exception IllegalStateException if no compression type is set.1129*/1130public String getLocalizedCompressionTypeName() {1131if (!canWriteCompressed()) {1132throw new UnsupportedOperationException(1133"Compression not supported.");1134}1135if (getCompressionMode() != MODE_EXPLICIT) {1136throw new IllegalStateException1137("Compression mode not MODE_EXPLICIT!");1138}1139if (getCompressionType() == null) {1140throw new IllegalStateException("No compression type set!");1141}1142return getCompressionType();1143}11441145/**1146* Returns {@code true} if the current compression type1147* provides lossless compression. If a plug-in provides only1148* one mandatory compression type, then this method may be1149* called without calling {@code setCompressionType} first.1150*1151* <p> If there are multiple compression types but none has1152* been set, an {@code IllegalStateException} is thrown.1153*1154* <p> The default implementation checks whether compression is1155* supported and the compression mode is1156* {@code MODE_EXPLICIT}. If so, if1157* {@code getCompressionTypes()} is {@code null} or1158* {@code getCompressionType()} is non-{@code null}1159* {@code true} is returned as a convenience.1160*1161* @return {@code true} if the current compression type is1162* lossless.1163*1164* @exception UnsupportedOperationException if the writer does not1165* support compression.1166* @exception IllegalStateException if the compression mode is not1167* {@code MODE_EXPLICIT}.1168* @exception IllegalStateException if the set of legal1169* compression types is non-{@code null} and the current1170* compression type is {@code null}.1171*/1172public boolean isCompressionLossless() {1173if (!canWriteCompressed()) {1174throw new UnsupportedOperationException(1175"Compression not supported");1176}1177if (getCompressionMode() != MODE_EXPLICIT) {1178throw new IllegalStateException1179("Compression mode not MODE_EXPLICIT!");1180}1181if ((getCompressionTypes() != null) &&1182(getCompressionType() == null)) {1183throw new IllegalStateException("No compression type set!");1184}1185return true;1186}11871188/**1189* Sets the compression quality to a value between {@code 0}1190* and {@code 1}. Only a single compression quality setting1191* is supported by default; writers can provide extended versions1192* of {@code ImageWriteParam} that offer more control. For1193* lossy compression schemes, the compression quality should1194* control the tradeoff between file size and image quality (for1195* example, by choosing quantization tables when writing JPEG1196* images). For lossless schemes, the compression quality may be1197* used to control the tradeoff between file size and time taken1198* to perform the compression (for example, by optimizing row1199* filters and setting the ZLIB compression level when writing1200* PNG images).1201*1202* <p> A compression quality setting of 0.0 is most generically1203* interpreted as "high compression is important," while a setting of1204* 1.0 is most generically interpreted as "high image quality is1205* important."1206*1207* <p> If there are multiple compression types but none has been1208* set, an {@code IllegalStateException} is thrown.1209*1210* <p> The default implementation checks that compression is1211* supported, and that the compression mode is1212* {@code MODE_EXPLICIT}. If so, if1213* {@code getCompressionTypes()} returns {@code null} or1214* {@code compressionType} is non-{@code null} it sets1215* the {@code compressionQuality} instance variable.1216*1217* @param quality a {@code float} between {@code 0} and1218* {@code 1} indicating the desired quality level.1219*1220* @exception UnsupportedOperationException if the writer does not1221* support compression.1222* @exception IllegalStateException if the compression mode is not1223* {@code MODE_EXPLICIT}.1224* @exception IllegalStateException if the set of legal1225* compression types is non-{@code null} and the current1226* compression type is {@code null}.1227* @exception IllegalArgumentException if {@code quality} is1228* not between {@code 0} and {@code 1}, inclusive.1229*1230* @see #getCompressionQuality1231*/1232public void setCompressionQuality(float quality) {1233if (!canWriteCompressed()) {1234throw new UnsupportedOperationException(1235"Compression not supported");1236}1237if (getCompressionMode() != MODE_EXPLICIT) {1238throw new IllegalStateException1239("Compression mode not MODE_EXPLICIT!");1240}1241if (getCompressionTypes() != null && getCompressionType() == null) {1242throw new IllegalStateException("No compression type set!");1243}1244if (quality < 0.0F || quality > 1.0F) {1245throw new IllegalArgumentException("Quality out of bounds!");1246}1247this.compressionQuality = quality;1248}12491250/**1251* Returns the current compression quality setting.1252*1253* <p> If there are multiple compression types but none has been1254* set, an {@code IllegalStateException} is thrown.1255*1256* <p> The default implementation checks that compression is1257* supported and that the compression mode is1258* {@code MODE_EXPLICIT}. If so, if1259* {@code getCompressionTypes()} is {@code null} or1260* {@code getCompressionType()} is non-{@code null}, it1261* returns the value of the {@code compressionQuality}1262* instance variable.1263*1264* @return the current compression quality setting.1265*1266* @exception UnsupportedOperationException if the writer does not1267* support compression.1268* @exception IllegalStateException if the compression mode is not1269* {@code MODE_EXPLICIT}.1270* @exception IllegalStateException if the set of legal1271* compression types is non-{@code null} and the current1272* compression type is {@code null}.1273*1274* @see #setCompressionQuality1275*/1276public float getCompressionQuality() {1277if (!canWriteCompressed()) {1278throw new UnsupportedOperationException(1279"Compression not supported.");1280}1281if (getCompressionMode() != MODE_EXPLICIT) {1282throw new IllegalStateException1283("Compression mode not MODE_EXPLICIT!");1284}1285if ((getCompressionTypes() != null) &&1286(getCompressionType() == null)) {1287throw new IllegalStateException("No compression type set!");1288}1289return compressionQuality;1290}129112921293/**1294* Returns a {@code float} indicating an estimate of the1295* number of bits of output data for each bit of input image data1296* at the given quality level. The value will typically lie1297* between {@code 0} and {@code 1}, with smaller values1298* indicating more compression. A special value of1299* {@code -1.0F} is used to indicate that no estimate is1300* available.1301*1302* <p> If there are multiple compression types but none has been set,1303* an {@code IllegalStateException} is thrown.1304*1305* <p> The default implementation checks that compression is1306* supported and the compression mode is1307* {@code MODE_EXPLICIT}. If so, if1308* {@code getCompressionTypes()} is {@code null} or1309* {@code getCompressionType()} is non-{@code null}, and1310* {@code quality} is within bounds, it returns1311* {@code -1.0}.1312*1313* @param quality the quality setting whose bit rate is to be1314* queried.1315*1316* @return an estimate of the compressed bit rate, or1317* {@code -1.0F} if no estimate is available.1318*1319* @exception UnsupportedOperationException if the writer does not1320* support compression.1321* @exception IllegalStateException if the compression mode is not1322* {@code MODE_EXPLICIT}.1323* @exception IllegalStateException if the set of legal1324* compression types is non-{@code null} and the current1325* compression type is {@code null}.1326* @exception IllegalArgumentException if {@code quality} is1327* not between {@code 0} and {@code 1}, inclusive.1328*/1329public float getBitRate(float quality) {1330if (!canWriteCompressed()) {1331throw new UnsupportedOperationException(1332"Compression not supported.");1333}1334if (getCompressionMode() != MODE_EXPLICIT) {1335throw new IllegalStateException1336("Compression mode not MODE_EXPLICIT!");1337}1338if ((getCompressionTypes() != null) &&1339(getCompressionType() == null)) {1340throw new IllegalStateException("No compression type set!");1341}1342if (quality < 0.0F || quality > 1.0F) {1343throw new IllegalArgumentException("Quality out of bounds!");1344}1345return -1.0F;1346}13471348/**1349* Returns an array of {@code String}s that may be used along1350* with {@code getCompressionQualityValues} as part of a user1351* interface for setting or displaying the compression quality1352* level. The {@code String} with index {@code i}1353* provides a description of the range of quality levels between1354* {@code getCompressionQualityValues[i]} and1355* {@code getCompressionQualityValues[i + 1]}. Note that the1356* length of the array returned from1357* {@code getCompressionQualityValues} will always be one1358* greater than that returned from1359* {@code getCompressionQualityDescriptions}.1360*1361* <p> As an example, the strings "Good", "Better", and "Best"1362* could be associated with the ranges {@code [0, .33)},1363* {@code [.33, .66)}, and {@code [.66, 1.0]}. In this1364* case, {@code getCompressionQualityDescriptions} would1365* return {@code { "Good", "Better", "Best" }} and1366* {@code getCompressionQualityValues} would return1367* {@code { 0.0F, .33F, .66F, 1.0F }}.1368*1369* <p> If no descriptions are available, {@code null} is1370* returned. If {@code null} is returned from1371* {@code getCompressionQualityValues}, this method must also1372* return {@code null}.1373*1374* <p> The descriptions should be localized for the1375* {@code Locale} returned by {@code getLocale}, if it1376* is non-{@code null}.1377*1378* <p> If there are multiple compression types but none has been set,1379* an {@code IllegalStateException} is thrown.1380*1381* <p> The default implementation checks that compression is1382* supported and that the compression mode is1383* {@code MODE_EXPLICIT}. If so, if1384* {@code getCompressionTypes()} is {@code null} or1385* {@code getCompressionType()} is non-{@code null}, it1386* returns {@code null}.1387*1388* @return an array of {@code String}s containing localized1389* descriptions of the compression quality levels.1390*1391* @exception UnsupportedOperationException if the writer does not1392* support compression.1393* @exception IllegalStateException if the compression mode is not1394* {@code MODE_EXPLICIT}.1395* @exception IllegalStateException if the set of legal1396* compression types is non-{@code null} and the current1397* compression type is {@code null}.1398*1399* @see #getCompressionQualityValues1400*/1401public String[] getCompressionQualityDescriptions() {1402if (!canWriteCompressed()) {1403throw new UnsupportedOperationException(1404"Compression not supported.");1405}1406if (getCompressionMode() != MODE_EXPLICIT) {1407throw new IllegalStateException1408("Compression mode not MODE_EXPLICIT!");1409}1410if ((getCompressionTypes() != null) &&1411(getCompressionType() == null)) {1412throw new IllegalStateException("No compression type set!");1413}1414return null;1415}14161417/**1418* Returns an array of {@code float}s that may be used along1419* with {@code getCompressionQualityDescriptions} as part of a user1420* interface for setting or displaying the compression quality1421* level. See {@link #getCompressionQualityDescriptions1422* getCompressionQualityDescriptions} for more information.1423*1424* <p> If no descriptions are available, {@code null} is1425* returned. If {@code null} is returned from1426* {@code getCompressionQualityDescriptions}, this method1427* must also return {@code null}.1428*1429* <p> If there are multiple compression types but none has been set,1430* an {@code IllegalStateException} is thrown.1431*1432* <p> The default implementation checks that compression is1433* supported and that the compression mode is1434* {@code MODE_EXPLICIT}. If so, if1435* {@code getCompressionTypes()} is {@code null} or1436* {@code getCompressionType()} is non-{@code null}, it1437* returns {@code null}.1438*1439* @return an array of {@code float}s indicating the1440* boundaries between the compression quality levels as described1441* by the {@code String}s from1442* {@code getCompressionQualityDescriptions}.1443*1444* @exception UnsupportedOperationException if the writer does not1445* support compression.1446* @exception IllegalStateException if the compression mode is not1447* {@code MODE_EXPLICIT}.1448* @exception IllegalStateException if the set of legal1449* compression types is non-{@code null} and the current1450* compression type is {@code null}.1451*1452* @see #getCompressionQualityDescriptions1453*/1454public float[] getCompressionQualityValues() {1455if (!canWriteCompressed()) {1456throw new UnsupportedOperationException(1457"Compression not supported.");1458}1459if (getCompressionMode() != MODE_EXPLICIT) {1460throw new IllegalStateException1461("Compression mode not MODE_EXPLICIT!");1462}1463if ((getCompressionTypes() != null) &&1464(getCompressionType() == null)) {1465throw new IllegalStateException("No compression type set!");1466}1467return null;1468}1469}147014711472