/**  RunOperators Class
   * @version 1.0  18 apr 2000
   * @author Lawrence Rodrigues
   **/
package app;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.geom.*;
import com.vistech.util.*;
import com.vistech.listselect.*;
import com.vistech.jai.imageio.*;
import com.vistech.jai.render.*;

import java.awt.image.RenderedImage;
import java.beans.*;
import javax.media.jai.*;
import com.sun.media.jai.codec.*;
import javax.media.jai.operator.*;

import java.awt.image.renderable.*;
import com.vistech.imageviewer.*;
import com.vistech.jai.util.*;

/** An application that allows users to apply a variety of JAI operators.
  * @version 1.0 18 Apr 2000
  * @author Lawrence Rodrigues
  **/
public class RunOperators extends TiledImageViewer{
   public static final int UNARY_FORMAT = 1;
   public static final int DYADIC_FORMAT = 2;

   protected PanZoom panzoom1, panzoom2, panzoom3;
   protected JButton resetb;
   protected ManipUI manippan;
   GeomManip manip;
   FileSelector  flSelector;
   RenderedImageCanvas sourceCanvas1, sourceCanvas2, destCanvas;
   protected int loadCount =0;
   protected PlanarImage sourceImage1, sourceImage2;
   protected int screenFormat = DYADIC_FORMAT;
   protected JSplitPane vsp, hsp, vp;
   protected JTabbedPane opTab;

   public void createUI() {
      int width, height;
      Dimension sd= Toolkit.getDefaultToolkit().getScreenSize();
      width = (int)(sd.width *3/4.0);
      height = (int)(sd.height* 6/7.0);

      setTitle("JAI Operators");
      viewer = new ImageManipulatorCanvas();
      
      sourceCanvas1 = new ImageManipulatorCanvas();
      sourceCanvas2 = new ImageManipulatorCanvas();
      destCanvas = new ImageManipulatorCanvas();

      JSplitPane vp = createDyadicPanel();
      Dimension d = new Dimension(width, height);//getViewerSize(width/(double)height);
      viewer.setPreferredSize(new Dimension(d.width, d.height));
      createImageLoaderAndSaver();
      loader.addPlanarImageLoadedListener(
          new PlanarImageLoadedListener() {
             public void imageLoaded(PlanarImageLoadedEvent e) {
                PlanarImage image = e.getImage();
                if(image == null) return;
                if(screenFormat == UNARY_FORMAT) {
                   SwingUtilities.invokeLater(new ImagePaint(image, sourceCanvas1));
                   sourceImage1 = image;
                   ((TabPanel)opTab.getSelectedComponent()).openPanel();
                   return;
                }
                if((loadCount %2) == 0){
                    SwingUtilities.invokeLater(new ImagePaint(image, sourceCanvas1));
                    sourceImage1 = image;
                }
                else {
                    SwingUtilities.invokeLater(new ImagePaint(image, sourceCanvas2));
                    sourceImage2 = image;
                }
                ((TabPanel)opTab.getSelectedComponent()).openPanel();
                loadCount++;
             }
         }
      );

      twidth = new JTextField(10);
      theight = new JTextField(10);

      renderGrid = new RenderGrid();
      theight.setText(Integer.toString(viewer.getTileHeight()));
      twidth.setText(Integer.toString(viewer.getTileWidth()));

      manip =  new GeomManip((ImageManipulator)viewer);
      manippan = new ManipUI(manip);
      JPanel gridpan = new JPanel();
      JPanel tilesetpan = createTileSetPanel();
      ArithOpPanel arithpan = new ArithOpPanel();
      LogicOpPanel logicpan = new LogicOpPanel();
      RelOpPanel relpan = new RelOpPanel();
      OverlayOpPanel overlaypan = new OverlayOpPanel();

      MathOpPanel mathpan = new MathOpPanel();
      FilterOpPanel filterpan = new FilterOpPanel();
      FrequencyOpPanel freqpan = new FrequencyOpPanel();
      InterpModePanel intermodepan = new InterpModePanel((ImageManipulator)viewer);

      JTabbedPane jtab1 = new JTabbedPane();
      jtab1.add("Tile Dimension",tilesetpan);
     
      opTab = new JTabbedPane();
      opTab.add("Arithmetic", arithpan);
      opTab.add("Logical", logicpan);
      opTab.add("Relational", relpan);
      opTab.add("Overlay", overlaypan);
      opTab.add("Filter", filterpan);
      opTab.add("Frequency", freqpan);
      opTab.addChangeListener(
         new ChangeListener() {
               public void stateChanged(ChangeEvent e) {
                  Component cmp = ((JTabbedPane)e.getSource()).getSelectedComponent();
                  if(cmp == null) { return;}
                  if(cmp instanceof TabPanel) {
                     TabPanel tp = (TabPanel)cmp;
                     tp.openPanel();
                  }
               }
         }
      );
      
      jtab1.setBorder(BorderFactory.createTitledBorder("Parameters"));
      opTab.setBorder(BorderFactory.createTitledBorder("Operators"));
      JSplitPane bsp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, jtab1,opTab);
      GridBagLayout gb = new GridBagLayout() ;
      GridBagConstraints c = new GridBagConstraints();
      gridpan.setLayout(gb);
      c.fill = GridBagConstraints.BOTH;
      c.gridwidth = GridBagConstraints.REMAINDER;
      c.weighty = 1.0; c.weightx = 1.0;
      gb.setConstraints(bsp, c);
      gridpan.add(bsp);
      resetb = new JButton("Reset");
      resetEventHandler();
      c.weighty = 0.1; c.weightx = 1.0;
      saver = new ImageSaverPanel();
      JTabbedPane jtp = new JTabbedPane();

