/**
   * Reads a standard PNM file.
   *
   * <p>Creates a <code>ParameterBlockJAI</code> from all supplied arguments except <code>hints
   * </code> and invokes {@link JAI#create(String,ParameterBlock,RenderingHints)}.
   *
   * @see JAI
   * @see ParameterBlockJAI
   * @see RenderedOp
   * @param stream A SeekableStream representing the PNM file.
   * @param hints The <code>RenderingHints</code> to use. May be <code>null</code>.
   * @return The <code>RenderedOp</code> destination.
   * @throws IllegalArgumentException if <code>stream</code> is <code>null</code>.
   */
  public static RenderedOp create(SeekableStream stream, RenderingHints hints) {
    ParameterBlockJAI pb = new ParameterBlockJAI("PNM", RenderedRegistryMode.MODE_NAME);

    pb.setParameter("stream", stream);

    return JAI.create("PNM", pb, hints);
  }
  /**
   * Reflects an image in a specified direction or rotates an image in multiples of 90 degrees.
   *
   * <p>Creates a <code>ParameterBlockJAI</code> from all supplied arguments except <code>hints
   * </code> and invokes {@link JAI#create(String,ParameterBlock,RenderingHints)}.
   *
   * @see JAI
   * @see ParameterBlockJAI
   * @see RenderedOp
   * @param source0 <code>RenderedImage</code> source 0.
   * @param type The The type of flip operation to be performed.
   * @param hints The <code>RenderingHints</code> to use. May be <code>null</code>.
   * @return The <code>RenderedOp</code> destination.
   * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
   * @throws IllegalArgumentException if <code>type</code> is <code>null</code>.
   */
  public static RenderedOp create(RenderedImage source0, TransposeType type, RenderingHints hints) {
    ParameterBlockJAI pb = new ParameterBlockJAI("Transpose", RenderedRegistryMode.MODE_NAME);

    pb.setSource("source0", source0);

    pb.setParameter("type", type);

    return JAI.create("Transpose", pb, hints);
  }
  /**
   * Applies a piecewise pixel value mapping.
   *
   * <p>Creates a <code>ParameterBlockJAI</code> from all supplied arguments except <code>hints
   * </code> and invokes {@link JAI#createRenderable(String,ParameterBlock,RenderingHints)}.
   *
   * @see JAI
   * @see ParameterBlockJAI
   * @see RenderableOp
   * @param source0 <code>RenderableImage</code> source 0.
   * @param breakPoints The breakpoint array. May be <code>null</code>.
   * @param hints The <code>RenderingHints</code> to use. May be <code>null</code>.
   * @return The <code>RenderableOp</code> destination.
   * @throws IllegalArgumentException if <code>source0</code> is <code>null</code>.
   */
  public static RenderableOp createRenderable(
      RenderableImage source0, float[][][] breakPoints, RenderingHints hints) {
    ParameterBlockJAI pb = new ParameterBlockJAI("Piecewise", RenderableRegistryMode.MODE_NAME);

    pb.setSource("source0", source0);

    pb.setParameter("breakPoints", breakPoints);

    return JAI.createRenderable("Piecewise", pb, hints);
  }
 private static BufferedImage getGaussianBlur(int size, BufferedImage image) {
   KernelJAI kernel = Functions.getGaussKernel(size / 3.0);
   ParameterBlock pb = new ParameterBlock();
   pb.addSource(image);
   pb.add(kernel);
   RenderingHints hints =
       new RenderingHints(
           JAI.KEY_BORDER_EXTENDER, BorderExtender.createInstance(BorderExtender.BORDER_COPY));
   hints.add(JAIContext.noCacheHint);
   return JAI.create("LCSeparableConvolve", pb, hints).getAsBufferedImage();
 }
  private BufferedImage cropScaleGrayscale(Rectangle visibleRect, RenderedImage image) {
    int minX = image.getMinX();
    int minY = image.getMinY();
    int width = image.getWidth();
    int height = image.getHeight();

    Rectangle bounds = new Rectangle(minX, minY, width, height);

    visibleRect = bounds.intersection(visibleRect);

    if (bounds.contains(visibleRect)) {
      ParameterBlock pb = new ParameterBlock();
      pb.addSource(image);
      pb.add((float) visibleRect.x);
      pb.add((float) visibleRect.y);
      pb.add((float) visibleRect.width);
      pb.add((float) visibleRect.height);
      image = JAI.create("Crop", pb, JAIContext.noCacheHint);
    }
    Dimension previewSize = getSize();

    if ((visibleRect.width > previewSize.width) || (visibleRect.height > previewSize.height)) {
      float scale =
          Math.min(
              previewSize.width / (float) visibleRect.width,
              previewSize.height / (float) visibleRect.height);

      image = ConvolveDescriptor.create(image, Functions.getGaussKernel(.25 / scale), null);
      ParameterBlock pb = new ParameterBlock();
      pb.addSource(image);
      pb.add(scale);
      pb.add(scale);
      image = JAI.create("Scale", pb, JAIContext.noCacheHint);
    }
    image = Functions.toColorSpace(image, JAIContext.systemColorSpace, null);

    if (image.getSampleModel().getDataType() == DataBuffer.TYPE_USHORT) {
      image = Functions.fromUShortToByte(image, null);
    }
    return Functions.toFastBufferedImage(image);
  }
  /**
   * Returns the specified property.
   *
   * @param name Property name.
   * @param opNode Operation node.
   */
  public Object getProperty(String name, Object opNode) {
    validate(name, opNode);

    if (opNode instanceof RenderedOp && name.equalsIgnoreCase("roi")) {
      RenderedOp op = (RenderedOp) opNode;

      ParameterBlock pb = op.getParameterBlock();

      // Retrieve the rendered source image and its ROI.
      PlanarImage src = (PlanarImage) pb.getRenderedSource(0);
      Object property = src.getProperty("ROI");
      if (property == null
          || property.equals(java.awt.Image.UndefinedProperty)
          || !(property instanceof ROI)) {
        return java.awt.Image.UndefinedProperty;
      }

      // Return undefined also if source ROI is empty.
      ROI srcROI = (ROI) property;
      if (srcROI.getBounds().isEmpty()) {
        return java.awt.Image.UndefinedProperty;
      }

      /// This should really create a proper AffineTransform
      /// and transform the ROI with it to avoid forcing
      /// ROI.getAsImage to be called.

      // Retrieve the transpose type and create a nearest neighbor
      // Interpolation object.
      TransposeType transposeType = (TransposeType) pb.getObjectParameter(0);
      Interpolation interp = Interpolation.getInstance(Interpolation.INTERP_NEAREST);

      // Return the transposed ROI.
      return new ROI(JAI.create("transpose", srcROI.getAsImage(), transposeType));
    }

    return java.awt.Image.UndefinedProperty;
  }
    public PlanarImage setFront() {
      if (chroma_domain == 0 && chroma_range == 0 && luma_domain == 0 && luma_range == 0)
        return back;

      PlanarImage front = back;

      ColorScience.LinearTransform transform = new ColorScience.YST();

      double[][] rgb2yst = transform.fromRGB(back.getSampleModel().getDataType());
      double[][] yst2rgb = transform.toRGB(back.getSampleModel().getDataType());

      ParameterBlock pb = new ParameterBlock();
      pb.addSource(back);
      pb.add(rgb2yst);
      RenderedOp ystImage = JAI.create("BandCombine", pb, null);

      RenderingHints mfHints =
          new RenderingHints(
              JAI.KEY_BORDER_EXTENDER, BorderExtender.createInstance(BorderExtender.BORDER_COPY));

      if (chroma_domain != 0 && chroma_range != 0) {
        pb = new ParameterBlock();
        pb.addSource(ystImage);
        pb.add(chroma_domain * scale);
        pb.add(0.02f + 0.001f * chroma_domain);
        // pb.add(0.1f);
        ystImage = JAI.create("BilateralFilter", pb, mfHints);
        ystImage.setProperty(JAIContext.PERSISTENT_CACHE_TAG, Boolean.TRUE);
      }

      if (luma_domain != 0 && luma_range != 0) {
        pb = new ParameterBlock();
        pb.addSource(ystImage);
        pb.add(new int[] {0});
        RenderedOp y = JAI.create("bandselect", pb, null);

        pb = new ParameterBlock();
        pb.addSource(ystImage);
        pb.add(new int[] {1, 2});
        RenderedOp cc = JAI.create("bandselect", pb, JAIContext.noCacheHint);

        pb = new ParameterBlock();
        pb.addSource(y);
        pb.add((2 + luma_domain / 10f) * scale);
        pb.add(0.005f * luma_domain);
        y = JAI.create("BilateralFilter", pb, mfHints);

        RenderingHints layoutHints =
            new RenderingHints(JAI.KEY_IMAGE_LAYOUT, Functions.getImageLayout(ystImage));
        pb = new ParameterBlock();
        pb.addSource(y);
        pb.addSource(cc);
        layoutHints.add(JAIContext.noCacheHint);
        ystImage = JAI.create("BandMerge", pb, layoutHints);
      }

      pb = new ParameterBlock();
      pb.addSource(ystImage);
      pb.add(yst2rgb);
      front = JAI.create("BandCombine", pb, null);
      front.setProperty(JAIContext.PERSISTENT_CACHE_TAG, Boolean.TRUE);

      return front;
    }