2009-11-20 22 views
10

Tengo un objeto global de gráficos creado a partir de un panel. A intervalos regulares, se toma una imagen del disco y se dibuja en el panel usando Graphics.DrawImage(). Funciona bien para unas pocas iteraciones y luego me estoy poniendo la siguiente excepción útiles:Al dibujar una imagen: System.Runtime.InteropServices.ExternalException: Se produjo un error genérico en GDI

System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+. 
at System.Drawing.Graphics.CheckErrorStatus(Int32 status) 
at System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y) 
at System.Drawing.Graphics.DrawImage(Image image, Point point) 

descarté pérdidas de memoria, ya que disponer del objeto de la imagen cuando he terminado con ella. Sé que las imágenes no están dañadas y se pueden leer bien, ya que el programa se ejecuta correctamente durante un tiempo antes de que el panel deje de mostrarse.

Me encontré con el mismo problema al usar un PictureBox, pero esta vez al menos he recibido un error en lugar de nada.

Comprobé los objetos GDI y los objetos USER en el Administrador de tareas pero siempre están alrededor de 65 objetos de usuario y 165 objetos GDI cuando la aplicación funciona y cuando no.

Necesito llegar al fondo de esto tan pronto como y no puedo pegar puntos de interrupción en las bibliotecas del Sistema .NET y ver dónde falla exactamente la ejecución.

Gracias de antemano.

EDITAR: Este es el código de visualización:

private void DrawImage(Image image) 
{ 
    Point leftCorner = new Point((this.Bounds.Width/2) - (image.Width/2), (this.Bounds.Height/2) - (image.Height/2)); 
    _graphics.DrawImage(image, leftCorner); 
} 

el código de carga de la imagen:

private void LoadImage(string filename, ref Image image) 
{ 
    MemoryStream memoryStream = DecryptImageBinary(Settings.Default.ImagePath + filename, _cryptPassword); 

    image = Image.FromStream(memoryStream); 

    memoryStream.Close(); 
    memoryStream.Dispose(); 
    memoryStream = null; 
} 

_image es global y su referencia se actualiza en LoadImage. Se pasan como parámetros, ya que quiero cambiar las referencias globales de la menor cantidad posible de lugares y mantener los otros métodos independientes. _graphics también es global.

También tengo un control webBrowser para sitios web y, o bien mostrar una imagen o un sitio web a la vez. cuando no hay tiempo para mostrar una imagen, el código siguiente ejecuta:

webBrowser.Visible = false; 
panel.Visible = true; 
DrawImage(_image) 
_image.Dispose(); 
_image = null; 

_image hace referencia a una imagen pre-cargado.

Espero que esto ayude.

Respuesta

14

Su problema es similar a lo que pensaba, pero no del todo . Cuando está cargando la imagen, la está cargando desde un MemoryStream. Debes mantener la transmisión abierta durante toda la vida de la imagen, ver MSDN Image.FromStream.

Debe mantener la secuencia abierta durante toda la vida de la imagen.

La solución es hacer una copia de la imagen en la función FromImage:

private void LoadImage(string filename, ref Image image) 
{ 
    using (MemoryStream memoryStream = DecryptImageBinary(Settings.Default.ImagePath + filename, _cryptPassword)) 
    { 
     using (tmpImage = Image.FromStream(memoryStream)) 
     { 
     image = new Bitmap(tmpImage); 
     } 
    } 

} 

similar al problema de disponer he mencionado, la imagen se parece a trabajar y luego dejar al azar cuando la corriente subyacente es basura recolectada

+0

Lo intentaré, gracias. ¿No es necesario que eliminemos tmpImage explícitamente? ¿La eliminación de memoryStream eliminará la imagen subyacente también? – Michali

+0

Sí, debe deshacerse de tmpImage explícitamente, aunque la eliminación del memoryStream hará que la basura recopile la mayoría de los datos subyacentes. Cambié la respuesta para mostrar eso. –

+0

Gracias. Eso parece haberlo resuelto. – Michali

2

Sin un poco más de código no es suficiente para diagnosticar correctamente aquí, sin embargo, una cosa a tener en cuenta es que puede haber eliminado en la imagen su dibujo en algún momento anterior y solo después del recolector de basura se ejecuta que su código está fallando. ¿Estás usando imágenes clonadas en cualquier lugar? Una cosa que me sorprendió al aprender es que si hace una recta clone de una imagen, no está clonando el mapa de bits subyacente sobre el que se basa la imagen, solo la estructura de la imagen, para crear una copia adecuada de una imagen debe crear una nueva imagen:

var newImage = new Bitmap(img) 

como

var newImage = oldImg.Clone(); 
oldImg.Dispose(); 
... 
gr.DrawImage(newImage, new Rectangle(0,0,newImage.Width,newImage.Height); 

va a funcionar por un tiempo, pero luego fallar en algún punto al azar ...

+0

He introducido más código ahora. Espero que arroje algo de luz. – Michali

+0

Solo para aclarar las cosas, he publicado la respuesta a su problema a continuación. –

Cuestiones relacionadas