2012-07-13 2 views
7

Ich versuche, ein Bild als einfarbig (schwarz & weiß, 1 Bit Tiefe) zu speichern, aber ich komme verloren, wie es geht.Konvertieren einer Bitmap in Monochrom

Ich beginne mit einem PNG und konvertiere zu einer Bitmap zum Drucken (es ist ein Thermodrucker und unterstützt sowieso nur Schwarz - und es ist langsam für große Bilder, wenn ich versuche, sie als Farbe/Graustufen zu senden).

Mein Code ist bis jetzt tot einfach zu einer Bitmap zu konvertieren, aber es behält die ursprüngliche Farbtiefe bei.

Image image = Image.FromFile("C:\\test.png"); 

byte[] bitmapFileData = null; 
int bitsPerPixel = 1; 
int bitmapDataLength; 

using (MemoryStream str = new MemoryStream()) 
{ 
    image.Save(str, ImageFormat.Bmp); 
    bitmapFileData = str.ToArray(); 
} 
+0

http://stackoverflow.com/questions/4669317/how-to-convert-a-bitmap-image-to-black-and-white-in-c – Dmitriy

+0

möglich Duplikat [konvertieren Bild zu Schwarz -Weiß oder Sepia in C#] (http://stackoverflow.com/questions/4624998/convert-image-to-black-white-or-sepia-in-c-sharp) – ken2k

+1

Eigentlich scheint es mir, dass diese Fragen sind über das Konvertieren in Graustufen - während das OP es in 1 BPP Monochrom konvertieren will, was Schwellwert/Dithering beinhaltet. – Ani

Antwort

10

Hier ist ein Code, den ich ein Vollfarbe (24 Bit/Pixel) Bild erstellt, und wandelt es in eine 1 Bit/Pixel-Ausgabe-Bitmap, eine Standard-RGB auf Graustufen Konvertierung und dann mit Floyd-Steinberg zu Graustufen in die 1-Bit/Pixel-Ausgabe konvertieren.

Beachten Sie, dass dies keineswegs als eine "ideale" Implementierung betrachtet werden sollte, aber es funktioniert. Es gibt eine Reihe von Verbesserungen, die angewendet werden können, wenn Sie möchten. Zum Beispiel kopiert es das gesamte Eingabebild in das data Array, während wir wirklich nur zwei Zeilen im Speicher behalten müssen (die "aktuellen" und "nächsten" Zeilen), um die Fehlerdaten zu akkumulieren. Trotzdem scheint die Leistung akzeptabel zu sein.

public static Bitmap ConvertTo1Bit(Bitmap input) 
{ 
    var masks = new byte[] { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; 
    var output = new Bitmap(input.Width, input.Height, PixelFormat.Format1bppIndexed); 
    var data = new sbyte[input.Width, input.Height]; 
    var inputData = input.LockBits(new Rectangle(0, 0, input.Width, input.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); 
    try 
    { 
     var scanLine = inputData.Scan0; 
     var line = new byte[inputData.Stride]; 
     for (var y = 0; y < inputData.Height; y++, scanLine += inputData.Stride) 
     { 
      Marshal.Copy(scanLine, line, 0, line.Length); 
      for (var x = 0; x < input.Width; x++) 
      { 
       data[x, y] = (sbyte)(64 * (GetGreyLevel(line[x * 3 + 2], line[x * 3 + 1], line[x * 3 + 0]) - 0.5)); 
      } 
     } 
    } 
    finally 
    { 
     input.UnlockBits(inputData); 
    } 
    var outputData = output.LockBits(new Rectangle(0, 0, output.Width, output.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed); 
    try 
    { 
     var scanLine = outputData.Scan0; 
     for (var y = 0; y < outputData.Height; y++, scanLine += outputData.Stride) 
     { 
      var line = new byte[outputData.Stride]; 
      for (var x = 0; x < input.Width; x++) 
      { 
       var j = data[x, y] > 0; 
       if (j) line[x/8] |= masks[x % 8]; 
       var error = (sbyte)(data[x, y] - (j ? 32 : -32)); 
       if (x < input.Width - 1) data[x + 1, y] += (sbyte)(7 * error/16); 
       if (y < input.Height - 1) 
       { 
        if (x > 0) data[x - 1, y + 1] += (sbyte)(3 * error/16); 
        data[x, y + 1] += (sbyte)(5 * error/16); 
        if (x < input.Width - 1) data[x + 1, y + 1] += (sbyte)(1 * error/16); 
       } 
      } 
      Marshal.Copy(line, 0, scanLine, outputData.Stride); 
     } 
    } 
    finally 
    { 
     output.UnlockBits(outputData); 
    } 
    return output; 
} 

public static double GetGreyLevel(byte r, byte g, byte b) 
{ 
    return (r * 0.299 + g * 0.587 + b * 0.114)/255; 
} 
4

Was Sie wollen, ist ein guter Dithering-Algorithmus wie Floyd-Steinberg oder Bayer ordered. Sie können die Binarisierung entweder selbst implementieren oder eine Bibliothek wie AForge.NET für Sie verwenden (laden Sie die Bildverarbeitungsbeispiele herunter). Sie finden die Binarisierungsdokumentation here.