Creazione e manipolazioni di immagini.


Java Sun

Earthweb
(ex Gamelan)

Jars

Java Boutique

JavaWorld

PIP






  JSem: 6.2

   

Il metodo createImage()

Il metodo createImage(int width, int height) della classe Component permette di creare un'immagine di larghezza width, altezza height. Attenzione questo metodo crea l'immagine solo se il peer del componente esiste (nb: il peer non è creato nel costruttore). In un'applet si può chiamare createImage() nel metodo init(); in una classe derivata da Component, nel metodo paint. Esempio:

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


public class Es1_Im{

public static void main(String[] args){
	
Image img;
Toolkit t;
t =  Toolkit.getDefaultToolkit();
img = t.getImage("strange.gif");
Frame f = new Frame("Es1_Im");
ImageFrame IM = new ImageFrame(f,img);
IM.addWindowListener(new WindowAdapter(){
		public void windowClosing(WindowEvent e){
			System.exit(0);
		}
	});
IM.setSize(210,230);
IM.setVisible(true);
	}
}

class ImageFrame extends Frame{

Frame f;
Image im;

//costruttore
ImageFrame(Frame f,Image im){
	this.f = f;
	this.im = im;
}

/*public void paint(Graphics g){
	g.drawImage(im,0,0,this);
	}*/
}


Se lasciate il metodo paint della classe ImageFrame commentato, il codice compila ed esegue, ma non vedete l'immagine; togliendo il commento al metodo paint e ricompilando, si vede l'immagine.

Il double buffering, come abbiamo già visto (cf PIP), usa il metodo createImage(w,h) per creare un'immagine fuori schermo sulla quale disegnare i vari frames di un'animazione.

La classe Image