      jtp.add("Load", flSelector);
      jtp.add("Save",  saver);
      hsp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, jtp,gridpan);
      vsp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, vp,hsp);
      getContentPane().setLayout(new GridLayout(1,1));
      getContentPane().add(vsp);
      pack();
      setSize(new Dimension(d.width+170, d.height));
      show();
      addEventAdapters();
      panzoom1 = new PanZoom((ImageManipulator)sourceCanvas1);
      panzoom2 = new PanZoom((ImageManipulator)sourceCanvas2);
      panzoom3 = new PanZoom((ImageManipulator)destCanvas);

      vsp.setDividerLocation(0.65);
      hsp.setDividerLocation(0.35);
      vp.setDividerLocation(0.35);
      bsp.setDividerLocation(0.3);
      bsp.setDividerSize(5);
      hsp.setDividerSize(5);
      vsp.setDividerSize(6);
      viewer.repaint();
   }

   protected void createNewLayout(int screenFormat) {
      Dimension size = this.getSize();
      if(this.screenFormat == screenFormat) return;
      this.screenFormat = screenFormat;
      switch (screenFormat){
         case DYADIC_FORMAT:
           vp = createDyadicPanel();
           break;
         case UNARY_FORMAT:
           vp = createUnaryPanel();
           break;
      }
      Dimension vspsize = vsp.getSize();
      vsp.setTopComponent(vp);
      vsp.setSize(vspsize);
      show();
      vsp.setDividerLocation(0.65);
      vp.setDividerLocation((screenFormat == DYADIC_FORMAT) ? 0.35 : 0.5);
      vp.revalidate();
      vsp.revalidate();
      hsp.setDividerSize(5);
      vsp.setDividerSize(6);
      repaint();
   }

   protected JSplitPane createDyadicPanel() {
      JScrollPane jsp1 = new JScrollPane(sourceCanvas1);
      JScrollPane jsp2 = new JScrollPane(sourceCanvas2);
      JScrollPane jsp3 = new JScrollPane(destCanvas);
      jsp3.setBorder(BorderFactory.createTitledBorder("Resulting Image"));
      JPanel src = new JPanel(new GridLayout(2,1));
      src.add(jsp1);
      src.add(jsp2);
      jsp1.setBorder(BorderFactory.createTitledBorder("Source1 "));
      jsp2.setBorder(BorderFactory.createTitledBorder("Source2 "));
      JSplitPane vp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, src,jsp3);
      return vp;
  }

  protected JSplitPane createUnaryPanel() {
      JScrollPane jsp1 = new JScrollPane(sourceCanvas1);
      JScrollPane jsp3 = new JScrollPane(destCanvas);
      jsp3.setBorder(BorderFactory.createTitledBorder("Resulting Image"));
      jsp1.setBorder(BorderFactory.createTitledBorder("Source Image"));
      JSplitPane vp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, jsp1,jsp3);
      return vp;
  }

   protected void resetEventHandler(){
      resetb.addActionListener(
         new ActionListener(){
            public void actionPerformed(ActionEvent e) {
               ((ImageManipulator)viewer).resetManipulation();
               manippan.resetManipulation();
             }
          }
       );
   }

   protected void createImageLoaderAndSaver(){
      loader = new ImageLoaderJAI();//flBrowser.getLoader(
      flSelector = new FileSelector();
      flSelector.addListSelectListener(loader);
      saver = new ImageSaverPanel();
      saver.setBorder(BorderFactory.createTitledBorder("Image Save"));
   }
   
   public static void  main(String[] args){
      RunOperators ip = new RunOperators();
      if(args.length <1) {
         ip.createUI();
      }else ip.loadAndDisplay(args[0]);
  }
   class ImagePaint implements Runnable {
      PlanarImage image;
      boolean firstTime = true;
      RenderedImageCanvas viewer;
      public ImagePaint(PlanarImage image, RenderedImageCanvas viewer){
         this.image = image;
         this.viewer = viewer;
      }
      public void run() {
         if(firstTime) {
            try {
            setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
            viewer.setImage(image);
            saver.setImage(image);
            int wid = (image.getWidth() < 1024) ?image.getWidth(): 1024;
            int ht = (image.getHeight()) < 1024 ? image.getHeight():1024;
            viewer.setPreferredSize(new Dimension(wid,ht));
            viewer.repaint();
            firstTime = false;
            SwingUtilities.invokeLater(this);
            }catch(Exception e) {
             SwingUtilities.invokeLater(this);
            }
         }
         else {
            if(!viewer.isImageDrawn()) SwingUtilities.invokeLater(this);
            else  setCursor(Cursor.getDefaultCursor());
         }
      }
   }

