2010-06-25 10 views
5

Estoy trabajando con imágenes de gran tamaño (por ejemplo, 16000x9440 px) y recorté algunas regiones para otras cosas. Estoy recibiendo una excepción "Memoria insuficiente" cuando se crea una nueva instancia de Bitmap:Error de memoria insuficiente al cargar un mapa de bits

using (FileStream fileStream = new FileStream(mapFileResized, FileMode.Open)) 
{ 
    byte[] data = new byte[fileStream.Length]; 
    fileStream.Read(data, 0, data.Length); 
    using (MemoryStream memoryStream = new MemoryStream(data)) 
    { 
     using (Bitmap src = new Bitmap(memoryStream)) // <-- exception 
     { 
      tile = new Bitmap(tileWidth, tileHeight, PixelFormat.Format24bppRgb); 
      tile.SetResolution(src.HorizontalResolution, src.VerticalResolution); 
      tile.MakeTransparent(); 
      using (Graphics grRect = Graphics.FromImage(tile)) 
      { 
       grRect.CompositingQuality = CompositingQuality.HighQuality; 
       grRect.SmoothingMode = SmoothingMode.HighQuality; 
       grRect.DrawImage(
         src, 
         new RectangleF(0, 0, tileWidth, tileHeight), 
         rTile, 
         GraphicsUnit.Pixel 
       ); 
      } 
     } 
    } 
} 

Cuando uso pequeños tamaños de las imágenes a continuación, todos muy bien el trabajo (por ej 8000x4720 px.).

¿Cómo puedo trabajar con imágenes de gran tamaño?

mosaico PS El mapa de bits está dispuesto en el bloque final.

Saludos cordiales, Alex.

Respuesta

3
No

una respuesta completa a su pregunta, pero usted es probablemente mejor de la utilización de una biblioteca como ImageMagick.NET

+0

Tiene el mismo problema. –

+0

De acuerdo con la página de arquitectura (http://www.imagemagick.org/script/architecture.php#tera-pixel) ImageMagick puede "leer, procesar o escribir tamaños de imágenes mega, giga o tera-pixel". No he intentado esto sin embargo. –

2

MemoryStream se implementa utilizando una matriz de bytes que almacena los datos. Si lee más datos de los que puede contener la matriz, se asigna una nueva matriz de tamaño doble y los bytes se copian de una matriz a la otra.

Dado que aparentemente sabe la cantidad de datos que va a necesitar, puede asignar el tamaño correcto por adelantado y así evitar el cambio de tamaño.

Sin embargo, una vez que alcance un determinado tamaño, se le agotará la memoria. .NET impone un límite de 2 GB en un solo objeto (even on 64 bit), por lo que la matriz interna en MemoryStream nunca podrá crecer más allá de eso. Si su imagen es más grande obtendrá una excepción de falta de memoria.

6

Usted está utilizando alrededor de un gigabyte de ram, no es sorprendente que se quede sin memoria.

Suponiendo que se utiliza una de Formatos de 32 bpp con 16000x9440 píxel se obtiene un tamaño de archivo de alrededor:

16000 * 9440 * (32/8) = ~ 576 MB

byte[] data = new byte[fileStream.Length]; 
fileStream.Read(data, 0, data.Length); 
using (MemoryStream memoryStream = new MemoryStream(data)) 
{ 
    [... snip ...] 
} 

Se carga el archivo completo en una flujo de memoria, esto requiere 576MB.

[... snip ...] 
    using (Bitmap src = new Bitmap(memoryStream)) // <-- exception 
    { 
     [... snip ...] 
    } 
[... snip ...] 

se carga todo el contenido de flujo en un mapa de bits, esto requiere al menos 576 MB otro (dependiendo de la cantidad de memoria el mapa de bits por píxel requiere, debe ser de al menos 4, además probablemente más). En ese punto, tienes la imagen dos veces en la memoria, lo que daña seriamente esas imágenes tan grandes.

Puede reducir la huella de memoria eliminando la secuencia de memoria y cargando el mapa de bits directamente desde la secuencia de archivos.

Otra solución sería cargar solo una parte del mapa de bits y cargar las otras partes bajo demanda (al igual que Google Maps), pero no puedo ayudarlo con esa solución, podría requerir leer el mapa de bits manualmente.

+0

+1 por, además de explicar cuál es el problema, ofrecer alternativas. – Aistina

+0

Thx por consejo, eliminé la declaración de MemoryStream y cargué Bitmap directamente desde fileStream: usando (Bitmap src = new Bitmap (fileStream)). Pero no ayudó = (Tengo un Windows 7 x64 y más de 5 GB de VRAM como gratis. Solución con el procedimiento de carga parcial suena bien, tal vez puede ser útil. –

+1

Esto no lo explica, a. El programa NET puede asignar fácilmente más de 1 gigabyte de memoria. –

Cuestiones relacionadas