/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id: PNGEncodeParam.java 1732018 2016-02-24 04:51:06Z gadams $ */

package org.apache.xmlgraphics.image.codec.png;

import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.xmlgraphics.image.codec.util.ImageEncodeParam;
import org.apache.xmlgraphics.image.codec.util.PropertyUtil;

// CSOFF: MemberName
// CSOFF: MultipleVariableDeclarations
// CSOFF: NeedBraces
// CSOFF: OperatorWrap
// CSOFF: ParameterName
// CSOFF: WhitespaceAround

An instance of ImageEncodeParam for encoding images in the PNG format.

This class is not a committed part of the JAI API. It may be removed or changed in future releases of JAI.

/** * 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 { private static final long serialVersionUID = -7851509538552141263L;
Constant for use with the sRGB chunk.
/** Constant for use with the sRGB chunk. */
public static final int INTENT_PERCEPTUAL = 0;
Constant for use with the sRGB chunk.
/** Constant for use with the sRGB chunk. */
public static final int INTENT_RELATIVE = 1;
Constant for use with the sRGB chunk.
/** Constant for use with the sRGB chunk. */
public static final int INTENT_SATURATION = 2;
Constant for use with the sRGB chunk.
/** Constant for use with the sRGB chunk. */
public static final int INTENT_ABSOLUTE = 3;
Constant for use in filtering.
/** Constant for use in filtering. */
public static final int PNG_FILTER_NONE = 0;
Constant for use in filtering.
/** Constant for use in filtering. */
public static final int PNG_FILTER_SUB = 1;
Constant for use in filtering.
/** Constant for use in filtering. */
public static final int PNG_FILTER_UP = 2;
Constant for use in filtering.
/** Constant for use in filtering. */
public static final int PNG_FILTER_AVERAGE = 3;
Constant for use in filtering.
/** Constant for use in filtering. */
public static final int PNG_FILTER_PAETH = 4;
Returns an instance of PNGEncodeParam.Palette, PNGEncodeParam.Gray, or PNGEncodeParam.RGB appropriate for encoding the given image.

If the image has an IndexColorModel, an instance of PNGEncodeParam.Palette is returned. Otherwise, if the image has 1 or 2 bands an instance of PNGEncodeParam.Gray is returned. In all other cases an instance of PNGEncodeParam.RGB is returned.

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.