class ArithOpPanel extends JPanel implements TabPanel {
   public static final int ADD = 1;
   public static final int SUBTRACT =2;
   public static final int MULTIPLY = 4;
   public static final int DIVIDE  = 8;
   protected int currentMode = ADD;

   public ArithOpPanel(){ createUI();}
   public void openPanel() {applyOperator(currentMode); }
   public void closePanel(){ }

   protected void createUI() {
      ButtonGroup bg = new ButtonGroup();
      JRadioButton add= new JRadioButton("Add");
      JRadioButton sub= new JRadioButton("Subtract");
      JRadioButton mul = new JRadioButton("Multiply");
      JRadioButton div= new JRadioButton("Divide");

      ArithOpAdapter adda = new ArithOpAdapter(ADD);
      ArithOpAdapter suba= new ArithOpAdapter(SUBTRACT);
      ArithOpAdapter mula = new ArithOpAdapter(MULTIPLY);
      ArithOpAdapter diva = new ArithOpAdapter(DIVIDE);
      add.setSelected(true);

      add.addActionListener(adda);
      sub.addActionListener(suba);
      mul.addActionListener(mula);
      div.addActionListener(diva);

      bg.add(add);
      bg.add(sub);
      bg.add(mul);
      bg.add(div);
      setLayout(new GridLayout(2,2));
      add(add);
      add(sub);
      add(mul);
      add(div);
   }
   protected void applyOperator(int mode) {
      if ((sourceImage1 == null) || (sourceImage2 == null))  return;
      RenderedOp op = null;
      switch(mode) {
            case ADD:
              op = JAIOpUtil.addImages(sourceImage1, sourceImage2);
              break;
            case SUBTRACT:
              op = JAIOpUtil.subtractImages(sourceImage1, sourceImage2);
              break;
            case MULTIPLY:
              op = JAIOpUtil.multiplyImages(sourceImage1, sourceImage2);
              break;
            case DIVIDE:
              op = JAIOpUtil.divideImages(sourceImage1, sourceImage2);
              break;
      }
      if(op == null) return;
      createNewLayout(DYADIC_FORMAT);
      PlanarImage destImage = op.createInstance();
      destCanvas.setImage(destImage);
   }
   class ArithOpAdapter implements ActionListener {
      int mode;
      public ArithOpAdapter( int type) {mode = type;}
      public void actionPerformed(ActionEvent e) {
         if ((sourceImage1 == null) || (sourceImage2 == null))  return;
         RenderedOp op = null;
         switch(mode) {
            case ADD:
              op = JAIOpUtil.addImages(sourceImage1, sourceImage2);

              break;
            case SUBTRACT:
              op = JAIOpUtil.subtractImages(sourceImage1, sourceImage2);
              break;
            case MULTIPLY:
              op = JAIOpUtil.multiplyImages(sourceImage1, sourceImage2);
              break;
            case DIVIDE:
              op = JAIOpUtil.divideImages(sourceImage1, sourceImage2);
              break;
        }
        if(op == null) return;
        createNewLayout(DYADIC_FORMAT);
        PlanarImage destImage = op.createInstance();
        destCanvas.setImage(destImage);
     }
   }
}

