Ich habe einen DrawingContext (Teil einer Visual oder DrawingGroup), wo ich eine Reihe von Rechtecken und / oder 1-Bit-Bildern übereinander zeichne. Stellen Sie es sich als maskierendes 1-Bit-Bild vor. Ich möchte dies in eine Bitmap-Bilddatei konvertieren.
Die Verwendung von RenderTargetBitmap
ist keine Option, da sie nur im 32-Bit-Pixel-Format rendern kann. Wenn ich also ein 20MB 1-Bit-Bild rendern muss, dann habe ich 640MB (20 * 32) Speicher auf meinem Haufen. Das erzeugt natürlich eine großartige LOH-Fragmentierung, und die Anwendung läuft auf der zweiten Aufnahme nicht mehr voll aus.
Ich brauche also eine Möglichkeit, um eine 1-Bit-Bitmap-Datei effizient aus einem Zeichnungskontext zu schreiben. Irgendwelche Ideen / Vorschläge / alternative Methoden würden geschätzt.
Eine Reihe von Ideen, einige sind ein wenig verworren ...
Sie könnten Visual
auf ein XPS-Dokument drucken.
Wenn Sie Glück haben, werden die 1-Bit-Bilder, die Sie in DrawingContext
gezeichnet haben, kombiniert und eine einzelne Bitmap in der XPS-Datei erzeugt.
Für die Rechtecke könnte es die Rechtecke als vektorbasierte Information im XPS behalten (die "Form" basierend auf Rectangle
oder DrawingContext
DrawRectangle
könnte beides tun) .... wenn das passiert, dann erstelle ein Bitmap in dem Sie den Rechteckteil zeichnen und diese Bitmap in den Kontext zeichnen.
Sobald Sie die XPS-Dateien haben, können Sie sie analysieren und das "Bild" extrahieren, wenn Sie Glück haben, dass es darin erzeugt wurde. (XPS ist nur eine ZIP-Datei, die XAML verwendet, um Inhalt zu beschreiben und verwendet Unterverzeichnisse, um Bitmap-Bilddateien, Schriftarten usw. zu speichern.)
(Ich denke, Sie können die Klasse Package
verwenden, um auf die Rohteile eines XPS-Dokuments zuzugreifen, oder XpsDocument
für eine Interpretation auf höherer Ebene).
Oder zeigen Sie das XPS einfach in einem XPS-Viewer an, wenn Sie nur versuchen möchten, Ihre kombinierten 1-Bit-Bilder in einem anderen Kontext anzuzeigen.
Das ist nicht ideal ... nicht zuletzt, weil Sie einen Druckertreiber auf dem Rechner installieren müssen ... aber Sie können vielleicht einen "Print to Image" -Druckertreiber verwenden und diesen dann zur Erstellung verwenden Ihre Bitmap. Hier sind einige Vorschläge:
[1] Erstellen Sie zuerst eine GDI + -Bitmap, die groß genug ist, um Ihr zusammengesetztes Rendering aufzunehmen.
(Es gibt ein paar verschiedene Möglichkeiten, dies zu tun ... Eine Möglichkeit besteht darin, eine WriteableBitmap zu verwenden, um die Backbuffer-Bits / Speicher bereitzustellen ... das heißt, wenn Sie auf die Bits im Speicher zugreifen wollten ... in Ihrem Fall I glaube nicht, dass du es tun musst / musst).
%Vor%Oder auf diese Weise, wenn Sie WriteableBitmap zugreifen möchten.
[2] Konvertieren Sie beliebige WPF-BitmapSources in GDI + -Bitmaps, sodass Sie sie mithilfe von DrawImage auf den GDI + -Grafikkontext zeichnen können.
Sie können das mit CopyPixels auf Ihren BitmapSources machen.
Für Ihre Rechtecke können Sie einfach den Renderbefehl GDI + DrawRectangle verwenden.
[3] Speichern Sie die GDI + Bitmap auf Festplatte
Verwenden Sie die .Save-Methode in System.Image.Bitmap, um sie als Bitmap zu speichern.
[4] Verwenden Sie das gespeicherte Bild als Quelle für ein Bildelement
(Beachten Sie, dass beim Laden des Bilds wahrscheinlich eine Menge Speicher verbraucht wird, obwohl es 1bpp ist, da der WPF-Rendering-Pfad alle 32 bpp beträgt).
[4] ODER umschließen Sie die GDI + -Bitmap für die Verwendung in WPF
Sie können InteropBitmap verwenden, um die GDI + -basierte Bitmap zu umbrechen, sodass Sie sie als BitmapSource in WPF verwenden können. (Bitte beachten Sie, dass es sich um eine 32bpp Eins handeln muss .... wenn es so ist ... dann sind Sie wieder an Platz 1 ... aber versuchen Sie es trotzdem).
Erzeuge einen anderen Prozess, der als Dienst dient (muss kein NT-Dienst sein ... könnte ein untergeordneter Prozess sein, den du startest), um deine kombinierten 1bpp-Bilder zu rendern .... es gibt verschiedene Möglichkeiten mit denen du kommunizieren kannst es gibt ihm die Rendering-Befehle.
Wenn der Speicherverbrauch zu hoch wird / die LOH fragmentiert wird, können Sie diesen Dienst neu starten.
Sie könnten mit OpenGL (zB OpenTK oder SharpGL) rendern, oder mit DirectX ... über den 3D-Pfad mit D3DImage oder Direct2D rendern (ob das sich genauso verhält wie RenderTargetBitmap in Bezug auf die Speichernutzung ... das ist zu finden aus).
Probiere NET 4.5 aus, da es im LOH Heap einige Verbesserungen gegeben hat:
Ich glaube nicht, dass Sie etwas besseres tun können. Da RenderTargetBitmap MILcore verwendet, auf das Sie nicht zugreifen können. Und ich glaube nicht, dass es eine andere Möglichkeit gibt, Visual zu kopieren. Aber ich denke, es gibt eine Option mehr. Es wird nicht eine Zeile sein, aber ich denke, es wird gut genug sein.
Grundsätzlich werden Sie visuell Block für Block rendern (PGBRA32) und es in BlackWhite im laufenden Betrieb konvertieren, und dann mit Blackwhite Buffer concat. Ich habe einen kleinen Beispielcode gestartet, aber auf halbem Weg entschieden, dass es nicht so einfach sein wird, aber Sie können es beenden.
%Vor%Legen Sie also im Grunde eine neue WriteableBitmap mit dem BlackWhite-Format an und rufen Sie diese Funktion dann wie folgt auf:
%Vor%// Speichern Sie dann blackWhiteFullBuffer bei Bedarf auf der Festplatte.
Was ist mit PixelFormats
?Bearbeiten : (Danke an Anders Gustafsson)
Das untere ist PixelFormats.BlackWhite
, mit 1bit pro Pixel.
Auf diese Weise können Sie jedes BitmapImage in eine FormatConvertedBitmap konvertieren, in der Sie das Format in ein niedrigeres bpp ändern können.
Tags und Links wpf .net c# rendertargetbitmap drawingcontext