Frage

Ich versuche, eine leichtgewichtige Bildüberprüfungs- Anwendung zu schreiben. Allerdings gibt es Systemspeicher Einschränkungen mit .NET.

Beim Versuch, große Bitmaps ( 9000 x 9000 px oder größer, 24-Bit) zu laden, erhalte ich eine System.OutOfMemoryException. Dies ist auf einem Windows 2000-PC mit 2 GB RAM (davon 1,3 GB aufgebraucht ist). Es braucht auch viel Zeit, um die Dateien zu versuchen, zu laden.

Der folgende Code erzeugt diesen Fehler:

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

Wie hat diesen Code:

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

Auch ist es genug, um dies zu tun, nur:

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

Dieser Code wurde für die Verwendung mit GDI bestimmt. Während dieser Forschung, fand ich heraus, dass dies in der Tat ist ein Speicher Problem, bei dem .NET doppelt so viel zu verteilen versucht, wie in einem einzigen contigous Speicherblock benötigt wird.

http://bytes.com/groups/net-c/ 279.493-Zeichnung-large-Bitmaps

Ich weiß von anderen Anwendungen (Internet Explorer, MS Paint etc.), dass es möglich ist, große Bilder zu öffnen, und ziemlich schnell. Meine Frage ist, wie kann ich verwenden, um große Bitmaps mit .NET?

Gibt es trotzdem, sie zu streamen oder Nicht-Speicher laden sie?

War es hilfreich?

Lösung

Dies ist eine zweiteilige Frage. Die erste Frage ist, wie man große Bilder ohne Lauf aus dem Speicher geladen werden kann (1), ist die zweite Ladeleistung zu verbessern (2).

(1) Concider einer Anwendung wie Photoshop, wo Sie die Möglichkeit haben, arbeiten mit großen Bildern gigabites auf dem Dateisystem raubend. Halten Sie das gesamte Bild im Speicher und noch genügend freien Speicher müssen Operationen (Filter, Bildverarbeitung und so weiter, oder auch nur das Hinzufügen Schicht) durchführen würde auf den meisten Systemen nicht möglich sein (auch 8gb x64-Systeme).

Deshalb Anwendungen wie dies das Konzept der Auslagerungsdateien verwendet. Intern Ich gehe davon aus, dass Photoshop ein proprietäres Dateiformat, geeignet für ihre Anwendung Design und gebaut verwendet Teilladungen aus dem Swap zu unterstützen, so dass sie Teile einer Datei in dem Speicher zu laden, sie zu verarbeiten.

(2) Performande verbessert werden (ziemlich viel) durch für jedes Dateiformat benutzerdefinierte Lader zu schreiben. Dies erfordert, dass Sie auf die Datei-Header zu lesen, und die Struktur der Dateiformate, die Sie bearbeiten möchten. Sobald Sie die Hand bekommen es seine nicht **** **** dass hart, aber es ist nicht so trivial, wie ein Methodenaufruf zu tun.

Zum Beispiel könnten Sie für FastBitmap google Beispiele auf, um zu sehen, wie Sie ein Bitmap laden kann (BMP-Datei) sehr schnell, enthalten sie die Bitmap-Header decodiert. Dies beinhaltet die pinvoke und Ihnen eine Vorstellung geben, was Sie sind gegen Sie die Bitmap-structues wie

müssen definieren
        [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;
        }

Möglicherweise arbeitet mit einem DIB zu schaffen ( http://www.herdsoft.com/ti /davincie/imex3j8i.htm ) und Seltsamkeiten wie Daten gespeichert werden „upside down“ in einer Bitmap, die Sie berücksichtigen müssen, oder Sie werden ein Spiegelbild sehen, wenn u es öffnen: -)

Nun, das ist nur für Bitmaps. Angenommen, Sie wollten PNG tun, dann müssten Sie ähnliche Dinge zu tun, aber die PNG-Header Decodierung, die in ihrer einfachsten Form ist nicht so schwer, aber wenn Sie die volle PNG-Spezifikation Unterstützung erhalten möchten, dann sind Sie in für eine lustige Fahrt: - )

PNG unterscheidet sich ein Bitmap zu sagen, da es ein Stück basiertes Format verwendet, wo es „Header“ können Sie loacate die diffrent Daten zu finden. Beispiel einiger Brocken ich verwenden, während mit dem Format spielen war

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

Sie werden auch über Adler32 Prüfsummen für PNG-Dateien zu lernen. So ist jedes Dateiformat Sie würden wollen, eine andere Reihe von Herausforderungen möchte hinzufügen, tun.

Ich wünsche, ich könnte mehr kompletten Quellcode-Beispiele in meiner Antwort geben, aber es ist ein komplexes Thema, und um ehrlich zu sein, ich nicht eine Swap umgesetzt habe ich so würde ich nicht in der Lage sein, zu viel solide Beratung zu geben, dass .

Die kurze Antwort ist, dass die Bildverarbeitung in der Leistungsziffern BCL ist nicht so heiß. Die mittlere Antwort wäre zu versuchen und zu finden, wenn jemand ein Bild Bibliothek geschrieben hat, die Sie und die lange Antwort helfen könnte, wäre die Ärmel hochziehen und den Kern Ihrer Anwendung selbst schreiben.

Da Sie mich im wirklichen Leben wissen Sie wissen, wo ich zu finden;)

Andere Tipps

Für eine wirklich umfassende Antwort, ich Reflector auf den Quellcode von Paint.NET suchen verwenden würden ( http: / /www.getpaint.net/ ); ein erweiterte Bildbearbeitungsprogramm in C # geschrieben.

(wie im Kommentar erwähnt, verwendet Paint.NET Open Source zu sein, ist aber jetzt geschlossen Quelle).

Was ist mit:

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

nur eine schnelle Lösung, ich hatte das gleiche Problem, habe ich eine zweite Bitmap-Instanz und übergeben Sie die Bitmap im Konstruktor.

Können Sie eine neue, leere, Bitmap mit den gleichen Abmessungen und Farbtiefe schaffen? Wenn das der Fall ist, wissen Sie zumindest, dass die Umgebung um das Bild verarbeiten kann. Dann liegt das Problem in der Bildlade Subsystem, wie natürlich Ihr Link angezeigt könnte der Fall sein.

Ich denke, Sie Ihre eigenen Bitmap-Ladern schreiben könnten, aber das ist eine Menge Arbeit für nicht-triviale Formate, so würde ich es nicht vorschlagen.

Vielleicht gibt es Ersatz-Bibliotheken zur Verfügung, die Arbeit um diese Probleme mit den Standardlader?

Sie sagen also, dass es nicht das Laden der Bitmap ist aber die Wiedergabe, die einen aus dem Speicher verursacht?

Wenn ja, können Sie Bitmap.LockBits verwenden ahold der Pixel zu erhalten und schreiben ein Grundbild selbst Resizer?

Eine Sache, schlug nur ich. Sind Sie das gesamte Bild zeichnen und nicht nur den sichtbaren Teil? Sie sollten nicht einen größeren Teil des Bildes ziehen, als Sie in Ihrer Anwendung angezeigt werden, verwenden Sie die x, y, Breite und Höhe Parameter den gezogenen Bereich zu beschränken.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top