/** * 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 { private static final long serialVersionUID = -5181545170427733891L;
Constructs an instance of PNGEncodeParam.Palette.
/** Constructs an instance of <code>PNGEncodeParam.Palette</code>. */
public Palette() { } // bKGD chunk private boolean backgroundSet;
Suppresses the 'bKGD' chunk from being output.
/** * Suppresses the 'bKGD' chunk from being output. */
public void unsetBackground() { backgroundSet = false; }
Returns true if a 'bKGD' chunk will be output.
/** * 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 IllegalArgumentException will be thrown.
/** * 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(PropertyUtil.getString("PNGEncodeParam2")); } this.bitDepth = bitDepth; bitDepthSet = true; } // PLTE chunk private int[] palette; private boolean paletteSet;
Sets the RGB palette of the image to be encoded. The rgb 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.

The 'PLTE' chunk will encode this information.

Params:
  • rgb – An array of ints.
/** * 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(PropertyUtil.getString("PNGEncodeParam0")); } if ((rgb.length % 3) != 0) { throw new IllegalArgumentException(PropertyUtil.getString("PNGEncodeParam1")); } palette = (int[])(rgb.clone()); paletteSet = true; }
Returns the current RGB palette.

If the palette has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the palette is not set.
Returns:An array of ints.
/** * 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(PropertyUtil.getString("PNGEncodeParam3")); } return (int[])(palette.clone()); }
Suppresses the 'PLTE' chunk from being output.
/** * Suppresses the 'PLTE' chunk from being output. */
public void unsetPalette() { palette = null; paletteSet = false; }
Returns true if a 'PLTE' chunk will be output.
/** * 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.

The 'bKGD' chunk will encode this information.

/** * 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.

If the background palette index has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the palette index is not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam4")); } return backgroundPaletteIndex; } // tRNS chunk private int[] transparency;
Sets the alpha values associated with each palette entry. The alpha parameter should have as many entries as there are RGB triples in the palette.

The 'tRNS' chunk will encode this information.

/** * 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.

If the palette transparency has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the palette transparency is not set.
/** * 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(PropertyUtil.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 { private static final long serialVersionUID = -2055439792025795274L;
Constructs an instance of PNGEncodeParam.Gray.
/** Constructs an instance of <code>PNGEncodeParam.Gray</code>. */
public Gray() { } // bKGD chunk private boolean backgroundSet;
Suppresses the 'bKGD' chunk from being output.
/** * Suppresses the 'bKGD' chunk from being output. */
public void unsetBackground() { backgroundSet = false; }
Returns true if a 'bKGD' chunk will be output.
/** * 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.

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 getBitShift(). When encoding a source image of a smaller bit depth, pixel values will be shifted and left-filled with zeroes.

/** * 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(PropertyUtil.getString("PNGEncodeParam2")); } this.bitDepth = bitDepth; bitDepthSet = true; } // bKGD chunk private int backgroundPaletteGray;
Sets the suggested gray level of the background.

The 'bKGD' chunk will encode this information.

/** * 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.

If the background gray level has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the background gray level is not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam6")); } return backgroundPaletteGray; } // tRNS chunk private int[] transparency;
Sets the gray value to be used to denote transparency.

Setting this attribute will cause the alpha channel of the input image to be ignored.

The 'tRNS' chunk will encode this information.

/** * 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.

If the transparent gray value has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the transparent gray value is not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam7")); } int gray = transparency[0]; return gray; } private int bitShift; private boolean bitShiftSet;
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.
/** * 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 IllegalArgumentException(PropertyUtil.getString("PNGEncodeParam25")); } this.bitShift = bitShift; bitShiftSet = true; }
Returns the desired bit shift for a grayscale image.

If the bit shift has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the bit shift is not set.
/** * 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(PropertyUtil.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.
/** * 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.
/** * Returns true if the bit shift has been set. */
public boolean isBitShiftSet() { return bitShiftSet; }
Returns true if the bit depth has been set.
/** * Returns true if the bit depth has been set. */
public boolean isBitDepthSet() { return bitDepthSet; } } public static class RGB extends PNGEncodeParam { private static final long serialVersionUID = -8918762026006670891L;
Constructs an instance of PNGEncodeParam.RGB.
/** Constructs an instance of <code>PNGEncodeParam.RGB</code>. */
public RGB() { } // bKGD chunk private boolean backgroundSet;
Suppresses the 'bKGD' chunk from being output.
/** * Suppresses the 'bKGD' chunk from being output. */
public void unsetBackground() { backgroundSet = false; }
Returns true if a 'bKGD' chunk will be output.
/** * 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.
/** * 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 IllegalArgumentException(PropertyUtil.getString("PNGEncodeParam26")); } this.bitDepth = bitDepth; bitDepthSet = true; } // bKGD chunk private int[] backgroundRGB;
Sets the RGB value of the suggested background color. The rgb parameter should have 3 entries.

The 'bKGD' chunk will encode this information.

/** * 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 IllegalArgumentException(PropertyUtil.getString("PNGEncodeParam27")); } backgroundRGB = rgb; backgroundSet = true; }
Returns the RGB value of the suggested background color.

If the background color has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the background color is not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam9")); } return backgroundRGB; } // tRNS chunk private int[] transparency;
Sets the RGB value to be used to denote transparency.

Setting this attribute will cause the alpha channel of the input image to be ignored.

The 'tRNS' chunk will encode this information.

/** * 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.

If the transparent color has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the transparent color is not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam10")); } return (int[])(transparency.clone()); } } protected int bitDepth; protected boolean bitDepthSet;
Sets the desired bit depth of an image.
/** * Sets the desired bit depth of an image. */
public abstract void setBitDepth(int bitDepth);
Returns the desired bit depth for a grayscale image.

If the bit depth has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the bit depth is not set.
/** * 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(PropertyUtil.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.
/** * 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;
Turns Adam7 interlacing on or off.
/** * Turns Adam7 interlacing on or off. */
public void setInterlacing(boolean useInterlacing) { this.useInterlacing = useInterlacing; }
Returns true if Adam7 interlacing will be used.
/** * 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 RuntimeException; accordingly, subclasses must provide their own implementations.
/** * 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(PropertyUtil.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 RuntimeException; accordingly, subclasses must provide their own implementations.
/** * 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(PropertyUtil.getString("PNGEncodeParam24")); } // cHRM chunk private float[] chromaticity; private boolean chromaticitySet;
Sets the white point and primary chromaticities in CIE (x, y) space.

The chromaticity parameter should be a float 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.

The 'cHRM' chunk will encode this information.

/** * 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(PropertyUtil.getString("PNGEncodeParam28")); } this.chromaticity = (float[])(chromaticity.clone()); chromaticitySet = true; }
A convenience method that calls the array version.
/** * 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.

See the documentation for the setChromaticity method for the format of the returned data.

If the chromaticity has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the chromaticity is not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam12")); } return (float[])(chromaticity.clone()); }
Suppresses the 'cHRM' chunk from being output.
/** * Suppresses the 'cHRM' chunk from being output. */
public void unsetChromaticity() { chromaticity = null; chromaticitySet = false; }
Returns true if a 'cHRM' chunk will be output.
/** * Returns true if a 'cHRM' chunk will be output. */
public boolean isChromaticitySet() { return chromaticitySet; } // gAMA chunk private float gamma; private boolean gammaSet;
Sets the file gamma value for the image.

The 'gAMA' chunk will encode this information.

/** * 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.

If the file gamma has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the gamma is not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam13")); } return gamma; }
Suppresses the 'gAMA' chunk from being output.
/** * Suppresses the 'gAMA' chunk from being output. */
public void unsetGamma() { gammaSet = false; }
Returns true if a 'gAMA' chunk will be output.
/** * Returns true if a 'gAMA' chunk will be output. */
public boolean isGammaSet() { return gammaSet; } // hIST chunk private int[] paletteHistogram; private boolean paletteHistogramSet;
Sets the palette histogram to be stored with this image. The histogram consists of an array of integers, one per palette entry.

The 'hIST' chunk will encode this information.

/** * 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.

If the histogram has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the histogram is not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam14")); } return paletteHistogram; }
Suppresses the 'hIST' chunk from being output.
/** * Suppresses the 'hIST' chunk from being output. */
public void unsetPaletteHistogram() { paletteHistogram = null; paletteHistogramSet = false; }
Returns true if a 'hIST' chunk will be output.
/** * Returns true if a 'hIST' chunk will be output. */
public boolean isPaletteHistogramSet() { return paletteHistogramSet; } // iCCP chunk private byte[] iccProfileData; private boolean iccProfileDataSet;
Sets the ICC profile data to be stored with this image. The profile is represented in raw binary form.

The 'iCCP' chunk will encode this information.

/** * 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.

If the ICC profile has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the ICC profile is not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam15")); } return (byte[])(iccProfileData.clone()); }
Suppresses the 'iCCP' chunk from being output.
/** * Suppresses the 'iCCP' chunk from being output. */
public void unsetICCProfileData() { iccProfileData = null; iccProfileDataSet = false; }
Returns true if a 'iCCP' chunk will be output.
/** * Returns true if a 'iCCP' chunk will be output. */
public boolean isICCProfileDataSet() { return iccProfileDataSet; } // pHYS chunk private int[] physicalDimension; private boolean physicalDimensionSet;
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).

