 	import java.awt.BorderLayout;
	import java.awt.Color;
	import java.awt.Graphics;
	import java.awt.GridLayout;
	import java.awt.Image;
	import java.awt.MediaTracker;
	import java.awt.event.ActionEvent;
	import java.awt.event.ActionListener;
	import java.awt.image.BufferedImage;
	import java.io.File;
	import java.io.IOException;
	import javax.imageio.ImageIO;
	import javax.swing.ImageIcon;
	import javax.swing.JButton;
	import javax.swing.JFileChooser;
	import javax.swing.JFrame;
	import javax.swing.JLabel;
	import javax.swing.JPanel;
	import javax.swing.JSlider;
	import javax.swing.JTextField;
	import javax.swing.event.*;

public class JFrameOutilsImage extends JFrame implements ActionListener, ChangeListener {


		private static final long serialVersionUID = 1L;
		protected JPanelTailleImage monJPanelTailleImage;
		private JSlider JSlideX, JSlideY;
		private JTextField JTextX, JTextY, JTextCoinX, JTextCoinY;
		private JButton annuler, enregistrer, tourner, gris, crop, raz;
		private int tailleX, tailleY;
		private JFileChooser fc;
		private BufferedImage monImage, monImageresize;
		private MediaTracker tracker;
		
		public JFrameOutilsImage(String monim)
		{
			super("Outils image");
			Image monImage = this.getToolkit().getImage(monim);
			this.tracker = new MediaTracker(this);
			this.tracker.addImage(monImage, 0);
      		// Attendre le chargement de toutes les images
			try
			{
				this.tracker.waitForAll();
				System.out.println("Fin d'attente de chargement des images");
				this.monImage = ImageOutils.Image2Buffered(monImage);
			}
			catch (InterruptedException e){System.out.println(e.getMessage());}
			
			this.setLayout(new BorderLayout());
			this.monJPanelTailleImage = new JPanelTailleImage(this.monImage);
			this.tailleX = this.monImage.getWidth(this);
			this.tailleY = this.monImage.getHeight(this);
		
			this.fc = new JFileChooser();
			//this.fc.setCurrentDirectory(new File("D:\\java\\Image_diaporama"));
			this.fc.setCurrentDirectory(new File("U:\\cours\\java\\Image_diaporama"));
			
			JPanel panoutils = new JPanel (new GridLayout(5, 3));
			this.JTextX = new JTextField(""+this.tailleX);
			this.JTextX.setText(""+this.tailleX);
			//this.JTextX.setEditable(false);
			this.JTextX.addActionListener(this);
			
			this.JTextCoinX = new JTextField("10");
			this.JTextCoinX.setText("0");
			this.JTextCoinX.addActionListener(this);
			this.JTextCoinY = new JTextField("10");
			this.JTextCoinY.setText("0");
			this.JTextCoinY.addActionListener(this);
			
			this.JTextY = new JTextField(""+this.tailleY);
			this.JTextY.setText(""+this.tailleY);
			//this.JTextY.setEditable(false);
			this.JTextY.addActionListener(this);
			
			this.JSlideX = new JSlider(0, this.tailleX, this.tailleX);
			this.JSlideX.setMajorTickSpacing(100);
			//this.JSlideX.setMinorTickSpacing(1);
			this.JSlideX.setPaintTicks(true);
			this.JSlideX.setPaintLabels(true);
			this.JSlideX.addChangeListener(this);

			this.JSlideY = new JSlider(0, this.tailleY, this.tailleY);
			this.JSlideY.setMajorTickSpacing(100);
			//this.JSlideY.setMinorTickSpacing(1);
			this.JSlideY.setPaintTicks(true);
			this.JSlideY.setPaintLabels(true);
			this.JSlideY.addChangeListener(this);

			this.enregistrer = new JButton("Enregistrer ...", new ImageIcon("icons/Save_enabled.PNG"));
			this.enregistrer.addActionListener(this);
			this.raz = new JButton("Remise zéro");
			this.raz.addActionListener(this);
			this.annuler = new JButton("Annuler");
			this.annuler.addActionListener(this);
			
			this.tourner = new JButton("Rotation ...");
			this.tourner.addActionListener(this);
			this.gris = new JButton("Niveau gris ...");
			this.gris.addActionListener(this);
			this.crop = new JButton("Recadrer ...");
			this.crop.addActionListener(this);
			
			panoutils.add(new JLabel("Recadr. horizontal :"));
			panoutils.add(this.JTextX);
			panoutils.add(this.JSlideX);
			
			panoutils.add(new JLabel("Recadr. vertical :"));
			panoutils.add(this.JTextY);
			panoutils.add(this.JSlideY);		
			
			panoutils.add(new JLabel("Recadr. Coin Sup. Gauche :"));
			panoutils.add(this.JTextCoinX);
			panoutils.add(this.JTextCoinY);	
			
			panoutils.add(this.tourner);
			panoutils.add(this.gris);
			panoutils.add(this.crop);
			
			panoutils.add(this.enregistrer);
			panoutils.add(this.raz);
			panoutils.add(this.annuler);	
			
			this.add(panoutils, BorderLayout.SOUTH);
			this.add(this.monJPanelTailleImage, BorderLayout.CENTER);
			
			this.pack();
		}

