2010-06-25 13 views
5

Sto lavorando con immagini di grandi dimensioni (ad esempio 16000x9440 px) e alcune aree vengono tagliate per altre cose. Sto diventando un'eccezione "Memoria insufficiente" quando si crea una nuova istanza Bitmap:Errore di memoria insufficiente durante il caricamento di una bitmap

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 
       ); 
      } 
     } 
    } 
} 

Quando uso le piccole dimensioni delle immagini poi tutti bene il lavoro (ad es 8000x4720 px.).

Come posso lavorare con immagini di grandi dimensioni?

Tegola PS Bitmap è disposto nel blocco finally.

Cordiali saluti, Alex.

risposta

3

Non una risposta completa alla tua domanda, ma si sono probabilmente meglio di usare una libreria come ImageMagick.NET

+0

Ha lo stesso problema. –

+0

Secondo la pagina di architettura (http://www.imagemagick.org/script/architecture.php#tera-pixel) ImageMagick può "leggere, elaborare o scrivere immagini di mega-, giga- o tera-pixel". Non ho provato questo però. –

2

MemoryStream è implementato utilizzando una matrice di byte che memorizza i dati. Se si leggono più dati di quanti l'array possa contenere, viene allocata una nuova matrice di doppia dimensione e i byte vengono copiati da una matrice all'altra.

Dal momento che a quanto pare tu sai quanti dati hai bisogno, puoi allocare la dimensione corretta in anticipo e quindi evitare il ridimensionamento.

Tuttavia, una volta raggiunta una certa dimensione, si esaurirà la memoria. .NET impone un limite di 2 GB su un singolo oggetto (even on 64 bit), quindi l'array interno in MemoryStream non potrà mai crescere oltre. Se la tua immagine è più grande, otterrai un'eccezione di memoria insufficiente.

6

Si sta utilizzando circa un gigabyte di ram, non molto sorprendente che si esaurisca la memoria.

Supponendo di utilizzare un fileformat 32bpp con 16000x9440 pixel si ottiene uno spazio di circa:

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

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

Si carica l'intero file in un flusso di memoria, questo richiede 576 MB.

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

di caricare l'intero contenuto del flusso in una bitmap, questo richiede almeno altri 576 MB (a seconda della quantità di memoria bitmap richiede per pixel, dovrebbe essere almeno 4, riordinata più). A quel punto hai l'immagine due volte in memoria che fa male seriamente per immagini così grandi.

È possibile ridurre l'ingombro di memoria eliminando il flusso di memoria e caricando la bitmap direttamente dal flusso di file.

Un'altra soluzione sarebbe quella di caricare solo una parte della bitmap e caricare le altre parti su richiesta (proprio come google maps), ma non posso aiutarti con quella soluzione, potrebbe richiedere la lettura manuale della bitmap.

+0

+1 per, oltre a spiegare qual è il problema, offrendo alternative. – Aistina

+0

Thx per un consiglio, ho rimosso la dichiarazione memoryStream e caricato Bitmap direttamente da fileStream: usando (Bitmap src = new Bitmap (fileStream)). = (Ho un Windows 7 x64 e superiore a 5 GB di VRAM gratis Soluzione con procedura di caricamento parziale suona bene, forse può essere utile –

+1

Questo non lo spiega, a. Il programma NET può facilmente allocare ben oltre 1 gigabyte di memoria –

Problemi correlati