2010-10-02 12 views
12

¿Es posible utilizar el método FromStream de System.Drawing.Image sin tener que mantener la secuencia abierta durante el tiempo de vida de la imagen?Cargando una imagen de una secuencia sin mantener la secuencia abierta

Tengo una aplicación que carga un montón de gráficos de la barra de herramientas de los archivos de recursos, usando una combinación de Image.FromStream y Assembly.GetManifestResourceStream.

El problema que tengo es que, aunque funciona bien en Windows 7, en Windows XP, la aplicación se bloquea si un elemento de la interfaz de usuario vinculado a una de estas imágenes está deshabilitado. En Windows 7, la imagen se muestra en escala de grises. En XP, se bloquea con una excepción de falta de memoria.

Después de un montón de capullo de cabello, finalmente lo he rastreado hasta la carga inicial de la imagen. Como una cuestión de rutina, si puedo crear cualquier objeto que implementa IDisposable que también se destruye en el mismo método, me envuelvo en una instrucción using, por ejemplo

using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName)) 
{ 
    image = Image.FromStream(resourceStream); 
} 

Si quito la instrucción using para que el ISN corriente no dispuesto, entonces la aplicación ya no se bloquea en XP. Pero ahora tengo un montón de secuencias "huérfanas" que cuelgan: las imágenes se almacenan en clases de comando y estas eliminan correctamente las imágenes cuando se eliminan, pero la transmisión original no está dispuesta.

Revisé la documentación para FromStream y confirma que la transmisión debe permanecer abierta. ¡Por qué esto no se ha estropeado y no se ha quemado en el sistema de desarrollo de Windows 7 es un misterio, sin embargo!

Realmente no quiero esta secuencia dando vueltas, y ciertamente no quiero tener que almacenar una referencia a esta secuencia así como a la imagen para poder deshacerme de ella más tarde. Solo necesito esa secuencia una vez, así que quiero deshacerme de ella :)

¿Es posible crear la imagen y luego matar la secuencia de vez en cuando?

+3

Por el manera, una 'OutOfMemoryException' en' System.Drawing' usualmente significa * error genérico * en GDI +. El motivo es [histórico] (http://stackoverflow.com/questions/2610416/is-there-a-reason-image-fromfile-throws-an-outofmemoryexception-for-an-invalid-im) y se debe al mapeo de códigos de error no gestionados. –

+0

Si la transmisión que pasa a Image.FromStream no se puede buscar, puede cerrar la secuencia de forma segura. Pero este es un comportamiento no documentado, así que utilícelo bajo su propio riesgo. – user2452157

Respuesta

19

La razón la corriente tiene que ser abierta es la following:

GDI +, y por lo tanto la System.Drawing espacio de nombres, puede diferir la decodificación de bits de imagen en bruto hasta que los bits son requeridos por la imagen . Además, incluso después de que la imagen ha sido decodificada, GDI + puede determinar que es más eficiente descartar la memoria para un mapa de bits grande y volver a decodificar más tarde. Por lo tanto, GDI + debe tener acceso a los bits de origen para la imagen durante la vida del objeto Bitmap o Image.

La solución documentado es crear ya sea una imagen no indexada utilizando Graphics.DrawImage o para crear un Bitmap indexadas de la imagen original tal como se describe aquí:

Bitmap and Image constructor dependencies

+0

¡Gracias por la respuesta extremadamente útil! Sabía de archivos de bloqueo de FromFile, pero nunca supe el motivo hasta ahora. Probé usando el enfoque Crear una imagen no indexada que funcionó bien y la aplicación ya no se cuelga en mi máquina virtual XP. Volveré a probar con el método Indexado y veré qué sucede; no tengo clara la diferencia entre los dos tipos. –

+2

Fwiw: corrigieron varios problemas con los formatos de píxeles indexados en la versión de Vista de gdiplus.dll. Es bueno que lo hagan, pero un dolor de cabeza cuando su código necesita ejecutarse en XP. En general, manténgase alejado de ellos para evitar este problema. –

0

Puede guardar la secuencia en un archivo temporal y usar el método Image.FromFile. O simplemente no incruste la imagen, consérvela como un archivo y cárguela desde este archivo en tiempo de ejecución.

+0

Gracias por la respuesta, aunque esto es algo que ya había descartado, ya que sé por experiencia que esto bloquea el archivo, por lo tanto, no podría eliminarlo hasta que la aplicación haya finalizado. –

2

De acuerdo con la documentación de Image.FromStream, la transmisión debe mantenerse abierta mientras la imagen está en uso. Por lo tanto, incluso si el cierre funcionó (y no hay nada que decir que no se puede cerrar una transmisión antes de que se elimine, por lo que respecta al objeto de transmisión en sí), puede que no sea un enfoque muy confiable.

Puede copiar la imagen a otro objeto de imagen y usarla. Sin embargo, es probable que requiera más memoria que solo mantener la secuencia abierta.

+0

Gracias por la respuesta. Esto es con lo que he trabajado, utilizando el artículo de KB vinculado anteriormente que proporciona las razones de por qué. –

+0

También detalla, aunque en algunos casos puede ser más eficiente mantener el flujo, lo que vale la pena tener en cuenta. –

Cuestiones relacionadas