1 /* 2 * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.imageio.plugins.jpeg; 27 28 import java.util.Locale; 29 import javax.imageio.ImageWriteParam; 30 31 import com.sun.imageio.plugins.jpeg.JPEG; 32 33 /** 34 * This class adds the ability to set JPEG quantization and Huffman 35 * tables when using the built-in JPEG writer plug-in, and to request that 36 * optimized Huffman tables be computed for an image. An instance of 37 * this class will be returned from the 38 * <code>getDefaultImageWriteParam</code> methods of the built-in JPEG 39 * <code>ImageWriter</code>. 40 41 * <p> The principal purpose of these additions is to allow the 42 * specification of tables to use in encoding abbreviated streams. 43 * The built-in JPEG writer will also accept an ordinary 44 * <code>ImageWriteParam</code>, in which case the writer will 45 * construct the necessary tables internally. 46 * 47 * <p> In either case, the quality setting in an <code>ImageWriteParam</code> 48 * has the same meaning as for the underlying library: 1.00 means a 49 * quantization table of all 1's, 0.75 means the "standard", visually 50 * lossless quantization table, and 0.00 means aquantization table of 51 * all 255's. 52 * 53 * <p> While tables for abbreviated streams are often specified by 54 * first writing an abbreviated stream containing only the tables, in 55 * some applications the tables are fixed ahead of time. This class 56 * allows the tables to be specified directly from client code. 57 * 58 * <p> Normally, the tables are specified in the 59 * <code>IIOMetadata</code> objects passed in to the writer, and any 60 * tables included in these objects are written to the stream. 61 * If no tables are specified in the metadata, then an abbreviated 62 * stream is written. If no tables are included in the metadata and 63 * no tables are specified in a <code>JPEGImageWriteParam</code>, then 64 * an abbreviated stream is encoded using the "standard" visually 65 * lossless tables. This class is necessary for specifying tables 66 * when an abbreviated stream must be written without writing any tables 67 * to a stream first. In order to use this class, the metadata object 68 * passed into the writer must contain no tables, and no stream metadata 69 * must be provided. See {@link JPEGQTable JPEGQTable} and 70 * {@link JPEGHuffmanTable JPEGHuffmanTable} for more 71 * information on the default tables. 72 * 73 * <p> The default <code>JPEGImageWriteParam</code> returned by the 74 * <code>getDefaultWriteParam</code> method of the writer contains no 75 * tables. Default tables are included in the default 76 * <code>IIOMetadata</code> objects returned by the writer. 77 * 78 * <p> If the metadata does contain tables, the tables given in a 79 * <code>JPEGImageWriteParam</code> are ignored. Furthermore, once a 80 * set of tables has been written, only tables in the metadata can 81 * override them for subsequent writes, whether to the same stream or 82 * a different one. In order to specify new tables using this class, 83 * the {@link javax.imageio.ImageWriter#reset reset} 84 * method of the writer must be called. 85 * 86 * <p> 87 * For more information about the operation of the built-in JPEG plug-ins, 88 * see the <A HREF="../../metadata/doc-files/jpeg_metadata.html">JPEG 89 * metadata format specification and usage notes</A>. 90 * 91 */ 92 public class JPEGImageWriteParam extends ImageWriteParam { 93 94 private JPEGQTable[] qTables = null; 95 private JPEGHuffmanTable[] DCHuffmanTables = null; 96 private JPEGHuffmanTable[] ACHuffmanTables = null; 97 private boolean optimizeHuffman = false; 98 private String[] compressionNames = {"JPEG"}; 99 private float[] qualityVals = { 0.00F, 0.30F, 0.75F, 1.00F }; 100 private String[] qualityDescs = { 101 "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 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 qualityVals.clone(); 183 } 184 /** 185 * Returns <code>true</code> if tables are currently set. 186 * 187 * @return <code>true</code> if tables are present. 188 */ 189 public boolean areTablesSet() { 190 return (qTables != null); 191 } 192 193 /** 194 * Sets the quantization and Huffman tables to use in encoding 195 * abbreviated streams. There may be a maximum of 4 tables of 196 * each type. These tables are ignored if tables are specified in 197 * the metadata. All arguments must be non-<code>null</code>. 198 * The two arrays of Huffman tables must have the same number of 199 * elements. The table specifiers in the frame and scan headers 200 * in the metadata are assumed to be equivalent to indices into 201 * these arrays. The argument arrays are copied by this method. 202 * 203 * @param qTables An array of quantization table objects. 204 * @param DCHuffmanTables An array of Huffman table objects. 205 * @param ACHuffmanTables An array of Huffman table objects. 206 * 207 * @exception IllegalArgumentException if any of the arguments 208 * is <code>null</code> or has more than 4 elements, or if the 209 * numbers of DC and AC tables differ. 210 * 211 * @see #unsetEncodeTables 212 */ 213 public void setEncodeTables(JPEGQTable[] qTables, 214 JPEGHuffmanTable[] DCHuffmanTables, 215 JPEGHuffmanTable[] ACHuffmanTables) { 216 if ((qTables == null) || 217 (DCHuffmanTables == null) || 218 (ACHuffmanTables == null) || 219 (qTables.length > 4) || 220 (DCHuffmanTables.length > 4) || 221 (ACHuffmanTables.length > 4) || 222 (DCHuffmanTables.length != ACHuffmanTables.length)) { 223 throw new IllegalArgumentException("Invalid JPEG table arrays"); 224 } 225 this.qTables = qTables.clone(); 226 this.DCHuffmanTables = DCHuffmanTables.clone(); 227 this.ACHuffmanTables = ACHuffmanTables.clone(); 228 } 229 230 /** 231 * Removes any quantization and Huffman tables that are currently 232 * set. 233 * 234 * @see #setEncodeTables 235 */ 236 public void unsetEncodeTables() { 237 this.qTables = null; 238 this.DCHuffmanTables = null; 239 this.ACHuffmanTables = null; 240 } 241 242 /** 243 * Returns a copy of the array of quantization tables set on the 244 * most recent call to <code>setEncodeTables</code>, or 245 * <code>null</code> if tables are not currently set. 246 * 247 * @return an array of <code>JPEGQTable</code> objects, or 248 * <code>null</code>. 249 * 250 * @see #setEncodeTables 251 */ 252 public JPEGQTable[] getQTables() { 253 return (qTables != null) ? qTables.clone() : null; 254 } 255 256 /** 257 * Returns a copy of the array of DC Huffman tables set on the 258 * most recent call to <code>setEncodeTables</code>, or 259 * <code>null</code> if tables are not currently set. 260 * 261 * @return an array of <code>JPEGHuffmanTable</code> objects, or 262 * <code>null</code>. 263 * 264 * @see #setEncodeTables 265 */ 266 public JPEGHuffmanTable[] getDCHuffmanTables() { 267 return (DCHuffmanTables != null) 268 ? DCHuffmanTables.clone() 269 : null; 270 } 271 272 /** 273 * Returns a copy of the array of AC Huffman tables set on the 274 * most recent call to <code>setEncodeTables</code>, or 275 * <code>null</code> if tables are not currently set. 276 * 277 * @return an array of <code>JPEGHuffmanTable</code> objects, or 278 * <code>null</code>. 279 * 280 * @see #setEncodeTables 281 */ 282 public JPEGHuffmanTable[] getACHuffmanTables() { 283 return (ACHuffmanTables != null) 284 ? ACHuffmanTables.clone() 285 : null; 286 } 287 288 /** 289 * Tells the writer to generate optimized Huffman tables 290 * for the image as part of the writing process. The 291 * default is <code>false</code>. If this flag is set 292 * to <code>true</code>, it overrides any tables specified 293 * in the metadata. Note that this means that any image 294 * written with this flag set to <code>true</code> will 295 * always contain Huffman tables. 296 * 297 * @param optimize A boolean indicating whether to generate 298 * optimized Huffman tables when writing. 299 * 300 * @see #getOptimizeHuffmanTables 301 */ 302 public void setOptimizeHuffmanTables(boolean optimize) { 303 optimizeHuffman = optimize; 304 } 305 306 /** 307 * Returns the value passed into the most recent call 308 * to <code>setOptimizeHuffmanTables</code>, or 309 * <code>false</code> if <code>setOptimizeHuffmanTables</code> 310 * has never been called. 311 * 312 * @return <code>true</code> if the writer will generate optimized 313 * Huffman tables. 314 * 315 * @see #setOptimizeHuffmanTables 316 */ 317 public boolean getOptimizeHuffmanTables() { 318 return optimizeHuffman; 319 } 320 }