The 'pHYS' chunk will encode this information.

/** * 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.
/** * 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.

If the physical dimension information has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the physical dimension information is not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam16")); } return (int[])(physicalDimension.clone()); }
Suppresses the 'pHYS' chunk from being output.
/** * Suppresses the 'pHYS' chunk from being output. */
public void unsetPhysicalDimension() { physicalDimension = null; physicalDimensionSet = false; }
Returns true if a 'pHYS' chunk will be output.
/** * Returns true if a 'pHYS' chunk will be output. */
public boolean isPhysicalDimensionSet() { return physicalDimensionSet; } // sPLT chunk private PNGSuggestedPaletteEntry[] suggestedPalette; private boolean suggestedPaletteSet;
Sets the suggested palette information to be stored with this image. The information is passed to this method as an array of PNGSuggestedPaletteEntry objects.

The 'sPLT' chunk will encode this information.

/** * 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.

If the suggested palette information has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the suggested palette information is not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam17")); } return (PNGSuggestedPaletteEntry[])(suggestedPalette.clone()); }
Suppresses the 'sPLT' chunk from being output.
/** * Suppresses the 'sPLT' chunk from being output. */
public void unsetSuggestedPalette() { suggestedPalette = null; suggestedPaletteSet = false; }
Returns true if a 'sPLT' chunk will be output.
/** * Returns true if a 'sPLT' chunk will be output. */
public boolean isSuggestedPaletteSet() { return suggestedPaletteSet; } // sBIT chunk private int[] significantBits; private boolean significantBitsSet;
Sets the number of significant bits for each band of the image.

The number of entries in the significantBits 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.

