Codice commentato di ImageChanger
Questa superclasse astratta pubblica tutte le funzioni necessarie perchè una classe sia abilitata a eseguire animazioni. Non ho utilizzato un interfaccia perchè avevo bisogno di implementare alcuni metodi comuni a tutte le classi. Di seguito mostro un implementazione di una semplice classe di animazione.
Indice
ImageChanger
Cliccate qui per il codice completo.
Di seguito dichiariamo le variabili:
dest_pix contiene i pixel in formato RGB dell'immagine di destinazione.
src_pix contiene i pixel in formato RGB dell'immagine sorgente.
cur_pix contiene i pixel in formato RGB attualmente visualizzata.
passaggi è un contatore per sapere quando una animazione è terminata.
mis è il MemoryImageSource associato all'animazione.
cur_img è l'Image associata a cur_pix.
width E' la larghezza dell'immagine.
height E' l'altezza dell'immagine.
size E' la dimensione degli array di pixel.
public abstract class ImageChanger {
protected int[] dest_pix, src_pix;
protected int[] cur_pix;
protected int passaggi;
protected MemoryImageSource mis;
protected Image cur_img;
protected int width, height, size;
Al costruttore bisogna passare l'immagine sorgente, l'immagine di destinazione, il numero dei passaggi voluti (potrebbe essere ignorato) e un componente AWT necessario per istanziare il PixelGrabber.
Il costruttore inizia ottenendo i pixel dalle immagini passate.
public ImageChanger(Image source, Image dest, int passaggi, Component comp)
throws DataException {
PixelGrabber pg = new PixelGrabber(source, 0,0, source.getWidth(null),
source.getHeight(null), true);
try {
if(!pg.grabPixels())
throw new DataException("Immagine sorgente ("+source+") non pronta.");
} catch(InterruptedException e) { return; }
src_pix = (int[])pg.getPixels();
width = source.getWidth(null);
height = source.getHeight(null);
size = width * height;
pg = new PixelGrabber(dest, 0,0, dest.getWidth(null), dest.getHeight(null), true);
try {
if(!pg.grabPixels())
throw new DataException("Immagine destinazione ("+dest+") non pronta.");
} catch(InterruptedException e) { return; }
dest_pix = (int[])pg.getPixels();
this.passaggi = passaggi;
Ora creo l'array che conterrà i pixel che verranno cambiati dinamicamente e lo riempio (default) con l'immagine sorgente. Nota: se avessi utilizzato System.arraycopy avrei avuto una esecuzione più rapida.
cur_pix = new int[size];
for(int i=0; i<size; i++) {
cur_pix[i] = src_pix[i];
}
Ora istanzio il MemoryImageSource e lo imposto perchè sviluppi animazioni. Ottengo inoltre un riferimento all'immagine dinamica.
mis = new MemoryImageSource(width, height, cur_pix, 0, width);
mis.setAnimated(true);
cur_img = comp.createImage(mis);
}
Segue la definizione della funzione astratta step(). Il valore di ritorno indica, se maggiore di 0, che la classe non ha ancora terminato l'animazione.
public abstract int step();
}
Segue ora l'implementazione di una classe istanziabile che estenda ImageChanger.
Indice
RandomPixel
Cliccate qui per il codice completo.
Il codice qui rappresentato non è completo. Consiglio di tenere come riferimento il codice completo.
Questa classe sostituisce un numero di pixel dipendente dai passaggi scelti rimpiazzandoli con quelli dell'immagine di destinazione. I pixel vengono scelti a caso.
public class RandomPixel extends ImageChanger {
public RandomPixel(Image source, Image dest, int passaggi, Component comp)
throws DataException {
super(source, dest, passaggi, comp);
Tramite l'array di boolean done[] tengo traccia di quali pixel sono stati già sostituiti.
done = new boolean[size];
for(int i=0; i<size; i++)
done[i] = false;
pixelToDo = size / passaggi;
count = passaggi;
}
L'implementazione di step() è semplice:
- Genero un numero a caso compreso tale che 0 < x < size.
- Se
done[x] è true vuol dire che il pixel è già stato rimpiazzato e quindi torno a 1 altrimenti continuo.
- Sostituisco il pixel.
- Imposto
done[x] = true per tenere traccia del cambiamento.
- Se non ho cambiato abbastanza pixel torno a 1 altrimenti ritorno il numero di
step() mancanti per finire l'animazione.
public int step() {
int num;
for(int i=0; i<pixelToDo; i++) {
num = (int)(Math.random() * size);
while(done[num])
num = (int)(Math.random() * size);
cur_pix[num] = dest_pix[num];
done[num] = true;
}
mis.newPixels();
return --count;
}
Indice
|