PNGImageDecoder.java
上传用户:btjssb159
上传日期:2018-01-04
资源大小:241k
文件大小:57k
源码类别:

DNA

开发平台:

Java

  1. /*
  2.  * Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without 
  5.  * modification, are permitted provided that the following conditions are met:
  6.  * 
  7.  * -Redistributions of source code must retain the above copyright notice, this 
  8.  * list of conditions and the following disclaimer.
  9.  *
  10.  * -Redistribution in binary form must reproduct the above copyright notice,
  11.  * this list of conditions and the following disclaimer in the documentation
  12.  * and/or other materials provided with the distribution.
  13.  * 
  14.  * Neither the name of Sun Microsystems, Inc. or the names of contributors may
  15.  * be used to endorse or promote products derived from this software without
  16.  * specific prior written permission.
  17.  * 
  18.  * This software is provided "AS IS," without a warranty of any kind. ALL
  19.  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
  20.  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
  21.  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
  22.  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
  23.  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
  24.  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
  25.  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
  26.  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
  27.  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
  28.  * POSSIBILITY OF SUCH DAMAGES.
  29.  * 
  30.  * You acknowledge that Software is not designed,licensed or intended for use in 
  31.  * the design, construction, operation or maintenance of any nuclear facility.
  32.  */
  33. import java.awt.Color;
  34. import java.awt.Point;
  35. import java.awt.RenderingHints;
  36. import java.awt.Transparency;
  37. import java.awt.color.ColorSpace;
  38. import java.awt.geom.AffineTransform;
  39. import java.awt.image.BufferedImage;
  40. import java.awt.image.ColorModel;
  41. import java.awt.image.ComponentColorModel;
  42. import java.awt.image.DataBuffer;
  43. import java.awt.image.DataBufferByte;
  44. import java.awt.image.DataBufferUShort;
  45. import java.awt.image.IndexColorModel;
  46. import java.awt.image.MultiPixelPackedSampleModel;
  47. import java.awt.image.PixelInterleavedSampleModel;
  48. import java.awt.image.Raster;
  49. import java.awt.image.RenderedImage;
  50. import java.awt.image.SampleModel;
  51. import java.awt.image.WritableRaster;
  52. import java.io.BufferedInputStream;
  53. import java.io.ByteArrayInputStream;
  54. import java.io.DataInputStream;
  55. import java.io.FileInputStream;
  56. import java.io.InputStream;
  57. import java.io.IOException;
  58. import java.io.SequenceInputStream;
  59. import java.text.DateFormat;
  60. import java.util.Date;
  61. import java.util.Enumeration;
  62. import java.util.GregorianCalendar;
  63. import java.util.Hashtable;
  64. import java.util.TimeZone;
  65. import java.util.Vector;
  66. import java.util.zip.Inflater;
  67. import java.util.zip.InflaterInputStream;
  68. /**
  69.  */
  70. public class PNGImageDecoder extends ImageDecoderImpl {
  71.     public PNGImageDecoder(InputStream input,
  72.                            PNGDecodeParam param) {
  73.         super(input, param);
  74.     }
  75.     public RenderedImage decodeAsRenderedImage(int page) throws IOException {
  76.         if (page != 0) {
  77.             throw new IOException(JaiI18N.getString("PNGImageDecoder19"));
  78.         }
  79.         return new PNGImage(input, (PNGDecodeParam)param);
  80.     }
  81. }
  82. class PNGChunk {
  83.     int length;
  84.     int type;
  85.     byte[] data;
  86.     int crc;
  87.     String typeString;
  88.     public PNGChunk(int length, int type, byte[] data, int crc) {
  89.         this.length = length;
  90.         this.type = type;
  91.         this.data = data;
  92.         this.crc = crc;
  93.         typeString = new String();
  94.         typeString += (char)(type >> 24);
  95.         typeString += (char)((type >> 16) & 0xff);
  96.         typeString += (char)((type >> 8) & 0xff);
  97.         typeString += (char)(type & 0xff);
  98.     }
  99.     public int getLength() {
  100.         return length;
  101.     }
  102.     public int getType() {
  103.         return type;
  104.     }
  105.     public String getTypeString() {
  106.         return typeString;
  107.     }
  108.     public byte[] getData() {
  109.         return data;
  110.     }
  111.     public byte getByte(int offset) {
  112.         return data[offset];
  113.     }
  114.     public int getInt1(int offset) {
  115.         return data[offset] & 0xff;
  116.     }
  117.     public int getInt2(int offset) {
  118.         return ((data[offset] & 0xff) << 8) |
  119.             (data[offset + 1] & 0xff);
  120.     }
  121.     public int getInt4(int offset) {
  122.         return ((data[offset] & 0xff) << 24) |
  123.             ((data[offset + 1] & 0xff) << 16) |
  124.             ((data[offset + 2] & 0xff) << 8) |
  125.             (data[offset + 3] & 0xff);
  126.     }
  127.     public String getString4(int offset) {
  128.         String s = new String();
  129.         s += (char)data[offset];
  130.         s += (char)data[offset + 1];
  131.         s += (char)data[offset + 2];
  132.         s += (char)data[offset + 3];
  133.         return s;
  134.     }
  135.     public boolean isType(String typeName) {
  136.         return typeString.equals(typeName);
  137.     }
  138. }
  139. /**
  140.  * TO DO:
  141.  *
  142.  * zTXt chunks
  143.  *
  144.  */
  145. class PNGImage extends SimpleRenderedImage {
  146.     public static final int PNG_COLOR_GRAY = 0;
  147.     public static final int PNG_COLOR_RGB = 2;
  148.     public static final int PNG_COLOR_PALETTE = 3;
  149.     public static final int PNG_COLOR_GRAY_ALPHA = 4;
  150.     public static final int PNG_COLOR_RGB_ALPHA = 6;
  151.     private static final String[] colorTypeNames = {
  152.         "Grayscale", "Error", "Truecolor", "Index",
  153.         "Grayscale with alpha", "Error", "Truecolor with alpha"
  154.     };
  155.     public static final int PNG_FILTER_NONE = 0;
  156.     public static final int PNG_FILTER_SUB = 1;
  157.     public static final int PNG_FILTER_UP = 2;
  158.     public static final int PNG_FILTER_AVERAGE = 3;
  159.     public static final int PNG_FILTER_PAETH = 4;
  160.     private static final int RED_OFFSET = 2;
  161.     private static final int GREEN_OFFSET = 1;
  162.     private static final int BLUE_OFFSET = 0;
  163.     private int[][] bandOffsets = {
  164.         null,
  165.         { 0 }, // G
  166.         { 0, 1 }, // GA in GA order
  167.         { 0, 1, 2 }, // RGB in RGB order
  168.         { 0, 1, 2, 3 } // RGBA in RGBA order
  169.     };
  170.     private int bitDepth;
  171.     private int colorType;
  172.     private int compressionMethod;
  173.     private int filterMethod;
  174.     private int interlaceMethod;
  175.     
  176.     private int paletteEntries;
  177.     private byte[] redPalette;
  178.     private byte[] greenPalette;
  179.     private byte[] bluePalette;
  180.     private byte[] alphaPalette;
  181.     private int bkgdRed;
  182.     private int bkgdGreen;
  183.     private int bkgdBlue;
  184.     private int grayTransparentAlpha;
  185.     private int redTransparentAlpha;
  186.     private int greenTransparentAlpha;
  187.     private int blueTransparentAlpha;
  188.     private int maxOpacity;
  189.     private int[] significantBits = null;
  190.     private boolean hasBackground = false;
  191.     // Parameter information
  192.     // If true, the user wants destination alpha where applicable.
  193.     private boolean suppressAlpha = false;
  194.     // If true, perform palette lookup internally
  195.     private boolean expandPalette = false;
  196.     
  197.     // If true, output < 8 bit gray images in 8 bit components format
  198.     private boolean output8BitGray = false;
  199.     // Create an alpha channel in the destination color model.
  200.     private boolean outputHasAlphaPalette = false;
  201.     // Perform gamma correction on the image
  202.     private boolean performGammaCorrection = false;
  203.     // Expand GA to GGGA for compatbility with Java2D
  204.     private boolean expandGrayAlpha = false;
  205.     // Produce an instance of PNGEncodeParam
  206.     private boolean generateEncodeParam = false;
  207.     // PNGDecodeParam controlling decode process
  208.     private PNGDecodeParam decodeParam = null;
  209.     // PNGEncodeParam to store file details in
  210.     private PNGEncodeParam encodeParam = null;
  211.     private boolean emitProperties = true;
  212.     private float fileGamma = 45455/100000.0F;
  213.     private float userExponent = 1.0F;
  214.     private float displayExponent = 2.2F;
  215.     private float[] chromaticity = null;
  216.     private int sRGBRenderingIntent = -1;
  217.     // Post-processing step implied by above parameters
  218.     private int postProcess = POST_NONE;
  219.     // Possible post-processing steps
  220.     // Do nothing
  221.     private static final int POST_NONE = 0;
  222.     // Gamma correct only
  223.     private static final int POST_GAMMA = 1;
  224.     // Push gray values through grayLut to expand to 8 bits
  225.     private static final int POST_GRAY_LUT = 2;
  226.     // Push gray values through grayLut to expand to 8 bits, add alpha
  227.     private static final int POST_GRAY_LUT_ADD_TRANS = 3;
  228.     // Push palette value through R,G,B lookup tables
  229.     private static final int POST_PALETTE_TO_RGB = 4;
  230.     // Push palette value through R,G,B,A lookup tables
  231.     private static final int POST_PALETTE_TO_RGBA = 5;
  232.     // Add transparency to a given gray value (w/ optional gamma)
  233.     private static final int POST_ADD_GRAY_TRANS = 6;
  234.     // Add transparency to a given RGB value (w/ optional gamma)
  235.     private static final int POST_ADD_RGB_TRANS = 7; 
  236.     // Remove the alpha channel from a gray image (w/ optional gamma)
  237.     private static final int POST_REMOVE_GRAY_TRANS = 8;
  238.     // Remove the alpha channel from an RGB image (w/optional gamma)
  239.     private static final int POST_REMOVE_RGB_TRANS = 9; 
  240.     // Mask to add expansion of GA -> GGGA
  241.     private static final int POST_EXP_MASK = 16;
  242.     // Expand gray to G/G/G
  243.     private static final int POST_GRAY_ALPHA_EXP =
  244.         POST_NONE | POST_EXP_MASK;
  245.     // Expand gray to G/G/G through a gamma lut
  246.     private static final int POST_GAMMA_EXP =
  247.         POST_GAMMA | POST_EXP_MASK;
  248.     // Push gray values through grayLut to expand to 8 bits, expand, add alpha
  249.     private static final int POST_GRAY_LUT_ADD_TRANS_EXP =
  250.         POST_GRAY_LUT_ADD_TRANS | POST_EXP_MASK;
  251.     // Add transparency to a given gray value, expand
  252.     private static final int POST_ADD_GRAY_TRANS_EXP = 
  253.         POST_ADD_GRAY_TRANS | POST_EXP_MASK;
  254.     private Vector streamVec = new Vector();
  255.     private DataInputStream dataStream;
  256.     private int bytesPerPixel; // number of bytes per input pixel
  257.     private int inputBands;
  258.     private int outputBands;
  259.     // Number of private chunks
  260.     private int chunkIndex = 0;
  261.     private Vector textKeys = new Vector();
  262.     private Vector textStrings = new Vector();
  263.     private Vector ztextKeys = new Vector();
  264.     private Vector ztextStrings = new Vector();
  265.     private WritableRaster theTile;
  266.     private int[] gammaLut = null;
  267.     private void initGammaLut(int bits) {
  268.         double exp = (double)userExponent/(fileGamma*displayExponent);
  269.         int numSamples = 1 << bits;
  270.         int maxOutSample = (bits == 16) ? 65535 : 255;
  271.         gammaLut = new int[numSamples];
  272.         for (int i = 0; i < numSamples; i++) {
  273.             double gbright = (double)i/(numSamples - 1);
  274.             double gamma = Math.pow(gbright, exp);
  275.             int igamma = (int)(gamma*maxOutSample + 0.5);
  276.             if (igamma > maxOutSample) {
  277.                 igamma = maxOutSample;
  278.             }
  279.             gammaLut[i] = igamma;
  280.         }
  281.     }
  282.     private final byte[][] expandBits = {
  283.         null,
  284.         { (byte)0x00, (byte)0xff },
  285.         { (byte)0x00, (byte)0x55, (byte)0xaa, (byte)0xff },
  286.         null,
  287.         { (byte)0x00, (byte)0x11, (byte)0x22, (byte)0x33,
  288.           (byte)0x44, (byte)0x55, (byte)0x66, (byte)0x77,
  289.           (byte)0x88, (byte)0x99, (byte)0xaa, (byte)0xbb,
  290.           (byte)0xcc, (byte)0xdd, (byte)0xee, (byte)0xff }
  291.     };
  292.     private int[] grayLut = null;
  293.     private void initGrayLut(int bits) {
  294.         int len = 1 << bits;
  295.         grayLut = new int[len];
  296.         if (performGammaCorrection) {
  297.             for (int i = 0; i < len; i++) {
  298.                 grayLut[i] = gammaLut[i];
  299.             }
  300.         } else {
  301.             for (int i = 0; i < len; i++) {
  302.                 grayLut[i] = expandBits[bits][i];
  303.             }
  304.         }
  305.     }
  306.     public PNGImage(InputStream stream, PNGDecodeParam decodeParam)
  307.         throws IOException {
  308.         if (!stream.markSupported()) {
  309.             stream = new BufferedInputStream(stream);
  310.         }
  311.         DataInputStream distream = new DataInputStream(stream);
  312.         if (decodeParam == null) {
  313.             decodeParam = new PNGDecodeParam();
  314.         }
  315.         this.decodeParam = decodeParam;
  316.         // Get parameter values
  317.         this.suppressAlpha = decodeParam.getSuppressAlpha();
  318.         this.expandPalette = decodeParam.getExpandPalette();
  319.         this.output8BitGray = decodeParam.getOutput8BitGray();
  320.         this.expandGrayAlpha = decodeParam.getExpandGrayAlpha();
  321.         if (decodeParam.getPerformGammaCorrection()) {
  322.             this.userExponent = decodeParam.getUserExponent();
  323.             this.displayExponent = decodeParam.getDisplayExponent();
  324.             performGammaCorrection = true;
  325.             output8BitGray = true;
  326.         }
  327.         this.generateEncodeParam = decodeParam.getGenerateEncodeParam();
  328.         
  329.         if (emitProperties) {
  330.             properties.put("file_type", "PNG v. 1.0");
  331.         }
  332.         try {
  333.             long magic = distream.readLong();
  334.             if (magic != 0x89504e470d0a1a0aL) {
  335.                 String msg = JaiI18N.getString("PNGImageDecoder0");
  336.                 throw new RuntimeException(msg);
  337.             }
  338.         } catch (Exception e) {
  339.             e.printStackTrace();
  340.             String msg = JaiI18N.getString("PNGImageDecoder1");
  341.             throw new RuntimeException(msg);
  342.         }
  343.             
  344.         do {
  345.             try {
  346.                 PNGChunk chunk;
  347.                 
  348.                 String chunkType = getChunkType(distream);
  349.                 if (chunkType.equals("IHDR")) {
  350.                     chunk = readChunk(distream);
  351.                     parse_IHDR_chunk(chunk);
  352.                 } else if (chunkType.equals("PLTE")) {
  353.                     chunk = readChunk(distream);
  354.                     parse_PLTE_chunk(chunk);
  355.                 } else if (chunkType.equals("IDAT")) {
  356.                     chunk = readChunk(distream);
  357.                     streamVec.add(new ByteArrayInputStream(chunk.getData()));
  358.                 } else if (chunkType.equals("IEND")) {
  359.                     chunk = readChunk(distream);
  360.                     parse_IEND_chunk(chunk);
  361.                     break; // fall through to the bottom
  362.                 } else if (chunkType.equals("bKGD")) {
  363.                     chunk = readChunk(distream);
  364.                     parse_bKGD_chunk(chunk);
  365.                 } else if (chunkType.equals("cHRM")) {
  366.                     chunk = readChunk(distream);
  367.                     parse_cHRM_chunk(chunk);
  368.                 } else if (chunkType.equals("gAMA")) {
  369.                     chunk = readChunk(distream);
  370.                     parse_gAMA_chunk(chunk);
  371.                 } else if (chunkType.equals("hIST")) {
  372.                     chunk = readChunk(distream);
  373.                     parse_hIST_chunk(chunk);
  374.                 } else if (chunkType.equals("iCCP")) {
  375.                     chunk = readChunk(distream);
  376.                     parse_iCCP_chunk(chunk);
  377.                 } else if (chunkType.equals("pHYs")) {
  378.                     chunk = readChunk(distream);
  379.                     parse_pHYs_chunk(chunk);
  380.                 } else if (chunkType.equals("sBIT")) {
  381.                     chunk = readChunk(distream);
  382.                     parse_sBIT_chunk(chunk);
  383.                 } else if (chunkType.equals("sRGB")) {
  384.                     chunk = readChunk(distream);
  385.                     parse_sRGB_chunk(chunk);
  386.                 } else if (chunkType.equals("tEXt")) {
  387.                     chunk = readChunk(distream);
  388.                     parse_tEXt_chunk(chunk);
  389.                 } else if (chunkType.equals("tIME")) {
  390.                     chunk = readChunk(distream);
  391.                     parse_tIME_chunk(chunk);
  392.                 } else if (chunkType.equals("tRNS")) {
  393.                     chunk = readChunk(distream);
  394.                     parse_tRNS_chunk(chunk);
  395.                 } else if (chunkType.equals("zTXt")) {
  396.                     chunk = readChunk(distream);
  397.                     parse_zTXt_chunk(chunk);
  398.                 } else {
  399.                     chunk = readChunk(distream);
  400.                     // Output the chunk data in raw form
  401.                     String type = chunk.getTypeString();
  402.                     byte[] data = chunk.getData();
  403.                     if (encodeParam != null) {
  404.                         encodeParam.addPrivateChunk(type, data);
  405.                     }
  406.                     if (emitProperties) {
  407.                         String key = "chunk_" + chunkIndex++ + ":" + type;
  408.                         properties.put(key.toLowerCase(), data);
  409.                     }
  410.                 }
  411.             } catch (Exception e) {
  412.                 e.printStackTrace();
  413.                 String msg = JaiI18N.getString("PNGImageDecoder2");
  414.                 throw new RuntimeException(msg);
  415.             }
  416.         } while (true);
  417.         // Final post-processing
  418.         if (significantBits == null) {
  419.             significantBits = new int[inputBands];
  420.             for (int i = 0; i < inputBands; i++) {
  421.                 significantBits[i] = bitDepth;
  422.             }
  423.             if (emitProperties) {
  424.                 properties.put("significant_bits", significantBits);
  425.             }
  426.         }
  427.     }
  428.     private static String getChunkType(DataInputStream distream) {
  429.         try {
  430.             distream.mark(8);
  431.             int length = distream.readInt();
  432.             int type = distream.readInt();
  433.             distream.reset();
  434.             String typeString = new String();
  435.             typeString += (char)(type >> 24);
  436.             typeString += (char)((type >> 16) & 0xff);
  437.             typeString += (char)((type >> 8) & 0xff);
  438.             typeString += (char)(type & 0xff);
  439.             return typeString;
  440.         } catch (Exception e) {
  441.             e.printStackTrace();
  442.             return null;
  443.         }
  444.     }
  445.     private static PNGChunk readChunk(DataInputStream distream) {
  446.         try {
  447.             int length = distream.readInt();
  448.             int type = distream.readInt();
  449.             byte[] data = new byte[length];
  450.             distream.readFully(data);
  451.             int crc = distream.readInt();
  452.             
  453.             return new PNGChunk(length, type, data, crc);
  454.         } catch (Exception e) {
  455.             e.printStackTrace();
  456.             return null;
  457.         }
  458.     }
  459.     private void parse_IHDR_chunk(PNGChunk chunk) {
  460.         tileWidth = width = chunk.getInt4(0);
  461.         tileHeight = height = chunk.getInt4(4);
  462.         bitDepth = chunk.getInt1(8);
  463.         
  464.         if ((bitDepth != 1) && (bitDepth != 2) && (bitDepth != 4) &&
  465.             (bitDepth != 8) && (bitDepth != 16)) {
  466.             // Error -- bad bit depth
  467.             String msg = JaiI18N.getString("PNGImageDecoder3");
  468.             throw new RuntimeException(msg);
  469.         }
  470.         maxOpacity = (1 << bitDepth) - 1;
  471.         colorType = chunk.getInt1(9);
  472.         if ((colorType != PNG_COLOR_GRAY) &&
  473.             (colorType != PNG_COLOR_RGB) &&
  474.             (colorType != PNG_COLOR_PALETTE) &&
  475.             (colorType != PNG_COLOR_GRAY_ALPHA) &&
  476.             (colorType != PNG_COLOR_RGB_ALPHA)) {
  477.             System.out.println(JaiI18N.getString("PNGImageDecoder4"));
  478.         }
  479.         if ((colorType == PNG_COLOR_RGB) && (bitDepth < 8)) {
  480.             // Error -- RGB images must have 8 or 16 bits
  481.             String msg = JaiI18N.getString("PNGImageDecoder5");
  482.             throw new RuntimeException(msg);
  483.         }
  484.         if ((colorType == PNG_COLOR_PALETTE) && (bitDepth == 16)) {
  485.             // Error -- palette images must have < 16 bits
  486.             String msg = JaiI18N.getString("PNGImageDecoder6");
  487.             throw new RuntimeException(msg);
  488.         }
  489.         if ((colorType == PNG_COLOR_GRAY_ALPHA) && (bitDepth < 8)) {
  490.             // Error -- gray/alpha images must have >= 8 bits
  491.             String msg = JaiI18N.getString("PNGImageDecoder7");
  492.             throw new RuntimeException(msg);
  493.         }
  494.         if ((colorType == PNG_COLOR_RGB_ALPHA) && (bitDepth < 8)) {
  495.             // Error -- RGB/alpha images must have >= 8 bits
  496.             String msg = JaiI18N.getString("PNGImageDecoder8");
  497.             throw new RuntimeException(msg);
  498.         }
  499.         if (emitProperties) {
  500.             properties.put("color_type", colorTypeNames[colorType]);
  501.         }
  502.         if (generateEncodeParam) {
  503.             if (colorType == PNG_COLOR_PALETTE) {
  504.                 encodeParam = new PNGEncodeParam.Palette();
  505.             } else if (colorType == PNG_COLOR_GRAY ||
  506.                        colorType == PNG_COLOR_GRAY_ALPHA) {
  507.                 encodeParam = new PNGEncodeParam.Gray();
  508.             } else {
  509.                 encodeParam = new PNGEncodeParam.RGB();
  510.             }
  511.             decodeParam.setEncodeParam(encodeParam);
  512.         }
  513.         if (encodeParam != null) {
  514.             encodeParam.setBitDepth(bitDepth);
  515.         }
  516.         if (emitProperties) {
  517.             properties.put("bit_depth", new Integer(bitDepth));
  518.         }
  519.         if (performGammaCorrection) {
  520.             // Assume file gamma is 1/2.2 unless we get a gAMA chunk
  521.             float gamma = (1.0F/2.2F)*(displayExponent/userExponent);
  522.             if (encodeParam != null) {
  523.                 encodeParam.setGamma(gamma);
  524.             }
  525.             if (emitProperties) {
  526.                 properties.put("gamma", new Float(gamma));
  527.             }
  528.         }
  529.         compressionMethod = chunk.getInt1(10); 
  530.         if (compressionMethod != 0) {
  531.             // Error -- only know about compression method 0
  532.             String msg = JaiI18N.getString("PNGImageDecoder9");
  533.             throw new RuntimeException(msg);
  534.         }
  535.         filterMethod = chunk.getInt1(11);
  536.         if (filterMethod != 0) {
  537.             // Error -- only know about filter method 0
  538.             String msg = JaiI18N.getString("PNGImageDecoder10");
  539.             throw new RuntimeException(msg);
  540.         }
  541.         interlaceMethod = chunk.getInt1(12);
  542.         if (interlaceMethod == 0) {
  543.             if (encodeParam != null) {
  544.                 encodeParam.setInterlacing(false);
  545.             }
  546.             if (emitProperties) {
  547.                 properties.put("interlace_method", "None");
  548.             }
  549.         } else if (interlaceMethod == 1) {
  550.             if (encodeParam != null) {
  551.                 encodeParam.setInterlacing(true);
  552.             }
  553.             if (emitProperties) {
  554.                 properties.put("interlace_method", "Adam7");
  555.             }
  556.         } else {
  557.             // Error -- only know about Adam7 interlacing
  558.             String msg = JaiI18N.getString("PNGImageDecoder11");
  559.             throw new RuntimeException(msg);
  560.         }
  561.         
  562.         bytesPerPixel = (bitDepth == 16) ? 2 : 1;
  563.         switch (colorType) {
  564.         case PNG_COLOR_GRAY:
  565.             inputBands = 1;
  566.             outputBands = 1;
  567.             if (output8BitGray && (bitDepth < 8)) {
  568.                 postProcess = POST_GRAY_LUT;
  569.             } else if (performGammaCorrection) {
  570.                 postProcess = POST_GAMMA;
  571.             } else {
  572.                 postProcess = POST_NONE;
  573.             }
  574.             break;
  575.         case PNG_COLOR_RGB:
  576.             inputBands = 3;
  577.             bytesPerPixel *= 3;
  578.             outputBands = 3;
  579.             if (performGammaCorrection) {
  580.                 postProcess = POST_GAMMA;
  581.             } else {
  582.                 postProcess = POST_NONE;
  583.             }
  584.             break;
  585.         case PNG_COLOR_PALETTE:
  586.             inputBands = 1;
  587.             bytesPerPixel = 1;
  588.             outputBands = expandPalette ? 3 : 1;
  589.             if (expandPalette) {
  590.                 postProcess = POST_PALETTE_TO_RGB;
  591.             } else {
  592.                 postProcess = POST_NONE;
  593.             }
  594.             break;
  595.         case PNG_COLOR_GRAY_ALPHA:
  596.             inputBands = 2;
  597.             bytesPerPixel *= 2;
  598.             if (suppressAlpha) {
  599.                 outputBands = 1;
  600.                 postProcess = POST_REMOVE_GRAY_TRANS;
  601.             } else {
  602.                 if (performGammaCorrection) {
  603.                     postProcess = POST_GAMMA;
  604.                 } else {
  605.                     postProcess = POST_NONE;
  606.                 }
  607.                 if (expandGrayAlpha) {
  608.                     postProcess |= POST_EXP_MASK;
  609.                     outputBands = 4;
  610.                 } else {
  611.                     outputBands = 2;
  612.                 }
  613.             }
  614.             break;
  615.         case PNG_COLOR_RGB_ALPHA:
  616.             inputBands = 4;
  617.             bytesPerPixel *= 4;
  618.             outputBands = (!suppressAlpha) ? 4 : 3;
  619.             if (suppressAlpha) {
  620.                 postProcess = POST_REMOVE_RGB_TRANS;
  621.             } else if (performGammaCorrection) {
  622.                 postProcess = POST_GAMMA;
  623.             } else {
  624.                 postProcess = POST_NONE;
  625.             }
  626.             break;
  627.         }
  628.     }
  629.     private void parse_IEND_chunk(PNGChunk chunk) throws Exception {
  630.         // Store text strings
  631.         int textLen = textKeys.size();
  632.         String[] textArray = new String[2*textLen];
  633.         for (int i = 0; i < textLen; i++) {
  634.             String key = (String)textKeys.elementAt(i);
  635.             String val = (String)textStrings.elementAt(i);
  636.             textArray[2*i] = key;
  637.             textArray[2*i + 1] = val;
  638.             if (emitProperties) {
  639.                 String uniqueKey = "text_" + i + ":" + key;
  640.                 properties.put(uniqueKey.toLowerCase(), val);
  641.             }
  642.         }
  643.         if (encodeParam != null) {
  644.             encodeParam.setText(textArray);
  645.         }
  646.         // Store compressed text strings
  647.         int ztextLen = ztextKeys.size();
  648.         String[] ztextArray = new String[2*ztextLen];
  649.         for (int i = 0; i < ztextLen; i++) {
  650.             String key = (String)ztextKeys.elementAt(i);
  651.             String val = (String)ztextStrings.elementAt(i);
  652.             ztextArray[2*i] = key;
  653.             ztextArray[2*i + 1] = val;
  654.             if (emitProperties) {
  655.                 String uniqueKey = "ztext_" + i + ":" + key;
  656.                 properties.put(uniqueKey.toLowerCase(), val);
  657.             }
  658.         }
  659.         if (encodeParam != null) {
  660.             encodeParam.setCompressedText(ztextArray);
  661.         }
  662.         // Parse prior IDAT chunks
  663.         InputStream seqStream = 
  664.             new SequenceInputStream(streamVec.elements());
  665.         InputStream infStream =
  666.             new InflaterInputStream(seqStream, new Inflater());
  667.         dataStream = new DataInputStream(infStream);
  668.         
  669.         // Create an empty WritableRaster
  670.         int depth = bitDepth;
  671.         if ((colorType == PNG_COLOR_GRAY) && 
  672.             (bitDepth < 8) && output8BitGray) {
  673.             depth = 8;
  674.         }
  675.         if ((colorType == PNG_COLOR_PALETTE) && expandPalette) {
  676.             depth = 8;
  677.         }
  678.         int bytesPerRow = (outputBands*width*depth + 7)/8;
  679.         int scanlineStride =
  680.             (depth == 16) ? (bytesPerRow/2) : bytesPerRow;
  681.         theTile = createRaster(width, height, outputBands,
  682.                                scanlineStride,
  683.                                depth);
  684.         if (performGammaCorrection && (gammaLut == null)) {
  685.             initGammaLut(bitDepth);
  686.         }
  687.         if ((postProcess == POST_GRAY_LUT) ||
  688.             (postProcess == POST_GRAY_LUT_ADD_TRANS) ||
  689.             (postProcess == POST_GRAY_LUT_ADD_TRANS_EXP)) {
  690.             initGrayLut(bitDepth);
  691.         }
  692.         decodeImage(interlaceMethod == 1);
  693.         sampleModel = theTile.getSampleModel();
  694.         if ((colorType == PNG_COLOR_PALETTE) && !expandPalette) {
  695.             if (outputHasAlphaPalette) {
  696.                 colorModel = new IndexColorModel(bitDepth,
  697.                                                  paletteEntries,
  698.                                                  redPalette,
  699.                                                  greenPalette,
  700.                                                  bluePalette,
  701.                                                  alphaPalette);
  702.             } else {
  703.                 colorModel = new IndexColorModel(bitDepth,
  704.                                                  paletteEntries,
  705.                                                  redPalette,
  706.                                                  greenPalette,
  707.                                                  bluePalette);
  708.             }
  709.         } else if ((colorType == PNG_COLOR_GRAY) && 
  710.                    (bitDepth < 8) && !output8BitGray) {
  711.             byte[] palette = expandBits[bitDepth];
  712.             colorModel = new IndexColorModel(bitDepth,
  713.                                              palette.length,
  714.                                              palette,
  715.                                              palette,
  716.                                              palette);
  717.         } else {
  718.             colorModel =
  719.                 ImageCodec.createComponentColorModel(sampleModel);
  720.         }
  721.     }
  722.     private void parse_PLTE_chunk(PNGChunk chunk) {
  723.         paletteEntries = chunk.getLength()/3;
  724.         redPalette = new byte[paletteEntries];
  725.         greenPalette = new byte[paletteEntries];
  726.         bluePalette = new byte[paletteEntries];
  727.         int pltIndex = 0;
  728.         // gAMA chunk must precede PLTE chunk 
  729.         if (performGammaCorrection) {
  730.             if (gammaLut == null) {
  731.                 initGammaLut(bitDepth == 16 ? 16 : 8);
  732.             }
  733.             
  734.             for (int i = 0; i < paletteEntries; i++) {
  735.                 byte r = chunk.getByte(pltIndex++);
  736.                 byte g = chunk.getByte(pltIndex++);
  737.                 byte b = chunk.getByte(pltIndex++);
  738.                 redPalette[i] = (byte)gammaLut[r & 0xff];
  739.                 greenPalette[i] = (byte)gammaLut[g & 0xff];
  740.                 bluePalette[i] = (byte)gammaLut[b & 0xff];
  741.             }
  742.         } else {
  743.             for (int i = 0; i < paletteEntries; i++) {
  744.                 redPalette[i] = chunk.getByte(pltIndex++);
  745.                 greenPalette[i] = chunk.getByte(pltIndex++);
  746.                 bluePalette[i] = chunk.getByte(pltIndex++);
  747.             }
  748.         }
  749.     }
  750.     private void parse_bKGD_chunk(PNGChunk chunk) {
  751.         hasBackground = true;
  752.         switch (colorType) {
  753.         case PNG_COLOR_PALETTE:
  754.             int bkgdIndex = chunk.getByte(0) & 0xff;
  755.             bkgdRed = redPalette[bkgdIndex] & 0xff;
  756.             bkgdGreen = greenPalette[bkgdIndex] & 0xff;
  757.             bkgdBlue = bluePalette[bkgdIndex] & 0xff;
  758.             if (encodeParam != null) {
  759.                 ((PNGEncodeParam.Palette)encodeParam).
  760.                     setBackgroundPaletteIndex(bkgdIndex);
  761.             }
  762.             break;
  763.         case PNG_COLOR_GRAY: case PNG_COLOR_GRAY_ALPHA:
  764.             int bkgdGray = chunk.getInt2(0);
  765.             bkgdRed = bkgdGreen = bkgdBlue = bkgdGray;
  766.             if (encodeParam != null) {
  767.                 ((PNGEncodeParam.Gray)encodeParam).
  768.                     setBackgroundGray(bkgdGray);
  769.             }
  770.             break;
  771.         case PNG_COLOR_RGB: case PNG_COLOR_RGB_ALPHA:
  772.             bkgdRed = chunk.getInt2(0);
  773.             bkgdGreen = chunk.getInt2(2);
  774.             bkgdBlue = chunk.getInt2(4);
  775.             int[] bkgdRGB = new int[3];
  776.             bkgdRGB[0] = bkgdRed;
  777.             bkgdRGB[1] = bkgdGreen;
  778.             bkgdRGB[2] = bkgdBlue;
  779.             if (encodeParam != null) {
  780.                 ((PNGEncodeParam.RGB)encodeParam).
  781.                     setBackgroundRGB(bkgdRGB);
  782.             }
  783.             break;
  784.         }
  785.         int r = 0, g = 0, b = 0;
  786.         if (bitDepth < 8) {
  787.             r = expandBits[bitDepth][bkgdRed];
  788.             g = expandBits[bitDepth][bkgdGreen];
  789.             b = expandBits[bitDepth][bkgdBlue];
  790.         } else if (bitDepth == 8) {
  791.             r = bkgdRed;
  792.             g = bkgdGreen;
  793.             b = bkgdBlue;
  794.         } else if (bitDepth == 16) {
  795.             r = bkgdRed >> 8;
  796.             g = bkgdGreen >> 8;
  797.             b = bkgdBlue >> 8;
  798.         }
  799.         if (emitProperties) {
  800.             properties.put("background_color", new Color(r, g, b));
  801.         }
  802.     }
  803.     private void parse_cHRM_chunk(PNGChunk chunk) {
  804.         // If an sRGB chunk exists, ignore cHRM chunks
  805.         if (sRGBRenderingIntent != -1) {
  806.             return;
  807.         }
  808.         chromaticity = new float[8];
  809.         chromaticity[0] = chunk.getInt4(0)/100000.0F;
  810.         chromaticity[1] = chunk.getInt4(4)/100000.0F;
  811.         chromaticity[2] = chunk.getInt4(8)/100000.0F;
  812.         chromaticity[3] = chunk.getInt4(12)/100000.0F;
  813.         chromaticity[4] = chunk.getInt4(16)/100000.0F;
  814.         chromaticity[5] = chunk.getInt4(20)/100000.0F;
  815.         chromaticity[6] = chunk.getInt4(24)/100000.0F;
  816.         chromaticity[7] = chunk.getInt4(28)/100000.0F;
  817.         if (encodeParam != null) {
  818.             encodeParam.setChromaticity(chromaticity);
  819.         }
  820.         if (emitProperties) {
  821.             properties.put("white_point_x", new Float(chromaticity[0]));
  822.             properties.put("white_point_y", new Float(chromaticity[1]));
  823.             properties.put("red_x", new Float(chromaticity[2]));
  824.             properties.put("red_y", new Float(chromaticity[3]));
  825.             properties.put("green_x", new Float(chromaticity[4]));
  826.             properties.put("green_y", new Float(chromaticity[5]));
  827.             properties.put("blue_x", new Float(chromaticity[6]));
  828.             properties.put("blue_y", new Float(chromaticity[7]));
  829.         }
  830.     }
  831.     private void parse_gAMA_chunk(PNGChunk chunk) {
  832.         // If an sRGB chunk exists, ignore gAMA chunks
  833.         if (sRGBRenderingIntent != -1) {
  834.             return;
  835.         }
  836.         fileGamma = chunk.getInt4(0)/100000.0F;
  837.         float exp =
  838.             performGammaCorrection ? displayExponent/userExponent : 1.0F;
  839.         if (encodeParam != null) {
  840.             encodeParam.setGamma(fileGamma*exp);
  841.         }
  842.         if (emitProperties) {
  843.             properties.put("gamma", new Float(fileGamma*exp));
  844.         }
  845.     }
  846.     
  847.     private void parse_hIST_chunk(PNGChunk chunk) {
  848.         if (redPalette == null) {
  849.             String msg = JaiI18N.getString("PNGImageDecoder18");
  850.             throw new RuntimeException(msg);
  851.         }
  852.         int length = redPalette.length;
  853.         int[] hist = new int[length];
  854.         for (int i = 0; i < length; i++) {
  855.             hist[i] = chunk.getInt2(2*i);
  856.         }
  857.         
  858.         if (encodeParam != null) {
  859.             encodeParam.setPaletteHistogram(hist);
  860.         }
  861.     }
  862.     private void parse_iCCP_chunk(PNGChunk chunk) {
  863.         String name = new String();
  864.         byte b;
  865.         int textIndex = 0;
  866.         while ((b = chunk.getByte(textIndex++)) != 0) {
  867.             name += (char)b;
  868.         }
  869.     }
  870.     private void parse_pHYs_chunk(PNGChunk chunk) {
  871.         int xPixelsPerUnit = chunk.getInt4(0);
  872.         int yPixelsPerUnit = chunk.getInt4(4);
  873.         int unitSpecifier = chunk.getInt1(8);
  874.         if (encodeParam != null) {
  875.             encodeParam.setPhysicalDimension(xPixelsPerUnit,
  876.                                              yPixelsPerUnit,
  877.                                              unitSpecifier);
  878.         }
  879.         if (emitProperties) {
  880.             properties.put("x_pixels_per_unit", new Integer(xPixelsPerUnit));
  881.             properties.put("y_pixels_per_unit", new Integer(yPixelsPerUnit));
  882.             properties.put("pixel_aspect_ratio", 
  883.                            new Float((float)xPixelsPerUnit/yPixelsPerUnit));
  884.             if (unitSpecifier == 1) {
  885.                 properties.put("pixel_units", "Meters");
  886.             } else if (unitSpecifier != 0) {
  887.                 // Error -- unit specifier must be 0 or 1
  888.                 String msg = JaiI18N.getString("PNGImageDecoder12");
  889.                 throw new RuntimeException(msg);
  890.             }
  891.         }
  892.     }
  893.     private void parse_sBIT_chunk(PNGChunk chunk) {
  894.         if (colorType == PNG_COLOR_PALETTE) {
  895.             significantBits = new int[3];
  896.         } else {
  897.             significantBits = new int[inputBands];
  898.         }
  899.         for (int i = 0; i < significantBits.length; i++) {
  900.             int bits = (int)chunk.getByte(i);
  901.             int depth = (colorType == PNG_COLOR_PALETTE) ? 8 : bitDepth;
  902.             if (bits <= 0 || bits > depth) {
  903.                 // Error -- significant bits must be between 0 and
  904.                 // image bit depth.
  905.                 String msg = JaiI18N.getString("PNGImageDecoder13");
  906.                 throw new RuntimeException(msg);
  907.             }
  908.             significantBits[i] = bits;
  909.         }
  910.         if (encodeParam != null) {
  911.             encodeParam.setSignificantBits(significantBits);
  912.         }
  913.         if (emitProperties) {
  914.             properties.put("significant_bits", significantBits);
  915.         }
  916.     }
  917.     private void parse_sRGB_chunk(PNGChunk chunk) {
  918.         sRGBRenderingIntent = chunk.getByte(0);
  919.         // The presence of an sRGB chunk implies particular
  920.         // settings for gamma and chroma.
  921.         fileGamma = 45455/100000.0F;
  922.         chromaticity = new float[8];
  923.         chromaticity[0] = 31270/10000.0F;
  924.         chromaticity[1] = 32900/10000.0F;
  925.         chromaticity[2] = 64000/10000.0F;
  926.         chromaticity[3] = 33000/10000.0F;
  927.         chromaticity[4] = 30000/10000.0F;
  928.         chromaticity[5] = 60000/10000.0F;
  929.         chromaticity[6] = 15000/10000.0F;
  930.         chromaticity[7] =  6000/10000.0F;
  931.         if (performGammaCorrection) {
  932.             // File gamma is 1/2.2
  933.             float gamma = fileGamma*(displayExponent/userExponent);
  934.             if (encodeParam != null) {
  935.                 encodeParam.setGamma(gamma);
  936.                 encodeParam.setChromaticity(chromaticity);
  937.             }
  938.             if (emitProperties) {
  939.                 properties.put("gamma", new Float(gamma));
  940.                 properties.put("white_point_x", new Float(chromaticity[0]));
  941.                 properties.put("white_point_y", new Float(chromaticity[1]));
  942.                 properties.put("red_x", new Float(chromaticity[2]));
  943.                 properties.put("red_y", new Float(chromaticity[3]));
  944.                 properties.put("green_x", new Float(chromaticity[4]));
  945.                 properties.put("green_y", new Float(chromaticity[5]));
  946.                 properties.put("blue_x", new Float(chromaticity[6]));
  947.                 properties.put("blue_y", new Float(chromaticity[7]));
  948.             }
  949.         }
  950.     }
  951.     private void parse_tEXt_chunk(PNGChunk chunk) {
  952.         String key = new String();
  953.         String value = new String();
  954.         byte b;
  955.         
  956.         int textIndex = 0;
  957.         while ((b = chunk.getByte(textIndex++)) != 0) {
  958.             key += (char)b;
  959.         }
  960.         for (int i = textIndex; i < chunk.getLength(); i++) {
  961.             value += (char)chunk.getByte(i);
  962.         }
  963.         textKeys.add(key);
  964.         textStrings.add(value);
  965.     }
  966.     private void parse_tIME_chunk(PNGChunk chunk) {
  967.         int year = chunk.getInt2(0);
  968.         int month = chunk.getInt1(2) - 1;
  969.         int day = chunk.getInt1(3);
  970.         int hour = chunk.getInt1(4);
  971.         int minute = chunk.getInt1(5);
  972.         int second = chunk.getInt1(6);
  973.         
  974.         TimeZone gmt = TimeZone.getTimeZone("GMT");
  975.         
  976.         GregorianCalendar cal = new GregorianCalendar(gmt);
  977.         cal.set(year, month, day,
  978.                 hour, minute, second);
  979.         Date date = cal.getTime();
  980.         
  981.         if (encodeParam != null) {
  982.             encodeParam.setModificationTime(date);
  983.         }
  984.         if (emitProperties) {
  985.             properties.put("timestamp", date);
  986.         }
  987.     }
  988.     private void parse_tRNS_chunk(PNGChunk chunk) {
  989.         if (colorType == PNG_COLOR_PALETTE) {
  990.             int entries = chunk.getLength();
  991.             if (entries > paletteEntries) {
  992.                 // Error -- mustn't have more alpha than RGB palette entries
  993.                 String msg = JaiI18N.getString("PNGImageDecoder14");
  994.                 throw new RuntimeException(msg);
  995.             }
  996.             // Load beginning of palette from the chunk
  997.             alphaPalette = new byte[paletteEntries];
  998.             for (int i = 0; i < entries; i++) {
  999.                 alphaPalette[i] = chunk.getByte(i);
  1000.             }
  1001.             
  1002.             // Fill rest of palette with 255
  1003.             for (int i = entries; i < paletteEntries; i++) {
  1004.                 alphaPalette[i] = (byte)255;
  1005.             }
  1006.             if (!suppressAlpha) {
  1007.                 if (expandPalette) {
  1008.                     postProcess = POST_PALETTE_TO_RGBA;
  1009.                     outputBands = 4;
  1010.                 } else {
  1011.                     outputHasAlphaPalette = true;
  1012.                 }
  1013.             }
  1014.         } else if (colorType == PNG_COLOR_GRAY) {
  1015.             grayTransparentAlpha = chunk.getInt2(0);
  1016.             
  1017.             if (!suppressAlpha) {
  1018.                 if (bitDepth < 8) {
  1019.                     output8BitGray = true;
  1020.                     maxOpacity = 255;
  1021.                     postProcess = POST_GRAY_LUT_ADD_TRANS;
  1022.                 } else {
  1023.                     postProcess = POST_ADD_GRAY_TRANS;
  1024.                 }
  1025.                 if (expandGrayAlpha) {
  1026.                     outputBands = 4;
  1027.                     postProcess |= POST_EXP_MASK;
  1028.                 } else {
  1029.                     outputBands = 2;
  1030.                 }
  1031.                 
  1032.                 if (encodeParam != null) {
  1033.                     ((PNGEncodeParam.Gray)encodeParam).
  1034.                         setTransparentGray(grayTransparentAlpha);
  1035.                 }
  1036.             }
  1037.         } else if (colorType == PNG_COLOR_RGB) {
  1038.             redTransparentAlpha = chunk.getInt2(0);
  1039.             greenTransparentAlpha = chunk.getInt2(2);
  1040.             blueTransparentAlpha = chunk.getInt2(4);
  1041.             if (!suppressAlpha) {
  1042.                 outputBands = 4;
  1043.                 postProcess = POST_ADD_RGB_TRANS;
  1044.                 
  1045.                 if (encodeParam != null) {
  1046.                     int[] rgbTrans = new int[3];
  1047.                     rgbTrans[0] = redTransparentAlpha;
  1048.                     rgbTrans[1] = greenTransparentAlpha;
  1049.                     rgbTrans[2] = blueTransparentAlpha;
  1050.                     ((PNGEncodeParam.RGB)encodeParam).
  1051.                         setTransparentRGB(rgbTrans);
  1052.                 }
  1053.             }
  1054.         } else if (colorType == PNG_COLOR_GRAY_ALPHA ||
  1055.                    colorType == PNG_COLOR_RGB_ALPHA) {
  1056.             // Error -- GA or RGBA image can't have a tRNS chunk.
  1057.             String msg = JaiI18N.getString("PNGImageDecoder15");
  1058.             throw new RuntimeException(msg);
  1059.         }
  1060.     }
  1061.     private void parse_zTXt_chunk(PNGChunk chunk) {
  1062.         String key = new String();
  1063.         String value = new String();
  1064.         byte b;
  1065.         
  1066.         int textIndex = 0;
  1067.         while ((b = chunk.getByte(textIndex++)) != 0) {
  1068.             key += (char)b;
  1069.         }
  1070.         int method = chunk.getByte(textIndex++);
  1071.         try {
  1072.             int length = chunk.getLength() - textIndex;
  1073.             byte[] data = chunk.getData();
  1074.             InputStream cis =
  1075.                 new ByteArrayInputStream(data, textIndex, length);
  1076.             InputStream iis = new InflaterInputStream(cis);
  1077.             
  1078.             int c;
  1079.             while ((c = iis.read()) != -1) {
  1080.                 value += (char)c;
  1081.             }
  1082.             
  1083.             ztextKeys.add(key);
  1084.             ztextStrings.add(value);
  1085.         } catch (Exception e) {
  1086.             e.printStackTrace();
  1087.         }
  1088.     }
  1089.     private WritableRaster createRaster(int width, int height, int bands,
  1090.                                         int scanlineStride,
  1091.                                         int bitDepth) {
  1092.         DataBuffer dataBuffer;
  1093.         WritableRaster ras = null;
  1094.         Point origin = new Point(0, 0);
  1095.         if ((bitDepth < 8) && (bands == 1)) {
  1096.             dataBuffer = new DataBufferByte(height*scanlineStride);
  1097.             ras = Raster.createPackedRaster(dataBuffer,
  1098.                                             width, height,
  1099.                                             bitDepth,
  1100.                                             origin);
  1101.         } else if (bitDepth <= 8) {
  1102.             dataBuffer = new DataBufferByte(height*scanlineStride);
  1103.            ras = Raster.createInterleavedRaster(dataBuffer,
  1104.                                                  width, height,
  1105.                                                  scanlineStride,
  1106.                                                  bands,
  1107.                                                  bandOffsets[bands],
  1108.                                                  origin);
  1109.         } else {
  1110.             dataBuffer = new DataBufferUShort(height*scanlineStride);
  1111.             ras = Raster.createInterleavedRaster(dataBuffer,
  1112.                                                  width, height,
  1113.                                                  scanlineStride,
  1114.                                                  bands,
  1115.                                                  bandOffsets[bands],
  1116.                                                  origin);
  1117.         }
  1118.         return ras;
  1119.     }
  1120.     // Data filtering methods
  1121.     private static void decodeSubFilter(byte[] curr, int count, int bpp) {
  1122.         for (int i = bpp; i < count; i++) {
  1123.             int val;
  1124.             val = curr[i] & 0xff;
  1125.             val += curr[i - bpp] & 0xff;
  1126.             curr[i] = (byte)val;
  1127.         }
  1128.     }
  1129.     private static void decodeUpFilter(byte[] curr, byte[] prev,
  1130.                                        int count) {
  1131.         for (int i = 0; i < count; i++) {
  1132.             int raw = curr[i] & 0xff;
  1133.             int prior = prev[i] & 0xff;
  1134.             curr[i] = (byte)(raw + prior);
  1135.         }
  1136.     }
  1137.     private static void decodeAverageFilter(byte[] curr, byte[] prev,
  1138.                                             int count, int bpp) {
  1139.         int raw, priorPixel, priorRow;
  1140.         for (int i = 0; i < bpp; i++) {
  1141.             raw = curr[i] & 0xff;
  1142.             priorRow = prev[i] & 0xff;
  1143.             
  1144.             curr[i] = (byte)(raw + priorRow/2);
  1145.         }
  1146.         for (int i = bpp; i < count; i++) {
  1147.             raw = curr[i] & 0xff;
  1148.             priorPixel = curr[i - bpp] & 0xff;
  1149.             priorRow = prev[i] & 0xff;
  1150.             
  1151.             curr[i] = (byte)(raw + (priorPixel + priorRow)/2);
  1152.         }
  1153.     }
  1154.     private static int paethPredictor(int a, int b, int c) {
  1155.         int p = a + b - c;
  1156.         int pa = Math.abs(p - a);
  1157.         int pb = Math.abs(p - b);
  1158.         int pc = Math.abs(p - c);
  1159.         if ((pa <= pb) && (pa <= pc)) {
  1160.             return a;
  1161.         } else if (pb <= pc) {
  1162.             return b;
  1163.         } else {
  1164.             return c;
  1165.         }
  1166.     } 
  1167.     private static void decodePaethFilter(byte[] curr, byte[] prev,
  1168.                                           int count, int bpp) {
  1169.         int raw, priorPixel, priorRow, priorRowPixel;
  1170.         for (int i = 0; i < bpp; i++) {
  1171.             raw = curr[i] & 0xff;
  1172.             priorRow = prev[i] & 0xff;
  1173.             curr[i] = (byte)(raw + priorRow);
  1174.         }
  1175.         for (int i = bpp; i < count; i++) {
  1176.             raw = curr[i] & 0xff;
  1177.             priorPixel = curr[i - bpp] & 0xff;
  1178.             priorRow = prev[i] & 0xff;
  1179.             priorRowPixel = prev[i - bpp] & 0xff;
  1180.             curr[i] = (byte)(raw + paethPredictor(priorPixel,
  1181.                                                   priorRow,
  1182.                                                   priorRowPixel));
  1183.         }
  1184.     }
  1185.     private void processPixels(int process,
  1186.                                Raster src, WritableRaster dst,
  1187.                                int xOffset, int step, int y, int width) {
  1188.         int srcX, dstX;
  1189.         // Create an array suitable for holding one pixel
  1190.         int[] ps = src.getPixel(0, 0, (int[])null);
  1191.         int[] pd = dst.getPixel(0, 0, (int[])null);
  1192.         dstX = xOffset;
  1193.         switch (process) {
  1194.         case POST_NONE:
  1195.             for (srcX = 0; srcX < width; srcX++) {
  1196.                 src.getPixel(srcX, 0, ps);
  1197.                 dst.setPixel(dstX, y, ps);
  1198.                 dstX += step;
  1199.             }
  1200.             break;
  1201.         case POST_GAMMA:
  1202.             for (srcX = 0; srcX < width; srcX++) {
  1203.                 src.getPixel(srcX, 0, ps);
  1204.                     
  1205.                 for (int i = 0; i < inputBands; i++) {
  1206.                     int x = ps[i];
  1207.                     ps[i] = gammaLut[x];
  1208.                 }
  1209.                     
  1210.                 dst.setPixel(dstX, y, ps);
  1211.                 dstX += step;
  1212.             }
  1213.             break;
  1214.         case POST_GRAY_LUT:
  1215.             for (srcX = 0; srcX < width; srcX++) {
  1216.                 src.getPixel(srcX, 0, ps);
  1217.                 pd[0] = grayLut[ps[0]];
  1218.                 dst.setPixel(dstX, y, pd);
  1219.                 dstX += step;
  1220.             }
  1221.             break;
  1222.         case POST_GRAY_LUT_ADD_TRANS:
  1223.             for (srcX = 0; srcX < width; srcX++) {
  1224.                 src.getPixel(srcX, 0, ps);
  1225.                 int val = ps[0];
  1226.                 pd[0] = grayLut[val];
  1227.                 if (val == grayTransparentAlpha) {
  1228.                     pd[1] = 0;
  1229.                 } else {
  1230.                     pd[1] = maxOpacity;
  1231.                 }
  1232.                 
  1233.                 dst.setPixel(dstX, y, pd);
  1234.                 dstX += step;
  1235.             }
  1236.             break;
  1237.         case POST_PALETTE_TO_RGB:
  1238.             for (srcX = 0; srcX < width; srcX++) {
  1239.                 src.getPixel(srcX, 0, ps);
  1240.                 
  1241.                 int val = ps[0];
  1242.                 pd[0] = redPalette[val];
  1243.                 pd[1] = greenPalette[val];
  1244.                 pd[2] = bluePalette[val];
  1245.                 
  1246.                 dst.setPixel(dstX, y, pd);
  1247.                 dstX += step;
  1248.             }
  1249.             break;
  1250.         case POST_PALETTE_TO_RGBA:
  1251.             for (srcX = 0; srcX < width; srcX++) {
  1252.                 src.getPixel(srcX, 0, ps);
  1253.                 int val = ps[0];
  1254.                 pd[0] = redPalette[val];
  1255.                 pd[1] = greenPalette[val];
  1256.                 pd[2] = bluePalette[val];
  1257.                 pd[3] = alphaPalette[val];
  1258.                 dst.setPixel(dstX, y, pd);
  1259.                 dstX += step;
  1260.             }
  1261.             break;
  1262.         case POST_ADD_GRAY_TRANS:
  1263.             for (srcX = 0; srcX < width; srcX++) {
  1264.                 src.getPixel(srcX, 0, ps);
  1265.                 int val = ps[0];
  1266.                 if (performGammaCorrection) {
  1267.                     val = gammaLut[val];
  1268.                 }
  1269.                 pd[0] = val;
  1270.                 if (val == grayTransparentAlpha) {
  1271.                     pd[1] = 0;
  1272.                 } else {
  1273.                     pd[1] = maxOpacity;
  1274.                 }
  1275.                 dst.setPixel(dstX, y, pd);
  1276.                 dstX += step;
  1277.             }
  1278.             break;
  1279.         case POST_ADD_RGB_TRANS:
  1280.             for (srcX = 0; srcX < width; srcX++) {
  1281.                 src.getPixel(srcX, 0, ps);
  1282.                 int r = ps[0];
  1283.                 int g = ps[1];
  1284.                 int b = ps[2];
  1285.                 if (performGammaCorrection) {
  1286.                     pd[0] = gammaLut[r];
  1287.                     pd[1] = gammaLut[g];
  1288.                     pd[2] = gammaLut[b];
  1289.                 } else {
  1290.                     pd[0] = r;
  1291.                     pd[1] = g;
  1292.                     pd[2] = b;
  1293.                 }
  1294.                 if ((r == redTransparentAlpha) &&
  1295.                     (g == greenTransparentAlpha) &&
  1296.                     (b == blueTransparentAlpha)) {
  1297.                     pd[3] = 0;
  1298.                 } else {
  1299.                     pd[3] = maxOpacity;
  1300.                 }
  1301.                 dst.setPixel(dstX, y, pd);
  1302.                 dstX += step;
  1303.             }
  1304.             break;
  1305.         case POST_REMOVE_GRAY_TRANS:
  1306.             for (srcX = 0; srcX < width; srcX++) {
  1307.                 src.getPixel(srcX, 0, ps);
  1308.                 int g = ps[0];
  1309.                 if (performGammaCorrection) {
  1310.                     pd[0] = gammaLut[g];
  1311.                 } else {
  1312.                     pd[0] = g;
  1313.                 }
  1314.                 dst.setPixel(dstX, y, pd);
  1315.                 dstX += step;
  1316.             }
  1317.             break;
  1318.         case POST_REMOVE_RGB_TRANS:
  1319.             for (srcX = 0; srcX < width; srcX++) {
  1320.                 src.getPixel(srcX, 0, ps);
  1321.                 int r = ps[0];
  1322.                 int g = ps[1];
  1323.                 int b = ps[2];
  1324.                 if (performGammaCorrection) {
  1325.                     pd[0] = gammaLut[r];
  1326.                     pd[1] = gammaLut[g];
  1327.                     pd[2] = gammaLut[b];
  1328.                 } else {
  1329.                     pd[0] = r;
  1330.                     pd[1] = g;
  1331.                     pd[2] = b;
  1332.                 }
  1333.                 dst.setPixel(dstX, y, pd);
  1334.                 dstX += step;
  1335.             }
  1336.             break;
  1337.         case POST_GAMMA_EXP:
  1338.             for (srcX = 0; srcX < width; srcX++) {
  1339.                 src.getPixel(srcX, 0, ps);
  1340.                     
  1341.                 int val = ps[0];
  1342.                 int alpha = ps[1];
  1343.                 int gamma = gammaLut[val];
  1344.                 pd[0] = gamma;
  1345.                 pd[1] = gamma;
  1346.                 pd[2] = gamma;
  1347.                 pd[3] = alpha;
  1348.                     
  1349.                 dst.setPixel(dstX, y, pd);
  1350.                 dstX += step;
  1351.             }
  1352.             break;
  1353.         case POST_GRAY_ALPHA_EXP:
  1354.             for (srcX = 0; srcX < width; srcX++) {
  1355.                 src.getPixel(srcX, 0, ps);
  1356.                     
  1357.                 int val = ps[0];
  1358.                 int alpha = ps[1];
  1359.                 pd[0] = val;
  1360.                 pd[1] = val;
  1361.                 pd[2] = val;
  1362.                 pd[3] = alpha;
  1363.                     
  1364.                 dst.setPixel(dstX, y, pd);
  1365.                 dstX += step;
  1366.             }
  1367.             break;
  1368.         case POST_ADD_GRAY_TRANS_EXP:
  1369.             for (srcX = 0; srcX < width; srcX++) {
  1370.                 src.getPixel(srcX, 0, ps);
  1371.                 int val = ps[0];
  1372.                 if (performGammaCorrection) {
  1373.                     val = gammaLut[val];
  1374.                 }
  1375.                 pd[0] = val;
  1376.                 pd[1] = val;
  1377.                 pd[2] = val;
  1378.                 if (val == grayTransparentAlpha) {
  1379.                     pd[3] = 0;
  1380.                 } else {
  1381.                     pd[3] = maxOpacity;
  1382.                 }
  1383.                 dst.setPixel(dstX, y, pd);
  1384.                 dstX += step;
  1385.             }
  1386.             break;
  1387.         case POST_GRAY_LUT_ADD_TRANS_EXP:
  1388.             for (srcX = 0; srcX < width; srcX++) {
  1389.                 src.getPixel(srcX, 0, ps);
  1390.                 int val = ps[0];
  1391.                 int val2 = grayLut[val];
  1392.                 pd[0] = val2;
  1393.                 pd[1] = val2;
  1394.                 pd[2] = val2;
  1395.                 if (val == grayTransparentAlpha) {
  1396.                     pd[3] = 0;
  1397.                 } else {
  1398.                     pd[3] = maxOpacity;
  1399.                 }
  1400.                 
  1401.                 dst.setPixel(dstX, y, pd);
  1402.                 dstX += step;
  1403.             }
  1404.             break;
  1405.         }
  1406.     }
  1407.     /**
  1408.      * Reads in an image of a given size and returns it as a 
  1409.      * WritableRaster.
  1410.      */
  1411.     private void decodePass(WritableRaster imRas,
  1412.                             int xOffset, int yOffset,
  1413.                             int xStep, int yStep,
  1414.                             int passWidth, int passHeight) {
  1415.         if ((passWidth == 0) || (passHeight == 0)) {
  1416.             return;
  1417.         }
  1418.         int bytesPerRow = (inputBands*passWidth*bitDepth + 7)/8;
  1419.         int eltsPerRow = (bitDepth == 16) ? bytesPerRow/2 : bytesPerRow;
  1420.         byte[] curr = new byte[bytesPerRow];
  1421.         byte[] prior = new byte[bytesPerRow];
  1422.         // Create a 1-row tall Raster to hold the data
  1423.         WritableRaster passRow =
  1424.             createRaster(passWidth, 1, inputBands,
  1425.                          eltsPerRow,
  1426.                          bitDepth);
  1427.         DataBuffer dataBuffer = passRow.getDataBuffer();
  1428.         int type = dataBuffer.getDataType();
  1429.         byte[] byteData = null;
  1430.         short[] shortData = null;
  1431.         if (type == DataBuffer.TYPE_BYTE) {
  1432.             byteData = ((DataBufferByte)dataBuffer).getData();
  1433.         } else {
  1434.             shortData = ((DataBufferUShort)dataBuffer).getData();
  1435.         }
  1436.         // Decode the (sub)image row-by-row
  1437.         int srcY, dstY;
  1438.         for (srcY = 0, dstY = yOffset;
  1439.              srcY < passHeight;
  1440.              srcY++, dstY += yStep) {
  1441.             // Read the filter type byte and a row of data
  1442.             int filter = 0;
  1443.             try {
  1444.                 filter = dataStream.read();
  1445.                 dataStream.readFully(curr, 0, bytesPerRow);
  1446.             } catch (Exception e) {
  1447.                 e.printStackTrace();
  1448.             }
  1449.             switch (filter) {
  1450.             case PNG_FILTER_NONE:
  1451.                 break;
  1452.             case PNG_FILTER_SUB:
  1453.                 decodeSubFilter(curr, bytesPerRow, bytesPerPixel);
  1454.                 break;
  1455.             case PNG_FILTER_UP:
  1456.                 decodeUpFilter(curr, prior, bytesPerRow);
  1457.                 break;
  1458.             case PNG_FILTER_AVERAGE:
  1459.                 decodeAverageFilter(curr, prior, bytesPerRow, bytesPerPixel);
  1460.                 break;
  1461.             case PNG_FILTER_PAETH:
  1462.                 decodePaethFilter(curr, prior, bytesPerRow, bytesPerPixel);
  1463.                 break;
  1464.             default:
  1465.                 // Error -- uknown filter type
  1466.                 String msg = JaiI18N.getString("PNGImageDecoder16");
  1467.                 throw new RuntimeException(msg);
  1468.             }
  1469.             // Copy data into passRow byte by byte
  1470.             if (bitDepth < 16) {
  1471.                 System.arraycopy(curr, 0, byteData, 0, bytesPerRow);
  1472.             } else {
  1473.                 int idx = 0;
  1474.                 for (int j = 0; j < eltsPerRow; j++) {
  1475.                     shortData[j] =
  1476.                         (short)((curr[idx] << 8) | (curr[idx + 1] & 0xff));
  1477.                     idx += 2;
  1478.                 }
  1479.             }
  1480.             processPixels(postProcess,
  1481.                           passRow, imRas, xOffset, xStep, dstY, passWidth);
  1482.             // Swap curr and prior
  1483.             byte[] tmp = prior;
  1484.             prior = curr;
  1485.             curr = tmp;
  1486.         }
  1487.     }
  1488.     private void decodeImage(boolean useInterlacing) {
  1489.         if (!useInterlacing) {
  1490.             decodePass(theTile, 0, 0, 1, 1, width, height);
  1491.         } else {
  1492.             decodePass(theTile, 0, 0, 8, 8, (width + 7)/8, (height + 7)/8);
  1493.             decodePass(theTile, 4, 0, 8, 8, (width + 3)/8, (height + 7)/8);
  1494.             decodePass(theTile, 0, 4, 4, 8, (width + 3)/4, (height + 3)/8);
  1495.             decodePass(theTile, 2, 0, 4, 4, (width + 1)/4, (height + 3)/4);
  1496.             decodePass(theTile, 0, 2, 2, 4, (width + 1)/2, (height + 1)/4);
  1497.             decodePass(theTile, 1, 0, 2, 2, width/2, (height + 1)/2);
  1498.             decodePass(theTile, 0, 1, 1, 2, width, height/2);
  1499.         }
  1500.     }
  1501.     // RenderedImage stuff
  1502.     public Raster getTile(int tileX, int tileY) {
  1503.         if (tileX != 0 || tileY != 0) {
  1504.             // Error -- bad tile requested
  1505.             String msg = JaiI18N.getString("PNGImageDecoder17");
  1506.             throw new IllegalArgumentException(msg);
  1507.         }
  1508.         return theTile;
  1509.     }
  1510. }