Newsgroup: it.comp.java
Titolo: ImageIcon non si aggiorna correttamente

Salve,
forse la mia � una domanda stupida ma vorrei capire in che modo il 
riutilizzo di un oggetto in Java possa generare problemi.
In una webapp faccio delle operazioni di resize con un immagine di cui 
l'utente fa l'upload e poi la visualizzo sulla pagina Web. Quando un 
utente carica una nuova immagine "sovrascrivo" la precedente (cancello 
il vecchio file e genero un nuovo file con lo stesso nome di quello che 
c'era prima), poi riutilizzo il reference precedente (la variabile 
dell'oggetto � di classe). L'immagine cambia (sulla visualizzazione) ma 
le sue propriet� invece no!
10 righe di codice di esempio che valgono pi� di 100 parole.
In c:/ ho messo le immagini 1.jpg e 2.jpg che hanno dimensioni (in 
pixel) diverse. (copyfile � una mia funzioncina)
    public static void main(String[] args) {
        ImageIcon image;
        copyfile("c:/1.jpg", "c:/tmp/12345.jpg");        
        image = new ImageIcon("c:/tmp/12345.jpg");
        System.out.println("height: " + image.getIconHeight());
        System.out.println("width: " + image.getIconWidth());
        System.out.println(image.toString());
        image = null;
        File f1 = new File("c:/tmp/12345.jpg");
        if (f1.exists()) {
            f1.delete();
        }
        copyfile("c:/2.jpg", "c:/tmp/12345.jpg");
        image = new ImageIcon("c:/tmp/12345.jpg");
        System.out.println("height: " + image.getIconHeight());
        System.out.println("width: " + image.getIconWidth());
        System.out.println(image.toString());
    }
Ecco l'output di questo codice:
height: 328
width: 340
c:/tmp/12345.jpg
height: 328
width: 340
c:/tmp/12345.jpg
a fine run il contenuto della cartella tmp contiene un file le cui 
dimensioni non sono 328x340. Chi mi aiuta a capire?
Grazie

 pixel) diverse. (copyfile è una mia funzioncina)

