You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1491 lines
47 KiB
1491 lines
47 KiB
5 years ago
|
package com.fr.third.JAI;
|
||
|
/*
|
||
|
* Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions are met:
|
||
|
*
|
||
|
* -Redistributions of source code must retain the above copyright notice, this
|
||
|
* list of conditions and the following disclaimer.
|
||
|
*
|
||
|
* -Redistribution in binary form must reproduct the above copyright notice,
|
||
|
* this list of conditions and the following disclaimer in the documentation
|
||
|
* and/or other materials provided with the distribution.
|
||
|
*
|
||
|
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
|
||
|
* be used to endorse or promote products derived from this software without
|
||
|
* specific prior written permission.
|
||
|
*
|
||
|
* This software is provided "AS IS," without a warranty of any kind. ALL
|
||
|
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
|
||
|
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
|
||
|
* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
|
||
|
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
|
||
|
* OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
|
||
|
* LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
|
||
|
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
|
||
|
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
|
||
|
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
|
||
|
* POSSIBILITY OF SUCH DAMAGES.
|
||
|
*
|
||
|
* You acknowledge that Software is not designed,licensed or intended for use in
|
||
|
* the design, construction, operation or maintenance of any nuclear facility.
|
||
|
*/
|
||
|
import java.awt.image.ColorModel;
|
||
|
import java.awt.image.IndexColorModel;
|
||
|
import java.awt.image.RenderedImage;
|
||
|
import java.awt.image.SampleModel;
|
||
|
import java.util.Date;
|
||
|
import java.util.Vector;
|
||
|
|
||
|
/**
|
||
|
* An instance of <code>ImageEncodeParam</code> for encoding images in
|
||
|
* the PNG format.
|
||
|
*
|
||
|
* <p><b> This class is not a committed part of the JAI API. It may
|
||
|
* be removed or changed in future releases of JAI.</b>
|
||
|
*/
|
||
|
public abstract class PNGEncodeParam implements ImageEncodeParam {
|
||
|
|
||
|
/** Constant for use with the sRGB chunk. */
|
||
|
public static final int INTENT_PERCEPTUAL = 0;
|
||
|
|
||
|
/** Constant for use with the sRGB chunk. */
|
||
|
public static final int INTENT_RELATIVE = 1;
|
||
|
|
||
|
/** Constant for use with the sRGB chunk. */
|
||
|
public static final int INTENT_SATURATION = 2;
|
||
|
|
||
|
/** Constant for use with the sRGB chunk. */
|
||
|
public static final int INTENT_ABSOLUTE = 3;
|
||
|
|
||
|
/** Constant for use in filtering. */
|
||
|
public static final int PNG_FILTER_NONE = 0;
|
||
|
|
||
|
/** Constant for use in filtering. */
|
||
|
public static final int PNG_FILTER_SUB = 1;
|
||
|
|
||
|
/** Constant for use in filtering. */
|
||
|
public static final int PNG_FILTER_UP = 2;
|
||
|
|
||
|
/** Constant for use in filtering. */
|
||
|
public static final int PNG_FILTER_AVERAGE = 3;
|
||
|
|
||
|
/** Constant for use in filtering. */
|
||
|
public static final int PNG_FILTER_PAETH = 4;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Returns an instance of <code>PNGEncodeParam.Palette</code>,
|
||
|
* <code>PNGEncodeParam.Gray</code>, or
|
||
|
* <code>PNGEncodeParam.RGB</code> appropriate for encoding
|
||
|
* the given image.
|
||
|
*
|
||
|
* <p> If the image has an <code>IndexColorModel</code>, an
|
||
|
* instance of <code>PNGEncodeParam.Palette</code> is returned.
|
||
|
* Otherwise, if the image has 1 or 2 bands an instance of
|
||
|
* <code>PNGEncodeParam.Gray</code> is returned. In all other
|
||
|
* cases an instance of <code>PNGEncodeParam.RGB</code> is
|
||
|
* returned.
|
||
|
*
|
||
|
* <p> Note that this method does not provide any guarantee that
|
||
|
* the given image will be successfully encoded by the PNG
|
||
|
* encoder, as it only performs a very superficial analysis of
|
||
|
* the image structure.
|
||
|
*/
|
||
|
public static PNGEncodeParam getDefaultEncodeParam(RenderedImage im) {
|
||
|
ColorModel colorModel = im.getColorModel();
|
||
|
if (colorModel instanceof IndexColorModel) {
|
||
|
return new PNGEncodeParam.Palette();
|
||
|
}
|
||
|
|
||
|
SampleModel sampleModel = im.getSampleModel();
|
||
|
int numBands = sampleModel.getNumBands();
|
||
|
|
||
|
if (numBands == 1 || numBands == 2) {
|
||
|
return new PNGEncodeParam.Gray();
|
||
|
} else {
|
||
|
return new PNGEncodeParam.RGB();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static class Palette extends PNGEncodeParam {
|
||
|
|
||
|
/** Constructs an instance of <code>PNGEncodeParam.Palette</code>. */
|
||
|
public Palette() {}
|
||
|
|
||
|
// bKGD chunk
|
||
|
|
||
|
private boolean backgroundSet = false;
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'bKGD' chunk from being output.
|
||
|
*/
|
||
|
public void unsetBackground() {
|
||
|
backgroundSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'bKGD' chunk will be output.
|
||
|
*/
|
||
|
public boolean isBackgroundSet() {
|
||
|
return backgroundSet;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the desired bit depth for a palette image. The bit
|
||
|
* depth must be one of 1, 2, 4, or 8, or else an
|
||
|
* <code>IllegalArgumentException</code> will be thrown.
|
||
|
*/
|
||
|
public void setBitDepth(int bitDepth) {
|
||
|
if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 &&
|
||
|
bitDepth != 8) {
|
||
|
throw new IllegalArgumentException(JaiI18N.getString("PNGEncodeParam2"));
|
||
|
}
|
||
|
this.bitDepth = bitDepth;
|
||
|
bitDepthSet = true;
|
||
|
}
|
||
|
|
||
|
// PLTE chunk
|
||
|
|
||
|
private int[] palette = null;
|
||
|
private boolean paletteSet = false;
|
||
|
|
||
|
/**
|
||
|
* Sets the RGB palette of the image to be encoded.
|
||
|
* The <code>rgb</code> parameter contains alternating
|
||
|
* R, G, B values for each color index used in the image.
|
||
|
* The number of elements must be a multiple of 3 between
|
||
|
* 3 and 3*256.
|
||
|
*
|
||
|
* <p> The 'PLTE' chunk will encode this information.
|
||
|
*
|
||
|
* @param rgb An array of <code>int</code>s.
|
||
|
*/
|
||
|
public void setPalette(int[] rgb) {
|
||
|
if (rgb.length < 1*3 || rgb.length > 256*3) {
|
||
|
throw new
|
||
|
IllegalArgumentException(JaiI18N.getString("PNGEncodeParam0"));
|
||
|
}
|
||
|
if ((rgb.length % 3) != 0) {
|
||
|
throw new
|
||
|
IllegalArgumentException(JaiI18N.getString("PNGEncodeParam1"));
|
||
|
}
|
||
|
|
||
|
palette = (int[])(rgb.clone());
|
||
|
paletteSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the current RGB palette.
|
||
|
*
|
||
|
* <p> If the palette has not previously been set, or has been
|
||
|
* unset, an <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the palette is not set.
|
||
|
*
|
||
|
* @return An array of <code>int</code>s.
|
||
|
*/
|
||
|
public int[] getPalette() {
|
||
|
if (!paletteSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam3"));
|
||
|
}
|
||
|
return (int[])(palette.clone());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'PLTE' chunk from being output.
|
||
|
*/
|
||
|
public void unsetPalette() {
|
||
|
palette = null;
|
||
|
paletteSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'PLTE' chunk will be output.
|
||
|
*/
|
||
|
public boolean isPaletteSet() {
|
||
|
return paletteSet;
|
||
|
}
|
||
|
|
||
|
// bKGD chunk
|
||
|
|
||
|
private int backgroundPaletteIndex;
|
||
|
|
||
|
/**
|
||
|
* Sets the palette index of the suggested background color.
|
||
|
*
|
||
|
* <p> The 'bKGD' chunk will encode this information.
|
||
|
*/
|
||
|
public void setBackgroundPaletteIndex(int index) {
|
||
|
backgroundPaletteIndex = index;
|
||
|
backgroundSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the palette index of the suggested background color.
|
||
|
*
|
||
|
* <p> If the background palette index has not previously been
|
||
|
* set, or has been unset, an
|
||
|
* <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the palette index is not set.
|
||
|
*/
|
||
|
public int getBackgroundPaletteIndex() {
|
||
|
if (!backgroundSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam4"));
|
||
|
}
|
||
|
return backgroundPaletteIndex;
|
||
|
}
|
||
|
|
||
|
// tRNS chunk
|
||
|
|
||
|
private int[] transparency;
|
||
|
|
||
|
/**
|
||
|
* Sets the alpha values associated with each palette entry.
|
||
|
* The <code>alpha</code> parameter should have as many entries
|
||
|
* as there are RGB triples in the palette.
|
||
|
*
|
||
|
* <p> The 'tRNS' chunk will encode this information.
|
||
|
*/
|
||
|
public void setPaletteTransparency(byte[] alpha) {
|
||
|
transparency = new int[alpha.length];
|
||
|
for (int i = 0; i < alpha.length; i++) {
|
||
|
transparency[i] = alpha[i] & 0xff;
|
||
|
}
|
||
|
transparencySet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the alpha values associated with each palette entry.
|
||
|
*
|
||
|
* <p> If the palette transparency has not previously been
|
||
|
* set, or has been unset, an
|
||
|
* <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the palette transparency is
|
||
|
* not set.
|
||
|
*/
|
||
|
public byte[] getPaletteTransparency() {
|
||
|
if (!transparencySet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam5"));
|
||
|
}
|
||
|
byte[] alpha = new byte[transparency.length];
|
||
|
for (int i = 0; i < alpha.length; i++) {
|
||
|
alpha[i] = (byte)transparency[i];
|
||
|
}
|
||
|
return alpha;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static class Gray extends PNGEncodeParam {
|
||
|
|
||
|
/** Constructs an instance of <code>PNGEncodeParam.Gray</code>. */
|
||
|
public Gray() {}
|
||
|
|
||
|
// bKGD chunk
|
||
|
|
||
|
private boolean backgroundSet = false;
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'bKGD' chunk from being output.
|
||
|
*/
|
||
|
public void unsetBackground() {
|
||
|
backgroundSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'bKGD' chunk will be output.
|
||
|
*/
|
||
|
public boolean isBackgroundSet() {
|
||
|
return backgroundSet;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the desired bit depth for a grayscale image. The bit
|
||
|
* depth must be one of 1, 2, 4, 8, or 16.
|
||
|
*
|
||
|
* <p> When encoding a source image of a greater bit depth,
|
||
|
* pixel values will be clamped to the smaller range after
|
||
|
* shifting by the value given by <code>getBitShift()</code>.
|
||
|
* When encoding a source image of a smaller bit depth, pixel
|
||
|
* values will be shifted and left-filled with zeroes.
|
||
|
*/
|
||
|
public void setBitDepth(int bitDepth) {
|
||
|
if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 &&
|
||
|
bitDepth != 8 && bitDepth != 16) {
|
||
|
throw new IllegalArgumentException();
|
||
|
}
|
||
|
this.bitDepth = bitDepth;
|
||
|
bitDepthSet = true;
|
||
|
}
|
||
|
|
||
|
// bKGD chunk
|
||
|
|
||
|
private int backgroundPaletteGray;
|
||
|
|
||
|
/**
|
||
|
* Sets the suggested gray level of the background.
|
||
|
*
|
||
|
* <p> The 'bKGD' chunk will encode this information.
|
||
|
*/
|
||
|
public void setBackgroundGray(int gray) {
|
||
|
backgroundPaletteGray = gray;
|
||
|
backgroundSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the suggested gray level of the background.
|
||
|
*
|
||
|
* <p> If the background gray level has not previously been
|
||
|
* set, or has been unset, an
|
||
|
* <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the background gray level
|
||
|
* is not set.
|
||
|
*/
|
||
|
public int getBackgroundGray() {
|
||
|
if (!backgroundSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam6"));
|
||
|
}
|
||
|
return backgroundPaletteGray;
|
||
|
}
|
||
|
|
||
|
// tRNS chunk
|
||
|
|
||
|
private int[] transparency;
|
||
|
|
||
|
/**
|
||
|
* Sets the gray value to be used to denote transparency.
|
||
|
*
|
||
|
* <p> Setting this attribute will cause the alpha channel
|
||
|
* of the input image to be ignored.
|
||
|
*
|
||
|
* <p> The 'tRNS' chunk will encode this information.
|
||
|
*/
|
||
|
public void setTransparentGray(int transparentGray) {
|
||
|
transparency = new int[1];
|
||
|
transparency[0] = transparentGray;
|
||
|
transparencySet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the gray value to be used to denote transparency.
|
||
|
*
|
||
|
* <p> If the transparent gray value has not previously been
|
||
|
* set, or has been unset, an
|
||
|
* <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the transparent gray value
|
||
|
* is not set.
|
||
|
*/
|
||
|
public int getTransparentGray() {
|
||
|
if (!transparencySet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam7"));
|
||
|
}
|
||
|
int gray = transparency[0];
|
||
|
return gray;
|
||
|
}
|
||
|
|
||
|
private int bitShift;
|
||
|
private boolean bitShiftSet = false;
|
||
|
|
||
|
/**
|
||
|
* Sets the desired bit shift for a grayscale image.
|
||
|
* Pixels in the source image will be shifted right by
|
||
|
* the given amount prior to being clamped to the maximum
|
||
|
* value given by the encoded image's bit depth.
|
||
|
*/
|
||
|
public void setBitShift(int bitShift) {
|
||
|
if (bitShift < 0) {
|
||
|
throw new RuntimeException();
|
||
|
}
|
||
|
this.bitShift = bitShift;
|
||
|
bitShiftSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the desired bit shift for a grayscale image.
|
||
|
*
|
||
|
* <p> If the bit shift has not previously been set, or has been
|
||
|
* unset, an <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the bit shift is not set.
|
||
|
*/
|
||
|
public int getBitShift() {
|
||
|
if (!bitShiftSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam8"));
|
||
|
}
|
||
|
return bitShift;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suppresses the setting of the bit shift of a grayscale image.
|
||
|
* Pixels in the source image will not be shifted prior to encoding.
|
||
|
*/
|
||
|
public void unsetBitShift() {
|
||
|
bitShiftSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the bit shift has been set.
|
||
|
*/
|
||
|
public boolean isBitShiftSet() {
|
||
|
return bitShiftSet;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the bit depth has been set.
|
||
|
*/
|
||
|
public boolean isBitDepthSet() {
|
||
|
return bitDepthSet;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static class RGB extends PNGEncodeParam {
|
||
|
|
||
|
/** Constructs an instance of <code>PNGEncodeParam.RGB</code>. */
|
||
|
public RGB() {}
|
||
|
|
||
|
// bKGD chunk
|
||
|
|
||
|
private boolean backgroundSet = false;
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'bKGD' chunk from being output.
|
||
|
*/
|
||
|
public void unsetBackground() {
|
||
|
backgroundSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'bKGD' chunk will be output.
|
||
|
*/
|
||
|
public boolean isBackgroundSet() {
|
||
|
return backgroundSet;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the desired bit depth for an RGB image. The bit
|
||
|
* depth must be 8 or 16.
|
||
|
*/
|
||
|
public void setBitDepth(int bitDepth) {
|
||
|
if (bitDepth != 8 && bitDepth != 16) {
|
||
|
throw new RuntimeException();
|
||
|
}
|
||
|
this.bitDepth = bitDepth;
|
||
|
bitDepthSet = true;
|
||
|
}
|
||
|
|
||
|
// bKGD chunk
|
||
|
|
||
|
private int[] backgroundRGB;
|
||
|
|
||
|
/**
|
||
|
* Sets the RGB value of the suggested background color.
|
||
|
* The <code>rgb</code> parameter should have 3 entries.
|
||
|
*
|
||
|
* <p> The 'bKGD' chunk will encode this information.
|
||
|
*/
|
||
|
public void setBackgroundRGB(int[] rgb) {
|
||
|
if (rgb.length != 3) {
|
||
|
throw new RuntimeException();
|
||
|
}
|
||
|
backgroundRGB = rgb;
|
||
|
backgroundSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the RGB value of the suggested background color.
|
||
|
*
|
||
|
* <p> If the background color has not previously been set, or has been
|
||
|
* unset, an <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the background color is not set.
|
||
|
*/
|
||
|
public int[] getBackgroundRGB() {
|
||
|
if (!backgroundSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam9"));
|
||
|
}
|
||
|
return backgroundRGB;
|
||
|
}
|
||
|
|
||
|
// tRNS chunk
|
||
|
|
||
|
private int[] transparency;
|
||
|
|
||
|
/**
|
||
|
* Sets the RGB value to be used to denote transparency.
|
||
|
*
|
||
|
* <p> Setting this attribute will cause the alpha channel
|
||
|
* of the input image to be ignored.
|
||
|
*
|
||
|
* <p> The 'tRNS' chunk will encode this information.
|
||
|
*/
|
||
|
public void setTransparentRGB(int[] transparentRGB) {
|
||
|
transparency = (int[])(transparentRGB.clone());
|
||
|
transparencySet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the RGB value to be used to denote transparency.
|
||
|
*
|
||
|
* <p> If the transparent color has not previously been set,
|
||
|
* or has been unset, an <code>IllegalStateException</code>
|
||
|
* will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the transparent color is not set.
|
||
|
*/
|
||
|
public int[] getTransparentRGB() {
|
||
|
if (!transparencySet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam10"));
|
||
|
}
|
||
|
return (int[])(transparency.clone());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected int bitDepth;
|
||
|
protected boolean bitDepthSet = false;
|
||
|
|
||
|
/**
|
||
|
* Sets the desired bit depth of an image.
|
||
|
*/
|
||
|
public abstract void setBitDepth(int bitDepth);
|
||
|
|
||
|
/**
|
||
|
* Returns the desired bit depth for a grayscale image.
|
||
|
*
|
||
|
* <p> If the bit depth has not previously been set, or has been
|
||
|
* unset, an <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the bit depth is not set.
|
||
|
*/
|
||
|
public int getBitDepth() {
|
||
|
if (!bitDepthSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam11"));
|
||
|
}
|
||
|
return bitDepth;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suppresses the setting of the bit depth of a grayscale image.
|
||
|
* The depth of the encoded image will be inferred from the source
|
||
|
* image bit depth, rounded up to the next power of 2 between 1
|
||
|
* and 16.
|
||
|
*/
|
||
|
public void unsetBitDepth() {
|
||
|
bitDepthSet = false;
|
||
|
}
|
||
|
|
||
|
private boolean useInterlacing = false;
|
||
|
|
||
|
/**
|
||
|
* Turns Adam7 interlacing on or off.
|
||
|
*/
|
||
|
public void setInterlacing(boolean useInterlacing) {
|
||
|
this.useInterlacing = useInterlacing;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns <code>true</code> if Adam7 interlacing will be used.
|
||
|
*/
|
||
|
public boolean getInterlacing() {
|
||
|
return useInterlacing;
|
||
|
}
|
||
|
|
||
|
// bKGD chunk - delegate to subclasses
|
||
|
|
||
|
// In JAI 1.0, 'backgroundSet' was private. The JDK 1.2 compiler
|
||
|
// was lenient and incorrectly allowed this variable to be
|
||
|
// accessed from the subclasses. The JDK 1.3 compiler correctly
|
||
|
// flags this as a use of a non-static variable in a static
|
||
|
// context. Changing 'backgroundSet' to protected would have
|
||
|
// solved the problem, but would have introduced a visible API
|
||
|
// change. Thus we are forced to adopt the solution of placing a
|
||
|
// separate private variable in each subclass and providing
|
||
|
// separate implementations of 'unsetBackground' and
|
||
|
// 'isBackgroundSet' in each concrete subclass.
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'bKGD' chunk from being output.
|
||
|
* For API compatibility with JAI 1.0, the superclass
|
||
|
* defines this method to throw a <code>RuntimeException</code>;
|
||
|
* accordingly, subclasses must provide their own implementations.
|
||
|
*/
|
||
|
public void unsetBackground() {
|
||
|
throw new RuntimeException(JaiI18N.getString("PNGEncodeParam23"));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'bKGD' chunk will be output.
|
||
|
* For API compatibility with JAI 1.0, the superclass
|
||
|
* defines this method to throw a <code>RuntimeException</code>;
|
||
|
* accordingly, subclasses must provide their own implementations.
|
||
|
*/
|
||
|
public boolean isBackgroundSet() {
|
||
|
throw new RuntimeException(JaiI18N.getString("PNGEncodeParam24"));
|
||
|
}
|
||
|
|
||
|
// cHRM chunk
|
||
|
|
||
|
private float[] chromaticity = null;
|
||
|
private boolean chromaticitySet = false;
|
||
|
|
||
|
/**
|
||
|
* Sets the white point and primary chromaticities in CIE (x, y)
|
||
|
* space.
|
||
|
*
|
||
|
* <p> The <code>chromaticity</code> parameter should be a
|
||
|
* <code>float</code> array of length 8 containing the white point
|
||
|
* X and Y, red X and Y, green X and Y, and blue X and Y values in
|
||
|
* order.
|
||
|
*
|
||
|
* <p> The 'cHRM' chunk will encode this information.
|
||
|
*/
|
||
|
public void setChromaticity(float[] chromaticity) {
|
||
|
if (chromaticity.length != 8) {
|
||
|
throw new IllegalArgumentException();
|
||
|
}
|
||
|
this.chromaticity = (float[])(chromaticity.clone());
|
||
|
chromaticitySet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* A convenience method that calls the array version.
|
||
|
*/
|
||
|
public void setChromaticity(float whitePointX, float whitePointY,
|
||
|
float redX, float redY,
|
||
|
float greenX, float greenY,
|
||
|
float blueX, float blueY) {
|
||
|
float[] chroma = new float[8];
|
||
|
chroma[0] = whitePointX;
|
||
|
chroma[1] = whitePointY;
|
||
|
chroma[2] = redX;
|
||
|
chroma[3] = redY;
|
||
|
chroma[4] = greenX;
|
||
|
chroma[5] = greenY;
|
||
|
chroma[6] = blueX;
|
||
|
chroma[7] = blueY;
|
||
|
setChromaticity(chroma);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the white point and primary chromaticities in
|
||
|
* CIE (x, y) space.
|
||
|
*
|
||
|
* <p> See the documentation for the <code>setChromaticity</code>
|
||
|
* method for the format of the returned data.
|
||
|
*
|
||
|
* <p> If the chromaticity has not previously been set, or has been
|
||
|
* unset, an <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the chromaticity is not set.
|
||
|
*/
|
||
|
public float[] getChromaticity() {
|
||
|
if (!chromaticitySet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam12"));
|
||
|
}
|
||
|
return (float[])(chromaticity.clone());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'cHRM' chunk from being output.
|
||
|
*/
|
||
|
public void unsetChromaticity() {
|
||
|
chromaticity = null;
|
||
|
chromaticitySet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'cHRM' chunk will be output.
|
||
|
*/
|
||
|
public boolean isChromaticitySet() {
|
||
|
return chromaticitySet;
|
||
|
}
|
||
|
|
||
|
// gAMA chunk
|
||
|
|
||
|
private float gamma;
|
||
|
private boolean gammaSet = false;
|
||
|
|
||
|
/**
|
||
|
* Sets the file gamma value for the image.
|
||
|
*
|
||
|
* <p> The 'gAMA' chunk will encode this information.
|
||
|
*/
|
||
|
public void setGamma(float gamma) {
|
||
|
this.gamma = gamma;
|
||
|
gammaSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the file gamma value for the image.
|
||
|
*
|
||
|
* <p> If the file gamma has not previously been set, or has been
|
||
|
* unset, an <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the gamma is not set.
|
||
|
*/
|
||
|
public float getGamma() {
|
||
|
if (!gammaSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam13"));
|
||
|
}
|
||
|
return gamma;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'gAMA' chunk from being output.
|
||
|
*/
|
||
|
public void unsetGamma() {
|
||
|
gammaSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'gAMA' chunk will be output.
|
||
|
*/
|
||
|
public boolean isGammaSet() {
|
||
|
return gammaSet;
|
||
|
}
|
||
|
|
||
|
// hIST chunk
|
||
|
|
||
|
private int[] paletteHistogram = null;
|
||
|
private boolean paletteHistogramSet = false;
|
||
|
|
||
|
/**
|
||
|
* Sets the palette histogram to be stored with this image.
|
||
|
* The histogram consists of an array of integers, one per
|
||
|
* palette entry.
|
||
|
*
|
||
|
* <p> The 'hIST' chunk will encode this information.
|
||
|
*/
|
||
|
public void setPaletteHistogram(int[] paletteHistogram) {
|
||
|
this.paletteHistogram = (int[])(paletteHistogram.clone());
|
||
|
paletteHistogramSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the palette histogram to be stored with this image.
|
||
|
*
|
||
|
* <p> If the histogram has not previously been set, or has been
|
||
|
* unset, an <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the histogram is not set.
|
||
|
*/
|
||
|
public int[] getPaletteHistogram() {
|
||
|
if (!paletteHistogramSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam14"));
|
||
|
}
|
||
|
return paletteHistogram;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'hIST' chunk from being output.
|
||
|
*/
|
||
|
public void unsetPaletteHistogram() {
|
||
|
paletteHistogram = null;
|
||
|
paletteHistogramSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'hIST' chunk will be output.
|
||
|
*/
|
||
|
public boolean isPaletteHistogramSet() {
|
||
|
return paletteHistogramSet;
|
||
|
}
|
||
|
|
||
|
// iCCP chunk
|
||
|
|
||
|
private byte[] ICCProfileData = null;
|
||
|
private boolean ICCProfileDataSet = false;
|
||
|
|
||
|
/**
|
||
|
* Sets the ICC profile data to be stored with this image.
|
||
|
* The profile is represented in raw binary form.
|
||
|
*
|
||
|
* <p> The 'iCCP' chunk will encode this information.
|
||
|
*/
|
||
|
public void setICCProfileData(byte[] ICCProfileData) {
|
||
|
this.ICCProfileData = (byte[])(ICCProfileData.clone());
|
||
|
ICCProfileDataSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the ICC profile data to be stored with this image.
|
||
|
*
|
||
|
* <p> If the ICC profile has not previously been set, or has been
|
||
|
* unset, an <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the ICC profile is not set.
|
||
|
*/
|
||
|
public byte[] getICCProfileData() {
|
||
|
if (!ICCProfileDataSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam15"));
|
||
|
}
|
||
|
return (byte[])(ICCProfileData.clone());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'iCCP' chunk from being output.
|
||
|
*/
|
||
|
public void unsetICCProfileData() {
|
||
|
ICCProfileData = null;
|
||
|
ICCProfileDataSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'iCCP' chunk will be output.
|
||
|
*/
|
||
|
public boolean isICCProfileDataSet() {
|
||
|
return ICCProfileDataSet;
|
||
|
}
|
||
|
|
||
|
// pHYS chunk
|
||
|
|
||
|
private int[] physicalDimension = null;
|
||
|
private boolean physicalDimensionSet = false;
|
||
|
|
||
|
/**
|
||
|
* Sets the physical dimension information to be stored with this
|
||
|
* image. The physicalDimension parameter should be a 3-entry
|
||
|
* array containing the number of pixels per unit in the X
|
||
|
* direction, the number of pixels per unit in the Y direction,
|
||
|
* and the unit specifier (0 = unknown, 1 = meters).
|
||
|
*
|
||
|
* <p> The 'pHYS' chunk will encode this information.
|
||
|
*/
|
||
|
public void setPhysicalDimension(int[] physicalDimension) {
|
||
|
this.physicalDimension = (int[])(physicalDimension.clone());
|
||
|
physicalDimensionSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* A convenience method that calls the array version.
|
||
|
*/
|
||
|
public void setPhysicalDimension(int xPixelsPerUnit,
|
||
|
int yPixelsPerUnit,
|
||
|
int unitSpecifier) {
|
||
|
int[] pd = new int[3];
|
||
|
pd[0] = xPixelsPerUnit;
|
||
|
pd[1] = yPixelsPerUnit;
|
||
|
pd[2] = unitSpecifier;
|
||
|
|
||
|
setPhysicalDimension(pd);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the physical dimension information to be stored
|
||
|
* with this image.
|
||
|
*
|
||
|
* <p> If the physical dimension information has not previously
|
||
|
* been set, or has been unset, an
|
||
|
* <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the physical dimension information
|
||
|
* is not set.
|
||
|
*/
|
||
|
public int[] getPhysicalDimension() {
|
||
|
if (!physicalDimensionSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam16"));
|
||
|
}
|
||
|
return (int[])(physicalDimension.clone());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'pHYS' chunk from being output.
|
||
|
*/
|
||
|
public void unsetPhysicalDimension() {
|
||
|
physicalDimension = null;
|
||
|
physicalDimensionSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'pHYS' chunk will be output.
|
||
|
*/
|
||
|
public boolean isPhysicalDimensionSet() {
|
||
|
return physicalDimensionSet;
|
||
|
}
|
||
|
|
||
|
// sPLT chunk
|
||
|
|
||
|
private PNGSuggestedPaletteEntry[] suggestedPalette = null;
|
||
|
private boolean suggestedPaletteSet = false;
|
||
|
|
||
|
/**
|
||
|
* Sets the suggested palette information to be stored with this
|
||
|
* image. The information is passed to this method as an array of
|
||
|
* <code>PNGSuggestedPaletteEntry</code> objects.
|
||
|
*
|
||
|
* <p> The 'sPLT' chunk will encode this information.
|
||
|
*/
|
||
|
public void setSuggestedPalette(PNGSuggestedPaletteEntry[] palette) {
|
||
|
suggestedPalette = (PNGSuggestedPaletteEntry[])(palette.clone());
|
||
|
suggestedPaletteSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the suggested palette information to be stored with this
|
||
|
* image.
|
||
|
*
|
||
|
* <p> If the suggested palette information has not previously
|
||
|
* been set, or has been unset, an
|
||
|
* <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the suggested palette
|
||
|
* information is not set.
|
||
|
*/
|
||
|
public PNGSuggestedPaletteEntry[] getSuggestedPalette() {
|
||
|
if (!suggestedPaletteSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam17"));
|
||
|
}
|
||
|
return (PNGSuggestedPaletteEntry[])(suggestedPalette.clone());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'sPLT' chunk from being output.
|
||
|
*/
|
||
|
public void unsetSuggestedPalette() {
|
||
|
suggestedPalette = null;
|
||
|
suggestedPaletteSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'sPLT' chunk will be output.
|
||
|
*/
|
||
|
public boolean isSuggestedPaletteSet() {
|
||
|
return suggestedPaletteSet;
|
||
|
}
|
||
|
|
||
|
// sBIT chunk
|
||
|
|
||
|
private int[] significantBits = null;
|
||
|
private boolean significantBitsSet = false;
|
||
|
|
||
|
/**
|
||
|
* Sets the number of significant bits for each band of the image.
|
||
|
*
|
||
|
* <p> The number of entries in the <code>significantBits</code>
|
||
|
* array must be equal to the number of output bands in the image:
|
||
|
* 1 for a gray image, 2 for gray+alpha, 3 for index or truecolor,
|
||
|
* and 4 for truecolor+alpha.
|
||
|
*
|
||
|
* <p> The 'sBIT' chunk will encode this information.
|
||
|
*/
|
||
|
public void setSignificantBits(int[] significantBits) {
|
||
|
this.significantBits = (int[])(significantBits.clone());
|
||
|
significantBitsSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the number of significant bits for each band of the image.
|
||
|
*
|
||
|
* <p> If the significant bits values have not previously been
|
||
|
* set, or have been unset, an <code>IllegalStateException</code>
|
||
|
* will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the significant bits values are
|
||
|
* not set.
|
||
|
*/
|
||
|
public int[] getSignificantBits() {
|
||
|
if (!significantBitsSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam18"));
|
||
|
}
|
||
|
return (int[])significantBits.clone();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'sBIT' chunk from being output.
|
||
|
*/
|
||
|
public void unsetSignificantBits() {
|
||
|
significantBits = null;
|
||
|
significantBitsSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if an 'sBIT' chunk will be output.
|
||
|
*/
|
||
|
public boolean isSignificantBitsSet() {
|
||
|
return significantBitsSet;
|
||
|
}
|
||
|
|
||
|
// sRGB chunk
|
||
|
|
||
|
private int SRGBIntent;
|
||
|
private boolean SRGBIntentSet = false;
|
||
|
|
||
|
/**
|
||
|
* Sets the sRGB rendering intent to be stored with this image.
|
||
|
* The legal values are 0 = Perceptual, 1 = Relative Colorimetric,
|
||
|
* 2 = Saturation, and 3 = Absolute Colorimetric. Refer to the
|
||
|
* PNG specification for information on these values.
|
||
|
*
|
||
|
* <p> The 'sRGB' chunk will encode this information.
|
||
|
*/
|
||
|
public void setSRGBIntent(int SRGBIntent) {
|
||
|
this.SRGBIntent = SRGBIntent;
|
||
|
SRGBIntentSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the sRGB rendering intent to be stored with this image.
|
||
|
*
|
||
|
* <p> If the sRGB intent has not previously been set, or has been
|
||
|
* unset, an <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the sRGB intent is not set.
|
||
|
*/
|
||
|
public int getSRGBIntent() {
|
||
|
if (!SRGBIntentSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam19"));
|
||
|
}
|
||
|
return SRGBIntent;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'sRGB' chunk from being output.
|
||
|
*/
|
||
|
public void unsetSRGBIntent() {
|
||
|
SRGBIntentSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if an 'sRGB' chunk will be output.
|
||
|
*/
|
||
|
public boolean isSRGBIntentSet() {
|
||
|
return SRGBIntentSet;
|
||
|
}
|
||
|
|
||
|
// tEXt chunk
|
||
|
|
||
|
private String[] text = null;
|
||
|
private boolean textSet = false;
|
||
|
|
||
|
/**
|
||
|
* Sets the textual data to be stored in uncompressed form with this
|
||
|
* image. The data is passed to this method as an array of
|
||
|
* <code>String</code>s.
|
||
|
*
|
||
|
* <p> The 'tEXt' chunk will encode this information.
|
||
|
*/
|
||
|
public void setText(String[] text) {
|
||
|
this.text = text;
|
||
|
textSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the text strings to be stored in uncompressed form with this
|
||
|
* image as an array of <code>String</code>s.
|
||
|
*
|
||
|
* <p> If the text strings have not previously been set, or have been
|
||
|
* unset, an <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the text strings are not set.
|
||
|
*/
|
||
|
public String[] getText() {
|
||
|
if (!textSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam20"));
|
||
|
}
|
||
|
return text;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'tEXt' chunk from being output.
|
||
|
*/
|
||
|
public void unsetText() {
|
||
|
text = null;
|
||
|
textSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'tEXt' chunk will be output.
|
||
|
*/
|
||
|
public boolean isTextSet() {
|
||
|
return textSet;
|
||
|
}
|
||
|
|
||
|
// tIME chunk
|
||
|
|
||
|
private Date modificationTime;
|
||
|
private boolean modificationTimeSet = false;
|
||
|
|
||
|
/**
|
||
|
* Sets the modification time, as a <code>Date</code>, to be
|
||
|
* stored with this image. The internal storage format will use
|
||
|
* UTC regardless of how the <code>modificationTime</code>
|
||
|
* parameter was created.
|
||
|
*
|
||
|
* <p> The 'tIME' chunk will encode this information.
|
||
|
*/
|
||
|
public void setModificationTime(Date modificationTime) {
|
||
|
this.modificationTime = modificationTime;
|
||
|
modificationTimeSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the modification time to be stored with this image.
|
||
|
*
|
||
|
* <p> If the bit depth has not previously been set, or has been
|
||
|
* unset, an <code>IllegalStateException</code> will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the bit depth is not set.
|
||
|
*/
|
||
|
public Date getModificationTime() {
|
||
|
if (!modificationTimeSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam21"));
|
||
|
}
|
||
|
return modificationTime;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'tIME' chunk from being output.
|
||
|
*/
|
||
|
public void unsetModificationTime() {
|
||
|
modificationTime = null;
|
||
|
modificationTimeSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'tIME' chunk will be output.
|
||
|
*/
|
||
|
public boolean isModificationTimeSet() {
|
||
|
return modificationTimeSet;
|
||
|
}
|
||
|
|
||
|
// tRNS chunk
|
||
|
|
||
|
boolean transparencySet = false;
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'tRNS' chunk from being output.
|
||
|
*/
|
||
|
public void unsetTransparency() {
|
||
|
transparencySet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'tRNS' chunk will be output.
|
||
|
*/
|
||
|
public boolean isTransparencySet() {
|
||
|
return transparencySet;
|
||
|
}
|
||
|
|
||
|
// zTXT chunk
|
||
|
|
||
|
private String[] zText = null;
|
||
|
private boolean zTextSet = false;
|
||
|
|
||
|
/**
|
||
|
* Sets the text strings to be stored in compressed form with this
|
||
|
* image. The data is passed to this method as an array of
|
||
|
* <code>String</code>s.
|
||
|
*
|
||
|
* <p> The 'zTXt' chunk will encode this information.
|
||
|
*/
|
||
|
public void setCompressedText(String[] text) {
|
||
|
this.zText = text;
|
||
|
zTextSet = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the text strings to be stored in compressed form with
|
||
|
* this image as an array of <code>String</code>s.
|
||
|
*
|
||
|
* <p> If the compressed text strings have not previously been
|
||
|
* set, or have been unset, an <code>IllegalStateException</code>
|
||
|
* will be thrown.
|
||
|
*
|
||
|
* @throws IllegalStateException if the compressed text strings are
|
||
|
* not set.
|
||
|
*/
|
||
|
public String[] getCompressedText() {
|
||
|
if (!zTextSet) {
|
||
|
throw new IllegalStateException(JaiI18N.getString("PNGEncodeParam22"));
|
||
|
}
|
||
|
return zText;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Suppresses the 'zTXt' chunk from being output.
|
||
|
*/
|
||
|
public void unsetCompressedText() {
|
||
|
zText = null;
|
||
|
zTextSet = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a 'zTXT' chunk will be output.
|
||
|
*/
|
||
|
public boolean isCompressedTextSet() {
|
||
|
return zTextSet;
|
||
|
}
|
||
|
|
||
|
// Other chunk types
|
||
|
|
||
|
Vector chunkType = new Vector();
|
||
|
Vector chunkData = new Vector();
|
||
|
|
||
|
/**
|
||
|
* Adds a private chunk, in binary form, to the list of chunks to
|
||
|
* be stored with this image.
|
||
|
*
|
||
|
* @param type a 4-character String giving the chunk type name.
|
||
|
* @param data an array of <code>byte</code>s containing the
|
||
|
* chunk data.
|
||
|
*/
|
||
|
public synchronized void addPrivateChunk(String type, byte[] data) {
|
||
|
chunkType.add(type);
|
||
|
chunkData.add((byte[])data.clone());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the number of private chunks to be written to the
|
||
|
* output file.
|
||
|
*/
|
||
|
public synchronized int getNumPrivateChunks() {
|
||
|
return chunkType.size();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the type of the private chunk at a given index, as a
|
||
|
* 4-character <code>String</code>. The index must be smaller
|
||
|
* than the return value of <code>getNumPrivateChunks</code>.
|
||
|
*/
|
||
|
public synchronized String getPrivateChunkType(int index) {
|
||
|
return (String)chunkType.elementAt(index);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the data associated of the private chunk at a given
|
||
|
* index, as an array of <code>byte</code>s. The index must be
|
||
|
* smaller than the return value of
|
||
|
* <code>getNumPrivateChunks</code>.
|
||
|
*/
|
||
|
public synchronized byte[] getPrivateChunkData(int index) {
|
||
|
return (byte[])chunkData.elementAt(index);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Remove all private chunks associated with this parameter instance
|
||
|
* whose 'safe-to-copy' bit is not set. This may be advisable when
|
||
|
* transcoding PNG images.
|
||
|
*/
|
||
|
public synchronized void removeUnsafeToCopyPrivateChunks() {
|
||
|
Vector newChunkType = new Vector();
|
||
|
Vector newChunkData = new Vector();
|
||
|
|
||
|
int len = getNumPrivateChunks();
|
||
|
for (int i = 0; i < len; i++) {
|
||
|
String type = getPrivateChunkType(i);
|
||
|
char lastChar = type.charAt(3);
|
||
|
if (lastChar >= 'a' && lastChar <= 'z') {
|
||
|
newChunkType.add(type);
|
||
|
newChunkData.add(getPrivateChunkData(i));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
chunkType = newChunkType;
|
||
|
chunkData = newChunkData;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Remove all private chunks associated with this parameter instance.
|
||
|
*/
|
||
|
public synchronized void removeAllPrivateChunks() {
|
||
|
chunkType = new Vector();
|
||
|
chunkData = new Vector();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* An abs() function for use by the Paeth predictor.
|
||
|
*/
|
||
|
private static final int abs(int x) {
|
||
|
return (x < 0) ? -x : x;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The Paeth predictor routine used in PNG encoding. This routine
|
||
|
* is included as a convenience to subclasses that override the
|
||
|
* <code>filterRow</code> method.
|
||
|
*/
|
||
|
public static final int paethPredictor(int a, int b, int c) {
|
||
|
int p = a + b - c;
|
||
|
int pa = abs(p - a);
|
||
|
int pb = abs(p - b);
|
||
|
int pc = abs(p - c);
|
||
|
|
||
|
if ((pa <= pb) && (pa <= pc)) {
|
||
|
return a;
|
||
|
} else if (pb <= pc) {
|
||
|
return b;
|
||
|
} else {
|
||
|
return c;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Performs filtering on a row of an image. This method may be
|
||
|
* overridden in order to provide a custom algorithm for choosing
|
||
|
* the filter type for a given row.
|
||
|
*
|
||
|
* <p> The method is supplied with the current and previous rows
|
||
|
* of the image. For the first row of the image, or of an
|
||
|
* interlacing pass, the previous row array will be filled with
|
||
|
* zeros as required by the PNG specification.
|
||
|
*
|
||
|
* <p> The method is also supplied with five scratch arrays.
|
||
|
* These arrays may be used within the method for any purpose.
|
||
|
* At method exit, the array at the index given by the return
|
||
|
* value of the method should contain the filtered data. The
|
||
|
* return value will also be used as the filter type.
|
||
|
*
|
||
|
* <p> The default implementation of the method performs a trial
|
||
|
* encoding with each of the filter types, and computes the sum of
|
||
|
* absolute values of the differences between the raw bytes of the
|
||
|
* current row and the predicted values. The index of the filter
|
||
|
* producing the smallest result is returned.
|
||
|
*
|
||
|
* <p> As an example, to perform only 'sub' filtering, this method
|
||
|
* could be implemented (non-optimally) as follows:
|
||
|
*
|
||
|
* <pre>
|
||
|
* for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) {
|
||
|
* int curr = currRow[i] & 0xff;
|
||
|
* int left = currRow[i - bytesPerPixel] & 0xff;
|
||
|
* scratchRow[PNG_FILTER_SUB][i] = (byte)(curr - left);
|
||
|
* }
|
||
|
* return PNG_FILTER_SUB;
|
||
|
* </pre>
|
||
|
*
|
||
|
* @param currRow The current row as an array of <code>byte</code>s
|
||
|
* of length at least <code>bytesPerRow + bytesPerPixel</code>.
|
||
|
* The pixel data starts at index <code>bytesPerPixel</code>;
|
||
|
* the initial <code>bytesPerPixel</code> bytes are zero.
|
||
|
* @param prevRow The current row as an array of <code>byte</code>s
|
||
|
* The pixel data starts at index <code>bytesPerPixel</code>;
|
||
|
* the initial <code>bytesPerPixel</code> bytes are zero.
|
||
|
* @param scratchRows An array of 5 <code>byte</code> arrays of
|
||
|
* length at least <code>bytesPerRow +
|
||
|
* bytesPerPixel</code>, useable to hold temporary results.
|
||
|
* The filtered row will be returned as one of the entries
|
||
|
* of this array. The returned filtered data should start
|
||
|
* at index <code>bytesPerPixel</code>; The initial
|
||
|
* <code>bytesPerPixel</code> bytes are not used.
|
||
|
* @param bytesPerRow The number of bytes in the image row.
|
||
|
* This value will always be greater than 0.
|
||
|
* @param bytesPerPixel The number of bytes representing a single
|
||
|
* pixel, rounded up to an integer. This is the 'bpp' parameter
|
||
|
* described in the PNG specification.
|
||
|
*
|
||
|
* @return The filter type to be used. The entry of
|
||
|
* <code>scratchRows[]</code> at this index holds the
|
||
|
* filtered data. */
|
||
|
public int filterRow(byte[] currRow,
|
||
|
byte[] prevRow,
|
||
|
byte[][] scratchRows,
|
||
|
int bytesPerRow,
|
||
|
int bytesPerPixel) {
|
||
|
int[] filterBadness = new int[5];
|
||
|
for (int i = 0; i < 5; i++) {
|
||
|
filterBadness[i] = Integer.MAX_VALUE;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
int badness = 0;
|
||
|
|
||
|
for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) {
|
||
|
int curr = currRow[i] & 0xff;
|
||
|
badness += curr;
|
||
|
}
|
||
|
|
||
|
filterBadness[0] = badness;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
byte[] subFilteredRow = scratchRows[1];
|
||
|
int badness = 0;
|
||
|
|
||
|
for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) {
|
||
|
int curr = currRow[i] & 0xff;
|
||
|
int left = currRow[i - bytesPerPixel] & 0xff;
|
||
|
int difference = curr - left;
|
||
|
subFilteredRow[i] = (byte)difference;
|
||
|
|
||
|
badness += abs(difference);
|
||
|
}
|
||
|
|
||
|
filterBadness[1] = badness;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
byte[] upFilteredRow = scratchRows[2];
|
||
|
int badness = 0;
|
||
|
|
||
|
for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) {
|
||
|
int curr = currRow[i] & 0xff;
|
||
|
int up = prevRow[i] & 0xff;
|
||
|
int difference = curr - up;
|
||
|
upFilteredRow[i] = (byte)difference;
|
||
|
|
||
|
badness += abs(difference);
|
||
|
}
|
||
|
|
||
|
filterBadness[2] = badness;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
byte[] averageFilteredRow = scratchRows[3];
|
||
|
int badness = 0;
|
||
|
|
||
|
for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) {
|
||
|
int curr = currRow[i] & 0xff;
|
||
|
int left = currRow[i - bytesPerPixel] & 0xff;
|
||
|
int up = prevRow[i] & 0xff;
|
||
|
int difference = curr - (left + up)/2;;
|
||
|
averageFilteredRow[i] = (byte)difference;
|
||
|
|
||
|
badness += abs(difference);
|
||
|
}
|
||
|
|
||
|
filterBadness[3] = badness;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
byte[] paethFilteredRow = scratchRows[4];
|
||
|
int badness = 0;
|
||
|
|
||
|
for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) {
|
||
|
int curr = currRow[i] & 0xff;
|
||
|
int left = currRow[i - bytesPerPixel] & 0xff;
|
||
|
int up = prevRow[i] & 0xff;
|
||
|
int upleft = prevRow[i - bytesPerPixel] & 0xff;
|
||
|
int predictor = paethPredictor(left, up, upleft);
|
||
|
int difference = curr - predictor;
|
||
|
paethFilteredRow[i] = (byte)difference;
|
||
|
|
||
|
badness += abs(difference);
|
||
|
}
|
||
|
|
||
|
filterBadness[4] = badness;
|
||
|
}
|
||
|
|
||
|
int filterType = 0;
|
||
|
int minBadness = filterBadness[0];
|
||
|
|
||
|
for (int i = 1; i < 5; i++) {
|
||
|
if (filterBadness[i] < minBadness) {
|
||
|
minBadness = filterBadness[i];
|
||
|
filterType = i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (filterType == 0) {
|
||
|
System.arraycopy(currRow, bytesPerPixel,
|
||
|
scratchRows[0], bytesPerPixel,
|
||
|
bytesPerRow);
|
||
|
}
|
||
|
|
||
|
return filterType;
|
||
|
}
|
||
|
}
|