Domanda

Sto cercando di scrivere un leggero applicazione di visualizzazione delle immagini. Tuttavia, vi sono limitazioni di memoria sistema con NET.

Quando si cerca di caricare bitmap di grandi dimensioni ( 9000 x 9000 px o più grande, 24-bit), ottengo uno System.OutOfMemoryException. Questo è su un 2000 PC Windows con 2GB di RAM (di cui 1,3 GB è esaurito). Ci vuole anche un sacco di tempo per tentare il caricamento dei file.

Il codice seguente genera questo errore:

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

Come funziona questo codice:

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

Inoltre, è sufficiente fare proprio questo:

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

Il secondo codice è stato progettato per essere utilizzato con GDI. Mentre la ricerca di questo, ho scoperto che questo è in realtà un problema di memoria in cui .NET tenta di allocare il doppio di quanto è necessario in un unico blocco contigui di memoria.

http://bytes.com/groups/net-c/ 279493-disegno-grande-bitmap

Lo so da altre applicazioni (Internet Explorer, MS Paint, ecc), che è possibile aprire immagini di grandi dimensioni, e piuttosto rapidamente. La mia domanda è, Come si usa bitmap di grandi dimensioni con .NET?

Esiste un modo per lo streaming di loro, o non-memoria caricarli?

È stato utile?

Soluzione

Questa è una domanda in due parti. La prima domanda è: come è possibile caricare immagini di grandi dimensioni, senza esaurire la memoria (1), la seconda è sul miglioramento delle prestazioni di carico (2).

(1) considerate questo un programma come Photoshop, dove si avrà la possibilità di lavorare con grandi immagini che consumano gigabites sul filesystem. Mantenere l'intera immagine in memoria e avere ancora abbastanza memoria libera per eseguire operazioni (filtri, elaborazione di immagini e così via, o anche solo l'aggiunta di strati) sarebbe impossibile sulla maggior parte dei sistemi (anche sistemi x64 8gb).

Ecco perché applicazioni come questo utilizza il concetto di file di swap. Internamente sto supponendo che Photoshop utilizza un formato proprietario, adatto per la progettazione di applicazioni e costruita per supportare carichi parziali allo swap, consentendo loro di caricare parti di un file nella memoria di elaborarlo.

(2) Performande può essere migliorata (un bel po '), scrivendo caricatori personalizzati per ogni formato di file. Ciò richiede di leggere sulle intestazioni dei file e la struttura dei formati di file che si desidera lavorare. Una volta che hai ottenuto la parte di esso la sua non **** che **** difficile, ma non è così banale come fare una chiamata di metodo.

Per esempio si potrebbe google per FastBitmap per vedere alcuni esempi su come si può caricare una bitmap (BMP) file molto veloce, ha incluso la decodifica l'intestazione bitmap. Ciò ha comportato PInvoke e per darvi qualche idea su ciò che si è di fronte è necessario definire le structues bitmap come

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

Forse lavorare con la creazione di un DIB ( http://www.herdsoft.com/ti /davincie/imex3j8i.htm ) e stranezze come i dati vengano memorizzati "a testa in giù" in una bitmap, che è necessario prendere in considerazione o che vedrete un'immagine speculare quando u aprirlo: -)

Ora che è solo per le bitmap. Diciamo che si voleva fare PNG, allora avresti bisogno di fare cose simili, ma la decodifica l'intestazione PNG, che nella sua forma più semplice isnt così difficile, ma se si vuole ottenere il pieno supporto specifiche PNG allora siete dentro per un giro di divertimento: - )

PNG è diverso da dire una bitmap in quanto utilizza un formato basato pezzo in cui ha "header" è possibile loacate per trovare i dati differenti. Esempio di alcuni pezzi che ho usato durante il gioco con il formato è stato

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

Siete anche andando ad avere per conoscere checksum Adler32 per i file PNG. Così ogni formato di file che ci si vuole fare sarebbe aggiungere un diverso insieme di sfide.

Vorrei davvero che potrei dare esempi più completi di codice sorgente nella mia risposta, ma è un argomento complesso, e ad essere onesti non ho implementato uno scambio di me così io non sarebbe in grado di dare troppi consigli solida su quel .

La risposta breve è che i cababilities elaborazione delle immagini del BCL non è così caldo. La risposta media sarebbe quella di cercare e trovare se qualcuno ha scritto una libreria di immagini che potrebbe aiutare voi e la risposta lunga potrebbe essere quella di tirare sulle maniche e scrivere il nucleo della vostra applicazione voi stessi.

Dal momento che tu mi conosci nella vita reale si sa dove trovarmi;)

Altri suggerimenti

Per una risposta davvero esauriente, vorrei utilizzare Reflector di guardare il codice sorgente di Paint.NET ( http: / /www.getpaint.net/ ); un programma di editing grafica avanzata scritto in C #.

(come sottolineato nel commento, Paint.NET utilizzato per essere open source, ma ora è closed source).

Che dire:

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

solo una soluzione rapida, ho avuto lo stesso problema, ho creato una seconda istanza bitmap e superato il bitmap nel costruttore.

Si può creare un nuovo, vuoto, bitmap delle stesse dimensioni e profondità di colore? Se questo è il caso, è almeno sapere che l'ambiente in grado di gestire l'immagine. Allora il problema risiede nel sottosistema caricamento delle immagini, come naturalmente il vostro link indicato potrebbe essere il caso.

Credo che si potrebbe scrivere i propri caricatori bitmap, ma che è un sacco di lavoro per i formati non banali, in modo da non suggerire.

Forse ci sono le librerie di sostituzione disponibili che risolvere questi problemi con i caricatori standard?

Quindi stai dicendo che non è il caricamento del bitmap, ma il rendering che provoca un esaurimento della memoria?

Se è così, si può utilizzare Bitmap.LockBits per ottenere ahold dei pixel e scrivere un'immagine di base Resizer te stesso?

Una cosa mi ha colpito. Stai disegnando l'intera immagine e non solo la parte visibile? Non si dovrebbe tracciare una porzione più grande dell'immagine che si sta mostrando nell'applicazione, utilizzare i parametri x, y, width e heigth per limitare l'area disegnato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top