none
OutOfMemoryException [RISOLTO] RRS feed

  • Domanda

  •  

    OutOfMemoryException

    Messaggioda bit » lun mag 30, 2011 11:23 am

    Salve a tutti, sono un neofita-niubbo, sto cercando di creare un programma che data una cartella di origine, carichi tutti i file fotografici contenuti (.jpg, .tif, .png, .bmp), li riduca di dimensione e li risalvi in un'altra cartella a scelta.
    Tramite un checkbox c'è la possibilità di inserire un logo ripetuto che funga da filigrana per evitare l'utilizzo fraudolento delle foto.
    Se elaboro le foto solo in riduzione, tutto ok;
    Se invece inserisco la filigrana dopo 5-6 foto ricevo il seguente messaggio di errore:

    System.OutOfMemoryException: Memoria insufficiente
    in System.Drawing.Graphics.CheckErrorStatus(Int32 status)
    in System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y)
    in System.drawing.Graphics.DrawImageUnscaled(Image image, Int32 x, Int32 y)
    in Resize.frmResize.inserisciFiligrana(String foto, String logo)
    in frmResize.cs:riga 55


    allego il listato circoscritto alla zona incriminata:

     

     

    private Image inserisciFiligrana(string foto, string logo)
     {
      int x, y;
    
      Image m = null;
      
    
    
      try
      {
       
       Graphics graphics = null;
    
       // jpg
       Image imgFoto = Image.FromFile(foto);
    
       // png con sfondo trasparente
       Image imgLogo = Image.FromFile(logo);
    
    
       // creo la nuova immagine
    
       m = Image.FromFile(foto);
    
       x = m.Width;
    
       y = m.Height;
    
    
       graphics = System.Drawing.Graphics.FromImage(m);
       graphics.DrawImageUnscaled(imgFoto, 0, 0);
    
       //due variabili prendono i valori di ripetizione logo dalle caselle di testo
    
       int righe, colonne;
       colonne = int.Parse(txtX.Text);
       righe = int.Parse(txtY.Text);
    
       // variabili contatore per i due cicli
       int k, j;
       j = 0;
       do
       {
        k = 0;
        do
        {
         graphics.DrawImageUnscaled(imgLogo, k, j);
         k = (x / colonne) + k;
        }
        while (k < x);
        j = (y / righe) + j;
       }
       while (j < y);
       graphics.Save();
       imgFoto.Dispose();
       imgLogo.Dispose();
       graphics.Dispose();
       
      }
      catch (System.FormatException)
      {
       MessageBox.Show("Inserire valori numerici interi", "Errore!", MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
      catch (System.DivideByZeroException)
      {
       MessageBox.Show("Inserire valori interi maggiori di 0", "Errore!", MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    
      catch (Exception ex)
      {
       MessageBox.Show(ex.ToString(), "Errore!", MessageBoxButtons.OK, MessageBoxIcon.Error);
       // throw new Exception("Errore", ex);
      }
    
      return m;
      
     }
    
    Spero mi possiate aiutare, comunque ringrazio tutti in anticipo.

     

     

     


    • Modificato bit72 domenica 5 giugno 2011 09:58
    lunedì 30 maggio 2011 17:07

Risposte

  • bit72 wrote:

    Innanzitutto grazie per la sollecitudine nel rispondere.

    Allora nella funzione in questione in effetti chiamo Dispose per ogni oggetto grafico tranne m, ma non so come fare dato che m deve restituire il valore al termine (Return m;)

    Modificando in using (m = Image.FromFile(foto))

    ricevo il messaggio:

     

    System.ArgumentException:Parametro non valido in System.Drawing.Image.get_Height()

    Resize.cs Riga 51

    Se lo passi in uscita chiaramente non puoi farlo in quel metodo.
    Devi però rifarlo quando non ti serve più ed evitare che vada in carico al GC.

    Il compito primario del GC è gestire la memoria e non i finalizzatori. (La Dispose a tutti gli effetti disalloca risorse native; se fosse solo un problema di memoria managed, la dispose non servirebbe).
    Il GC si prende carico dei finalizzatori in una sorta di "ultima chance" per rimediare alle dimenticanze dello sviluppatore. Se però tu allochi troppo velocemente rispetto alla velocità del processo di finalizzazione, ecco fatto che esaurisci velocemente la memoria.

    Se poi non risolvi in quel modo e non riesci a capire quale allocazione stia rompendo le scatole, puoi usare un memory profiler per capirlo.


    Raffaele Rialdi  http://www.iamraf.net
    Weblog: http://blogs.ugidotnet.org/raffaele
    Microsoft MVP profile https://mvp.support.microsoft.com/profile/raffaele
    UGIdotNET - http://www.ugidotnet.org/


    Raffaele Rialdi [MVP] My articles and videos: http://www.iamraf.net Italian blog: http://blogs.ugidotnet.org/raffaele
    • Contrassegnato come risposta bit72 martedì 31 maggio 2011 09:36
    martedì 31 maggio 2011 07:02
  • bit72 wrote:

    Ok, m mi serve finchè non restituisce l'immagine con la filigrana, cioè alla fine della funzione (return m).

    Allora dovrei modificare la funzione eliminando il return e fornendo il contenuto di m in un altro modo?

    Forse non capisco il flusso della tua applicazione...

    Avevi scritto nel primo messaggio che volevi convertire un'immagine e salvarla in un'altra cartella.
    Quindi nel metodo che hai postato fai la conversione e restituisci un'immagine. Fin qui tutto ok
    Il metodo chiamante riceve l'immagine e immagino che la salverai su disco.
    A questo punto l'immagine ti serve ancora? Oppure la mostri in un controllo?

    Se non ti serve, chiami la dispose subito dopo averla salvata.
    Se ti serve perché la mostri in un controllo la dispose dovrai chiamarla subito prima di disfartene per mostrare l'immagine successiva.

    Diciamo che tu abbia la picturebox che mostra l'immagine "vecchia". Devi solo fare la dispose della vecchia:
    var img = pbox.Image
    pbox.Image = newImage
    if(img != null) img.Dispose();


    Raffaele Rialdi  http://www.iamraf.net
    Weblog: http://blogs.ugidotnet.org/raffaele
    Microsoft MVP profile https://mvp.support.microsoft.com/profile/raffaele
    UGIdotNET - http://www.ugidotnet.org/


    Raffaele Rialdi [MVP] My articles and videos: http://www.iamraf.net Italian blog: http://blogs.ugidotnet.org/raffaele
    • Contrassegnato come risposta bit72 martedì 31 maggio 2011 15:36
    martedì 31 maggio 2011 14:23
  • bit72 wrote:

    Si avevi capito perfettamente, le immagini una per volta, dopo aver inserito la filigrana vengono riprese da una funzione che le riduce di dimensione e poi salvate senza visualizzzarle.

    Per chiamare m.dispose devo quindi dichiarare m al di fuori della funzione inserisciFiligrana !?

    Il metodo che hai postato restituisce un'immagine, quindi il chiamante farà riferimento a quell'immagine e la salverà su disco, giusto?
    Dopo averla salvata, chiama la dispose


    Raffaele Rialdi  http://www.iamraf.net
    Weblog: http://blogs.ugidotnet.org/raffaele
    Microsoft MVP profile https://mvp.support.microsoft.com/profile/raffaele
    UGIdotNET - http://www.ugidotnet.org/


    Raffaele Rialdi [MVP] My articles and videos: http://www.iamraf.net Italian blog: http://blogs.ugidotnet.org/raffaele
    • Contrassegnato come risposta bit72 martedì 31 maggio 2011 22:44
    martedì 31 maggio 2011 16:58
  • bit72 wrote:

    Ecco di seguito il codice in cui si effettua la chiamata :

    Il codice è parecchio incricchiato ...

    foreach (string s in files) { nomeFile = Path.GetFileName(s); Estensione = nomeFile.ToUpper(); if (Estensione.EndsWith(".JPG")||Estensione.EndsWith(".TIF")||Estensione.EndsWith(".BMP")||Estensione.EndsWith(".PNG")) { i++; this.progressBar1.Focus(); this.progressBar1.Value = i; nomeFileDest = System.IO.Path.Combine(txtCartellaDestinazione.Text, nomeFile); //Crea un'immagine ridimensionata e la salva nella cartella destinazione nomeFileSorgente = System.IO.Path.Combine(txtCartellaSorgente.Text, nomeFile); // se è stato impostata l'opzione filigrana, allora applicala al file prima di salvarlo Image immag = Image.FromFile(nomeFileSorgente); if ((chbFiligrana.Checked == true) && (pbLogo.Image != null)) { immag = inserisciFiligrana(nomeFileSorgente, txtBufferLogo.Text); }

    Se passa dentro l'"if" riassegni immag due volte, il che è uno spreco di tempo.

    img = this.resizeImage(immag, new Size(e.Width, e.Height));

    Se fai il resize dopo aver applicato la filigrana, la filigrana sarà orribile perhcé è testo e il resize di tipo bitmap impoverisce il testo

    nomeFileDest = Path.ChangeExtension(nomeFileDest, "jpg"); this.saveJpeg(nomeFileDest, new Bitmap(img), 85L);

    Ed ecco l'immagine di cui non fai il dispose e che con tutta probabilità scatena l'eccezione dopo "n" volte che la chiami: new Bitmap(img)

    Application.DoEvents(); img.Dispose(); immag.Dispose(); // System.IO.File.Copy(nomeFileSorgente, nomeFileDest, true); copia i file senza modifiche } }

    Infine dovresti lanciare tutto questo codice utilizzando un BackgroundWorker in modo da usare un altro thread ed evitare di bloccare l'interfaccia utente quando trasformi tante immagini.


    Raffaele Rialdi  http://www.iamraf.net
    Weblog: http://blogs.ugidotnet.org/raffaele
    Microsoft MVP profile https://mvp.support.microsoft.com/profile/raffaele
    UGIdotNET - http://www.ugidotnet.org/


    Raffaele Rialdi [MVP] My articles and videos: http://www.iamraf.net Italian blog: http://blogs.ugidotnet.org/raffaele
    • Contrassegnato come risposta bit72 mercoledì 1 giugno 2011 15:34
    mercoledì 1 giugno 2011 12:10
  • bit72 wrote:

    questa operazione la fa anche se disattivo la filigrana, cioè:

     
    prendo 100 foto e faccio solo il ridimensionamento e salvataggio,

    this.saveJpeg(nomeFileDest, new Bitmap(img), 85L); 

    ho provato anche con tif ad alta risoluzione, con 300 file senza problemi.

    Se attivo la filigrana non riesce a fare nemmeno 10 foto
    e si pianta con l'errore che lamento, evidenziando questa riga

    graphics.DrawImageUnscaled(imgFoto, 0, 0);

    che si trova all'interno di

    private Image inserisciFiligrana(string foto, string logo)

    vedi primo post.

    Questi test non sono attendibili perché tutti gli oggetti non referenziati che possiedono un finalizzatore vengono messi in coda di finalizzazione che poi chiama la Dispose. Per cui è come una roulette russa.

    Si può capire con precisione cosa provoca il problema utilizzando un profiler di memoria con quel codice.
    Un altro strumento utile all'indagine è il performance monitor (perfmon di windows) che ti permette di vedere l'attività del GC e la quantità di memoria allocata/utilizzata.

    Praticamente si blocca solo se attivo l'opzione filigrana, altrimenti posso ridurre tutte le immagini che voglio senza problemi

    Quello della bitmap è comunque un errore a prescindere che non sia la causa primaria del problema.
    Il codice che hai postato ha comunque lati oscuri, per esempio non capisco perché chiami la Graphics.Save o fai due volte Image.FromFile dello stesso file disegnando la foto sopra se stessa.

    Se ti può essere di aiuto, qui trovi un po' di codice su come effettuare operazioni classiche usando GDI+:
    http://www.bobpowell.net/faqmain.htm


    Raffaele Rialdi  http://www.iamraf.net
    Weblog: http://blogs.ugidotnet.org/raffaele
    Microsoft MVP profile https://mvp.support.microsoft.com/profile/raffaele
    UGIdotNET - http://www.ugidotnet.org/


    Raffaele Rialdi [MVP] My articles and videos: http://www.iamraf.net Italian blog: http://blogs.ugidotnet.org/raffaele
    • Contrassegnato come risposta bit72 giovedì 2 giugno 2011 18:08
    giovedì 2 giugno 2011 16:05
  • bit72 wrote:

    Se invece inserisco la filigrana dopo 5-6 foto ricevo il seguente messaggio di errore:

    System.OutOfMemoryException: Memoria insufficiente

    Credo che il problema sia che tu continui ad allocare memoria prima che venga rimessa quella che non usi più.
    Specificamente stai dimenticando di chiamare esplicitamente Dispose su tutti gli oggetti che possono essere disposti.

          Image imgFoto = Image.FromFile(foto);
          Image imgLogo = Image.FromFile(logo);
          m = Image.FromFile(foto);

          graphics = System.Drawing.Graphics.FromImage(m);
          imgFoto.Dispose();
          imgLogo.Dispose();
          graphics.Dispose();

    Il pezzo ultra-ridotto di codice mostra più chiaramente che m non viene mai rilasciato.
    La cosa migliore è di usare sempre lo statament using per gli oggetti che implementano IDisposable:
    using(m = Image.FromFile(foto))
    {
     using(graphics = FromImage(m)
     {
     ...
     }
    }


    Raffaele Rialdi  http://www.iamraf.net
    Weblog: http://blogs.ugidotnet.org/raffaele
    Microsoft MVP profile https://mvp.support.microsoft.com/profile/raffaele
    UGIdotNET - http://www.ugidotnet.org/


    Raffaele Rialdi [MVP] My articles and videos: http://www.iamraf.net Italian blog: http://blogs.ugidotnet.org/raffaele
    • Contrassegnato come risposta bit72 lunedì 30 maggio 2011 21:20
    • Contrassegno come risposta annullato bit72 lunedì 30 maggio 2011 21:41
    • Contrassegnato come risposta bit72 lunedì 30 maggio 2011 23:02
    lunedì 30 maggio 2011 17:47

Tutte le risposte

  • bit72 wrote:

    Se invece inserisco la filigrana dopo 5-6 foto ricevo il seguente messaggio di errore:

    System.OutOfMemoryException: Memoria insufficiente

    Credo che il problema sia che tu continui ad allocare memoria prima che venga rimessa quella che non usi più.
    Specificamente stai dimenticando di chiamare esplicitamente Dispose su tutti gli oggetti che possono essere disposti.

          Image imgFoto = Image.FromFile(foto);
          Image imgLogo = Image.FromFile(logo);
          m = Image.FromFile(foto);

          graphics = System.Drawing.Graphics.FromImage(m);
          imgFoto.Dispose();
          imgLogo.Dispose();
          graphics.Dispose();

    Il pezzo ultra-ridotto di codice mostra più chiaramente che m non viene mai rilasciato.
    La cosa migliore è di usare sempre lo statament using per gli oggetti che implementano IDisposable:
    using(m = Image.FromFile(foto))
    {
     using(graphics = FromImage(m)
     {
     ...
     }
    }


    Raffaele Rialdi  http://www.iamraf.net
    Weblog: http://blogs.ugidotnet.org/raffaele
    Microsoft MVP profile https://mvp.support.microsoft.com/profile/raffaele
    UGIdotNET - http://www.ugidotnet.org/


    Raffaele Rialdi [MVP] My articles and videos: http://www.iamraf.net Italian blog: http://blogs.ugidotnet.org/raffaele
    • Contrassegnato come risposta bit72 lunedì 30 maggio 2011 21:20
    • Contrassegno come risposta annullato bit72 lunedì 30 maggio 2011 21:41
    • Contrassegnato come risposta bit72 lunedì 30 maggio 2011 23:02
    lunedì 30 maggio 2011 17:47
  • Innanzitutto grazie per la sollecitudine nel rispondere.

    Allora nella funzione in questione in effetti chiamo Dispose per ogni oggetto grafico tranne m, ma non so come fare dato che m deve restituire il valore al termine (Return m;)

    Modificando in using (m = Image.FromFile(foto))

    ricevo il messaggio:

     

    System.ArgumentException:Parametro non valido in System.Drawing.Image.get_Height()

    Resize.cs Riga 51



    lunedì 30 maggio 2011 21:27
  • bit72 wrote:

    Innanzitutto grazie per la sollecitudine nel rispondere.

    Allora nella funzione in questione in effetti chiamo Dispose per ogni oggetto grafico tranne m, ma non so come fare dato che m deve restituire il valore al termine (Return m;)

    Modificando in using (m = Image.FromFile(foto))

    ricevo il messaggio:

     

    System.ArgumentException:Parametro non valido in System.Drawing.Image.get_Height()

    Resize.cs Riga 51

    Se lo passi in uscita chiaramente non puoi farlo in quel metodo.
    Devi però rifarlo quando non ti serve più ed evitare che vada in carico al GC.

    Il compito primario del GC è gestire la memoria e non i finalizzatori. (La Dispose a tutti gli effetti disalloca risorse native; se fosse solo un problema di memoria managed, la dispose non servirebbe).
    Il GC si prende carico dei finalizzatori in una sorta di "ultima chance" per rimediare alle dimenticanze dello sviluppatore. Se però tu allochi troppo velocemente rispetto alla velocità del processo di finalizzazione, ecco fatto che esaurisci velocemente la memoria.

    Se poi non risolvi in quel modo e non riesci a capire quale allocazione stia rompendo le scatole, puoi usare un memory profiler per capirlo.


    Raffaele Rialdi  http://www.iamraf.net
    Weblog: http://blogs.ugidotnet.org/raffaele
    Microsoft MVP profile https://mvp.support.microsoft.com/profile/raffaele
    UGIdotNET - http://www.ugidotnet.org/


    Raffaele Rialdi [MVP] My articles and videos: http://www.iamraf.net Italian blog: http://blogs.ugidotnet.org/raffaele
    • Contrassegnato come risposta bit72 martedì 31 maggio 2011 09:36
    martedì 31 maggio 2011 07:02
  • Grazie tante per il chiarimento, purtroppo ciò che mi consigli non è alla mia portata, proverò ad implementare la funzione aiutandomi con un file temporaneo e facendo il dispose anche su m.

    Ciao a tutti.

    martedì 31 maggio 2011 09:36
  • bit72 wrote:

    Grazie tante per il chiarimento, purtroppo ciò che mi consigli non è alla mia portata, proverò ad implementare la funzione aiutandomi con un file temporaneo e facendo il dispose anche su m.

    Però così rallenti di parecchio la conversione.
    Quello che stai facendo è assolutamente possibile. Si tratta solo di identificare dove fare la dispose di m (cioè trovare il momento in cui non ti serve più)


    Ciao a tutti.

    Ciao


    Raffaele Rialdi  http://www.iamraf.net
    Weblog: http://blogs.ugidotnet.org/raffaele
    Microsoft MVP profile https://mvp.support.microsoft.com/profile/raffaele
    UGIdotNET - http://www.ugidotnet.org/


    Raffaele Rialdi [MVP] My articles and videos: http://www.iamraf.net Italian blog: http://blogs.ugidotnet.org/raffaele
    martedì 31 maggio 2011 11:49
  • Ok, m mi serve finchè non restituisce l'immagine con la filigrana, cioè alla fine della funzione (return m).

    Allora dovrei modificare la funzione eliminando il return e fornendo il contenuto di m in un altro modo?

    martedì 31 maggio 2011 13:56
  • bit72 wrote:

    Ok, m mi serve finchè non restituisce l'immagine con la filigrana, cioè alla fine della funzione (return m).

    Allora dovrei modificare la funzione eliminando il return e fornendo il contenuto di m in un altro modo?

    Forse non capisco il flusso della tua applicazione...

    Avevi scritto nel primo messaggio che volevi convertire un'immagine e salvarla in un'altra cartella.
    Quindi nel metodo che hai postato fai la conversione e restituisci un'immagine. Fin qui tutto ok
    Il metodo chiamante riceve l'immagine e immagino che la salverai su disco.
    A questo punto l'immagine ti serve ancora? Oppure la mostri in un controllo?

    Se non ti serve, chiami la dispose subito dopo averla salvata.
    Se ti serve perché la mostri in un controllo la dispose dovrai chiamarla subito prima di disfartene per mostrare l'immagine successiva.

    Diciamo che tu abbia la picturebox che mostra l'immagine "vecchia". Devi solo fare la dispose della vecchia:
    var img = pbox.Image
    pbox.Image = newImage
    if(img != null) img.Dispose();


    Raffaele Rialdi  http://www.iamraf.net
    Weblog: http://blogs.ugidotnet.org/raffaele
    Microsoft MVP profile https://mvp.support.microsoft.com/profile/raffaele
    UGIdotNET - http://www.ugidotnet.org/


    Raffaele Rialdi [MVP] My articles and videos: http://www.iamraf.net Italian blog: http://blogs.ugidotnet.org/raffaele
    • Contrassegnato come risposta bit72 martedì 31 maggio 2011 15:36
    martedì 31 maggio 2011 14:23
  • Si avevi capito perfettamente, le immagini una per volta, dopo aver inserito la filigrana vengono riprese da una funzione che le riduce di dimensione e poi salvate senza visualizzzarle.

    Per chiamare m.dispose devo quindi dichiarare m al di fuori della funzione inserisciFiligrana !?

    martedì 31 maggio 2011 15:36
  • bit72 wrote:

    Si avevi capito perfettamente, le immagini una per volta, dopo aver inserito la filigrana vengono riprese da una funzione che le riduce di dimensione e poi salvate senza visualizzzarle.

    Per chiamare m.dispose devo quindi dichiarare m al di fuori della funzione inserisciFiligrana !?

    Il metodo che hai postato restituisce un'immagine, quindi il chiamante farà riferimento a quell'immagine e la salverà su disco, giusto?
    Dopo averla salvata, chiama la dispose


    Raffaele Rialdi  http://www.iamraf.net
    Weblog: http://blogs.ugidotnet.org/raffaele
    Microsoft MVP profile https://mvp.support.microsoft.com/profile/raffaele
    UGIdotNET - http://www.ugidotnet.org/


    Raffaele Rialdi [MVP] My articles and videos: http://www.iamraf.net Italian blog: http://blogs.ugidotnet.org/raffaele
    • Contrassegnato come risposta bit72 martedì 31 maggio 2011 22:44
    martedì 31 maggio 2011 16:58

  • Dopo averla salvata, chiama la dispose



    Non capisco:

     

    il metodo restituisce l'immagine tramite la variabile m;

    se chiamo m.dispose() ottengo un errore perchè m non esiste all'esterno del metodo.

     

    martedì 31 maggio 2011 22:43
  • bit72 wrote:


    Dopo averla salvata, chiama la dispose

    --

    Non capisco:

     

    il metodo restituisce l'immagine tramite la variabile m;

    se chiamo m.dispose() ottengo un errore perchè m non esiste all'esterno del metodo.

     

    Posta il codice con cui chiami la funzione che hai postato ...


    Raffaele Rialdi  http://www.iamraf.net
    Weblog: http://blogs.ugidotnet.org/raffaele
    Microsoft MVP profile https://mvp.support.microsoft.com/profile/raffaele
    UGIdotNET - http://www.ugidotnet.org/


    Raffaele Rialdi [MVP] My articles and videos: http://www.iamraf.net Italian blog: http://blogs.ugidotnet.org/raffaele
    mercoledì 1 giugno 2011 06:30

  • Posta il codice con cui chiami la funzione che hai postato ...



    Ecco di seguito il codice in cui si effettua la chiamata :

     if ((chbFiligrana.Checked == true) && (pbLogo.Image != null))
             {
               immag = inserisciFiligrana(nomeFileSorgente, txtBufferLogo.Text);
             }

    di sotto, se può aiutare, posto tutto il metodo.

    void infoForm_resizeOK(object sender, ResizeInfoEventArgs e)
      {
       
       String nomeFile = "";
       String nomeFileDest = "";
       String Estensione = "";
       String nomeFileSorgente = "";
       int i=0;
    
       
         // Creo un array di stringhe (files) che assume il nome di ogni file della cartella sorgente
         // grazie al contatore s
    
       
       this.Text = "Elaborazione in corso...";
       lblElaborazioneInCorso.Visible = true;
    
       try
       {
         string[] files = System.IO.Directory.GetFiles(txtCartellaSorgente.Text);
         this.progressBar1.Minimum = 0;
         this.progressBar1.Maximum = files.Length;
    
         foreach (string s in files)
         {
    
           nomeFile = Path.GetFileName(s);
           Estensione = nomeFile.ToUpper();
    
           if (Estensione.EndsWith(".JPG")||Estensione.EndsWith(".TIF")||Estensione.EndsWith(".BMP")||Estensione.EndsWith(".PNG"))
           {
    
             i++;
             this.progressBar1.Focus();
             this.progressBar1.Value = i;
             
             nomeFileDest = System.IO.Path.Combine(txtCartellaDestinazione.Text, nomeFile);
    
             //Crea un'immagine ridimensionata e la salva nella cartella destinazione
             nomeFileSorgente = System.IO.Path.Combine(txtCartellaSorgente.Text, nomeFile);
             
                      
             // se è stato impostata l'opzione filigrana, allora applicala al file prima di salvarlo
             Image immag = Image.FromFile(nomeFileSorgente);
    
             if ((chbFiligrana.Checked == true) && (pbLogo.Image != null))
             {
               immag = inserisciFiligrana(nomeFileSorgente, txtBufferLogo.Text);
             }
             
               
             
             img = this.resizeImage(immag, new Size(e.Width, e.Height));
          
             nomeFileDest = Path.ChangeExtension(nomeFileDest, "jpg");
             this.saveJpeg(nomeFileDest, new Bitmap(img), 85L);
             Application.DoEvents();
             
             img.Dispose();
             immag.Dispose();
    
    
             // System.IO.File.Copy(nomeFileSorgente, nomeFileDest, true); copia i file senza modifiche
    
           }
    
    
         }
    
         if (MessageBox.Show("Vuoi aprire la cartella creata", "Operazione terminata.", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
         {
           ApriCartellaDestinazione();
         }
       }
       catch (Exception ex)
       {
         MessageBox.Show(ex.Message , "Errore!!!",MessageBoxButtons.OK, MessageBoxIcon.Error);
       }
    
    
        this.Text = "Resize";
        progressBar1.Value = 0; 
        lblElaborazioneInCorso.Visible = false;
    
      }

    mercoledì 1 giugno 2011 09:43
  • bit72 wrote:

    Ecco di seguito il codice in cui si effettua la chiamata :

    Il codice è parecchio incricchiato ...

    foreach (string s in files) { nomeFile = Path.GetFileName(s); Estensione = nomeFile.ToUpper(); if (Estensione.EndsWith(".JPG")||Estensione.EndsWith(".TIF")||Estensione.EndsWith(".BMP")||Estensione.EndsWith(".PNG")) { i++; this.progressBar1.Focus(); this.progressBar1.Value = i; nomeFileDest = System.IO.Path.Combine(txtCartellaDestinazione.Text, nomeFile); //Crea un'immagine ridimensionata e la salva nella cartella destinazione nomeFileSorgente = System.IO.Path.Combine(txtCartellaSorgente.Text, nomeFile); // se è stato impostata l'opzione filigrana, allora applicala al file prima di salvarlo Image immag = Image.FromFile(nomeFileSorgente); if ((chbFiligrana.Checked == true) && (pbLogo.Image != null)) { immag = inserisciFiligrana(nomeFileSorgente, txtBufferLogo.Text); }

    Se passa dentro l'"if" riassegni immag due volte, il che è uno spreco di tempo.

    img = this.resizeImage(immag, new Size(e.Width, e.Height));

    Se fai il resize dopo aver applicato la filigrana, la filigrana sarà orribile perhcé è testo e il resize di tipo bitmap impoverisce il testo

    nomeFileDest = Path.ChangeExtension(nomeFileDest, "jpg"); this.saveJpeg(nomeFileDest, new Bitmap(img), 85L);

    Ed ecco l'immagine di cui non fai il dispose e che con tutta probabilità scatena l'eccezione dopo "n" volte che la chiami: new Bitmap(img)

    Application.DoEvents(); img.Dispose(); immag.Dispose(); // System.IO.File.Copy(nomeFileSorgente, nomeFileDest, true); copia i file senza modifiche } }

    Infine dovresti lanciare tutto questo codice utilizzando un BackgroundWorker in modo da usare un altro thread ed evitare di bloccare l'interfaccia utente quando trasformi tante immagini.


    Raffaele Rialdi  http://www.iamraf.net
    Weblog: http://blogs.ugidotnet.org/raffaele
    Microsoft MVP profile https://mvp.support.microsoft.com/profile/raffaele
    UGIdotNET - http://www.ugidotnet.org/


    Raffaele Rialdi [MVP] My articles and videos: http://www.iamraf.net Italian blog: http://blogs.ugidotnet.org/raffaele
    • Contrassegnato come risposta bit72 mercoledì 1 giugno 2011 15:34
    mercoledì 1 giugno 2011 12:10
  • questa operazione la fa anche se disattivo la filigrana, cioè:

     

    prendo 100 foto e faccio solo il ridimensionamento e salvataggio,

    this.saveJpeg(nomeFileDest, new Bitmap(img), 85L); 

    ho provato anche con tif ad alta risoluzione, con 300 file senza problemi.

    Se attivo la filigrana non riesce a fare nemmeno 10 foto

    e si pianta con l'errore che lamento, evidenziando questa riga

    graphics.DrawImageUnscaled(imgFoto, 0, 0);

    che si trova all'interno di

    private Image inserisciFiligrana(string foto, string logo)

    vedi primo post.

    Praticamente si blocca solo se attivo l'opzione filigrana, altrimenti posso ridurre tutte le immagini che voglio senza problemi

    mercoledì 1 giugno 2011 15:49
  • bit72 wrote:

    questa operazione la fa anche se disattivo la filigrana, cioè:

     
    prendo 100 foto e faccio solo il ridimensionamento e salvataggio,

    this.saveJpeg(nomeFileDest, new Bitmap(img), 85L); 

    ho provato anche con tif ad alta risoluzione, con 300 file senza problemi.

    Se attivo la filigrana non riesce a fare nemmeno 10 foto
    e si pianta con l'errore che lamento, evidenziando questa riga

    graphics.DrawImageUnscaled(imgFoto, 0, 0);

    che si trova all'interno di

    private Image inserisciFiligrana(string foto, string logo)

    vedi primo post.

    Questi test non sono attendibili perché tutti gli oggetti non referenziati che possiedono un finalizzatore vengono messi in coda di finalizzazione che poi chiama la Dispose. Per cui è come una roulette russa.

    Si può capire con precisione cosa provoca il problema utilizzando un profiler di memoria con quel codice.
    Un altro strumento utile all'indagine è il performance monitor (perfmon di windows) che ti permette di vedere l'attività del GC e la quantità di memoria allocata/utilizzata.

    Praticamente si blocca solo se attivo l'opzione filigrana, altrimenti posso ridurre tutte le immagini che voglio senza problemi

    Quello della bitmap è comunque un errore a prescindere che non sia la causa primaria del problema.
    Il codice che hai postato ha comunque lati oscuri, per esempio non capisco perché chiami la Graphics.Save o fai due volte Image.FromFile dello stesso file disegnando la foto sopra se stessa.

    Se ti può essere di aiuto, qui trovi un po' di codice su come effettuare operazioni classiche usando GDI+:
    http://www.bobpowell.net/faqmain.htm


    Raffaele Rialdi  http://www.iamraf.net
    Weblog: http://blogs.ugidotnet.org/raffaele
    Microsoft MVP profile https://mvp.support.microsoft.com/profile/raffaele
    UGIdotNET - http://www.ugidotnet.org/


    Raffaele Rialdi [MVP] My articles and videos: http://www.iamraf.net Italian blog: http://blogs.ugidotnet.org/raffaele
    • Contrassegnato come risposta bit72 giovedì 2 giugno 2011 18:08
    giovedì 2 giugno 2011 16:05
  • Graizie 1000 per l'aiuto.

    Cercherò di studiare bene l'utilizzo delle operazioni con le gdi+ dal link che suggerisci.

    giovedì 2 giugno 2011 18:11