		// Les action sur les bouttons et les JTextField
		public void actionPerformed(ActionEvent e) {
		
			if (e.getSource() == this.enregistrer)
			{	
				// Sauver le fichier
		        int returnVal = fc.showOpenDialog(this);
		        if (returnVal == JFileChooser.APPROVE_OPTION) {
		            File fichier = fc.getSelectedFile();
		            try{
		            	ImageIO.write(this.monImageresize, "png", fichier);
		            }
		            catch (IOException ee){
		            	System.out.println("Problème de sauvegarde " + ee.getMessage());
		            }
		        } 
			}
			if (e.getSource() == this.raz)
			{
				this.monJPanelTailleImage.monImage = this.monImage;
				this.monJPanelTailleImage.repaint();
			}
			if (e.getSource() == this.annuler)
			{
				this.dispose();
			}

			if (e.getSource() == this.tourner){
				this.monImageresize = ImageOutils.Rotate(ImageOutils.Image2Buffered(this.monJPanelTailleImage.monImage));
				this.monJPanelTailleImage.monImage = this.monImageresize;
		        this.monJPanelTailleImage.repaint();
			}
			if (e.getSource() == this.gris){
				this.monImageresize = ImageOutils.GrayScale(ImageOutils.Image2Buffered(this.monJPanelTailleImage.monImage));
				this.monJPanelTailleImage.monImage = this.monImageresize;
		        this.monJPanelTailleImage.repaint();
			}
			if (e.getSource() == this.crop){
				int x = Integer.parseInt(this.JTextCoinX.getText());
				int y = Integer.parseInt(this.JTextCoinY.getText());
				int tailleX = this.JSlideX.getValue();
				int tailleY = this.JSlideY.getValue();
				// Si la zone de crop est correcte
				if (this.verifieCrop(x, y, tailleX, tailleY)){
					this.BlackTextField();
					this.monImageresize = 
						ImageOutils.Crop(ImageOutils.Image2Buffered(this.monJPanelTailleImage.monImage),
						x, y, tailleX, tailleY);
					this.monJPanelTailleImage.monImage = this.monImageresize;
					this.monJPanelTailleImage.repaint();
				}
			}

			// On redessine le rectangle si changement du coin
			if ((e.getSource() == this.JTextCoinX) || (e.getSource() == this.JTextCoinY)){
				this.dessineRect();
			}
			
			// Ajustement des SlideBar si changement dans le TextField
			if (e.getSource() == this.JTextX){
				this.JSlideX.setValue(Integer.parseInt(this.JTextX.getText()));
				this.dessineRect();
			}
			if (e.getSource() == this.JTextY){
				this.JSlideY.setValue(Integer.parseInt(this.JTextY.getText()));
				this.dessineRect();
			}
		}

