Konvertieren Sie eine Bitmap in ein Byte-Array


233

Gibt es mit C # eine bessere Möglichkeit, ein Windows Bitmapin ein zu konvertieren , byte[]als in eine temporäre Datei zu speichern und das Ergebnis mit einem zu lesen FileStream?

Antworten:


418

Es gibt verschiedene Möglichkeiten.

ImageConverter

public static byte[] ImageToByte(Image img)
{
    ImageConverter converter = new ImageConverter();
    return (byte[])converter.ConvertTo(img, typeof(byte[]));
}

Dieser ist praktisch, weil er nicht viel Code erfordert.

Speicherstrom

public static byte[] ImageToByte2(Image img)
{
    using (var stream = new MemoryStream())
    {
        img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
        return stream.ToArray();
    }
}

Dieser entspricht dem, was Sie tun, außer dass die Datei im Speicher statt auf der Festplatte gespeichert wird. Obwohl Sie mehr Code haben, haben Sie die Option von ImageFormat und es kann leicht zwischen dem Speichern auf Speicher oder Festplatte geändert werden.

Quelle: http://www.vcskicks.com/image-to-byte.php


2
Sie können auch bitmap.Lockbits und Marshal.Copy für eine einfache schnelle Kopie ohne Zwischenspeicherströme usw. verwenden
deegee

4
Bitte beachten Sie, dass die ImageConverterMethode das Bild als Png speichert, was zu RIESIGEN Dateien führt.
Skolima

8
Sie müssen den Stream nicht schließen, wenn Sie 'using' verwenden
LastTribunal

2
Kann mir jemand ein bisschen mehr Informationen darüber geben, wie dieses Array aufgebaut ist? Beginnt es mit x = 0 und durchläuft jedes y und erhöht dann x? Und dann speichern Sie es wie folgt: [0,0,1,1,1,1,0,0,1,1]?
Raymond Timmermans

1
ImageConverterist kein .net-Standard, den Sie verwenden könntenMemoryStream
Alexandre

95

Ein MemoryStream kann dabei hilfreich sein. Sie könnten es in eine Erweiterungsmethode setzen:

public static class ImageExtensions
{
    public static byte[] ToByteArray(this Image image, ImageFormat format)
    {
        using(MemoryStream ms = new MemoryStream())
        {
            image.Save(ms, format);
            return ms.ToArray();
        }
    }
}

Sie könnten es einfach so verwenden:

var image = new Bitmap(10, 10);
// Draw your image
byte[] arr = image.ToByteArray(ImageFormat.Bmp);

Ich bin teilweise anderer Meinung als die Antwort von prestomanifto in Bezug auf den ImageConverter. Verwenden Sie ImageConverter nicht. Es ist technisch nichts falsch daran, aber die Tatsache, dass es Boxing / Unboxing von Objekt verwendet, sagt mir, dass es Code aus den alten dunklen Stellen des .NET Frameworks ist und nicht ideal für die Bildverarbeitung ist (es ist übertrieben für die Konvertierung in ein Byte [] zumindest), insbesondere wenn Sie Folgendes berücksichtigen.

Ich habe mir den ImageConverterCode angesehen, der vom .Net-Framework verwendet wird, und intern wird Code verwendet, der fast identisch mit dem oben angegebenen ist. Es erstellt ein neues MemoryStream, speichert das Bitmapin dem Format, in dem es bei der Bereitstellung angegeben wurde, und gibt das Array zurück. Überspringen Sie den zusätzlichen Aufwand beim Erstellen einer ImageConverterKlasse mithilfe vonMemoryStream


Schön. Das wird gehen! Ich gehe davon aus, dass Sie den MemoryStream entsorgen möchten - möchten Sie ihn aktualisieren?
Jeremy McGee

