001: /*
002: * $RCSfile: JPEGEncodeParam.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:55:31 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.codec;
013:
014: import java.awt.image.RenderedImage;
015:
016: /**
017: * A class which encapsulates the most common functionality required for
018: * the parameters to a Jpeg encode operation. It does not include all of
019: * the parameters of the <code>com.sun.image.codec.jpeg</code> classes.
020: * Users needing that additional functionality should use those classes
021: * directly, bearing in mind that they are part of an uncommitted non-core
022: * interface that may be modified or removed in the future.
023: *
024: * This class makes very simple assumptions about the image colorspaces.
025: * Images with a single band are assumed to be grayscale.
026: * Images with three bands are assumed to be RGB and are encoded to YCbCr.
027: *
028: * <p><b> This class is not a committed part of the JAI API. It may
029: * be removed or changed in future releases of JAI.</b>
030: */
031: public class JPEGEncodeParam implements ImageEncodeParam {
032:
033: private static int JPEG_MAX_BANDS = 3;
034:
035: private int[] hSamp;
036: private int[] vSamp;
037: private int[][] qTab;
038: private int[] qTabSlot;
039: private float qual;
040: private int rstInterval;
041: private boolean writeImageOnly;
042: private boolean writeTablesOnly;
043: private boolean writeJFIFHeader;
044: private boolean qualitySet;
045: private boolean[] qTabSet;
046:
047: /**
048: * Constructs a JAI JPEGEncodeParam object with default settings.
049: */
050: public JPEGEncodeParam() {
051: //
052: // Set all the defaults
053: //
054: hSamp = new int[JPEG_MAX_BANDS];
055: vSamp = new int[JPEG_MAX_BANDS];
056: qTabSlot = new int[JPEG_MAX_BANDS];
057: qTab = new int[JPEG_MAX_BANDS][];
058: qTabSet = new boolean[JPEG_MAX_BANDS];
059:
060: // Y channel - full resolution sampling
061: hSamp[0] = 1;
062: vSamp[0] = 1;
063: qTabSlot[0] = 0;
064: qTab[0] = null;
065: qTabSet[0] = false;
066:
067: // Cb channel - sample by 2 in each axis
068: hSamp[1] = 2;
069: vSamp[1] = 2;
070: qTabSlot[1] = 1;
071: qTab[1] = null;
072: qTabSet[1] = false;
073:
074: // Cr channel - sample by 2 in each axis
075: hSamp[2] = 2;
076: vSamp[2] = 2;
077: qTabSlot[2] = 1;
078: qTab[2] = null;
079: qTabSet[2] = false;
080:
081: qual = 0.75F;
082: rstInterval = 0;
083: writeImageOnly = false;
084: writeTablesOnly = false;
085: writeJFIFHeader = true;
086: }
087:
088: /**
089: * Sets the horizontal subsampling to be applied to an image band.
090: * Defaults to 1 for grayscale and (1,2,2) for RGB.
091: * @param component The band for which to set horizontal subsampling.
092: * @param subsample The horizontal subsampling factor.
093: */
094: public void setHorizontalSubsampling(int component, int subsample) {
095: hSamp[component] = subsample;
096: }
097:
098: /**
099: * Get the horizontal subsampling factor for a band.
100: * @param component The band of the image for which to retrieve subsampling.
101: * @return The horizontal subsampling factor to be applied to this band
102: */
103: public int getHorizontalSubsampling(int component) {
104: return hSamp[component];
105: }
106:
107: /**
108: * Sets the vertical subsampling to be applied to an image band.
109: * Defaults to 1 for grayscale and (1,2,2) for RGB.
110: * @param component The band for which to set vertical subsampling.
111: * @param subsample The vertical subsampling factor.
112: */
113: public void setVerticalSubsampling(int component, int subsample) {
114: vSamp[component] = subsample;
115: }
116:
117: /**
118: * Get the vertical subsampling factor for a band.
119: * @param component The band of the image for which to retrieve subsampling.
120: * @return The vertical subsampling factor to be applied to this band
121: */
122: public int getVerticalSubsampling(int component) {
123: return vSamp[component];
124: }
125:
126: /**
127: * Sets the quantization table to be used for luminance data.
128: * This is a convenience method which explicitly sets the
129: * contents of quantization table 0. The length of the table must be 64.
130: * This disables any quality setting.
131: * @param qTable Quantization table values in "zig-zag" order.
132: */
133: public void setLumaQTable(int[] qTable) {
134: setQTable(0, 0, qTable);
135: qTabSet[0] = true;
136: qualitySet = false;
137: }
138:
139: /**
140: * Sets the quantization table to be used for chrominance data.
141: * This is a convenience method which explicitly sets the
142: * contents of quantization table 1. The length of the table must be 64.
143: * This method assumes that all chroma components will use the same table.
144: * This disables any quality setting.
145: * @param qTable Quantization table values in "zig-zag" order.
146: */
147: public void setChromaQTable(int[] qTable) {
148: setQTable(1, 1, qTable);
149: setQTable(2, 1, qTable);
150: qTabSet[1] = true;
151: qTabSet[2] = true;
152: qualitySet = false;
153: }
154:
155: /**
156: * Sets a quantization table to be used for a component.
157: * This method allows up to four independent tables to be specified.
158: * This disables any quality setting.
159: * @param component The band to which this table applies.
160: * @param tableSlot The table number that this table is assigned to (0 to 3).
161: * @param qTable Quantization table values in "zig-zag" order.
162: */
163: public void setQTable(int component, int tableSlot, int[] qTable) {
164: qTab[component] = (int[]) (qTable.clone());
165: qTabSlot[component] = tableSlot;
166: qTabSet[component] = true;
167: qualitySet = false;
168: }
169:
170: /**
171: * Tests if a Quantization table has been set.
172: * @return Returns true is the specified quantization table has been set.
173: */
174: public boolean isQTableSet(int component) {
175: return qTabSet[component];
176: }
177:
178: /**
179: * Retrieve the contents of the quantization table used for a component.
180: * @param component The band to which this table applies.
181: * @return The contents of the quantization table as a reference.
182: * @throws IllegalStateException if table has not been previously set for this component.
183: */
184: public int[] getQTable(int component) {
185: if (!qTabSet[component]) {
186: throw new IllegalStateException(JaiI18N
187: .getString("JPEGEncodeParam0"));
188: }
189: return qTab[component];
190: }
191:
192: /**
193: * Retrieve the quantization table slot used for a component.
194: * @param component The band to which this table slot applies.
195: * @return The table slot used for this band.
196: * @throws IllegalStateException if table has not been previously set for this component.
197: */
198: public int getQTableSlot(int component) {
199: if (!qTabSet[component]) {
200: throw new IllegalStateException(JaiI18N
201: .getString("JPEGEncodeParam0"));
202: }
203: return qTabSlot[component];
204: }
205:
206: /**
207: * Sets the restart interval in Minimum Coded Units (MCUs).
208: * This can be useful in some environments to limit the effect
209: * of bitstream errors to a single restart interval.
210: * The default is zero (no restart interval markers).
211: * @param restartInterval Number of MCUs between restart markers.
212: */
213: public void setRestartInterval(int restartInterval) {
214: rstInterval = restartInterval;
215: }
216:
217: /**
218: * Gets the restart interval in Minimum Coded Units (MCUs).
219: * @return The restart interval in MCUs (0 if not set).
220: */
221: public int getRestartInterval() {
222: return rstInterval;
223: }
224:
225: /**
226: * This creates new quantization tables that replace the currently
227: * installed quantization tables.
228:
229: * The created quantization table varies from very high
230: * compression, very low quality, (0.0) to low compression, very
231: * high quality (1.0) based on the quality parameter.<P>
232:
233: * At a quality level of 1.0 the table will be all 1's which will
234: * lead to no loss of data due to quantization (however chrominace
235: * subsampling, if used, and roundoff error in the DCT will still
236: * degrade the image some what).<P>
237:
238: * The default setting is 0.75 which provides high quality while
239: * insuring a good compression ratio.
240:
241: * <pre>Some guidelines: 0.75 high quality
242: * 0.5 medium quality
243: * 0.25 low quality
244: * </pre>
245: * @param quality 0.0-1.0 setting of desired quality level.
246: */
247: public void setQuality(float quality) {
248: qual = quality;
249: // Reset custom Q tables
250: for (int i = 0; i < JPEG_MAX_BANDS; i++) {
251: qTabSet[i] = false;
252: }
253: qualitySet = true;
254: }
255:
256: /**
257: * Tests if the quality parameter has been set in this JPEGEncodeParam.
258: * @return True/false flag indicating if quality has been set.
259: */
260: public boolean isQualitySet() {
261: return qualitySet;
262: }
263:
264: /**
265: * Retrieve the quality setting for this encoding.
266: * This is a number between 0.0 and 1.0.
267: *
268: * @return The specified quality setting (0.75 if not set).
269: */
270: public float getQuality() {
271: return qual;
272: }
273:
274: /**
275: * Instructs the encoder to write only the table data to the output stream.
276: * This is considered an abbreviated JPEG stream. Defaults to false -- normally
277: * both tables and encoded image data are written.
278: * @param tablesOnly If true, only the tables will be written.
279: */
280: public void setWriteTablesOnly(boolean tablesOnly) {
281: writeTablesOnly = tablesOnly;
282: }
283:
284: /**
285: * Retrieve the setting of the writeTablesOnly flag.
286: * @return The setting of the writeTablesOnly flag (false if not set).
287: */
288: public boolean getWriteTablesOnly() {
289: return writeTablesOnly;
290: }
291:
292: /**
293: * Controls whether the encoder writes only the compressed image data
294: * to the output stream.
295: * This is considered an abbreviated JPEG stream. Defaults to false -- normally
296: * both tables and compressed image data are written.
297: * @param imageOnly If true, only the compressed image will be written.
298: */
299: public void setWriteImageOnly(boolean imageOnly) {
300: writeImageOnly = imageOnly;
301: }
302:
303: /**
304: * Retrieve the setting of the writeImageOnly flag.
305: * @return The setting of the writeImageOnly flag (false if not set).
306: */
307: public boolean getWriteImageOnly() {
308: return writeImageOnly;
309: }
310:
311: /**
312: * Controls whether the encoder writes a JFIF header using the APP0 marker.
313: * By default an APP0 marker is written to create a JFIF file.
314: * @param writeJFIF If true, writes a JFIF header.
315: */
316: public void setWriteJFIFHeader(boolean writeJFIF) {
317: writeJFIFHeader = writeJFIF;
318: }
319:
320: /**
321: * Retrieve the setting of the writeJFIF flag.
322: * @return The setting of the writeJFIF flag (true if not set).
323: */
324: public boolean getWriteJFIFHeader() {
325: return writeJFIFHeader;
326: }
327:
328: /**
329: * Returns a copy of this <code>JPEGEncodeParam</code> object.
330: */
331: public Object clone() {
332: try {
333: return super .clone();
334: } catch (CloneNotSupportedException e) {
335: // this shouldn't happen, since we are Cloneable
336: throw new InternalError();
337: }
338: }
339: }
|