/**
   * Reads image meta data.
   *
   * @param oimage
   * @return
   */
  public static Map<String, String> readImageData(IIOImage oimage) {
    Map<String, String> dict = new HashMap<String, String>();

    IIOMetadata imageMetadata = oimage.getMetadata();
    if (imageMetadata != null) {
      IIOMetadataNode dimNode = (IIOMetadataNode) imageMetadata.getAsTree("javax_imageio_1.0");
      NodeList nodes = dimNode.getElementsByTagName("HorizontalPixelSize");
      int dpiX;
      if (nodes.getLength() > 0) {
        float dpcWidth = Float.parseFloat(nodes.item(0).getAttributes().item(0).getNodeValue());
        dpiX = (int) Math.round(25.4f / dpcWidth);
      } else {
        dpiX = Toolkit.getDefaultToolkit().getScreenResolution();
      }
      dict.put("dpiX", String.valueOf(dpiX));

      nodes = dimNode.getElementsByTagName("VerticalPixelSize");
      int dpiY;
      if (nodes.getLength() > 0) {
        float dpcHeight = Float.parseFloat(nodes.item(0).getAttributes().item(0).getNodeValue());
        dpiY = (int) Math.round(25.4f / dpcHeight);
      } else {
        dpiY = Toolkit.getDefaultToolkit().getScreenResolution();
      }
      dict.put("dpiY", String.valueOf(dpiY));
    }

    return dict;
  }
  /**
   * Gets pixel data of an <code>IIOImage</code> object.
   *
   * @param image an <code>IIOImage</code> object
   * @return a byte buffer of pixel data
   * @throws Exception
   */
  public static ByteBuffer getImageByteBuffer(IIOImage image) throws IOException {
    // Set up the writeParam
    TIFFImageWriteParam tiffWriteParam = new TIFFImageWriteParam(Locale.US);
    tiffWriteParam.setCompressionMode(ImageWriteParam.MODE_DISABLED);

    // Get tif writer and set output to file
    Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(TIFF_FORMAT);
    ImageWriter writer = writers.next();

    if (writer == null) {
      throw new RuntimeException(
          "Need to install JAI Image I/O package.\nhttps://jai-imageio.dev.java.net");
    }

    // Get the stream metadata
    IIOMetadata streamMetadata = writer.getDefaultStreamMetadata(tiffWriteParam);

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    ImageOutputStream ios = ImageIO.createImageOutputStream(outputStream);
    writer.setOutput(ios);
    writer.write(
        streamMetadata, new IIOImage(image.getRenderedImage(), null, null), tiffWriteParam);
    //        writer.write(image.getRenderedImage());
    writer.dispose();
    //        ImageIO.write(image.getRenderedImage(), "tiff", ios); // this can be used in lieu of
    // writer
    ios.seek(0);
    BufferedImage bi = ImageIO.read(ios);
    return convertImageData(bi);
  }
  public static List<File> createTiffFiles(List<IIOImage> imageList, int index, int dpiX, int dpiY)
      throws IOException {
    List<File> tiffFiles = new ArrayList<File>();

    // Set up the writeParam
    TIFFImageWriteParam tiffWriteParam = new TIFFImageWriteParam(Locale.US);
    tiffWriteParam.setCompressionMode(ImageWriteParam.MODE_DISABLED);

    // Get tif writer and set output to file
    Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(TIFF_FORMAT);
    ImageWriter writer = writers.next();

    if (writer == null) {
      throw new RuntimeException(
          "Need to install JAI Image I/O package.\nhttps://jai-imageio.dev.java.net");
    }

    // Get the stream metadata
    IIOMetadata streamMetadata = writer.getDefaultStreamMetadata(tiffWriteParam);

    // all if index == -1; otherwise, only index-th
    for (IIOImage oimage : (index == -1 ? imageList : imageList.subList(index, index + 1))) {
      if (dpiX != 0 && dpiY != 0) {
        // Get the default image metadata.
        ImageTypeSpecifier imageType =
            ImageTypeSpecifier.createFromRenderedImage(oimage.getRenderedImage());
        IIOMetadata imageMetadata = writer.getDefaultImageMetadata(imageType, null);
        imageMetadata = setDPIViaAPI(imageMetadata, dpiX, dpiY);
        oimage.setMetadata(imageMetadata);
      }

      File tiffFile = File.createTempFile(OUTPUT_FILE_NAME, TIFF_EXT);
      ImageOutputStream ios = ImageIO.createImageOutputStream(tiffFile);
      writer.setOutput(ios);
      writer.write(streamMetadata, oimage, tiffWriteParam);
      ios.close();
      tiffFiles.add(tiffFile);
    }
    writer.dispose();

    return tiffFiles;
  }
  public void writeToSequence(IIOImage img, ImageWriteParam param) throws IOException {
    ImageOutputStream out = (ImageOutputStream) getOutput();
    if (!(img.getRenderedImage() instanceof BufferedImage)) {
      throw new IOException(
          getClass().getName() + "writeToSequence:\n\tCan only write BufferedImage objects");
    }
    BufferedImage image = (BufferedImage) img.getRenderedImage();
    /*
        // Attempt to convert metadata, if present
        IIOMetadata  imd      = img.getMetadata();
        TIFFMetadata metadata = null;
        if(imd!=null){
          ImageTypeSpecifier type=ImageTypeSpecifier.createFromRenderedImage(image);
          metadata=(TIFFMetadata)convertImageMetadata(imd,type,null);
        }
        // Output metadata if present
        if(metadata != null){
          Iterator keywordIter = metadata.keywords.iterator();
          Iterator valueIter   = metadata.values.iterator();
          while(keywordIter.hasNext()){
            String keyword = (String)keywordIter.next();
            String value   = (String)valueIter.next();
            System.out.println("9\bKEYWORD: "+keyword);
            System.out.println("9\bVALUE: "+value);
          }
        }
    */
    IFD ifd;
    int pmi = RGB, comp = compNone, tiffComp = NOCOMPRESSION;

    TIFFImageWriteParam p = null;
    if ((param != null) && (param instanceof TIFFImageWriteParam)) {
      p = (TIFFImageWriteParam) param;
      pmi = p.getPhotometricInterpretation();
      if (p.getCompressionType().equals("none")) {
        comp = compNone;
        tiffComp = NOCOMPRESSION;
      } else if (p.getCompressionType().equals("mh")) {
        comp = compBaselineMH;
        tiffComp = CCITTGROUP3MODHUFFMAN;
      } else if (p.getCompressionType().equals("t4mh")) {
        comp = compT4MH;
        tiffComp = CCITTFAXT4;
      } else if (p.getCompressionType().equals("t4mr")) {
        comp = compT4MR;
        tiffComp = CCITTFAXT4;
      } else if (p.getCompressionType().equals("t6mmr")) {
        comp = compT6MMR;
        tiffComp = CCITTFAXT6;
      } else if (p.getCompressionType().equals("packbits")) {
        comp = compPackBits;
        tiffComp = PACKBITS;
      } else if (p.getCompressionType().equals("lzw")) {
        comp = compLZW;
        tiffComp = LZW;
      } else if (p.getCompressionType().equals("jpeg")) {
        comp = compJPEG;
        tiffComp = JPEG;
      }
      //      System.out.println("comp = "+p.getCompressionType()+" "+comp);
    }
    switch (pmi) {
      case WhiteIsZero:
        switch (comp) {
          case compBaselineMH:
            ifd = writeBModHufImage(out, image, p);
            break;
          case compT4MH:
          case compT4MR:
          case compT6MMR:
            ifd = TIFFClassFFactory.writeImage(out, image, comp, p);
            break;
          default:
            ifd = writeRGBImage(out, image, NOCOMPRESSION, p);
            break; // write image data as uncompressed rgb data.
        }
        break;
      case BlackIsZero:
        switch (comp) {
          default:
            ifd = writeGrayImage(out, image, tiffComp, p);
            break;
        }
        break;
      case RGB: // write image data as uncompressed rgb data.
        switch (comp) {
          default:
            ifd = writeRGBImage(out, image, tiffComp, p);
            break;
        }
        break;
      case CMYK:
        switch (comp) {
          default:
            ifd = writeCMYKImage(out, image, p);
            break;
        }
        break;
      case YCbCr:
        switch (comp) {
          default:
            ifd = writeYCbCrImage(out, image, tiffComp, p);
            break;
        }
        break;
      default:
        ifd = writeRGBImage(out, image, NOCOMPRESSION, p);
        break; // write image data as uncompressed rgb data.
    }
    ifdptr = ifd.write(out, ifdptr); // write ifd contents, entries and set ifd linked list pointer
  }