The 'sBIT' chunk will encode this information.

/** * 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.

If the significant bits values have not previously been set, or have been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the significant bits values are not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam18")); } return (int[])significantBits.clone(); }
Suppresses the 'sBIT' chunk from being output.
/** * Suppresses the 'sBIT' chunk from being output. */
public void unsetSignificantBits() { significantBits = null; significantBitsSet = false; }
Returns true if an 'sBIT' chunk will be output.
/** * Returns true if an 'sBIT' chunk will be output. */
public boolean isSignificantBitsSet() { return significantBitsSet; } // sRGB chunk private int srgbIntent; private boolean srgbIntentSet;
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.

The 'sRGB' chunk will encode this information.

/** * 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.

If the sRGB intent has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the sRGB intent is not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam19")); } return srgbIntent; }
Suppresses the 'sRGB' chunk from being output.
/** * Suppresses the 'sRGB' chunk from being output. */
public void unsetSRGBIntent() { srgbIntentSet = false; }
Returns true if an 'sRGB' chunk will be output.
/** * Returns true if an 'sRGB' chunk will be output. */
public boolean isSRGBIntentSet() { return srgbIntentSet; } // tEXt chunk private String[] text; private boolean textSet;
Sets the textual data to be stored in uncompressed form with this image. The data is passed to this method as an array of Strings.

The 'tEXt' chunk will encode this information.

/** * 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 Strings.

If the text strings have not previously been set, or have been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the text strings are not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam20")); } return text; }
Suppresses the 'tEXt' chunk from being output.
/** * Suppresses the 'tEXt' chunk from being output. */
public void unsetText() { text = null; textSet = false; }
Returns true if a 'tEXt' chunk will be output.
/** * Returns true if a 'tEXt' chunk will be output. */
public boolean isTextSet() { return textSet; } // tIME chunk private Date modificationTime; private boolean modificationTimeSet;
Sets the modification time, as a Date, to be stored with this image. The internal storage format will use UTC regardless of how the modificationTime parameter was created.

The 'tIME' chunk will encode this information.

/** * 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.

If the bit depth has not previously been set, or has been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the bit depth is not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam21")); } return modificationTime; }
Suppresses the 'tIME' chunk from being output.
/** * Suppresses the 'tIME' chunk from being output. */
public void unsetModificationTime() { modificationTime = null; modificationTimeSet = false; }
Returns true if a 'tIME' chunk will be output.
/** * Returns true if a 'tIME' chunk will be output. */
public boolean isModificationTimeSet() { return modificationTimeSet; } // tRNS chunk boolean transparencySet;
Suppresses the 'tRNS' chunk from being output.
/** * Suppresses the 'tRNS' chunk from being output. */
public void unsetTransparency() { transparencySet = false; }
Returns true if a 'tRNS' chunk will be output.
/** * Returns true if a 'tRNS' chunk will be output. */
public boolean isTransparencySet() { return transparencySet; } // zTXT chunk private String[] zText; private boolean zTextSet;
Sets the text strings to be stored in compressed form with this image. The data is passed to this method as an array of Strings.

The 'zTXt' chunk will encode this information.

/** * 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 Strings.

If the compressed text strings have not previously been set, or have been unset, an IllegalStateException will be thrown.

Throws:
  • IllegalStateException – if the compressed text strings are not set.
/** * 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(PropertyUtil.getString("PNGEncodeParam22")); } return zText; }
Suppresses the 'zTXt' chunk from being output.
/** * Suppresses the 'zTXt' chunk from being output. */
public void unsetCompressedText() { zText = null; zTextSet = false; }
Returns true if a 'zTXT' chunk will be output.
/** * Returns true if a 'zTXT' chunk will be output. */
public boolean isCompressedTextSet() { return zTextSet; } // Other chunk types List chunkType = new ArrayList(); List chunkData = new ArrayList();
Adds a private chunk, in binary form, to the list of chunks to be stored with this image.
Params:
  • type – a 4-character String giving the chunk type name.
  • data – an array of bytes containing the chunk data.
