next up previous contents index
Next: 31 Le son Up: Java: Programmation graphique Previous: 29 Couleurs et Fontes

Subsections

30 Images

 

30.1 Introduction

Java fournit des facilités pour manipuler des images au format GIF et JPEG . On trouvera dans les packages java.awt et java.awt.image tout un ensemble de classes pour le faire. Une image est un objet de la classe java.awt.Image. On crée généralement un objet de type Image en invoquant la méthode getImage de la classe java.applet.Applet ou java.awt.Toolkit

 

uneImage = uneApplet.getImage(URL);
uneImage = uneApplet.getImage(URL, String);

uneImage = unComposant.getToolkit().getImage(URL);
uneImage = unComposant.getToolkit().getImage(String);
uneImage = unComposant.getToolkit().getImage(URL);

uneImage = Toolkit.getDefaultToolkit().getImage(URL);
uneImage = ToolKit.getDefaultToolkit().getImage(String);
uneImage = Toolkit.getDefaultToolkit().getImage(URL);

La méthode getImage ne se préoccupe pas du chargement de l'image; elle se termine dès que le fichier image est trouvé. Le chargement de l'image ne se fait que lorsque celle-ci doit être réellement nécessaire : par exemple, lors de l'invocation de la méthode drawImage. Ce chargement se fait de manière asynchrone. Ceci permet de ne pas attendre la fin du chargement de l'image pour continuer la suite du programme. Cette approche est évidemment essentielle pour pouvoir télécharger des images sur le réseau sans bloquer l'application. C'est, par exemple, des browser WEB qui peuvent afficher les images au fur et mesure de leur chargement tout en permettant de continuer à exécuter d'autres tâches.

Dans certaines applications, il faut donc contrôler le chargement effectif de l'image; ce que l'on fera en utilisant un MediaTracker ou en implantant la méthode imageUpdate de l'interface ImageObserver.

L'exemple qui suit affiche une image à l'écran. Par souci de simplicité, l'implantation est plutôt sommaire. Nous verrons un peu plus loin les diverses manières de contrôler le chargement des images.

Votre browser ne peut exécuter les applets Java

 

public class UneImage extends java.applet.Applet {
  java.awt.Image image;
  public void init() {
    image = getImage(getCodeBase(), "tourai.gif");
    prepareImage(image, this);
  }
  public void paint(java.awt.Graphics g) { g.drawImage(image, 0, 0, this); }
}

L'affichage d'un objet de type Image se fait en invoquant la méthode drawImage sur le contexte graphique

 

drawImage(Image, int, int, ImageObserver)

30.2 Manipulation des images

La méthode drawImage se décline sous les formes suivantes:

 

drawImage(Image img, int x, int y, Color bgc, ImageObserver o)
drawImage(Image img, int x, int y, ImageObserver o)
drawImage(Image img, int x, int y, int l, int h, Color bgc, ImageObserver o)
drawImage(Image img, int x, int y, int l, int h, ImageObserver o)
drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgc, ImageObserver o)
drawImage(Image img, int, int, int, int, int, int, int, int, ImageObserver o)

Votre browser ne peut exécuter les applets Java

 

public class UneImageee extends java.applet.Applet {
  java.awt.Image image;
  public void init() {
    image = getImage(getCodeBase(), "photo.jpg");
  }
  public void paint (java.awt.Graphics g) {
    g.drawImage(image, 0, 0, 400, 150, this);
    g.drawImage(image, 0, 0, 80, 80, this);
  }
}

Comme nous l'avons dit, le chargement d'une image ne se fait que lors qu'on en a réellement besoin :

30.3 Contrôle du chargement des images

Les objets qui manipulent les images se rangent dans trois catégories:

30.3.1 La méthode checkImage

Lorsqu'on utilise des images (particulièrement avec les applets pour lesquelles leur chargement est généralement long), il convient de vérifier si l'image est effectivement disponible pour affichage ou pas.

 

public void paint(Graphics g) {
   int n = checkImage(im, this) & ImageObserver.ALLBITS;
   if (n == ImageObserver.ALLBITS) g.drawImage(im, 50, 50, this);
   else g.drawString("Chargement en cours ...")
}

Nous verrons dans la section suivante tous les champs de la classe ImageObserver.

30.3.2 Observateur d'images