La classe java.awt.Image è una classe astratta (quindi non si può istanziare un'immagine con new) che fornisce, tra altri, i seguenti metodi:
  • public abstract int getWidth(ImageObserver obs)
    questo metodo ritorna un int che è la larghezza dell'immagine. Si ricorda che Component implementa ImageObserver; cioè il parametro può essere un componente; in un'applet si può mettere this con riferimento all'applet.

  • public abstract int getHeight(ImageObserver obs)
    Come prima, ma con l'altezza.

  • public abstract Graphics getGraphics()
    Ritorna un contesto grafico col quale si può disegnare sull'immagine.

  • La classe MemoryImageSource

    La classe java.awt.image.MemoryImageSource implementa l'interfaccia ImageProducer e permette di creare un'immagine partendo da un array di int (int[]) dove ogni int dell'array corrisponde a un pixel dell'immagine (di solito si parla di array di pixels).
    Esempio:

    import java.applet.*;
    import java.awt.*;
    import java.awt.image.*;
    
    public class MemoIm extends Applet{
    
    
    
    int w, h;
    Image img;
    
    
    public void init(){
    	setBackground(new Color(128, 0, 255));
    	w = getSize().width;
    	h = getSize().height;
    	int[] pix = new int[w*h];
    	int index = 0;
    	for(int y = 0; y < h; y++){
    	int red = (y * 255)/(h - 1);
    		for(int x = 0; x < w; x++){
    		int green = (x * 255)/(w - 1);
    		pix[index] = (255 << 24| red << 16 | green << 8| 0);
    		index++;
    		}
    	}
    	img = createImage(new MemoryImageSource(w,h,pix,0,w));
    }//fine init()
    
    public void paint(Graphics g){
    g.drawImage(img,0,0,w/2,h/3,0,0,w,h,this);
    g.drawImage(img,w/2,0,w,h/3,0,0,w,h,this);
    g.drawImage(img,0,h/3,w/2,h,0,0,w,h,this);
    g.drawImage(img,w/2,h/3,w,h,0,0,w,h,this);
    	}
    }

    L'immagine creata presenta una gradazione dal nero al verde lungo l'asse delle X e dal nero al rosso lungo l'asse delle Y; con il metodo drawImage() si disegna poi l'immagine 4 volte con varie dimensioni.

    Il costruttore usato qui è:

    MemoryImageSource(int w, int h, int[] pix, int off, int scan)

    dove w, h sono le dimensioni dell'immagine, int[] pix è l'array di pixels che verrà usato, int off è il punto di partenza nell'array di pixels per leggere i dati, int scan è il passo della scansione (larghezza di una linea di scansione). Di solito off = 0 e scan = w.
    Questo costruttore usa il modello di colori RGB di default (ci sono altri modelli, vedere la doc). In questo modello, un pixel è un int con Alpha, Red, Green, Blue (0xAARRGGBB in esadecimale). Alpha rappresenta il grado di trasparenza del pixel (trasparenza totale = 0, opacità totale = 255), è consigliato impostare Alpha = 255 in quanto gli effetti di trasparenza non vengono implementati molto bene a meno di avere dell'hardware di ottima qualità. Un int è un intero a 32 bit, ogni colore è rappresentato da 8 bit (28 = 256); negli 8 bit superiori (da 32 a 24) abbiamo Alpha, negli 8 successivi (24-16) abbiamo R, poi (16-8) G e negli ultimi 8, B. L'operatore di scorrimento a sinistra (<<) sposta a sinistra di un numero specificato di volte tutti i bit appartenenti a un valore: val << num sposta a sinistra i bit di val per il numero specificato da num.

    Attenzione! potreste avere delle sorprese, provate per esempio a fare girare il seguente programma:

    class bitNero{
    
    public static void main(String[] args){
    
    int n = (255 << 24|0 << 16|0 << 8|0);
    System.out.print("il valore del nero con Alpha = 255 è : "+n);
    	}
    }

    L'output è: "il valore del nero con Alpha = 255 è : -16777216"
    Forse non è esattamente quello che aspettavate. Il fatto è che gli interi di Java sono interi col segno, il bit superiore contiene il segno e si ottiene il valore con il "complemento di due" cioè invertendo i bit (scambiando gli 1 con 0 e viceversa) e aggiungendo 1. Per esempio (con 8 bit): 11010110 è un numero negativo perchè il bit superiore è pieno. Invertiamo i bit: 00101001, aggiungiamo 1: 00101010, questo vale 22+23+25 = 42; quindi 11010110 = -42. Tornando all'int n che rappresenta il nero con Alpha = 255, abbiamo (con 32 bit) solo gli ultimi 8 bit pieni (i valori RGB del nero sono (0,0,0)) che corrispondono a Alpha = 255 = 20+...+27. Quindi l'ultimo bit è pieno e n è negativo. Per avere il valore invertiamo i bit: 00000000 e aggiungiamo 1: 00000001; tenuto conto che questi sono gli ultimi 8 dei 32 bit (da 20 a 231), questo vale 224 = 16777216, pertanto n = -16777216.

    Un altro esempio di utilizzo di MemoryImageSource


    Per scaricare il codice

    La classe PixelGrabber

    La classe PixelGrabber esegue il processo inverso di MemoryImageSource, cioè PixelGrabber prende un'immagine esistente e crea da essa un array di pixels.
    La classe PixelGrabber implementa l'interfaccia ImageConsumer. Le interfacce ImageProducer e ImageConsumer sono complementari: un ImageProducer produce l'immagine a partire da dati, mentre un ImageConsumer fornisce dati a partire da un'immagine.

    Un costruttore di PixelGrabber è:

    PixelGrabber(Image im,int x, int y, int w, int h, int[] pix,int off, int scan)

    PixelGrabber elabora un rettangolo dell'immagine im, (x,y) sono le coordinate dell'angolo superiore sinistro del rettangolo, (w,h) sono le sue dimensioni, pix è l'array nel quale verrano memorizzati i dati iniziando da off; finalmente scan è il passo di scansione.

    Dopo avere istanziato un PixelGrabber, bisogna chiamare il suo metodo grabPixels(), questo metodo ritorna un booleano (true se è andato a buon fine, false altrimenti).

    Combinando PixelGrabber e MemoryImageSource è possibile manipolare le immagini.
    Ecco per esempio il codice di un filtro negativo:

    import java.awt.*;
    import java.applet.*;
    import java.awt.image.*;
    
    
    public class Filtro_Neg extends Applet{
    
    Image im,img;
    int iw,ih,w,h;
    int[] pixels;
    int[] pixbis;
    
    public void init(){
    setBackground(new Color(238,238,238));
    w = getSize().width;
    h = getSize().height;
    String S = getParameter("immagine");
    //parametro di nome "immagine"
    //value la nostra immagine
    img = getImage(getCodeBase(), S);
    try{
    MediaTracker track = new MediaTracker(this);
    track.addImage(img,0);
    track.waitForID(0);
    iw = img.getWidth(this);
    ih = img.getHeight(this);
    //caricamento dell'immagine
    //e misure dell'immagine
    pixels = new int[iw*ih];
    PixelGrabber pg = new PixelGrabber(img,0,0,iw,ih,pixels,0,iw);
    pg.grabPixels();
    //pixels contiene i pixels della nostra immagine
    }catch(InterruptedException e){};
    pixbis = new int[iw*ih];
    for(int i=0; i < iw*ih;i++){
    int p = pixels[i];
    int r = (0xff - (p >> 16)) & 0xff;
    int gr = (0xff - (p >> 8)) & 0xff;
    int b = (0xff - p) & 0xff;
    pixbis[i] = (255 << 24|r << 16| gr << 8| b);
    //pixbis sono i pixels dell'immagine negativa
    	}
    im = createImage(new MemoryImageSource(iw,ih,pixbis,0,iw));
    //im è l'immagine negativa
    }
    
    public void paint(Graphics g){
    	g.drawImage(img,0,0,this);
    	g.drawImage(im,iw+10,0,this);
    }
    }


    Questa applet utilizza un parametro di nome "immagine" e di valore un file .gif o .jpg
    Il principio del filtro è semplice: si prendono i vari canali di colori (RGB) e se ne sottrae il valore da 255 (nb: 0xff = 255 in esadecimale). Si usa l'operatore logico & sui bit che ritorna 1 se e soltanto se entrambi i bit valgono 1.



     next		content		previous