class LogicOpPanel extends JPanel implements TabPanel {
   public static final int AND= 1;
   public static final int OR =2;
   public static final int XOR = 4;
   public static final int NOT = 8;
   protected int currentMode = AND;

   public LogicOpPanel(){ createUI();}
   public void openPanel() {applyOperator(currentMode); }
   public void closePanel(){ }

   protected void createUI() {
      ButtonGroup bg = new ButtonGroup();
      JRadioButton add= new JRadioButton("And");
      JRadioButton sub= new JRadioButton("Or");
      JRadioButton mul = new JRadioButton("Xor");
      JRadioButton not = new JRadioButton("Not");

      LogicOpAdapter adda = new LogicOpAdapter(AND);
      LogicOpAdapter suba= new LogicOpAdapter(OR);
      LogicOpAdapter mula = new LogicOpAdapter(XOR);
      LogicOpAdapter nota = new LogicOpAdapter(NOT);
      add.setSelected(true);

      add.addActionListener(adda);
      sub.addActionListener(suba);
      mul.addActionListener(mula);
      not.addActionListener(nota);

      bg.add(add);
      bg.add(sub);
      bg.add(mul);
      bg.add(not);

      setLayout(new GridLayout(2,2));
      add(add);
      add(sub);
      add(mul);
      add(not);
  }
  protected void applyOperator(int mode) {
      if (sourceImage1 == null) return;
      RenderedOp op = null;
      switch(mode) {
            case AND:
              if(sourceImage2 == null)  return;
              op = JAIOpUtil.andImages(sourceImage1, sourceImage2);
              createNewLayout(DYADIC_FORMAT);
              break;
            case OR:
              if(sourceImage2 == null)  return;
              op = JAIOpUtil.orImages(sourceImage1, sourceImage2);
              createNewLayout(DYADIC_FORMAT);
              break;
            case XOR:
              if(sourceImage2 == null)  return;
              op = JAIOpUtil.xorImages(sourceImage1, sourceImage2);
              createNewLayout(DYADIC_FORMAT);
              break;
            case NOT:
              op = JAIOpUtil.notImage(sourceImage1);
              createNewLayout(UNARY_FORMAT);
              break;
      }
      if(op == null) return;
      PlanarImage destImage = op.createInstance();
      destCanvas.setImage(destImage);
  }
  class LogicOpAdapter implements ActionListener {
      int mode;
      public LogicOpAdapter( int type) {mode = type;}
      public void actionPerformed(ActionEvent e) {
         currentMode = mode;
         applyOperator(mode);
      }
  }
}

class RelOpPanel extends JPanel implements TabPanel {
   public static final int MIN = 1;
   public static final int MAX =2;
   protected int currentMode = MIN;

   public RelOpPanel(){ createUI();}
   public void openPanel() {applyOperator(currentMode); }
   public void closePanel(){ }

