001 /*
002 * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.imageio.plugins.jpeg;
027
028 import java.util.Locale;
029 import javax.imageio.ImageWriteParam;
030
031 import com.sun.imageio.plugins.jpeg.JPEG;
032
033 /**
034 * This class adds the ability to set JPEG quantization and Huffman
035 * tables when using the built-in JPEG writer plug-in, and to request that
036 * optimized Huffman tables be computed for an image. An instance of
037 * this class will be returned from the
038 * <code>getDefaultImageWriteParam</code> methods of the built-in JPEG
039 * <code>ImageWriter</code>.
040
041 * <p> The principal purpose of these additions is to allow the
042 * specification of tables to use in encoding abbreviated streams.
043 * The built-in JPEG writer will also accept an ordinary
044 * <code>ImageWriteParam</code>, in which case the writer will
045 * construct the necessary tables internally.
046 *
047 * <p> In either case, the quality setting in an <code>ImageWriteParam</code>
048 * has the same meaning as for the underlying library: 1.00 means a
049 * quantization table of all 1's, 0.75 means the "standard", visually
050 * lossless quantization table, and 0.00 means aquantization table of
051 * all 255's.
052 *
053 * <p> While tables for abbreviated streams are often specified by
054 * first writing an abbreviated stream containing only the tables, in
055 * some applications the tables are fixed ahead of time. This class
056 * allows the tables to be specified directly from client code.
057 *
058 * <p> Normally, the tables are specified in the
059 * <code>IIOMetadata</code> objects passed in to the writer, and any
060 * tables included in these objects are written to the stream.
061 * If no tables are specified in the metadata, then an abbreviated
062 * stream is written. If no tables are included in the metadata and
063 * no tables are specified in a <code>JPEGImageWriteParam</code>, then
064 * an abbreviated stream is encoded using the "standard" visually
065 * lossless tables. This class is necessary for specifying tables
066 * when an abbreviated stream must be written without writing any tables
067 * to a stream first. In order to use this class, the metadata object
068 * passed into the writer must contain no tables, and no stream metadata
069 * must be provided. See {@link JPEGQTable <code>JPEGQTable</code>} and
070 * {@link JPEGHuffmanTable <code>JPEGHuffmanTable</code>} for more
071 * information on the default tables.
072 *
073 * <p> The default <code>JPEGImageWriteParam</code> returned by the
074 * <code>getDefaultWriteParam</code> method of the writer contains no
075 * tables. Default tables are included in the default
076 * <code>IIOMetadata</code> objects returned by the writer.
077 *
078 * <p> If the metadata does contain tables, the tables given in a
079 * <code>JPEGImageWriteParam</code> are ignored. Furthermore, once a
080 * set of tables has been written, only tables in the metadata can
081 * override them for subsequent writes, whether to the same stream or
082 * a different one. In order to specify new tables using this class,
083 * the {@link javax.imageio.ImageWriter#reset <code>reset</code>}
084 * method of the writer must be called.
085 *
086 * <p>
087 * For more information about the operation of the built-in JPEG plug-ins,
088 * see the <A HREF="../../metadata/doc-files/jpeg_metadata.html">JPEG
089 * metadata format specification and usage notes</A>.
090 *
091 * @version 0.5
092 */
093 public class JPEGImageWriteParam extends ImageWriteParam {
094
095 private JPEGQTable[] qTables = null;
096 private JPEGHuffmanTable[] DCHuffmanTables = null;
097 private JPEGHuffmanTable[] ACHuffmanTables = null;
098 private boolean optimizeHuffman = false;
099 private String[] compressionNames = { "JPEG" };
100 private float[] qualityVals = { 0.00F, 0.30F, 0.75F, 1.00F };
101 private String[] qualityDescs = { "Low quality", // 0.00 -> 0.30
102 "Medium quality", // 0.30 -> 0.75
103 "Visually lossless" // 0.75 -> 1.00
104 };
105
106 /**
107 * Constructs a <code>JPEGImageWriteParam</code>. Tiling is not
108 * supported. Progressive encoding is supported. The default
109 * progressive mode is MODE_DISABLED. A single form of compression,
110 * named "JPEG", is supported. The default compression quality is
111 * 0.75.
112 *
113 * @param locale a <code>Locale</code> to be used by the
114 * superclass to localize compression type names and quality
115 * descriptions, or <code>null</code>.
116 */
117 public JPEGImageWriteParam(Locale locale) {
118 super (locale);
119 this .canWriteProgressive = true;
120 this .progressiveMode = MODE_DISABLED;
121 this .canWriteCompressed = true;
122 this .compressionTypes = compressionNames;
123 this .compressionType = compressionTypes[0];
124 this .compressionQuality = JPEG.DEFAULT_QUALITY;
125 }
126
127 /**
128 * Removes any previous compression quality setting.
129 *
130 * <p> The default implementation resets the compression quality
131 * to <code>0.75F</code>.
132 *
133 * @exception IllegalStateException if the compression mode is not
134 * <code>MODE_EXPLICIT</code>.
135 */
136 public void unsetCompression() {
137 if (getCompressionMode() != MODE_EXPLICIT) {
138 throw new IllegalStateException(
139 "Compression mode not MODE_EXPLICIT!");
140 }
141 this .compressionQuality = JPEG.DEFAULT_QUALITY;
142 }
143
144 /**
145 * Returns <code>false</code> since the JPEG plug-in only supports
146 * lossy compression.
147 *
148 * @return <code>false</code>.
149 *
150 * @exception IllegalStateException if the compression mode is not
151 * <code>MODE_EXPLICIT</code>.
152 */
153 public boolean isCompressionLossless() {
154 if (getCompressionMode() != MODE_EXPLICIT) {
155 throw new IllegalStateException(
156 "Compression mode not MODE_EXPLICIT!");
157 }
158 return false;
159 }
160
161 public String[] getCompressionQualityDescriptions() {
162 if (getCompressionMode() != MODE_EXPLICIT) {
163 throw new IllegalStateException(
164 "Compression mode not MODE_EXPLICIT!");
165 }
166 if ((getCompressionTypes() != null)
167 && (getCompressionType() == null)) {
168 throw new IllegalStateException("No compression type set!");
169 }
170 return (String[]) qualityDescs.clone();
171 }
172
173 public float[] getCompressionQualityValues() {
174 if (getCompressionMode() != MODE_EXPLICIT) {
175 throw new IllegalStateException(
176 "Compression mode not MODE_EXPLICIT!");
177 }
178 if ((getCompressionTypes() != null)
179 && (getCompressionType() == null)) {
180 throw new IllegalStateException("No compression type set!");
181 }
182 return (float[]) qualityVals.clone();
183 }
184
185 /**
186 * Returns <code>true</code> if tables are currently set.
187 *
188 * @return <code>true</code> if tables are present.
189 */
190 public boolean areTablesSet() {
191 return (qTables != null);
192 }
193
194 /**
195 * Sets the quantization and Huffman tables to use in encoding
196 * abbreviated streams. There may be a maximum of 4 tables of
197 * each type. These tables are ignored if tables are specified in
198 * the metadata. All arguments must be non-<code>null</code>.
199 * The two arrays of Huffman tables must have the same number of
200 * elements. The table specifiers in the frame and scan headers
201 * in the metadata are assumed to be equivalent to indices into
202 * these arrays. The argument arrays are copied by this method.
203 *
204 * @param qTables An array of quantization table objects.
205 * @param DCHuffmanTables An array of Huffman table objects.
206 * @param ACHuffmanTables An array of Huffman table objects.
207 *
208 * @exception IllegalArgumentException if any of the arguments
209 * is <code>null</code> or has more than 4 elements, or if the
210 * numbers of DC and AC tables differ.
211 *
212 * @see #unsetEncodeTables
213 */
214 public void setEncodeTables(JPEGQTable[] qTables,
215 JPEGHuffmanTable[] DCHuffmanTables,
216 JPEGHuffmanTable[] ACHuffmanTables) {
217 if ((qTables == null) || (DCHuffmanTables == null)
218 || (ACHuffmanTables == null) || (qTables.length > 4)
219 || (DCHuffmanTables.length > 4)
220 || (ACHuffmanTables.length > 4)
221 || (DCHuffmanTables.length != ACHuffmanTables.length)) {
222 throw new IllegalArgumentException(
223 "Invalid JPEG table arrays");
224 }
225 this .qTables = (JPEGQTable[]) qTables.clone();
226 this .DCHuffmanTables = (JPEGHuffmanTable[]) DCHuffmanTables
227 .clone();
228 this .ACHuffmanTables = (JPEGHuffmanTable[]) ACHuffmanTables
229 .clone();
230 }
231
232 /**
233 * Removes any quantization and Huffman tables that are currently
234 * set.
235 *
236 * @see #setEncodeTables
237 */
238 public void unsetEncodeTables() {
239 this .qTables = null;
240 this .DCHuffmanTables = null;
241 this .ACHuffmanTables = null;
242 }
243
244 /**
245 * Returns a copy of the array of quantization tables set on the
246 * most recent call to <code>setEncodeTables</code>, or
247 * <code>null</code> if tables are not currently set.
248 *
249 * @return an array of <code>JPEGQTable</code> objects, or
250 * <code>null</code>.
251 *
252 * @see #setEncodeTables
253 */
254 public JPEGQTable[] getQTables() {
255 return (qTables != null) ? (JPEGQTable[]) qTables.clone()
256 : null;
257 }
258
259 /**
260 * Returns a copy of the array of DC Huffman tables set on the
261 * most recent call to <code>setEncodeTables</code>, or
262 * <code>null</code> if tables are not currently set.
263 *
264 * @return an array of <code>JPEGHuffmanTable</code> objects, or
265 * <code>null</code>.
266 *
267 * @see #setEncodeTables
268 */
269 public JPEGHuffmanTable[] getDCHuffmanTables() {
270 return (DCHuffmanTables != null) ? (JPEGHuffmanTable[]) DCHuffmanTables
271 .clone()
272 : null;
273 }
274
275 /**
276 * Returns a copy of the array of AC Huffman tables set on the
277 * most recent call to <code>setEncodeTables</code>, or
278 * <code>null</code> if tables are not currently set.
279 *
280 * @return an array of <code>JPEGHuffmanTable</code> objects, or
281 * <code>null</code>.
282 *
283 * @see #setEncodeTables
284 */
285 public JPEGHuffmanTable[] getACHuffmanTables() {
286 return (ACHuffmanTables != null) ? (JPEGHuffmanTable[]) ACHuffmanTables
287 .clone()
288 : null;
289 }
290
291 /**
292 * Tells the writer to generate optimized Huffman tables
293 * for the image as part of the writing process. The
294 * default is <code>false</code>. If this flag is set
295 * to <code>true</code>, it overrides any tables specified
296 * in the metadata. Note that this means that any image
297 * written with this flag set to <code>true</code> will
298 * always contain Huffman tables.
299 *
300 * @param optimize A boolean indicating whether to generate
301 * optimized Huffman tables when writing.
302 *
303 * @see #getOptimizeHuffmanTables
304 */
305 public void setOptimizeHuffmanTables(boolean optimize) {
306 optimizeHuffman = optimize;
307 }
308
309 /**
310 * Returns the value passed into the most recent call
311 * to <code>setOptimizeHuffmanTables</code>, or
312 * <code>false</code> if <code>setOptimizeHuffmanTables</code>
313 * has never been called.
314 *
315 * @return <code>true</code> if the writer will generate optimized
316 * Huffman tables.
317 *
318 * @see #setOptimizeHuffmanTables
319 */
320 public boolean getOptimizeHuffmanTables() {
321 return optimizeHuffman;
322 }
323 }
|