Ciao
La domanda non è stupida, e il problema a cui sei arrivato non è di
certo banale. Ti faccio innanzi tutti i complimenti per aver tentato
autonomamente di risolvere la questione: ho provato il tuo codice ed
effettivamente produce gli stessi risultati, quindi il dubbio che ci
fosse qualche problemino "dietro le quinte" è sorto inevitabilmente.
Gli sviluppatori di Sun (Oracle) però non sono gli "ultimi arrivati",
quindi deve esserci per forza un motivo per questo comportamento.
A guardare bene, hai usato ImageIcon per gestire le tue immagini.
ImageIcon è una classe proveniente dal package javax.swing , quindi si
tratta di classi estremamente ottimizzate, visto che vengono usate per
la creazione di GUI per applicazioni desktop.
Nello specifico, ImageIcon è stato pensato come contenitore di icone
visualizzate accanto a JLabel: il più delle volte si tratta di immagini
situate all'interno dei JAR e caricate tramite ClassLoader, quindi ha
senso che queste immagini vengano inserite in una cache locale, nel
caso in cui lo stesso "new ImageIcon(...)" venga invocato più volte.
Effettuando un debugging a basso livello (con step all'interno delle
classi fornite "chiavi in mano" con il JRE) durante l'esecuzione del
costruttore di ImageIcon arriviamo ad una chiamata di questo tipo:
sun.awt.SunToolkit.getImageFromHash(java.awt.Toolkit, java.lang.String)
Anche senza avere il sorgente sotto mano, mi sembra abbastanza chiaro
che SunToolkit (che estende java.awt.Toolkit) mantiene un riferimento
alle immagini caricate tramite hash sull'URL, e se viene richiesta
un'immagine con lo stesso URL di un'altra già caricata, viene evitata
l'operazione di caricamento e viene restituita l'immagine già in
memoria.
Per poter caricare una nuova immagine da un file con lo stesso nome, ti
conviene allontanarti dalle API di Swing, tanto più che in questo modo
(vista l'esecuzione in una webapp) stai costringendo la JVM
dell'application server a caricare tutte le risorse necessare per
un'applicazione desktop: nel caso in cui la tua webapp finisse in
esecuzione su un server headless (senza monitor nè scheda video)
inizierebbero ad arrivarti eccezioni apparentemente senza senso.
Esiste un package appositamente studiato per quello che devi fare:
javax.imageio . Nel tuo caso, il codice che hai postato dovrebbe essere
modificato in questo modo:
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
...
         BufferedImage image;
         copyfile("c:/1.jpg", "c:/tmp/12345.jpg");
         image = ImageIO.read(new File("c:/tmp/12345.jpg"));
         System.out.println("height: " + image.getHeight());
         System.out.println("width: " + image.getWidth());
         System.out.println(image.toString());
         image = null;
         File f1 = new File("c:/tmp/12345.jpg");
         if (f1.exists()) {
             f1.delete();
         }
         copyfile("c:/2.jpg", "c:/tmp/12345.jpg");
         image = ImageIO.read(new File("c:/tmp/12345.jpg"));
         System.out.println("height: " + image.getHeight());
         System.out.println("width: " + image.getWidth());
         System.out.println(image.toString());
...
In questo modo l'immagine viene sempre caricata e decodificata, senza
cache di mezzo.
Hope That Helps!
-- 
erk: C0 CE FE 84 C2 27 F7 5B D0 7A 7E B8 46 50 9F 93 B2 38 E7 70 DA CB
9F F4 A3 88 F8 12 48 2B E2 1B riv: 47 EE 74 54 E4 77 4C C9 B8 96 0C 7B
59 F4 C1 4D - further info: Google it!
(per rispondere personalmente leva IlDitoDalCulo)


No, scusami... davvero... il film di Albanese non c'entra nulla...
assolutamente (ehm...)
Non l'ho nemmeno visto, almeno, non ancora...


 cache di mezzo.
Se posso intromettermi nella discussione, vorrei chiedere a kaiser se
oltre a leggere le proprietà dell'immagine, gli occorre anche fare
delle elaborazioni grafiche, chessò unresize, crop, etc.
Lo chiedo perché ho dedicato parecchie ore qualche anno fa per trovare
il modo migliore di processare le immagini uploadate e sono arrivato
alla conclusione che si risparmia tempo e si ottengono risultati
migliori, interfacciando ImageMagick.
Ciao, Davide.

 Non l'ho nemmeno visto, almeno, non ancora...
E' tristemente divertente, merita davvero!

 modificato in questo modo:
Riscrivere tutto il codice daccapo era abbastanza oneroso vista 
l'urgenza del progetto (ovviamente quello da me postato era un esempio 
ridottissimo). Per ora mi son assicurato che il server su cui andrï¿œ a 
far girare la webapp non sarï¿œ headless ed ho bypassato il problema 
usando il costruttore di ImageIcon con un oggetto Image che io gli do in 
pasto ed al quale ho preventivamente associato il file.
Mi sono ripromesso di fare refactoring di quell'area di codice non 
appena l'applicazione sarï¿œ stabile. Early optimization is the root of 
all Evil, diceva Knuth. Io gli credo.
Grazie mille per l'aiuto.
It helped
Kaiser

 migliori, interfacciando ImageMagick.
Non ho abbastanza esperienza nello specifico per fare una valutazione di 
questo tipo. Per un resize, un crop ed in generale per operazioni che 
non richiedano "formule magiche" penso sia tutto gestibile a manina.
Se già si parla di disegnare testi nell'immagine, applicare effetti o 
fare particolari conversioni di formato allora credo che farei subito 
affidamento su qualcosa di pronto.
Saluti
Kaiser

 affidamento su qualcosa di pronto.
Se un giorno ti servisse, chiedi pure, ormai sono un esperto ;)
Ciao, Davide.

[CUT]

Ciao OcchioDelDrago,
sto facendo un po di prove con il tuo codice e, debuggando, ho notato
che anche in questo caso si carica molte librerie dell'ambiente
desktop.
Quando il debugger passa da questa riga di codice
			BufferedImage inImage = javax.imageio.ImageIO.read(new
File(orig));
e legge l'immagine dal disco, mac osx mostra una nuova applicazione
visuale col nome di org.apache.catalina.startup.Bootstrap
e scopare dal monitoraggio delle attività, il processo java legato al
tomcat.
In pratica, ancora, si carica in memoria, anche se in maniera ridotta,
tutto l'ambaradan di classi e librerie dell'ambiente desktop. Il che
non va bene...
Strano, non trovi?