   protected void createUI() {
      ButtonGroup bg = new ButtonGroup();
      JRadioButton min = new JRadioButton("Min");
      JRadioButton max = new JRadioButton("max");

      RelOpAdapter mina = new RelOpAdapter(MIN);
      RelOpAdapter  maxa= new RelOpAdapter(MAX);
      min.setSelected(true);

      min.addActionListener(mina);
      max.addActionListener(maxa);
      bg.add(min);
      bg.add(max);
      setLayout(new GridLayout(1,2));
      add(min);
      add(max);
   }
   protected void applyOperator(int mode) {
         if ((sourceImage1 == null) || (sourceImage2 == null))  return;
         RenderedOp op = null;
         switch(mode) {
            case MIN:
              op = JAIOpUtil.minImages(sourceImage1, sourceImage2);
              break;
            case MAX:
              op = JAIOpUtil.maxImages(sourceImage1, sourceImage2);
              break;
        }
        if(op == null) return;
        createNewLayout(DYADIC_FORMAT);
        PlanarImage destImage = op.createInstance();
        destCanvas.setImage(destImage);
     }
   class RelOpAdapter implements ActionListener {
      int mode;
      public RelOpAdapter( int type) {mode = type;}
      public void actionPerformed(ActionEvent e) {
         currentMode = mode;
         applyOperator(mode);
      }
   }
 }
class OverlayOpPanel extends JPanel implements TabPanel {
   public static final int OVERLAY = 1;
   public static final int COMPOSITE =2;
   protected ButtonGroup bg;
   protected int currentMode = OVERLAY;

   public OverlayOpPanel(){ createUI();}
   public void openPanel() {
      applyOperator(currentMode);
   }
   public void closePanel(){ }

   protected void createUI() {
      bg = new ButtonGroup();
      JRadioButton overlay = new JRadioButton("Overlay");
      JRadioButton composite = new JRadioButton("Composite");

      OverlayOpAdapter overlaya = new OverlayOpAdapter(OVERLAY);
      OverlayOpAdapter  compositea= new OverlayOpAdapter(COMPOSITE);
      overlay.setSelected(true);

      overlay.addActionListener(overlaya);
      composite.addActionListener(compositea);
      bg.add(overlay);
      bg.add(composite);
      setLayout(new GridLayout(1,2));
      add(overlay);
      add(composite);
   }
   protected void applyOperator(int mode) {
      if ((sourceImage1 == null) || (sourceImage2 == null))  return;
      RenderedOp op = null;
      switch(mode) {
             case OVERLAY:
              op = JAIOpUtil.overlayImages(sourceImage1, sourceImage2);
                break;
              case COMPOSITE:
                op = JAIOpUtil.compositeImages(sourceImage1, sourceImage2,
                             false,
                javax.media.jai.operator.CompositeDescriptor.DESTINATION_ALPHA_FIRST);
              break;
       }
       if(op == null) return;
         createNewLayout(DYADIC_FORMAT);
       PlanarImage destImage = op.createInstance();
       destCanvas.setImage(destImage);
   }
   class OverlayOpAdapter implements ActionListener {
      int mode;
      public OverlayOpAdapter( int type) {mode = type;}
      public void actionPerformed(ActionEvent e) {
         currentMode = mode;
         applyOperator(mode);
     }
   }
}
class FrequencyOpPanel extends JPanel implements TabPanel {
   public static final int DFT = 1;
   public static final int DCT =2;
   public static final int MAG = 4;
   public static final int MAG_SQ = 8;
   public static final int PHASE = 16;
   public static final int DFT_CHAIN = 32;

   protected ButtonGroup bg;
   protected int currentMode = DCT;

   public FrequencyOpPanel(){ createUI();}
   public void openPanel() {
      applyOperator(currentMode);
   }
   public void closePanel(){ }