Ich habe meine Antwort mit einigen Diskussionen darüber aktualisiert, warum ImageConverter nicht verwendet werden soll, wie in Ihrer ausgewählten Antwort vorgeschlagen, sowie durch Hinzufügen von Entsorgung.
Christopher Currens

Gute Verwendung einer Erweiterungsmethode, ich mag es!
Dude Pascalou

3
+1 für den Blick in ImageConverter und die Berichterstattung über die Ergebnisse Ihrer Forschung. Ich glaube jedoch nicht, dass das, was Sie entdeckt haben, die Aussage "Verwenden Sie ImageConverter nicht" rechtfertigt. Es bietet auf jeden Fall nützliche Dienste, die vom Byte-Array zum Bild in die andere Richtung gehen, z. B. das Einstellen der Bildauflösung (dpi). Und der "zusätzliche Aufwand beim Erstellen einer ImageConverter-Klasse" ist vermutlich vernachlässigbar und muss nur einmal durchgeführt werden, unabhängig davon, wie oft Sie sie verwenden.
RenniePet

1
Ich fand ImageConverter auch hilfreich, da es den Typ des Bildes automatisch bestimmen kann - zum Beispiel, wenn Sie ein Byte-Array des Bildes haben, aber das Format nicht kennen - Sie könnten versuchen, Header zu lesen und Hinweise von dort zu erhalten, aber, na ja, ... mit (Bild img = (Image) myImgConverter.ConvertFrom (byteImage)) und dann die Überprüfung img.PixelFormat usw. ist nur einfacher .. - natürlich je nachdem , was Sie tun wollen
hello_earth

45

Sie können auch nur Marshal.Copy die Bitmap-Daten. Kein zwischengeschalteter Memorystream usw. und eine schnelle Speicherkopie. Dies sollte sowohl auf 24-Bit- als auch auf 32-Bit-Bitmaps funktionieren.

public static byte[] BitmapToByteArray(Bitmap bitmap)
{

    BitmapData bmpdata = null;

    try
    {
        bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
        int numbytes = bmpdata.Stride * bitmap.Height;
        byte[] bytedata = new byte[numbytes];
        IntPtr ptr = bmpdata.Scan0;

        Marshal.Copy(ptr, bytedata, 0, numbytes);

        return bytedata;
    }
    finally
    {
        if (bmpdata != null)
            bitmap.UnlockBits(bmpdata);
    }

}

.


1
Hallo, ich habe diese Methode verwendet, aber ich kann dieses Byte-Array nicht wieder in ein Bild konvertieren. Bitmap bitmap1 = neue Bitmap (neuer MemoryStream (Array)); Es wird eine Ausnahme von ungültigen Parametern ausgelöst. Gibt es einen Fehler?
Howard

1
Hallo, der Kommentarbereich ist zu klein, als dass ich einen vollständigen, sauberen Code veröffentlichen könnte. Am einfachsten ist es, das Array zu pinnen: GCHandle handle = GCHandle.Alloc (bufferarray, GCHandleType.Pinned); den Zeiger auf das Array abrufen IntPtr iptr = Marshal.UnsafeAddrOfPinnedArrayElement (bufferarray, 0); Erstellen Sie dann eine neue Bitmap mit IntPtr: bitmap = new Bitmap (Breite, Höhe, (Breite * 4), PixelFormat.Format32bppArgb, iptr); Sie müssen jedoch die entsprechenden Parameter für die Bitmap-Erstellung für Ihr Bitmap-Format verwenden. Stellen Sie sicher, dass Sie aufräumen: iptr = IntPtr.Zero; handle.Free ();
Deegee

3
Was ist der Fehler? Viele Programmierer, einschließlich mir, verwenden diesen Codestil und er funktioniert einwandfrei.
Deegee

4
@ mini-me - Ich empfehle nachzuschlagen, wie groß der Bitmap-Schritt im Vergleich zur Bitmap-Breite ist. Dies ist kein Fehler in meinem Code. So geht Windows mit Bitmaps um. Stride kann zusätzliche Daten am Ende jeder Zeile (Breite) enthalten, damit jedes Zeilenende endet und an einer 32-Bit-Grenze für die Speicherausrichtung und -leistung beginnt.
Deegee