L'interface ImageObserver définit une seule méthode imageUpdate qui est invoquée chaque fois qu'une portion d'image est chargée. En implantant cette méthode, un composant peut définir ce qu'il convient de faire à chaque acquisition d'une partie de l'image (l'afficher ou le transformer etc.)

 

   public interface ImageObserver {
      public static final int WIDTH
      public static final int HEIGHT
      public static final int PROPERTIES
      public static final int SOMEBITS
      public static final int FRAMEBITS
      public static final int ALLBITS
      public static final int ERROR
      public static final int ABORT
      public abstract boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
   }

Votre browser ne peut exécuter les applets Java

 

public class Observ extends java.applet.Applet {
  java.awt.TextArea textArea;
  java.awt.Image image;
  Trombine panel;
  String rc = System.getProperty("line.separator");
  public void init() {
    textArea = new java.awt.TextArea(8, 50);
    textArea.setEditable(false);
    add(textArea);
    image = getImage(getCodeBase(), "photo.jpg");
    panel = new Trombine(image, this);
    add(panel);
    prepareImage(image, panel);
  }
  public void afficher(String s) { textArea.append(s + rc); textArea.setCaretPosition(2000); }
}


class Trombine extends java.awt.Panel {
  java.awt.Dimension d = new java.awt.Dimension(150, 150);
  java.awt.Image image;
  Observ app;
  boolean tout = false;
  public Trombine(java.awt.Image image, Observ app) { this.image = image; this.app = app; }
  public void paint(java.awt.Graphics g) { if (tout) g.drawImage(image, 0, 0, this); }
  public java.awt.Dimension getMinimumSize() { return d; }
  public java.awt.Dimension getPreferredSize() { return getMinimumSize(); }
  public boolean imageUpdate(java.awt.Image img, int infoflags, int x, int y, int width, int height) {
    String str = "x="+x+" ";
    str += "y="+y+" ";
    str += "width="+width+" ";
    str += "height="+height+" ";
    str += "  infoflags=";
    if ((infoflags & ABORT) != 0) str += "ABORT ";
    if ((infoflags & ALLBITS) != 0) 
      { str += "ALLBITS "; tout = true; repaint(); }
    if ((infoflags & ERROR) != 0) str += "ERROR ";
    if ((infoflags & FRAMEBITS) != 0) str += "FRAMEBITS ";
    if ((infoflags & HEIGHT) != 0) str += "HEIGHT ";
    if ((infoflags & PROPERTIES) != 0) str += "PROPERTIES ";
    if ((infoflags & SOMEBITS) != 0) str += "SOMEBITS ";
    if ((infoflags & WIDTH)!= 0) str += "WIDTH ";
    app.afficher(str);
    return true;
  }
}

On a rarement besoin d'un contrôle si fin du chargement des images; en général, on veut juste savoir si notre image est disponible ou pas. Dans ces cas, on pourra utiliser la classe MediaTracker qui fournit les méthodes pour charger des images (chechID, checkAll) et attendre que les images soit chargées (waitForID, waitAll).

 

   public class MediaTracker  implements Serializable {
      public static final int LOADING
      public static final int ABORTED
      public static final int ERRORED
      public static final int COMPLETE
      public MediaTracker(Component comp)
      public void addImage(Image image, int id)
      public void addImage(Image image, int id, int w, int h)
      public boolean checkAll()
      public boolean checkAll(boolean load)
      public boolean isErrorAny()
      public Object[] getErrorsAny()
      public void waitForAll() throws InterruptedException
      public boolean waitForAll(long ms) throws InterruptedException
      public int statusAll(boolean load)
      public boolean checkID(int id)
      public boolean checkID(int id, boolean load)
      public boolean isErrorID(int id)
      public Object[] getErrorsID(int id)
      public void waitForID(int id) throws InterruptedException
      public boolean waitForID(int id, long ms) throws InterruptedException
      public int statusID(int id, boolean load)
      public void removeImage(Image image)
      public void removeImage(Image image, int id)
      public void removeImage(Image image, int id, int width, int height)
   }

Votre browser ne peut exécuter les applets Java

 

   import java.applet.Applet;
   import java.awt.*;
   import java.awt.event.*;

   public class MTracker extends Applet implements ActionListener {
      Button b;
      Fenetre fenetre;
      Image[] images;
      MediaTracker tracker;
      public void init() {
         b = new Button("Cliquez ici pour ouvrir/fermer une fenetre");
         add(b);
         b.addActionListener(this);
         images = new Image[16];
         tracker = new MediaTracker(this);
         for (int i = 1; i <= 16; i++) {
            images[i-1] = getImage(getCodeBase(), "tumble/t"+i+".gif");
            tracker.addImage(images[i-1], 0);
         }
         fenetre = new Fenetre("MediaTracker", images, tracker);
      }
      public void actionPerformed(ActionEvent e) {
         if (! fenetre.isShowing()) fenetre.setVisible(true);
         else fenetre.setVisible(false);
      }
      public static void main(String[] args) {
         Frame f = new Frame("Position et Dimensions");
         MTracker p =  new MTracker();
         f.addWindowListener(
                               new WindowAdapter() {
                                  public void windowClosing(WindowEvent e) { 
                                     System.exit(0); }
                               });
         p.init();
         f.add(p);
         f.pack();
         f.show();
      }
   }

   class Fenetre extends Frame  implements ActionListener {
      MCanvas f;
      Button b1, b2, b3, b4;
      public  Fenetre(String s, Image [] images, MediaTracker tracker) {
         super(s);
         setLayout(new BorderLayout());
         add("Center", f = new MCanvas(images, tracker));
         add("North", b1 = new Button("Premier"));
         add("East", b2 = new Button("Dernier"));
         add("South", b3 = new Button("Suivant"));
         add("West", b4 = new Button("Precedant"));
         b1.addActionListener(this);
         b2.addActionListener(this);
         b3.addActionListener(this);
         b4.addActionListener(this);
         setSize(250, 100);
      }
      public void actionPerformed(ActionEvent e) {
         String s = e.getActionCommand();
         if ("Premier".equals(s)) f.num = 0;
         else if ("Dernier".equals(s)) f.num = 15;
         else if ("Suivant".equals(s)) f.num = (f.num+1)%16 ;
         else if ("Precedant".equals(s)) f.num = (f.num+15)%16;
         f.repaint();
      }
   
      class MCanvas extends Canvas {
         Image[] images;
         MediaTracker tracker;
         int num = 0;
         Dimension d = new Dimension(130, 80);
         public MCanvas(Image[] images, MediaTracker tracker) { 
            setBackground(Color.white); 
            this.images = images;
            this.tracker = tracker;
            try {
               tracker.waitForAll();  // Attendre le chargement
            } 
               catch (InterruptedException e) {
               }
            setSize(130, 80);
         }
         public void paint(Graphics g) {
            if (! tracker.checkAll()) { g.drawString("Please wait...", 10, 10); }
            else g.drawImage(images[num], 0, 0, this);
         }
         public Dimension getMinimumSize() { return d;}
         public Dimension getPreferredSize() { return d;}
      }
   }

30.4 Les animations graphiques

30.4.1 Un premier exemple d'animation

Votre browser ne peut exécuter les applets Java

 

package td.threads;

import java.applet.*;
import java.awt.*;

public class Tumble extends Applet implements Runnable {

  Image im[] = new Image[32];
  Image  imCourant;
  Image  Ivir;
  Graphics  Gvir;
  Thread th;
  
  public void init() { 
    Ivir = createImage(300,300); 
    Gvir = Ivir.getGraphics(); 
    for (int i=0; i<16; i++) {
      im[i] = getImage(getCodeBase(), "tumble/T"+(i+1)+".gif");
      im[31-i] = getImage(getCodeBase(), "tumble/T"+(i+1)+".gif");
      imCourant = im[0];
    }
  }
  
  public void start() { if (th == null)  { th = new Thread(this);  th.start(); } }
  
  public void stop() { if (th != null) { th.stop(); th = null; } }
  public void run() {
    while (true) {
      for (int i=0; i<32; i++) {
	try { th.sleep(100); }
	catch (InterruptedException e) {}
	imCourant = im[i];
	repaint();
      }
      try { th.sleep(1000); }
      catch (InterruptedException e) {} 
    }
  }
  public void paint(Graphics g) {
    Gvir.drawImage(imCourant, 15, 50, this);
    //g.drawImage(imCourant, 15, 50, this);
    g.drawImage(Ivir, 0, 0, this);
  }
}

30.4.2 Un exemple plus agréable

 

A TERMINER

30.5 Producteurs, consommateurs et filtres d'images

Un producteur d'images est un objet d'une classe qui implante l'interface ImageProducer. Il produit des images pour un ou plusieurs consommateurs. Dans beaucoup de cas, il n'est pas nécessaire de soucier des producteurs et consommateurs d'images. La production et la consommation d'images se fait de manière transparente pour le programmeur.

Décrivons un peu la face caché d'une utilisation standard d'une image. De manière simplifiée, un code comme celui suit devrait exister dans une telle application:

 

public class UneApplet extends Applet {
   private Image img = null;
   public void init() {
      img = getImage(getDocumentBase(), "image.gif");
      prepareImage(img, this);
   }
   public void paint(Graphics g) { g.drawImage(img, 50, 50, this); }
}

La création d'une image nécessite un producteur d'images. Ici, ce producteur est caché profondément dans l'implantation de la classe Component.

La préparation de l'image et son affichage requiert un consommateur d'images qui, lui aussi, est caché profondément dans l'implantation de la classe Component.

Enfin, au fur et à mesure du chargement de l'image, l'observateur d'images reçoit une notification de l'état du chargement. Cet observateur est également caché l'implantation de la classe Component.

30.5.1 Filtres d'images

Entre la production d'images et la consommation d'images, il est possible de placer un filtre de transformation. Un filtre de transformation est un objet la classe ImageFilter ou de l'une de ses classes dérivées:

30.5.2 Un exemple

 

   import java.awt.*;
   import java.applet.*;
   import java.awt.image.*;
   import java.awt.event.*;

   public class Filtre extends Applet  implements AdjustmentListener  {
      Image im ;
      int x0=0, y0=0;
      int x1=0, y1=0;
      Image imm;
      Button b1, b2;
      CopieImage cp; 
      PlusOuMoinsRouge colorfilter ;
      ImageProducer prodCrop;
      public void init() {
         cp = new CopieImage(this);
         im = getImage(getCodeBase(), "pp.gif");
         setForeground(Color.white);
         addMouseMotionListener(
                                 new MouseMotionAdapter() {
                                    public void mouseDragged(MouseEvent e) {
                                       x1 = e.getX(); y1 = e.getY(); repaint();
                                    }
                                 }
                              );
         addMouseListener(
                            new MouseAdapter() {
                               public void mousePressed(MouseEvent e) { 
                                  x1 = x0 = e.getX(); y1 = y0 = e.getY();
                               } 
                               public void mouseReleased(MouseEvent e) {
                                  x1 = e.getX(); y1 = e.getY(); BoutDImage(); repaint();
                               }
                            }
                         );      
      }
      public void update(Graphics g) { 
         paint(g);
         cp.redessiner(imm);
      }
      public void paint(Graphics g) { 
         g.drawImage(im, 0, 0, this); 
         g.drawRect((x0 < x1) ? x0 : x1, (y0 < y1) ? y0 : y1, Math.abs(x1-x0), Math.abs(y1-y0));
      }
      void BoutDImage() {
         ImageFilter cropfilter = new CropImageFilter((x0 < x1) ? x0 : x1, (y0 < y1) ? y0 : y1, Math.abs(x1-x0), Math.abs(y1-y0));
         ImageProducer prod = im.getSource();
         prodCrop = new FilteredImageSource(prod, cropfilter);
         colorfilter = new PlusOuMoinsRouge();
         prod = new FilteredImageSource(prodCrop, colorfilter);       
         imm =  createImage(prod);    
      }
   
      public static int i = 100;   
   
      public  void adjustmentValueChanged(AdjustmentEvent e) {
         i = e.getValue();
         cp.redessiner(imm);
      }
   }

   class CopieImage extends Frame {
      Copie c;
      ImageFilter colorfilter;
      FilteredImageSource prod;
      Filtre f;
      Scrollbar scb;
      public CopieImage(Filtre f) {
         this.f = f;
         setLayout(new BorderLayout());
         c = new Copie(f);
         add(c, "Center");
         scb = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, 360);
         add(scb, "South"); 
         scb.addAdjustmentListener(f);
      
      
         setVisible(true);
         addWindowListener(
                             new WindowAdapter() {
                                public void windowClosing(WindowEvent e) { setVisible(false); }
                             }
                          );
      }
      void redessiner(Image imm) { 
         setVisible(true); 
         c.redessiner(f.imm);
      }
   }

   class Copie extends Canvas {
      Filtre f;
      int x0 = 50, y0 = 50;
      public Copie(Filtre f) {
         this.f = f;      
         addKeyListener( 
                          new KeyAdapter() {
                             public void keyTyped(KeyEvent e) {
                                switch (e.getKeyChar()) {
                                   case 'a' : System.out.println("agrandir");
                                      break;
                                   case 'r' : System.out.println("reduire");
                                      break;
                                   case 'g' : 
                                      if (--x0 < 0) x0=0;
                                      repaint();
                                      break;
                                   case 'd' :  
                                      x0++;  
                                      repaint();
                                      break;
                                   case 'h' : 
                                      if (--y0 < 0) y0=0;
                                      repaint();
                                      break;   
                                   case 'b' :  
                                      y0++;  
                                      repaint();
                                      break;
                                }
                             }
                          }
                       );
      }
      void redessiner(Image imm) { repaint(); }
      public void paint(Graphics g) { 
         if (f.imm != null) g.drawImage(f.imm, x0, y0, this);
         else g.drawString("Aucune portion d'image selectionnée", 10, 10); 
      }
   }

   class PlusOuMoinsRouge extends RGBImageFilter {
      public int filterRGB(int x, int y, int rgb) {
         return (rgb & 0xff000000)  | ((rgb & 0x00000ff) << 16)
                                   |  (rgb & 0x0000ff00) | ((rgb & 0x00ff0000) >> 16) ;
      }
   }

30.6 Fabriquer des images "à la main"

 

A TERMINER


next up previous contents index
Next: 31 Le son Up: Java: Programmation graphique Previous: 29 Couleurs et Fontes
Touraivane
6/12/1998