   protected void createUI() {
      bg = new ButtonGroup();
      JRadioButton dct = new JRadioButton("DCT");
      JRadioButton dft = new JRadioButton("DFT");
      JRadioButton dftchain = new JRadioButton("DFT Chain");

      JRadioButton mag = new JRadioButton("Magnitude");
      JRadioButton magsq = new JRadioButton("Magnitide Squared");
      JRadioButton phase = new JRadioButton("Phase");


      FequencyOpAdapter dfta = new FequencyOpAdapter(DFT);
      FequencyOpAdapter  dcta= new FequencyOpAdapter(DCT);
      FequencyOpAdapter maga = new FequencyOpAdapter(MAG);
      FequencyOpAdapter magsqa= new FequencyOpAdapter(MAG_SQ);
      FequencyOpAdapter  phasea= new FequencyOpAdapter(PHASE);
      FequencyOpAdapter  dftchaina= new FequencyOpAdapter(DFT_CHAIN);

      dct.setSelected(true);

      dft.addActionListener(dfta);
      dct.addActionListener(dcta);
      mag.addActionListener(maga);
      magsq.addActionListener(magsqa);
      phase.addActionListener(phasea);
      dftchain.addActionListener(dftchaina);

      bg.add(dft);
      bg.add(mag);
      bg.add(magsq);
      bg.add(phase);
      bg.add(dct);
      bg.add(dftchain);

      setLayout(new GridLayout(2,3));
      add(dct);
      add(dft);
      add(dftchain);
      add(mag);
      add(magsq);
      add(phase);

   }
   protected void applyOperator(int mode) {
      if (sourceImage1 == null)  return;
      RenderedOp op = null, op1=null;
      switch(mode) {
         case DFT:
             op = JAIOpUtil.DFTImage(sourceImage1,
                                     javax.media.jai.operator.DFTDescriptor.SCALING_NONE,
                                     javax.media.jai.operator.DFTDescriptor.REAL_TO_COMPLEX);
             //op = createDFTChain();
             break;
         case DFT_CHAIN:
             op = createDFTChain();
             break;
         case DCT:
             op = JAIOpUtil.DCTImage(sourceImage1);
             //op = createDCTChain();
             break;
         case MAG:
             op1 = JAIOpUtil.DFTImage(sourceImage1,
                                     javax.media.jai.operator.DFTDescriptor.SCALING_NONE,
                                     javax.media.jai.operator.DFTDescriptor.REAL_TO_COMPLEX);
             op = JAIOpUtil.magnitudeImage(op1);
              break;
         case MAG_SQ:
             op1 = JAIOpUtil.DFTImage(sourceImage1,
                                     javax.media.jai.operator.DFTDescriptor.SCALING_NONE,
                                     javax.media.jai.operator.DFTDescriptor.REAL_TO_COMPLEX);
             op = JAIOpUtil.magnitudeSquaredImage(op1);
             break;
         case PHASE:
             op1 = JAIOpUtil.DFTImage(sourceImage1,
                                     javax.media.jai.operator.DFTDescriptor.SCALING_NONE,
                                     javax.media.jai.operator.DFTDescriptor.REAL_TO_COMPLEX);
             op = JAIOpUtil.phaseImage(op1);
             break;
       }
       if(op == null) return;
       RenderedOp  fop = formatImage(op);
       createNewLayout(UNARY_FORMAT);
       PlanarImage destImage = fop.createInstance();
       destCanvas.setImage(destImage);
   }

    protected RenderedOp createDCTChain(){
      System.out.println("Source Image");
      printImageImfo(sourceImage1);
      RenderedOp dctop= JAIOpUtil.DCTImage(sourceImage1);
      System.out.println("Source Image");
      printImageImfo(dctop);
      //Apply your operator.
      return JAIOpUtil.inverseDCTImage(dctop);
   }
   public String getDataTypeAsText(int dttype){
      switch(dttype) {
         case DataBuffer.TYPE_BYTE:
           return " Byte";
         case DataBuffer.TYPE_SHORT:
           return " Short";
         case DataBuffer.TYPE_USHORT:
           return " Unsigned short";
         case DataBuffer.TYPE_INT:
           return " int";
         case DataBuffer.TYPE_FLOAT:
           return " Float";
         case DataBuffer.TYPE_DOUBLE:
           return " Double";
         case DataBuffer.TYPE_UNDEFINED:
           return " Undefined";
         default:
           return " Unknown";
        }
   }

   public double[][] computeMinMax(PlanarImage image) {
      ParameterBlock pb = new ParameterBlock();
      pb.addSource(image);
      pb.add(null);
      pb.add(1);
      pb.add(1);
      RenderedOp op = JAI.create("extrema", pb);
      double[][] minmax = (double[][]) op.getProperty("extrema");
      //System.out.println("first = " + minmax.length+ " second = "+minmax[0].length);

      return minmax;
   }