		// Vérification de la cohérence de la zone de croping
		private boolean verifieCrop(int x, int y, int tailleX, int tailleY){
			boolean res = true;
			this.BlackTextField();
			
			if((x<0)||(x>this.monImage.getWidth())){
				this.JTextCoinX.setForeground(Color.RED);
				this.JTextCoinX.repaint();
				res = false;
			}
			if((y<0)||(y>this.monImage.getHeight())){
				this.JTextCoinY.setForeground(Color.RED);
				this.JTextCoinY.repaint();
				res = false;
			}
			if((tailleX<0)||(tailleX>this.monImage.getWidth())){
				this.JTextX.setForeground(Color.RED);
				this.JTextX.repaint();
				res = false;
			}
			if((tailleY<0)||(tailleY>this.monImage.getHeight())){
				this.JTextY.setForeground(Color.RED);
				this.JTextY.repaint();
				res = false;
			}
			
			if(y + tailleY > this.monImage.getHeight()){
				this.JTextY.setForeground(Color.RED);
				this.JTextCoinY.setForeground(Color.RED);
				this.JTextY.repaint();
				this.JTextCoinY.repaint();
				res = false;
			}
			if(x + tailleX > this.monImage.getWidth()){
				this.JTextX.setForeground(Color.RED);
				this.JTextCoinX.setForeground(Color.RED);
				this.JTextX.repaint();
				this.JTextCoinX.repaint();
				res = false;
			}

		return res;	
		}
		// Remise en Noir de tous les TextField
		private void BlackTextField(){
			this.JTextCoinX.setForeground(Color.BLACK);
			this.JTextCoinY.setForeground(Color.BLACK);
			this.JTextX.setForeground(Color.BLACK);
			this.JTextY.setForeground(Color.BLACK);
		}

		// Tracer un rectangle délimitant la zone de croping
		private void dessineRect(){
			int x = Integer.parseInt(this.JTextCoinX.getText());
			int y = Integer.parseInt(this.JTextCoinY.getText());
			int tailleX = this.JSlideX.getValue();
			int tailleY = this.JSlideY.getValue();
			int decalX = this.monJPanelTailleImage.getWidth()/2-this.monJPanelTailleImage.monImage.getWidth(this)/2;
			int decalY = this.monJPanelTailleImage.getHeight()/2-this.monJPanelTailleImage.monImage.getHeight(this)/2;
			Graphics g = this.monJPanelTailleImage.getGraphics();
			
			//this.monJPanelTailleImage.repaint();
			this.monJPanelTailleImage.paintComponent(this.monJPanelTailleImage.getGraphics());
			this.monJPanelTailleImage.paintComponent(g);
			g.setColor(Color.RED);
			g.drawRect(x+decalX, y+decalY, tailleX, tailleY);
			//System.out.println("Rectangle = "+(x+decalX)+","+(y+decalY)+","+(tailleX)+","+tailleY);
		}
		
		// Pour traiter les actions sur les JSlider
		public void stateChanged(ChangeEvent e) {
		    JSlider source = (JSlider)e.getSource();
		    
		    if (!source.getValueIsAdjusting()) {
		    	if (e.getSource() == this.JSlideX){
						this.JTextX.setText(Integer.toString(this.JSlideX.getValue()));
				}
		    	else{
						this.JTextY.setText(Integer.toString(this.JSlideY.getValue()));
		    	}
		    	this.dessineRect();
		        }
		    }
		
			public static void main(String[] argv){
				JFrameOutilsImage monJFrameOutilsImage = new JFrameOutilsImage("Wait.png");
				
				monJFrameOutilsImage.pack();
				monJFrameOutilsImage.setVisible(true);
			}
}