2013-04-17 13 views
6

Non riesco proprio a capire perché sto ricevendo un'eccezione di memoria qui, anche dopo molte ricerche su vari siti Web e forum. Qualcuno è in grado di far luce sulla radice di tutti i mali in questo codice? L'eccezione viene generata dalla chiamata al metodo Graphics.DrawImage(), la linea 79.Graphics.DrawImage: Eccezione di memoria

[HttpPost] 
    [ValidateAntiForgeryToken] 
    public ActionResult EditImage(FileModel model) 
    { 
     var fileData = new MySite.Models.File(model.FileID, model.ClientID, ConfigurationManager.ConnectionStrings["MySite"].ConnectionString).Data; 
     Image image = null; 

     using (var memStream = new MemoryStream()) 
     { 
      memStream.Write(fileData, 0, fileData.Length); 
      image = Image.FromStream(memStream); 
     } 

     using (var graphics = Graphics.FromImage(image)) 
     { 
      graphics.DrawImage(image, model.x1, model.y1, (model.x2 - model.x1), (model.y2 - model.y1)); 
      graphics.Save(); 
     } 

     using (var memStream = new MemoryStream()) 
     { 
      image.Save(memStream, System.Drawing.Imaging.ImageFormat.Jpeg); 
      return File(memStream.ToArray(), "image/jpeg"); 
     } 
    } 

Stack trace:

[OutOfMemoryException: Out of memory.] 
System.Drawing.Graphics.CheckErrorStatus(Int32 status) +1143476 
System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y, Int32 width, Int32 height) +141 
ProPilot.Controllers.DocumentsController.EditImage(FileModel model) in C:\DEV\Web\Controllers\DocumentsController.cs:79 
lambda_method(Closure , ControllerBase , Object[]) +104 
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +14 
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +211 
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +27 
System.Web.Mvc.Async.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41() +28 
System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +10 
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +57 
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +48 
System.Web.Mvc.Async.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33() +57 
System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +223 
System.Web.Mvc.Async.<>c__DisplayClass37.<BeginInvokeActionMethodWithFilters>b__36(IAsyncResult asyncResult) +10 
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +57 
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +48 
System.Web.Mvc.Async.<>c__DisplayClass2a.<BeginInvokeAction>b__20() +24 
System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__22(IAsyncResult asyncResult) +102 
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +57 
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +43 
System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__18(IAsyncResult asyncResult) +14 
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23 
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62 
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +57 
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23 
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62 
System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +47 
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10 
System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__3(IAsyncResult asyncResult) +25 
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23 
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62 
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +47 
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9 
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9629296 
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155 
+3

su quale linea .. – Sayse

+2

Possiamo forse ottenere lo stacktrace? – uriDium

+0

@uriDium Ah, sì certo. Ci scusiamo per non averlo incluso immediatamente! – Maritim

risposta

9

@Sayse colpito il chiodo sulla testa con il suo commento di cui sopra.

Quando si utilizza Image.FromStream:

è necessario mantenere il flusso aperto per tutta la durata del Immagine.

Fonte: http://msdn.microsoft.com/en-AU/library/93z9ee4x.aspx

using (var memStream = new MemoryStream()) 
{ 
    memStream.Write(fileData, 0, fileData.Length); 
    using(Image image = Image.FromStream(memStream)) 
    { 
     using (var graphics = Graphics.FromImage(image)) 
     { 
      graphics.DrawImage(image, model.x1, model.y1, (model.x2 - model.x1), (model.y2 - model.y1)); 
      graphics.Save(); 
     } 

     using (var outStream = new MemoryStream()) 
     { 
      image.Save(outStream, System.Drawing.Imaging.ImageFormat.Jpeg); 
      return File(outStream.ToArray(), "image/jpeg"); 
     } 
    } 
} 
+0

Spiegheresti di più? –

+2

@minhcat_vo L'immagine si basa sul flusso di memoria disponibile per tutta la sua durata. Se il flusso di memoria è in * usando * e l'immagine è usata al di fuori dell'ambito di questo * usando * il flusso di memoria sarà già eliminato. Pertanto l'immagine non può accedervi e ottieni eccezioni come sopra. – Lummo

+0

Che design STUPID è questo? Se il file immagine è stato letto in memoria e memorizzato in un oggetto Immagine, qual è lo stream necessario fino alla fine della vita? – Elmue

1

Se si lavora con la classe Bitmap o Image troverete diversi problemi.

Se si carica un'immagine con Image.FromFile(), il framework non chiude l'handle di file dopo aver caricato l'immagine. Il file rimane aperto fino a quando il garbage collector non ricorda l'immagine. Questo è un grave errore in GDI +. Non è necessario tenere aperto un file dopo che l'immagine è già stata letta in memoria.

Quindi ho provato a ovviare a questo problema utilizzando Image.FromStream() invece. Ma questa non è una soluzione perché quando lo stream è stato chiuso l'operazione DrawImage() su quell'immagine fallirà con "Memoria insufficiente".

Quindi, se si desidera leggere, ad esempio una bitmap da un file e si vuole assicurare che l'handle di file è chiuso è necessario utilizzare una soluzione brutto come questo:

Bitmap ReadBitmapFromFile(String s_Path) 
{ 
    using (FileStream i_Stream = new FileStream(s_Path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
    { 
     using (Bitmap i_Bmp = new Bitmap(i_Stream)) 
     { 
      return new Bitmap(i_Bmp); 
     } 
    } 
} 

A proposito: Image.Clone() produce un problema simile

Invece di

Bitmap i_Clone = (Bitmap)i_Bmp.Clone() 

ho dovuto usare:?

Bitmap i_Clone = new Bitmap(i_Bmp); 
+0

Ri "Non è necessario mantenere un file aperto dopo che l'immagine è già stata letta in memoria." IMHO, Questa è una speculazione sul design interno di GDI + - Chiaramente, c'è un qualche (interno) bisogno di mantenere la fonte disponibile - Purtroppo, i documenti non spiegano PERCHE ', ma i documenti non lo fanno mai. – ToolmakerSteve

+0

Bene. Non so perché. Non lo sai neanche tu. Ma il fatto è che eseguendo il mio codice sopra avrete l'immagine in memoria e il file verrà chiuso. Che conferma la mia frase: non è necessario mantenere un file aperto dopo che l'immagine è già stata letta in memoria. – Elmue

Problemi correlati