    public  void printImageImfo(PlanarImage img) {
       int width = img.getWidth();
       int height = img.getHeight();
       int numbands = img.getSampleModel().getNumBands();
       int datatype = img.getSampleModel().getDataType();
       String datatypestr = getDataTypeAsText(datatype);
       System.out.println("width = " +width + " height = " + height);
       System.out.println("num band = " + numbands + " data type = " + datatypestr);
       double[][] minmax = computeMinMax(img);
       for(int i=0;i<numbands;i++) {
           System.out.println("min = " + minmax[0][i]+ " max = "+minmax[1][i]);
       }
   }

   public RenderedOp formatImage(RenderedOp img) {
      ImageLayout il = new ImageLayout(img);
      il.setColorModel(sourceImage1.getColorModel());
      il.setSampleModel(sourceImage1.getSampleModel());
      RenderingHints tileHints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, il);
      ParameterBlock pb = new ParameterBlock();
      pb.addSource(img);
      RenderedOp fop = JAI.create("format", pb, tileHints);
      System.out.println("format image");
      printImageImfo(fop);
      return fop;
  }

   protected RenderedOp createDFTChain(){
      System.out.println("Source Image");
      printImageImfo(sourceImage1);
      RenderedOp dftop= JAIOpUtil.DFTImage(sourceImage1,
                                     javax.media.jai.operator.DFTDescriptor.SCALING_NONE,
                                     javax.media.jai.operator.DFTDescriptor.REAL_TO_COMPLEX);
      System.out.println("DFT Image");
      printImageImfo(dftop);

      RenderedOp magop = JAIOpUtil.magnitudeImage(dftop);
      System.out.println("Mag image");
      printImageImfo(magop);

      RenderedOp phaseop = JAIOpUtil.magnitudeImage(dftop);
      System.out.println("Phase image");
      printImageImfo(phaseop);

      // Apply your operator

      RenderedOp complexop = JAIOpUtil.polarToComplexImage(magop, phaseop);
      System.out.println("Complex image");
      printImageImfo(complexop);

      return  JAIOpUtil.inverseDFTImage(complexop,
                                     javax.media.jai.operator.DFTDescriptor.SCALING_NONE,
                                     javax.media.jai.operator.DFTDescriptor.COMPLEX_TO_REAL);



   }

   class FequencyOpAdapter implements ActionListener {
      int mode;
      public FequencyOpAdapter( int type) {mode = type;}
      public void actionPerformed(ActionEvent e) {
         currentMode = mode;
         applyOperator(mode);
     }
   }
}

class MathOpPanel extends JPanel implements TabPanel {
   public static final int LOG = 1;
   public static final int EXP =2;

   protected int currentMode = LOG;

   public MathOpPanel(){ createUI();}
   public void openPanel() {applyOperator(currentMode); }
   public void closePanel(){ }

   protected void createUI() {
      ButtonGroup bg = new ButtonGroup();
      JRadioButton log= new JRadioButton("Log");
      JRadioButton exp = new JRadioButton("Exp");
      log.setSelected(true);

      MathOpAdapter loga = new MathOpAdapter(LOG);
      MathOpAdapter expa= new MathOpAdapter(EXP);

      log.addActionListener(loga);
      exp.addActionListener(expa);

      bg.add(log);
      bg.add(exp);

      setLayout(new GridLayout(1,2));
      add(log);
      add(exp);
  }
  protected void applyOperator(int mode) {
      if (sourceImage1 == null) return;
      RenderedOp op = null;
      switch(mode) {
          case LOG:
            op = JAIOpUtil.logImage(sourceImage1);
            createNewLayout(UNARY_FORMAT);
            break;
          case EXP:
            op = JAIOpUtil.expImage(sourceImage1);
            createNewLayout(UNARY_FORMAT);
            break;
      }
      if(op == null) return;
      PlanarImage destImage = op.createInstance();
      destCanvas.setImage(destImage);
  }

