Newsgroup: it.comp.dotnet
Titolo: rendere persistente una immagine e errore GDI+

Ciao a tutti,
sto lavorando ad un progettino che deve essere in grado di rendere 
persistente (su file in primis, ma non solo) una serie di oggetti che hanno, 
tra le varie proprieta', una immagine.
Immaginate un catalogo di oggetti, dove ogni oggetto ha un codice articolo, 
un prezzo ed una foto illustrativa.
Questo progettino implementa una funzione per salvare il catalogo, generando 
un file xml che ha tanti elementi quanti sono gli oggetti del catalogo 
stesso.
Sono riuscito anche a trovare un modo per rendere persistente le immagini, 
senza naturalmente salvare l'immagine in formati immagine, e per fare questo 
uso, per salvare l'immagine:
 
Dim bt() As Byte
Dim cnv As System.ComponentModel.TypeConverter = 
System.ComponentModel.TypeDescriptor.GetConverter(GetType(System.Drawing.Bitmap))
bt = DirectCast(cnv.ConvertTo(ImageToSerialize, GetType(Byte())), Byte())
SerImg = Convert.ToBase64String(bt)
 
a questo punto posso salvare SerImg come testo all'interno del mio xml. 
Naturalmente la ImageToSerialize e' la mia immagine (System.Drawing.Image)
 
 
Per recuperare l'immagine, invece, uso:
 
Dim bt() As Byte = Convert.FromBase64String(strImg)
Dim mem As System.IO.MemoryStream = New System.IO.MemoryStream(bt)
Dim img As System.Drawing.Image = New System.Drawing.Bitmap(mem)
mem.Dispose()
mem = Nothing
 
ed ora sono in grado di restituire la img come System.Drawing.Image
 
Apparentemente funziona tutto. Se ad esempio mi creo un catalogo con diversi 
oggetti, e provo a fare un salvataggio verso un file xml, ho il mio bel file 
con i vari oggetti dentro. Una volta creato il file, tento di riaprirlo, et 
voila', ho il mio catalogo caricato.
Il problema nasce quando tento di risalvare un catalogo (anche con un altro 
nome su un file inesistente); nel tentare di "codificare" la mia immagine, 
alla chiamata
 
bt = DirectCast(cnv.ConvertTo(ImageToSerialize, GetType(Byte())), Byte())
 
viene sollevata una System.Runtime.InteropServices.ExternalException , che 
come descrizione ha semplicemente un "Errore generico in GDI+"
 
Avete qualche idea di cosa sta succedendo?
Qualche altra idea per fare quanto mi serve?
Ciao  e grazie...Maurizio
 

Aggiornamenti:
come da guida msdn, quando si crea una bitmap da stream, "È necessario 
mantenere il flusso aperto per l'intera durata di Bitmap".
Quindi, eliminando le righe di codice che "chiudono" lo stream, torna a 
funzionare tutto.
Non mi piace molto, pero', lasciare aperta tutta questa roba, quindi cerco 
di girare intorno alla cosa, vediamo che esce fuori.
Si accettano suggerimenti :-)
 

Mi rispondo da solo.
Ho prima provato a creare un clone della immagine, chiudere lo stream e a 
restituire l'immagine clonata, dopo di cio' ho chiuso lo stream, ma comunque 
l'errore persisteva.
Per ovviare, dall'immagine originale, ho creato una pseudo-miniatura, 
utilizzando il metodo GetThumbnailImage dell'immagine originale, passando 
come argomenti di larghezza ed altezza, gli stessi valori ricavati 
dall'immagine originale, creando quindi una "miniatura" delle medesime 
dimensioni dell'originale.
Una volta ottenuta la nuova immagine, ho potuto chiudere lo stream di 
memoria, restituire al chiamate la nuova immagine, e tutto si e' messo a 
funzionare correttamente.
Mi rimarrebbe da capire come mail il metodo Clone della immagine originale, 
che dovrebbe restituire un nuovo oggetto, non ha funzionato allo stesso 
modo.
 
Posto un po' di codice, chissa' se puo' essere utile a qualcuno.
 
Dim bt() As Byte = Convert.FromBase64String(strImg)
Dim mem As System.IO.MemoryStream = New System.IO.MemoryStream(bt)
Dim img As System.Drawing.Image = New System.Drawing.Bitmap(mem)
bt = Nothing
Dim img2 = img.GetThumbnailImage(img.Width, img.Height, Nothing, 
System.IntPtr.Zero)
mem.Close()
mem.Dispose()
mem = Nothing
img.Dispose()
img = Nothing
Return img2 
 

 Posto un po' di codice, chissa' se puo' essere utile a qualcuno.
 
Il tuo codice ha alcuni problemi: 1) andrebbe usato il pattern Using (che e' 
un try-finally), altrimenti le risorse non vengono rilasciate in caso di 
eccezione; 2) garbage collection non avviene ogni pochi colpi di clock, per 
cui non e' necessario nullificare le referenze se non nel caso di metodi che 
impiegano molto tempo ad eseguire!  Nel tuo caso quindi stai aggiungendo 
istruzioni inutili che, oltre al fatto piuttosto di rallentare (per quanto 
di poco) l'esecuzione, rendendo anche il codice piu' difficile da leggere.
 
-LV


Il tuo codice ha alcuni problemi:
1) andrebbe usato il pattern Using
...
Ok, terro' conto
 
...
2) garbage collection non avviene ogni pochi colpi di clock, per
cui non e' necessario nullificare le referenze se non nel caso di metodi che
impiegano molto tempo ad eseguire!
...
Si, lo so che quel settare a Nothing e' abbastanza ridondante, e' che ho 
preso l'abitudine di impostare a nothing quello che non uso, subito dopo 
averli usati.
 
Grazie ancora... Maurizio