2009-02-20 18 views
11

Estoy tratando de escribir una aplicación de visualización de imágenes liviana. Sin embargo, hay limitaciones de memoria del sistema con .NET.¿Cómo uso mapas de bits grandes en .NET?

Al intentar cargar mapas de bits grandes (9000 x 9000 px o superior, 24 bits), obtengo una System.OutOfMemoryException. Esto es en una PC con Windows 2000 con 2 GB de RAM (de los cuales se agotaron 1.3 GB). También lleva mucho tiempo intentar cargar los archivos.

El siguiente código genera este error:

Image image = new Bitmap(filename); 
using (Graphics gfx = this.CreateGraphics()) 
{ 
    gfx.DrawImage(image, new Point(0, 0)); 
} 

como lo hace este código:

Stream stream = (Stream)File.OpenRead(filename); 
Image image = Image.FromStream(stream, false, false); 
using (Graphics gfx = this.CreateGraphics()) 
{ 
    gfx.DrawImage(image, new Rectangle(0, 0, 100, 100), 4000, 4000, 100, 100, GraphicsUnit.Pixel); 
} 

Además, es suficiente para hacer precisamente esto:

Bitmap bitmap = new Bitmap(filename); 
IntPtr handle = bitmap.GetHbitmap(); 

Este último código fue diseñado para usar con GDI. Mientras investigaba esto, descubrí que esto es de hecho un problema de memoria donde .NET intenta asignar el doble de lo que se necesita en un solo bloque de memoria.

http://bytes.com/groups/net-c/279493-drawing-large-bitmaps

Sé por otras aplicaciones (Internet Explorer, MS Paint, etc.) que es posible abrir imágenes grandes, y con bastante rapidez. Mi pregunta es: ¿cómo uso mapas de bits grandes con .NET?

¿Hay algún modo para transmitirlos o cargarlos sin memoria?

Respuesta

8

Esta es una pregunta de dos partes.La primera pregunta es cómo puede cargar imágenes grandes sin quedarse sin memoria (1), la segunda está mejorando el rendimiento de carga (2).

(1) concider una aplicación como Photoshop, donde usted tiene la capacidad de trabajar con imágenes de gran consumo de gigabites en el sistema de archivos. Mantener la imagen completa en la memoria y aún tener suficiente memoria libre para realizar operaciones (filtros, procesamiento de imágenes, etc., o simplemente agregar capas) sería imposible en la mayoría de los sistemas (incluso en sistemas de 8gb x64).

Es por eso que aplicaciones como esta utilizan el concepto de archivos de intercambio. Internamente, estoy asumiendo que photoshop usa un formato de archivo propietario, adecuado para el diseño de su aplicación y construido para admitir cargas parciales del intercambio, lo que les permite cargar partes de un archivo en la memoria para procesarlo.

(2) Performande se puede mejorar (mucho) escribiendo cargadores personalizados para cada formato de archivo. Esto requiere que lea los encabezados de los archivos y la estructura de los formatos de archivo con los que desea trabajar. Una vez que tienes la mano, no es tan malo, pero no es tan trivial como hacer una llamada a un método.