  class MathOpAdapter implements ActionListener {
      int mode;
      public MathOpAdapter( int type) {mode = type;}
      public void actionPerformed(ActionEvent e) {
         currentMode = mode;
         applyOperator(mode);
     }
   }

}

class FilterOpPanel extends JPanel implements TabPanel {
   public static final int BOX = 1;
   public static final int MEDIAN =2;
   public static final int MASK = 3;
   public static final int SIZE =4;

   protected int currentMode = MEDIAN;
   private String[] sizelabel = { "3x3", "5x5", "7x7", "9x9"};
   private int[] sizes = {3,5,7,9};
   private String[] masktypes = {"Square", "Separable square","Plus", "X"};
   private MedianFilterShape[] masks = { //JAI 1.1 change
        MedianFilterDescriptor.MEDIAN_MASK_SQUARE,
        MedianFilterDescriptor.MEDIAN_MASK_SQUARE_SEPARABLE,
        MedianFilterDescriptor.MEDIAN_MASK_PLUS,
        MedianFilterDescriptor.MEDIAN_MASK_X
    };

   private int currentSize = sizes[0];
   private MedianFilterShape currentMask = masks[0];//JAI 1.1 change
   private JComboBox sizebox, maskbox;
   private JPanel cbox;

   public FilterOpPanel(){ createUI();}
   public void openPanel() {applyOperator(currentMode); }
   public void closePanel(){ }

   protected void createUI() {
      ButtonGroup bg = new ButtonGroup();
      JRadioButton box = new JRadioButton("Box");
      JRadioButton median = new JRadioButton("Median");
      median.setSelected(true);

      FilterOpAdapter boxa = new FilterOpAdapter(BOX);
      FilterOpAdapter mediana= new FilterOpAdapter(MEDIAN);

      box.addActionListener(boxa);
      median.addActionListener(mediana);

      bg.add(box); bg.add(median);

      sizebox = new JComboBox();
      for (int i = 0; i < sizelabel.length; i++) sizebox.addItem(sizelabel[i]);
      ItemAdapter sizea = new ItemAdapter(SIZE);

      sizebox.addItemListener(sizea);
      maskbox = new JComboBox();
      for (int i = 0; i < masktypes.length; i++) maskbox.addItem(masktypes[i]);
      ItemAdapter maska = new ItemAdapter(MASK);
      maskbox.addItemListener(maska);
      cbox = new JPanel(new GridLayout(2,2));
      cbox.add(new JLabel("Mask Size"));
      cbox.add(sizebox);
      cbox.add(new JLabel("Mask Type"));
      cbox.add(maskbox);
      cbox.setBorder(BorderFactory.createTitledBorder("Filter params"));
      JPanel medpan = new JPanel();
      medpan.add(median);
      medpan.add(box);

      setLayout(new GridLayout(2,1));
      add(medpan);
      add(cbox);
  }
  protected void applyOperator(int mode) {
      if (sourceImage1 == null) return;
      RenderedOp op = null;
      createNewLayout(UNARY_FORMAT);
      switch(mode) {
          case BOX:
            maskbox.setEnabled(false);
            op = JAIOpUtil.boxFilterImage(sourceImage1,
                                          currentSize,
                                          currentSize,
                                          new Point(currentSize/2,currentSize/2));
            break;
          case MEDIAN:
            maskbox.setEnabled(true);
            op = JAIOpUtil.medianFilterImage(sourceImage1, currentMask,
                                             currentSize);
            break;
      }
      if(op == null) return;
      PlanarImage destImage = op.createInstance();
      destCanvas.setImage(destImage);
  }
 
  class ItemAdapter implements ItemListener {
    int mode;
      public ItemAdapter( int type) {mode = type;}
      public void itemStateChanged(ItemEvent e) {
         JComboBox jc = (JComboBox)e.getSource();
         int index = jc.getSelectedIndex();
         if(mode == MASK) currentMask = masks[index];
         else currentSize = sizes[index];
         applyOperator(currentMode);
     }
 }
 class FilterOpAdapter implements ActionListener {
      int mode;
      public FilterOpAdapter( int type) {mode = type;}
      public void actionPerformed(ActionEvent e) {
         currentMode = mode;
         applyOperator(mode);
     }
   }
 }
}

