001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: PNGDecodeParam.java 447277 2006-09-18 06:19:34Z jeremias $ */
019:
020: package org.apache.xmlgraphics.image.codec.png;
021:
022: import org.apache.xmlgraphics.image.codec.util.ImageDecodeParam;
023: import org.apache.xmlgraphics.image.codec.util.PropertyUtil;
024:
025: /**
026: * An instance of <code>ImageDecodeParam</code> for decoding images in
027: * the PNG format.
028: *
029: * <code>PNGDecodeParam</code> allows several aspects of the decoding
030: * process for PNG images to be controlled. By default, decoding produces
031: * output images with the following properties:
032: *
033: * <p> Images with a bit depth of 8 or less use a
034: * <code>DataBufferByte</code> to hold the pixel data. 16-bit images
035: * use a <code>DataBufferUShort</code>.
036: *
037: * <p> Palette color images and non-transparent grayscale images with
038: * bit depths of 1, 2, or 4 will have a
039: * <code>MultiPixelPackedSampleModel</code> and an
040: * <code>IndexColorModel</code>. For palette color images, the
041: * <code>ColorModel</code> palette contains the red, green, blue, and
042: * optionally alpha palette information. For grayscale images, the
043: * palette is used to expand the pixel data to cover the range 0-255.
044: * The pixels are stored packed 8, 4, or 2 to the byte.
045: *
046: * <p> All other images are stored using a
047: * <code>PixelInterleavedSampleModel</code> with each sample of a pixel
048: * occupying its own <code>byte</code> or <code>short</code> within
049: * the <code>DataBuffer</code>. A <code>ComponentColorModel</code> is
050: * used which simply extracts the red, green, blue, gray, and/or alpha
051: * information from separate <code>DataBuffer</code> entries.
052: *
053: * <p> Five aspects of this process may be altered by means of methods
054: * in this class.
055: *
056: * <p> <code>setSuppressAlpha()</code> prevents an alpha channel
057: * from appearing in the output.
058: *
059: * <p> <code>setExpandPalette()</code> turns palette-color images into
060: * 3-or 4-channel full-color images.
061: *
062: * <p> <code>setOutput8BitGray()</code> causes 1, 2, or 4 bit
063: * grayscale images to be output in 8-bit form, using a
064: * <code>ComponentSampleModel</code> and
065: * <code>ComponentColorModel</code>.
066: *
067: * <p> <code>setDecodingExponent()</code> causes the output image to be
068: * gamma-corrected using a supplied output gamma value.
069: *
070: * <p> <code>setExpandGrayAlpha()</code> causes 2-channel gray/alpha
071: * (GA) images to be output as full-color (GGGA) images, which may
072: * simplify further processing and display.
073: *
074: * <p><b> This class is not a committed part of the JAI API. It may
075: * be removed or changed in future releases of JAI.</b>
076: */
077: public class PNGDecodeParam implements ImageDecodeParam {
078:
079: /**
080: * Constructs a default instance of <code>PNGDecodeParam</code>.
081: */
082: public PNGDecodeParam() {
083: }
084:
085: private boolean suppressAlpha = false;
086:
087: /**
088: * Returns <code>true</code> if alpha (transparency) will
089: * be prevented from appearing in the output.
090: */
091: public boolean getSuppressAlpha() {
092: return suppressAlpha;
093: }
094:
095: /**
096: * If set, no alpha (transparency) channel will appear in the
097: * output image.
098: *
099: * <p> The default is to allow transparency to appear in the
100: * output image.
101: */
102: public void setSuppressAlpha(boolean suppressAlpha) {
103: this .suppressAlpha = suppressAlpha;
104: }
105:
106: private boolean expandPalette = false;
107:
108: /**
109: * Returns true if palette-color images will be expanded to
110: * produce full-color output.
111: */
112: public boolean getExpandPalette() {
113: return expandPalette;
114: }
115:
116: /**
117: * If set, palette color images (PNG color type 3) will
118: * be decoded into full-color (RGB) output images. The output
119: * image may have 3 or 4 channels, depending on the presence of
120: * transparency information.
121: *
122: * <p> The default is to output palette images using a single
123: * channel. The palette information is used to construct the
124: * output image's <code>ColorModel</code>.
125: */
126: public void setExpandPalette(boolean expandPalette) {
127: this .expandPalette = expandPalette;
128: }
129:
130: private boolean output8BitGray = false;
131:
132: /**
133: * Returns the current value of the 8-bit gray output parameter.
134: */
135: public boolean getOutput8BitGray() {
136: return output8BitGray;
137: }
138:
139: /**
140: * If set, grayscale images with a bit depth less than 8
141: * (1, 2, or 4) will be output in 8 bit form. The output values
142: * will occupy the full 8-bit range. For example, gray values
143: * 0, 1, 2, and 3 of a 2-bit image will be output as
144: * 0, 85, 170, and 255.
145: *
146: * <p> The decoding of non-grayscale images and grayscale images
147: * with a bit depth of 8 or 16 are unaffected by this setting.
148: *
149: * <p> The default is not to perform expansion. Grayscale images
150: * with a depth of 1, 2, or 4 bits will be represented using
151: * a <code>MultiPixelPackedSampleModel</code> and an
152: * <code>IndexColorModel</code>.
153: */
154: public void setOutput8BitGray(boolean output8BitGray) {
155: this .output8BitGray = output8BitGray;
156: }
157:
158: private boolean performGammaCorrection = true;
159:
160: /**
161: * Returns <code>true</code> if gamma correction is to be performed
162: * on the image data. The default is <code>true</code>.
163: *
164: * <p> If gamma correction is to be performed, the
165: * <code>getUserExponent()</code> and
166: * <code>getDisplayExponent()</code> methods are used in addition to
167: * the gamma value stored within the file (or the default value of
168: * 1/2.2 used if no value is found) to produce a single exponent
169: * using the formula:
170: * <pre>
171: * decoding_exponent = user_exponent/(gamma_from_file * display_exponent)
172: * </pre>
173: */
174: public boolean getPerformGammaCorrection() {
175: return performGammaCorrection;
176: }
177:
178: /**
179: * Turns gamma corection of the image data on or off.
180: */
181: public void setPerformGammaCorrection(boolean performGammaCorrection) {
182: this .performGammaCorrection = performGammaCorrection;
183: }
184:
185: private float userExponent = 1.0F;
186:
187: /**
188: * Returns the current value of the user exponent parameter.
189: * By default, the user exponent is equal to 1.0F.
190: */
191: public float getUserExponent() {
192: return userExponent;
193: }
194:
195: /**
196: * Sets the user exponent to a given value. The exponent
197: * must be positive. If not, an
198: * <code>IllegalArgumentException</code> will be thrown.
199: *
200: * <p> The output image pixels will be placed through a transformation
201: * of the form:
202: *
203: * <pre>
204: * sample = integer_sample / (2^bitdepth - 1.0)
205: * decoding_exponent = user_exponent/(gamma_from_file * display_exponent)
206: * output = sample ^ decoding_exponent
207: * </pre>
208: *
209: * where <code>gamma_from_file</code> is the gamma of the file
210: * data, as determined by the <code>gAMA</code>, </code>sRGB</code>,
211: * and/or <code>iCCP</code> chunks, and <code>display_exponent</code>
212: * is the exponent of the intrinsic transfer curve of the display,
213: * generally 2.2.
214: *
215: * <p> Input files which do not specify any gamma are assumed to
216: * have a gamma of <code>1/2.2</code>; such images may be displayed
217: * on a CRT with an exponent of 2.2 using the default user
218: * exponent of 1.0.
219: *
220: * <p> The user exponent may be used in order to change the
221: * effective gamma of a file. If a file has a stored gamma of
222: * X, but the decoder believes that the true file gamma is Y,
223: * setting a user exponent of Y/X will produce the same result
224: * as changing the file gamma.
225: *
226: * <p> This parameter affects the decoding of all image types.
227: *
228: * @throws IllegalArgumentException if <code>userExponent</code> is
229: * negative.
230: */
231: public void setUserExponent(float userExponent) {
232: if (userExponent <= 0.0F) {
233: throw new IllegalArgumentException(PropertyUtil
234: .getString("PNGDecodeParam0"));
235: }
236: this .userExponent = userExponent;
237: }
238:
239: private float displayExponent = 2.2F;
240:
241: /**
242: * Returns the current value of the display exponent parameter.
243: * By default, the display exponent is equal to 2.2F.
244: */
245: public float getDisplayExponent() {
246: return displayExponent;
247: }
248:
249: /**
250: * Sets the display exponent to a given value. The exponent
251: * must be positive. If not, an
252: * <code>IllegalArgumentException</code> will be thrown.
253: *
254: * <p> The output image pixels will be placed through a transformation
255: * of the form:
256: *
257: * <pre>
258: * sample = integer_sample / (2^bitdepth - 1.0)
259: * decoding_exponent = user_exponent/(gamma_from_file * display_exponent)
260: * output = sample ^ decoding_exponent
261: * </pre>
262: *
263: * where <code>gamma_from_file</code> is the gamma of the file
264: * data, as determined by the <code>gAMA</code>, </code>sRGB</code>,
265: * and/or <code>iCCP</code> chunks, and <code>user_exponent</code>
266: * is an additional user-supplied parameter.
267: *
268: * <p> Input files which do not specify any gamma are assumed to
269: * have a gamma of <code>1/2.2</code>; such images should be
270: * decoding using the default display exponent of 2.2.
271: *
272: * <p> If an image is to be processed further before being displayed,
273: * it may be preferable to set the display exponent to 1.0 in order
274: * to produce a linear output image.
275: *
276: * <p> This parameter affects the decoding of all image types.
277: *
278: * @throws IllegalArgumentException if <code>userExponent</code> is
279: * negative.
280: */
281: public void setDisplayExponent(float displayExponent) {
282: if (displayExponent <= 0.0F) {
283: throw new IllegalArgumentException(PropertyUtil
284: .getString("PNGDecodeParam1"));
285: }
286: this .displayExponent = displayExponent;
287: }
288:
289: private boolean expandGrayAlpha = false;
290:
291: /**
292: * Returns the current setting of the gray/alpha expansion.
293: */
294: public boolean getExpandGrayAlpha() {
295: return expandGrayAlpha;
296: }
297:
298: /**
299: * If set, images containing one channel of gray and one channel of
300: * alpha (GA) will be output in a 4-channel format (GGGA). This
301: * produces output that may be simpler to process and display.
302: *
303: * <p> This setting affects both images of color type 4 (explicit
304: * alpha) and images of color type 0 (grayscale) that contain
305: * transparency information.
306: *
307: * <p> By default, no expansion is performed.
308: */
309: public void setExpandGrayAlpha(boolean expandGrayAlpha) {
310: this .expandGrayAlpha = expandGrayAlpha;
311: }
312:
313: private boolean generateEncodeParam = false;
314:
315: private PNGEncodeParam encodeParam = null;
316:
317: /**
318: * Returns <code>true</code> if an instance of
319: * <code>PNGEncodeParam</code> will be available after an image
320: * has been decoded via the <code>getEncodeParam</code> method.
321: */
322: public boolean getGenerateEncodeParam() {
323: return generateEncodeParam;
324: }
325:
326: /**
327: * If set, an instance of <code>PNGEncodeParam</code> will be
328: * available after an image has been decoded via the
329: * <code>getEncodeParam</code> method that encapsulates information
330: * about the contents of the PNG file. If not set, this information
331: * will not be recorded and <code>getEncodeParam()</code> will
332: * return <code>null</code>.
333: */
334: public void setGenerateEncodeParam(boolean generateEncodeParam) {
335: this .generateEncodeParam = generateEncodeParam;
336: }
337:
338: /**
339: * If <code>getGenerateEncodeParam()</code> is <code>true</code>,
340: * this method may be called after decoding has completed, and
341: * will return an instance of <code>PNGEncodeParam</code> containing
342: * information about the contents of the PNG file just decoded.
343: */
344: public PNGEncodeParam getEncodeParam() {
345: return encodeParam;
346: }
347:
348: /**
349: * Sets the current encoder param instance. This method is
350: * intended to be called by the PNG decoder and will overwrite the
351: * current instance returned by <code>getEncodeParam</code>.
352: */
353: public void setEncodeParam(PNGEncodeParam encodeParam) {
354: this.encodeParam = encodeParam;
355: }
356: }
|