/** * 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(data.clone()); }
Returns the number of private chunks to be written to the output file.
/** * 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 String. The index must be smaller than the return value of getNumPrivateChunks.
/** * 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.get(index); }
Returns the data associated of the private chunk at a given index, as an array of bytes. The index must be smaller than the return value of getNumPrivateChunks.
/** * 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.get(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.
/** * 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() { List newChunkType = new ArrayList(); List newChunkData = new ArrayList(); 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.
/** * Remove all private chunks associated with this parameter instance. */
public synchronized void removeAllPrivateChunks() { chunkType = new ArrayList(); chunkData = new ArrayList(); }
An abs() function for use by the Paeth predictor.
/** * An abs() function for use by the Paeth predictor. */
private static 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 filterRow method.
/** * 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 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.

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.

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.

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.

As an example, to perform only 'sub' filtering, this method could be implemented (non-optimally) as follows:

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;
Params:
  • currRow – The current row as an array of bytes of length at least bytesPerRow + bytesPerPixel. The pixel data starts at index bytesPerPixel; the initial bytesPerPixel bytes are zero.
  • prevRow – The current row as an array of bytes The pixel data starts at index bytesPerPixel; the initial bytesPerPixel bytes are zero.
  • scratchRows – An array of 5 byte arrays of length at least bytesPerRow + bytesPerPixel, 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 bytesPerPixel; The initial bytesPerPixel bytes are not used.
  • bytesPerRow – The number of bytes in the image row. This value will always be greater than 0.
  • bytesPerPixel – The number of bytes representing a single pixel, rounded up to an integer. This is the 'bpp' parameter described in the PNG specification.
Returns:The filter type to be used. The entry of scratchRows[] at this index holds the filtered data.
/** * 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 &lt; bytesPerRow + bytesPerPixel; i++) { * int curr = currRow[i] &amp; 0xff; * int left = currRow[i - bytesPerPixel] &amp; 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 [] badness = {0, 0, 0, 0, 0}; int curr; int left; int up; int upleft; int diff; int pa; int pb; int pc; for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { curr = currRow[i] & 0xff; left = currRow[i - bytesPerPixel] & 0xff; up = prevRow[i] & 0xff; upleft = prevRow[i - bytesPerPixel] & 0xff; // no filter badness[0] += curr; // sub filter diff = curr - left; scratchRows[1][i] = (byte)diff; badness [1] += (diff > 0) ? diff : -diff; // up filter diff = curr - up; scratchRows[2][i] = (byte)diff; badness [2] += (diff >= 0) ? diff : -diff; // average filter diff = curr - ((left + up) >> 1); scratchRows[3][i] = (byte)diff; badness [3] += (diff >= 0) ? diff : -diff; // paeth filter // Original code much simplier but doesn't take full // advantage of relationship between pa/b/c and // information gleaned in abs operations. /// pa = up -upleft; /// pb = left-upleft; /// pc = pa+pb; /// pa = abs(pa); /// pb = abs(pb); /// pc = abs(pc); /// if ((pa <= pb) && (pa <= pc)) /// diff = curr-left; /// else if (pb <= pc) /// diff = curr-up; /// else /// diff = curr-upleft; pa = up - upleft; pb = left - upleft; if (pa < 0) { if (pb < 0) { // both pa & pb neg so pc is always greater than or // equal to pa or pb; if (pa >= pb) { // since pa & pb neg check sense is reversed. diff = curr - left; } else { diff = curr - up; } } else { // pa neg pb pos so we must compute pc... pc = pa + pb; pa = -pa; if (pa <= pb) { // pc is positive and less than pb if (pa <= pc) { diff = curr - left; } else { diff = curr - upleft; } } else { // pc is negative and less than or equal to pa, // but since pa is greater than pb this isn't an issue... if (pb <= -pc) { diff = curr - up; } else { diff = curr - upleft; } } } } else { if (pb < 0) { pb = -pb; // make it positive... if (pa <= pb) { // pc would be negative and less than or equal to pb pc = pb - pa; if (pa <= pc) { diff = curr - left; } else if (pb == pc) { // if pa is zero then pc==pb otherwise // pc must be less than pb. diff = curr - up; } else { diff = curr - upleft; } } else { // pc would be positive and less than pa. pc = pa - pb; if (pb <= pc) { diff = curr - up; } else { diff = curr - upleft; } } } else { // both pos so pa+pb is always greater than pa/pb if (pa <= pb) { diff = curr - left; } else { diff = curr - up; } } } scratchRows[4][i] = (byte)diff; badness [4] += (diff >= 0) ? diff : -diff; } int filterType = 0; int minBadness = badness[0]; for (int i = 1; i < 5; i++) { if (badness[i] < minBadness) { minBadness = badness[i]; filterType = i; } } if (filterType == 0) { System.arraycopy(currRow, bytesPerPixel, scratchRows[0], bytesPerPixel, bytesPerRow); } return filterType; } }