void decodeIdat() {
    int nbitDepth = bitDepth;
    if (nbitDepth == 16) nbitDepth = 8;
    int size = -1;
    bytesPerPixel = (bitDepth == 16) ? 2 : 1;
    switch (colorType) {
      case 0:
        size = (nbitDepth * width + 7) / 8 * height;
        break;
      case 2:
        size = width * 3 * height;
        bytesPerPixel *= 3;
        break;
      case 3:
        if (interlaceMethod == 1) size = (nbitDepth * width + 7) / 8 * height;
        bytesPerPixel = 1;
        break;
      case 4:
        size = width * height;
        bytesPerPixel *= 2;
        break;
      case 6:
        size = width * 3 * height;
        bytesPerPixel *= 4;
        break;
    }
    if (size >= 0) image = new byte[size];
    if (palShades) smask = new byte[width * height];
    else if (genBWMask) smask = new byte[(width + 7) / 8 * height];
    ByteArrayInputStream bai = new ByteArrayInputStream(idat.getBuf(), 0, idat.size());
    InputStream infStream = new InflaterInputStream(bai, new Inflater());
    dataStream = new DataInputStream(infStream);

    if (interlaceMethod != 1) {
      decodePass(0, 0, 1, 1, width, height);
    } else {
      decodePass(0, 0, 8, 8, (width + 7) / 8, (height + 7) / 8);
      decodePass(4, 0, 8, 8, (width + 3) / 8, (height + 7) / 8);
      decodePass(0, 4, 4, 8, (width + 3) / 4, (height + 3) / 8);
      decodePass(2, 0, 4, 4, (width + 1) / 4, (height + 3) / 4);
      decodePass(0, 2, 2, 4, (width + 1) / 2, (height + 1) / 4);
      decodePass(1, 0, 2, 2, width / 2, (height + 1) / 2);
      decodePass(0, 1, 1, 2, width, height / 2);
    }
  }
 Image getImage() throws IOException {
   readPng();
   try {
     int pal0 = 0;
     int palIdx = 0;
     palShades = false;
     if (trans != null) {
       for (int k = 0; k < trans.length; ++k) {
         int n = trans[k] & 0xff;
         if (n == 0) {
           ++pal0;
           palIdx = k;
         }
         if (n != 0 && n != 255) {
           palShades = true;
           break;
         }
       }
     }
     if ((colorType & 4) != 0) palShades = true;
     genBWMask = (!palShades && (pal0 > 1 || transRedGray >= 0));
     if (!palShades && !genBWMask && pal0 == 1) {
       additional.put(PdfName.MASK, new PdfLiteral("[" + palIdx + " " + palIdx + "]"));
     }
     boolean needDecode =
         (interlaceMethod == 1)
             || (bitDepth == 16)
             || ((colorType & 4) != 0)
             || palShades
             || genBWMask;
     switch (colorType) {
       case 0:
         inputBands = 1;
         break;
       case 2:
         inputBands = 3;
         break;
       case 3:
         inputBands = 1;
         break;
       case 4:
         inputBands = 2;
         break;
       case 6:
         inputBands = 4;
         break;
     }
     if (needDecode) decodeIdat();
     int components = inputBands;
     if ((colorType & 4) != 0) --components;
     int bpc = bitDepth;
     if (bpc == 16) bpc = 8;
     Image img;
     if (image != null) img = Image.getInstance(width, height, components, bpc, image);
     else {
       img = new ImgRaw(width, height, components, bpc, idat.toByteArray());
       img.setDeflated(true);
       PdfDictionary decodeparms = new PdfDictionary();
       decodeparms.put(PdfName.BITSPERCOMPONENT, new PdfNumber(bitDepth));
       decodeparms.put(PdfName.PREDICTOR, new PdfNumber(15));
       decodeparms.put(PdfName.COLUMNS, new PdfNumber(width));
       decodeparms.put(
           PdfName.COLORS, new PdfNumber((colorType == 3 || (colorType & 2) == 0) ? 1 : 3));
       additional.put(PdfName.DECODEPARMS, decodeparms);
     }
     if (additional.get(PdfName.COLORSPACE) == null)
       additional.put(PdfName.COLORSPACE, getColorspace());
     if (intent != null) additional.put(PdfName.INTENT, intent);
     if (additional.size() > 0) img.setAdditional(additional);
     if (icc_profile != null) img.tagICC(icc_profile);
     if (palShades) {
       Image im2 = Image.getInstance(width, height, 1, 8, smask);
       im2.makeMask();
       img.setImageMask(im2);
     }
     if (genBWMask) {
       Image im2 = Image.getInstance(width, height, 1, 1, smask);
       im2.makeMask();
       img.setImageMask(im2);
     }
     img.setDpi(dpiX, dpiY);
     img.setXYRatio(XYRatio);
     img.setOriginalType(Image.ORIGINAL_PNG);
     return img;
   } catch (Exception e) {
     throw new ExceptionConverter(e);
   }
 }
  void readPng() throws IOException {
    for (int i = 0; i < PNGID.length; i++) {
      if (PNGID[i] != is.read()) {
        throw new IOException("File is not a valid PNG.");
      }
    }
    byte buffer[] = new byte[TRANSFERSIZE];
    while (true) {
      int len = getInt(is);
      String marker = getString(is);
      if (len < 0 || !checkMarker(marker)) throw new IOException("Corrupted PNG file.");
      if (IDAT.equals(marker)) {
        int size;
        while (len != 0) {
          size = is.read(buffer, 0, Math.min(len, TRANSFERSIZE));
          if (size < 0) return;
          idat.write(buffer, 0, size);
          len -= size;
        }
      } else if (tRNS.equals(marker)) {
        switch (colorType) {
          case 0:
            if (len >= 2) {
              len -= 2;
              int gray = getWord(is);
              if (bitDepth == 16) transRedGray = gray;
              else additional.put(PdfName.MASK, new PdfLiteral("[" + gray + " " + gray + "]"));
            }
            break;
          case 2:
            if (len >= 6) {
              len -= 6;
              int red = getWord(is);
              int green = getWord(is);
              int blue = getWord(is);
              if (bitDepth == 16) {
                transRedGray = red;
                transGreen = green;
                transBlue = blue;
              } else
                additional.put(
                    PdfName.MASK,
                    new PdfLiteral(
                        "[" + red + " " + red + " " + green + " " + green + " " + blue + " " + blue
                            + "]"));
            }
            break;
          case 3:
            if (len > 0) {
              trans = new byte[len];
              for (int k = 0; k < len; ++k) trans[k] = (byte) is.read();
              len = 0;
            }
            break;
        }
        Utilities.skip(is, len);
      } else if (IHDR.equals(marker)) {
        width = getInt(is);
        height = getInt(is);

        bitDepth = is.read();
        colorType = is.read();
        compressionMethod = is.read();
        filterMethod = is.read();
        interlaceMethod = is.read();
      } else if (PLTE.equals(marker)) {
        if (colorType == 3) {
          PdfArray colorspace = new PdfArray();
          colorspace.add(PdfName.INDEXED);
          colorspace.add(getColorspace());
          colorspace.add(new PdfNumber(len / 3 - 1));
          ByteBuffer colortable = new ByteBuffer();
          while ((len--) > 0) {
            colortable.append_i(is.read());
          }
          colorspace.add(new PdfString(colorTable = colortable.toByteArray()));
          additional.put(PdfName.COLORSPACE, colorspace);
        } else {
          Utilities.skip(is, len);
        }
      } else if (pHYs.equals(marker)) {
        int dx = getInt(is);
        int dy = getInt(is);
        int unit = is.read();
        if (unit == 1) {
          dpiX = (int) ((float) dx * 0.0254f + 0.5f);
          dpiY = (int) ((float) dy * 0.0254f + 0.5f);
        } else {
          if (dy != 0) XYRatio = (float) dx / (float) dy;
        }
      } else if (cHRM.equals(marker)) {
        xW = (float) getInt(is) / 100000f;
        yW = (float) getInt(is) / 100000f;
        xR = (float) getInt(is) / 100000f;
        yR = (float) getInt(is) / 100000f;
        xG = (float) getInt(is) / 100000f;
        yG = (float) getInt(is) / 100000f;
        xB = (float) getInt(is) / 100000f;
        yB = (float) getInt(is) / 100000f;
        hasCHRM =
            !(Math.abs(xW) < 0.0001f
                || Math.abs(yW) < 0.0001f
                || Math.abs(xR) < 0.0001f
                || Math.abs(yR) < 0.0001f
                || Math.abs(xG) < 0.0001f
                || Math.abs(yG) < 0.0001f
                || Math.abs(xB) < 0.0001f
                || Math.abs(yB) < 0.0001f);
      } else if (sRGB.equals(marker)) {
        int ri = is.read();
        intent = intents[ri];
        gamma = 2.2f;
        xW = 0.3127f;
        yW = 0.329f;
        xR = 0.64f;
        yR = 0.33f;
        xG = 0.3f;
        yG = 0.6f;
        xB = 0.15f;
        yB = 0.06f;
        hasCHRM = true;
      } else if (gAMA.equals(marker)) {
        int gm = getInt(is);
        if (gm != 0) {
          gamma = 100000f / (float) gm;
          if (!hasCHRM) {
            xW = 0.3127f;
            yW = 0.329f;
            xR = 0.64f;
            yR = 0.33f;
            xG = 0.3f;
            yG = 0.6f;
            xB = 0.15f;
            yB = 0.06f;
            hasCHRM = true;
          }
        }
      } else if (iCCP.equals(marker)) {
        do {
          --len;
        } while (is.read() != 0);
        is.read();
        --len;
        byte icccom[] = new byte[len];
        int p = 0;
        while (len > 0) {
          int r = is.read(icccom, p, len);
          if (r < 0) throw new IOException("Premature end of file.");
          p += r;
          len -= r;
        }
        byte iccp[] = PdfReader.FlateDecode(icccom, true);
        icccom = null;
        //                try {
        //                    icc_profile = ICC_Profile.getInstance(iccp);
        //                }
        // catch (Exception e) {
        icc_profile = null;
        // }
      } else if (IEND.equals(marker)) {
        break;
      } else {
        Utilities.skip(is, len);
      }
      Utilities.skip(is, 4);
    }
  }