16

Speichern Sie das Image in einem MemoryStream und greifen Sie dann auf das Byte-Array zu.

http://msdn.microsoft.com/en-us/library/ms142148.aspx

  Byte[] data;

  using (var memoryStream = new MemoryStream())
  {
    image.Save(memoryStream, ImageFormat.Bmp);

    data = memoryStream.ToArray();
  }

Es gibt keine Speichermethode für das Bild.
Prescott Chartier

@ PrescottChartier Das obige Beispiel setzt voraus, dass Sie von einem Typ arbeiten, der von System.Drawing.Image (siehe: docs.microsoft.com/en-us/dotnet/api/… )
Chris Baxter

Yup und ich bekommen System.Drawing.Image does not exist. Also .. nein, funktioniert nicht :(
Prescott Chartier

Sie können hier sehen, was ich versuche: stackoverflow.com/questions/55084620/…
Prescott Chartier

10

Verwenden Sie a MemoryStreamanstelle von a FileStreamwie folgt:

MemoryStream ms = new MemoryStream();
bmp.Save (ms, ImageFormat.Jpeg);
byte[] bmpBytes = ms.ToArray();

Sie wollen wahrscheinlich ToArraynicht GetBuffer.
vcsjones

GetBuffer gibt ein Array von vorzeichenlosen Bytes (Byte-Array) zurück
Jeff Reddy

4
Es könnte Fülldaten enthalten, die nicht Teil des Bildes sind. Aus Dokumenten: Note that the buffer contains allocated bytes which might be unused. For example, if the string "test" is written into the MemoryStream object, the length of the buffer returned from GetBuffer is 256, not 4, with 252 bytes unused. To obtain only the data in the buffer, use the ToArray method.Jetzt gibt das Byte-Array von GetBufferdas Bild plus nicht verwendete Bytes zurück, was wahrscheinlich zu einem beschädigten Bild führt.
vcsjones

1
Gut zu wissen. Danke für den Kommentar vcs!
Jeff Reddy

Bei diesem Ansatz wird das Bild als JPEG mit Standardkomprimierungseinstellungen gespeichert, wodurch Komprimierungsartefakte eingeführt werden, die Ihr Bild sichtbar beeinträchtigen können.
Richard Ev

8

Versuche Folgendes:

MemoryStream stream = new MemoryStream();
Bitmap bitmap = new Bitmap();
bitmap.Save(stream, ImageFormat.Jpeg);

byte[] byteArray = stream.GetBuffer();

Stellen Sie sicher, dass Sie Folgendes verwenden:

System.Drawing & using System.Drawing.Imaging;

1
Bei diesem Ansatz wird das Bild als JPEG mit Standardkomprimierungseinstellungen gespeichert, wodurch Komprimierungsartefakte eingeführt werden, die Ihr Bild sichtbar beeinträchtigen können.
Richard Ev

Wieder keine Speichermethode für Bitmap.
Prescott Chartier

7

Ich glaube, Sie können einfach tun:

ImageConverter converter = new ImageConverter();
var bytes = (byte[])converter.ConvertTo(img, typeof(byte[]));

6
MemoryStream ms = new MemoryStream();
yourBitmap.Save(ms, ImageFormat.Bmp);
byte[] bitmapData = ms.ToArray();

5

Einfacher:

return (byte[])System.ComponentModel.TypeDescriptor.GetConverter(pImagen).ConvertTo(pImagen, typeof(byte[]))

-3

Verwenden Sie dies ganz einfach in einer Zeile:

byte[] imgdata = File.ReadAllBytes(@"C:\download.png");

op sagte, er sei nicht an dieser Option interessiert
Mauro Sampietro
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.