Por ejemplo, usted podría google para FastBitmap para ver ejemplos de cómo se puede cargar un mapa de bits (BMP) presentar muy rápido, incluyó decodificar la cabecera de mapa de bits. Esto implicó PInvoke y para darle una idea de lo que está en contra tendrá que definir los structues de mapa de bits, como

 [StructLayout(LayoutKind.Sequential, Pack = 1)] 
     public struct BITMAPFILEHEADER 
     { 
      public Int16 bfType; 
      public Int32 bfSize; 
      public Int16 bfReserved1; 
      public Int16 bfReserved2; 
      public Int32 bfOffBits; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct BITMAPINFO 
     { 
      public BITMAPINFOHEADER bmiHeader; 
      public RGBQUAD bmiColors; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct BITMAPINFOHEADER 
     { 
      public uint biSize; 
      public int biWidth; 
      public int biHeight; 
      public ushort biPlanes; 
      public ushort biBitCount; 
      public BitmapCompression biCompression; 
      public uint biSizeImage; 
      public int biXPelsPerMeter; 
      public int biYPelsPerMeter; 
      public uint biClrUsed; 
      public uint biClrImportant; 
     } 

Posiblemente trabajar con la creación de un DIB (http://www.herdsoft.com/ti/davincie/imex3j8i.htm) y rarezas como los datos que se almacenan "al revés "en un mapa de bits, que es necesario tomar en cuenta o se verá una imagen de espejo cuando u abrirlo :-)

Ahora eso es sólo para mapas de bits. Digamos que querías hacer PNG, entonces necesitarías hacer cosas similares, pero decodificando el encabezado PNG, que en su forma más simple no es tan difícil, pero si quieres obtener soporte completo para la especificación PNG, entonces te espera un divertido paseo: -)

PNG es diferente decir un mapa de bits, ya que utiliza un formato basado trozo donde tiene "cabeceras" se puede loacate para encontrar los datos diffrent. Ejemplo de algunos trozos que utilicé mientras juega con el formato era

string[] chunks = 
new string[] {"?PNG", "IHDR","PLTE","IDAT","IEND","tRNS", 
"cHRM","gAMA","iCCP","sBIT","sRGB","tEXt","zTXt","iTXt", 
"bKGD","hIST","pHYs","sPLT","tIME"}; 

Usted también va a tener que aprender sobre las sumas de comprobación Adler32 para archivos PNG. Por lo tanto, cada formato de archivo que desee hacer agregará un conjunto diferente de desafíos.

Realmente me gustaría poder dar ejemplos de código fuente más completos en mi respuesta, pero es un tema complejo, y para ser sincero, no he implementado un intercambio yo mismo, así que no podría dar demasiados consejos sólidos sobre ese.

La respuesta corta es que las capacidades de procesamiento de imágenes en el BCL no son tan altas. La respuesta mediana sería intentar y encontrar si alguien ha escrito una biblioteca de imágenes que podría ayudarlo y la respuesta más larga sería quitarse las mangas y escribir el núcleo de su aplicación usted mismo.

Desde que me conoces en la vida real ya sabes dónde encontrarme;)

0

¿Qué hay de:

Image image = new Bitmap(filename); 
using (Graphics gfx = Graphics.FromImage(image)) 
{  
// Stuff 
} 
+0

No creo que esto va a funcionar en un sistema de 32 bits basado en las limitaciones – WiiMaxx

0

sólo una solución rápida, que tenía el mismo problema, he creado una segunda instancia de mapa de bits y se pasa el mapa de bits en el constructor.

0

¿Se puede crear un nuevo mapa de bits en blanco con las mismas dimensiones y profundidad de color? Si ese es el caso, al menos sabe que su entorno puede manejar la imagen. Entonces, el problema reside en el subsistema de carga de imágenes, ya que, por supuesto, el enlace indicado podría ser el caso.

Supongo que podría escribir sus propios cargadores de mapas de bits, pero eso es mucho trabajo para formatos no triviales, así que no lo sugeriría.

Quizás haya bibliotecas de reemplazo disponibles que solucionen estos problemas con los cargadores estándar?

0

Entonces, ¿está diciendo que no es la carga del mapa de bits sino la representación la que causa la falta de memoria?

Si es así, ¿puede usar Bitmap.LockBits para obtener los píxeles y escribir un ajuste de imagen básico usted mismo?

3

Para una respuesta realmente completa, usaría Reflector para ver el código fuente de Paint.NET (http://www.getpaint.net/); un programa avanzado de edición de gráficos escrito en C#.

(como se señala en el comentario, Paint.NET solía ser de código abierto, pero ahora está cerrado).

+0

Paint.net es un programa de código cerrado desde finales de 2007 (http: //blog.getpaint.net/2007/12/04/freeware-authors-beware-of-% E2% 80% 9Cbackspaceware% E2% 80% 9D /) – zihotki

+0

Eso es muy malo. Lo edité para reflejar tu comentario. – ine

0

Una cosa simplemente me llamó la atención. ¿Estás dibujando la imagen completa y no solo la parte visible? No debe dibujar una porción más grande de la imagen de la que muestra en su aplicación, use los parámetros x, y, ancho y alto para restringir el área dibujada.

Cuestiones relacionadas