001    /* JPEGImageWriteParam.java --
002     Copyright (C)  2006  Free Software Foundation, Inc.
003    
004     This file is part of GNU Classpath.
005    
006     GNU Classpath is free software; you can redistribute it and/or modify
007     it under the terms of the GNU General Public License as published by
008     the Free Software Foundation; either version 2, or (at your option)
009     any later version.
010    
011     GNU Classpath is distributed in the hope that it will be useful, but
012     WITHOUT ANY WARRANTY; without even the implied warranty of
013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     General Public License for more details.
015    
016     You should have received a copy of the GNU General Public License
017     along with GNU Classpath; see the file COPYING.  If not, write to the
018     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019     02110-1301 USA.
020    
021     Linking this library statically or dynamically with other modules is
022     making a combined work based on this library.  Thus, the terms and
023     conditions of the GNU General Public License cover the whole
024     combination.
025    
026     As a special exception, the copyright holders of this library give you
027     permission to link this library with independent modules to produce an
028     executable, regardless of the license terms of these independent
029     modules, and to copy and distribute the resulting executable under
030     terms of your choice, provided that you also meet, for each linked
031     independent module, the terms and conditions of the license of that
032     module.  An independent module is a module which is not derived from
033     or based on this library.  If you modify this library, you may extend
034     this exception to your version of the library, but you are not
035     obligated to do so.  If you do not wish to do so, delete this
036     exception statement from your version. */
037    
038    
039    package javax.imageio.plugins.jpeg;
040    
041    import java.util.Locale;
042    import java.util.PropertyResourceBundle;
043    import java.util.ResourceBundle;
044    import javax.imageio.ImageWriteParam;
045    
046    /**
047     * The JPEGImageWriteParam class can be used to specify tables and
048     * settings used in the JPEG encoding process.  Encoding tables are
049     * taken from the metadata associated with the output stream, and
050     * failing that (if the metadata tables are null) from an instance of
051     * JPEGImageWriteParam.  The default metadata uses the standard JPEG
052     * tables from the JPEGQTable and JPEGHuffmanTable classes.  Non-null
053     * metadata tables override JPEGImageWriteParam tables.  Compression
054     * settings range from 1.0, best compression, through 0.75, default
055     * compression, to 0.0, worst compression.
056     *
057     * A JPEGImageWriteParam instance is retrieved from the built-in JPEG
058     * ImageWriter using the getDefaultImageWriteParam method.
059     */
060    public class JPEGImageWriteParam
061      extends ImageWriteParam
062    {
063      private JPEGQTable[] qTables;
064      private JPEGHuffmanTable[] DCHuffmanTables;
065      private JPEGHuffmanTable[] ACHuffmanTables;
066      private boolean optimize;
067      private String[] compressionQualityDescriptions;
068      private float[] compressionQualityValues;
069    
070      /**
071       * Localized messages are stored in separate files.
072       */
073      private ResourceBundle messages;
074    
075      /**
076       * Construct a JPEGImageWriteParam with the following state: tiling
077       * is not supported, progressive mode is supported, initial
078       * progressive mode is MODE_DISABLED, compression is supported, one
079       * compression type named "JPEG" is supported and the default
080       * compression quality is 0.75f.  Compression type names and
081       * compression quality descriptions are localized to the given
082       * locale.
083       *
084       * @param locale the locale used for message localization
085       */
086      public JPEGImageWriteParam(Locale locale)
087      {
088        super(locale);
089    
090        // Get localized compression type and compression quality
091        // description strings for the given locale.
092        messages = PropertyResourceBundle.getBundle
093          ("javax/imageio/plugins/jpeg/MessagesBundle", locale);
094    
095        // Initialize inherited ImageWriter fields.
096        canWriteTiles = false;
097        canWriteProgressive = true;
098        progressiveMode = MODE_DISABLED;
099        canWriteCompressed = true;
100        compressionTypes = new String[]
101          {
102            messages.getString("compression.types.jpeg")
103          };
104        compressionType = compressionTypes[0];
105        compressionQuality = 0.75f;
106      }
107    
108      /**
109       * Reset the compression quality to 0.75f.
110       */
111      public void unsetCompression()
112      {
113        compressionQuality = 0.75f;
114      }
115    
116      /**
117       * Check if compression algorithm is lossless.  JPEGImageWriteParam
118       * overrides this ImageWriteParam method to always return false
119       * since JPEG compression is inherently lossy.
120       *
121       * @return false
122       */
123      public boolean isCompressionLossless()
124      {
125        return false;
126      }
127    
128      /**
129       * Retrieve an array of compression quality descriptions.  These
130       * messages are localized using the locale provided upon
131       * construction.  Each compression quality description in the
132       * returned array corresponds to the compression quality value at
133       * the same index in the array returned by
134       * getCompressionQualityValues.
135       *
136       * @return an array of strings each of which describes a compression
137       * quality value
138       */
139      public String[] getCompressionQualityDescriptions()
140      {
141        // Make sure exceptions are thrown when this image write param is
142        // in the wrong state.
143        super.getCompressionQualityDescriptions();
144    
145        if (compressionQualityDescriptions == null)
146          {
147            compressionQualityDescriptions = new String[]
148              {
149                messages.getString("compression.minimum"),
150                messages.getString("compression.default"),
151                messages.getString("compression.maximum")
152              };
153          }
154    
155        return compressionQualityDescriptions;
156      }
157    
158      /**
159       * Retrieve an array of compression quality values, ordered from
160       * lowest quality to highest quality.
161       *
162       * @return an array of compressions quality values
163       */
164      public float[] getCompressionQualityValues()
165      {
166        // Make sure exceptions are thrown when this image write param is
167        // in the wrong state.
168        super.getCompressionQualityValues();
169    
170        if (compressionQualityValues == null)
171          compressionQualityValues = new float[] { 0.05f, 0.75f, 0.95f };
172    
173        return compressionQualityValues;
174      }
175    
176      /**
177       * Check if the encoding tables are set.
178       *
179       * @return true if the encoding tables are set, false otherwise
180       */
181      public boolean areTablesSet()
182      {
183        // If qTables is not null then all tables are set.
184        return (qTables != null);
185      }
186    
187      /**
188       * Set the quantization and Huffman tables that will be used to
189       * encode the stream.  Copies are created of the array arguments.
190       * The number of Huffman tables must be the same in both Huffman
191       * table arrays.  No argument may be null and no array may be longer
192       * than four elements.
193       *
194       * @param qTables JPEG quantization tables
195       * @param DCHuffmanTables JPEG DC Huffman tables
196       * @param ACHuffmanTables JPEG AC Huffman tables
197       *
198       * @throws IllegalArgumentException if any argument is null, if any
199       * of the arrays are longer than four elements, or if the Huffman
200       * table arrays do not have the same number of elements
201       */
202      public void setEncodeTables(JPEGQTable[] qTables,
203                                  JPEGHuffmanTable[] DCHuffmanTables,
204                                  JPEGHuffmanTable[] ACHuffmanTables)
205      {
206        if (qTables == null || DCHuffmanTables == null || ACHuffmanTables == null)
207          throw new IllegalArgumentException("null argument");
208    
209        if (qTables.length > 4 || DCHuffmanTables.length > 4
210            || ACHuffmanTables.length > 4)
211          throw new IllegalArgumentException("argument has too many elements");
212    
213        if (DCHuffmanTables.length != ACHuffmanTables.length)
214          throw new IllegalArgumentException("Huffman table arrays differ in length");
215    
216        // Do a shallow copy.  JPEGQTable's data is not directly
217        // modifyable since JPEGQTable.getTable returns a copy.  Therefore
218        // it is safe to have multiple references to a single JPEGQTable.
219        // Likewise for JPEGHuffmanTable.
220        this.qTables = (JPEGQTable[]) qTables.clone();
221        this.DCHuffmanTables = (JPEGHuffmanTable[]) DCHuffmanTables.clone();
222        this.ACHuffmanTables = (JPEGHuffmanTable[]) ACHuffmanTables.clone();
223      }
224    
225      /**
226       * Clear the quantization and Huffman encoding tables.
227       */
228      public void unsetEncodeTables()
229      {
230        qTables = null;
231        DCHuffmanTables = null;
232        ACHuffmanTables = null;
233      }
234    
235      /**
236       * Retrieve the quantization tables.
237       *
238       * @returns an array of JPEG quantization tables
239       */
240      public JPEGQTable[] getQTables()
241      {
242        return qTables == null ? qTables : (JPEGQTable[]) qTables.clone();
243      }
244    
245      /**
246       * Retrieve the DC Huffman tables.
247       *
248       * @return an array of JPEG DC Huffman tables
249       */
250      public JPEGHuffmanTable[] getDCHuffmanTables()
251      {
252        return DCHuffmanTables == null ? DCHuffmanTables
253          : (JPEGHuffmanTable[]) DCHuffmanTables.clone();
254      }
255    
256      /**
257       * Retrieve the AC Huffman tables.
258       *
259       * @return an array of JPEG AC Huffman tables
260       */
261      public JPEGHuffmanTable[] getACHuffmanTables()
262      {
263        return ACHuffmanTables == null ? ACHuffmanTables
264          : (JPEGHuffmanTable[]) ACHuffmanTables.clone();
265      }
266    
267      /**
268       * Specify whether or not Huffman tables written to the output
269       * stream should be optimized.  Every image encoded with this flag
270       * set will contain a Huffman table, and the generated Huffman
271       * tables will override those specified in the metadata.
272       *
273       * @param optimize true to generate optimized Huffman tables, false
274       * otherwise
275       */
276      public void setOptimizeHuffmanTables(boolean optimize)
277      {
278        this.optimize = optimize;
279      }
280    
281      /**
282       * Check whether or not Huffman tables written to the output stream
283       * will be optimized.  Unless otherwise set using
284       * setOptimizeHuffmanTables, this returns false.
285       *
286       * @return true Huffman tables written to the output stream will be
287       * optimized, false otherwise
288       */
289      public boolean getOptimizeHuffmanTables()
290      {
291        return optimize;
292      }
293    }