2013-10-31 7 views
7

Der generische GDI + Fehler beim Speichern einer Bitmap ist offensichtlich ein häufiges Problem meiner Forschung hier auf SO und im Internet. Gegeben folgendes vereinfachtes Schnipsel:GDI + generischer Fehler beim Speichern von Bitmap aus Speicher mit LockBits

byte[] bytes = new byte[2048 * 2048 * 2]; 

for (int i = 0; i < bytes.Length; i++) 
{ 
    // set random or constant pixel data, whatever you want 
} 

Bitmap bmp = new Bitmap(2048, 2048, PixelFormat.Format16bppGrayScale); 
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, 2048, 2048), ImageLockMode.ReadWrite, bmp.PixelFormat); 
System.Runtime.InteropServices.Marshal.Copy(bytes, 0, bmpData.Scan0, 8388608); 
bmp.UnlockBits(bmpData); 
bmp.Save(@"name.bmp"); 

Dies führt zu dem allgemeinen Fehler 0x80004005. Der übliche Grund dafür sind angeblich Sperren auf Komponenten, aber ich sehe hier nichts. Bin ich nur blind? Der Pfad zu dem ich speichere besteht natürlich nur aus einer leeren bmp Datei (0B).

Hintergrund: Ich erhalte Pixeldaten von einem Kameratreiber, den ich mit einem C++/CLI-Wrapper nach .NET übertrage, sodass das obige Bitmap-Objekt von einem Funktionsaufruf zurückgegeben wird. Aber da dieses kleine Beispiel bereits fehlschlägt, denke ich, dass mit dem Adapter nichts falsch ist.

Alle Vorschläge werden sehr geschätzt!

+0

16-Bit-Graustufen ist vielleicht kein gültiges BMP-Format? –

+0

Ich habe das nicht berücksichtigt, um ehrlich zu sein. Die Umstellung auf 8bpp indiziert erstellt die Datei ohne Fehler. Das ultimative Ziel ist es, das Graustufen-16bpp-Bild als PNG zu speichern, aber das Ersetzen durch "bmp.Save" (@ "name.bmp", ImageFormat.Png); "hat auch nicht funktioniert. – simd

+0

Haben Sie versucht, ImageFormat.Bmp beim Speichern anzugeben? Siehe diese Antwort: http://social.msdn.microsoft.com/Forums/vstudio/en-US/10252c05-c4b6-49dc-b2a3-4c1396e2c3ab/action?threadDisplayName=writing-a-16bit-grayscale-image – Ben

Antwort

15
Bitmap bmp = new Bitmap(2048, 2048, PixelFormat.Format16bppGrayScale); 

GDI + Ausnahmen sind eher schlecht, hast du wenig Hoffnung haben die beiden Fehler zu diagnostizieren. Der kleinere ist Ihr Save() - Aufruf, er spezifiziert nicht das ImageFormat, das Sie speichern möchten. Der Standardwert ist PNG, nicht BMP, wie Sie es sich erhofft haben.

Aber der Kern ist PixelFormat.Format16bppGrayScale. Als GDI + entwickelt wurde, lange bevor .NET auf den Markt kam, benutzten alle immer noch CRT anstelle von LCD-Monitoren. CRTs waren ziemlich gut in der Darstellung einer Farbskala. Obwohl es gut war, gab es noch keine Mainstream-CRTs, die in der Lage waren, 65536 verschiedene Grautöne anzuzeigen. Am meisten eingeschränkt durch den DAC im Videoadapter ist der Chip, der den digitalen Pixelwert in ein analoges Signal für die CRT umwandelt. Ein DAC, der mit 16-Bit-Genauigkeit bei 100 MHz oder mehr umwandeln kann, war noch nicht technisch machbar. Microsoft spielte auf Display-Technologie, um dieses Format zu ermöglichen, so dass Format16bppGrayScale als ein Pixel-Format, das eines Tages sein könnte.

Das ist nicht passiert. Im Gegenteil, LCDs sind bei der Farbauflösung deutlich schlechter. Typische LCD-Panels können nur 6 Bit einer Farbe auflösen, anstatt der 8 Bit, die aus dem Pixelformat verfügbar sind. Die Farbauflösung von 16 Bit erfordert einen erheblichen technologischen Durchbruch.

Also raten sie falsch und, da das Pixelformat nicht nützlich ist, hat GDI + nicht wirklich einen Bildgeber, der ein 16bpp Graustufenbildformat schreiben kann. Kaboom, wenn Sie versuchen, es auf dem Datenträger zu speichern, unabhängig von dem ImageFormat, das Sie auswählen.

16bpp Graustufen wird tatsächlich verwendet, radiologische Bildgebung verwendet dieses Pixelformat. Mit sehr teuren Displays, um es tatsächlich sinnvoll zu machen. Solche Geräte verwenden jedoch invariablerweise ein benutzerdefiniertes Bildformat, DICOM ist die übliche Wahl. GDI + hat keinen Codec dafür.

Sie müssen eine Bibliothek kaufen, die das von Ihrem Kunden gewünschte Bildformat unterstützt. Lead Tools ist der Tausend-Pfund-Gorilla in diesem Produktsegment.

+0

Vielen Dank für Ihre ausführliche Antwort, immer nett, um etwas Hintergrund mit der Erklärung zu bekommen. Der Punkt hier ist, dass die Bilder für die Anzeige eher weniger verwendet werden, sondern anschließend von der Software analysiert werden. Die Bilder stammen aus der Zeitraffer-Mikroskopie, und die 16-Bit-Auflösung bietet uns mehr Möglichkeiten als 8-Bit. Also, wenn ich mit einer zusätzlichen lib gehen müsste, würde WIC hier arbeiten (bereits im Kameraadapter dagegen verlinken), oder muss ich auf libpng zurückgreifen? – simd

+3

Sie sind in diesem Fall einfach nicht an ein unterstütztes Bildformat gebunden. Das schlaue Ding, hier zu tun, ist, die Daten nur in Ihrem eigenen Format zu speichern. Nichts, was BinaryWriter zum Beispiel nicht könnte. –

+1

16-Bit-Bitmaps sind auch nützlich für Bereichsdaten (wie sie beispielsweise von Kinect erzeugt werden) – Eponymous