Der schnellste Weg, um ein Bild in ein Byte-Array zu konvertieren


106

Ich erstelle eine Remotedesktop-Freigabeanwendung, in der ich ein Bild des Desktops aufnehme, komprimiere und an den Empfänger sende. Um das Bild zu komprimieren, muss ich es in ein Byte [] konvertieren.

Derzeit benutze ich dies:

public byte[] imageToByteArray(System.Drawing.Image imageIn)
{
    MemoryStream ms = new MemoryStream();
    imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Gif);
    return  ms.ToArray();
}

public Image byteArrayToImage(byte[] byteArrayIn)
{
     MemoryStream ms = new MemoryStream(byteArrayIn);
     Image returnImage = Image.FromStream(ms);
     return returnImage;
}

Aber ich mag es nicht, weil ich es in einem ImageFormat speichern muss und das möglicherweise auch Ressourcen verbraucht (Verlangsamung) sowie unterschiedliche Komprimierungsergebnisse erzeugt. Ich habe weiter mit Marshal.Copy und memcpy gelesen, kann es aber nicht verstehe sie.

Gibt es also eine andere Methode, um dieses Ziel zu erreichen?


Sowohl MemoryStream als auch Image verfügen über eine Entsorgungsmethode. Stellen Sie sicher, dass Sie sie entsorgen, da dies zu MemoryLeaks führen kann.
abc123

3
@ abc123: Sie müssen a nicht entsorgen MemoryStream; Es handelt sich um eine vollständig verwaltete Ressource, es sei denn, Sie verwenden sie beim Remoting. In beiden Fällen wäre es unangemessen, die Ressource zu entsorgen.
Jon Skeet

1
@ JonSkeet interessant, hast du einen Benchmark dafür gemacht? um zu sehen, mit welcher Geschwindigkeit .net das Objekt freigibt? Ich weiß, dass es ein ähnliches Argument für DataTable gibt, und dennoch gibt es einen spürbaren Unterschied in der Geschwindigkeit, mit der der GarbageCollector den zugewiesenen Speicher sammelt, wenn eine Entsorgung verwendet wird.
abc123

@ abc123: Ich würde wirklich nicht erwarten, dass es das gibt - das Entsorgen des Streams hat nichts mit dem Array zu tun, und MemoryStream hat keinen Finalizer (im Gegensatz zu DataTable, das einen von MarshalByValueComponent erbt).
Jon Skeet

2
Gibt es eine endgültige Lösung mit vollständigem Quellcode?
Kiquenet

Antworten:


39

Gibt es also eine andere Methode, um dieses Ziel zu erreichen?

Nein . Um ein Bild zu einer Byte - Array zu konvertieren Sie haben ein Bildformat angeben - so wie Sie eine Codierung angeben, wenn Sie Text in einer Byte - Array zu konvertieren.

Wenn Sie sich Sorgen über Komprimierungsartefakte machen, wählen Sie ein verlustfreies Format. Wenn Sie sich Sorgen um die CPU-Ressourcen machen, wählen Sie ein Format, das die Komprimierung nicht stört - zum Beispiel nur rohe ARGB-Pixel. Aber das führt natürlich zu einem größeren Byte-Array.

Beachten Sie, dass wenn Sie ein Format auswählen , das tut Kompression ist, gibt es keinen Punkt in dann danach den Byte - Array Komprimieren - es ist fast sicher ist , keine positive Wirkung haben.


12
Anstatt ein verlustfreies Format auszuwählen, können Sie auswählen, imageIn.RawFormatwelche Versuche ausgeführt werden sollen, um die Rohbildbytes ohne weitere Neucodierung zu speichern.
Chris F Carroll

52

Es gibt eine RawFormat-Eigenschaft des Image-Parameters, die das Dateiformat des Bildes zurückgibt. Sie könnten Folgendes versuchen:

// extension method
public static byte[] imageToByteArray(this System.Drawing.Image image)
{
    using(var ms = new MemoryStream())
    {
        image.Save(ms, image.RawFormat);
        return ms.ToArray();
    }
}

9
Ich würde empfehlen, entweder den MemoryStream zu entsorgen oder den Hauptteil dieser Methode in eine using () {}
-Anweisung zu verpacken

@ Neil.Allen Ich bin neu hier Kannst du bitte sagen warum?
Khalil Khalaf

3
@FirstStep Weil aufräumen nach sich selbst :)
Sinaesthetic

@Sinaesthetic Ich sehe. Und die Routine besteht darin, jede Funktion, die ich ausführen möchte, in ein using () {} zu setzen?
Khalil Khalaf

2
@ FirstStep Nicht ganz. Genauer gesagt: Wenn Sie ein Objekt verwenden, das IDisposable implementiert hat, sollten Sie Dispose () aufrufen, wenn Sie damit fertig sind, damit alle gebundenen Ressourcen bereinigt werden. Die using () {} -Anweisung ruft sie nur für Sie auf, wenn das Objekt den Gültigkeitsbereich dieser Anweisung verlässt. Sie können also myObject.Dispose()oder using(myObject){}- beide tun dasselbe, aber die using-Anweisung erstellt im Grunde einen Bereich, der für Sie bereinigt.
Sinaesthetic

14

Ich bin mir nicht sicher, ob Sie aus Gründen, auf die Jon Skeet hingewiesen hat, große Gewinne erzielen werden. Sie können jedoch versuchen, die TypeConvert.ConvertTo- Methode zu vergleichen und zu sehen, wie sie mit Ihrer aktuellen Methode verglichen wird.

ImageConverter converter = new ImageConverter();
byte[] imgArray = (byte[])converter.ConvertTo(imageIn, typeof(byte[]));

Objekt vom Typ 'System.Byte []' kann nicht in 'System.Drawing.Image' umgewandelt werden.
user123

14
public static byte[] ReadImageFile(string imageLocation)
    {
        byte[] imageData = null;
        FileInfo fileInfo = new FileInfo(imageLocation);
        long imageFileLength = fileInfo.Length;
        FileStream fs = new FileStream(imageLocation, FileMode.Open, FileAccess.Read);
        BinaryReader br = new BinaryReader(fs);
        imageData = br.ReadBytes((int)imageFileLength);
        return imageData;
    }

5
Willkommen bei stackoverflow.com. Können Sie ein kleines Detail hinzufügen, das erklärt, warum das obige Codebeispiel hilfreich ist? Es ist für andere SO-Benutzer, die es möglicherweise nicht ganz verstehen ... stackoverflow.com/help/how-to-answer
Mack

Dies gilt für Dateien in Bytes, aber das OP wollte ein Zeichenobjekt, das in Bytes konvertiert wird. Zeichnungsobjekte können in Datenbanken, nicht unbedingt im Dateisystem, als Array von Bytes gespeichert werden und müssen daher hin und her transformiert werden ... aber nicht als Dateien in einem FileStream, die in Bytes konvertiert werden sollen - außer vielleicht während des Erster Upload.
Vapcguy

Dies hat mir geholfen, als ich dies mit Dateien tun wollte. Gut zu haben, wie es verwandt ist.
Justin

5
public static class HelperExtensions
{
    //Convert Image to byte[] array:
    public static byte[] ToByteArray(this Image imageIn)
    {
        var ms = new MemoryStream();
        imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
        return ms.ToArray();
    }

    //Convert byte[] array to Image:
    public static Image ToImage(this byte[] byteArrayIn)
    {
        var ms = new MemoryStream(byteArrayIn);
        var returnImage = Image.FromStream(ms);
        return returnImage;
    }
}

2

Der schnellste Weg, den ich herausfinden konnte, ist folgender:

var myArray = (byte[]) new ImageConverter().ConvertTo(InputImg, typeof(byte[]));

Ich hoffe, nützlich zu sein


Seien Sie vorsichtig damit, insbesondere wenn Sie WPF verwenden, wo Sie System.Windows.Controls.ImageObjekte haben würden . Wenn Sie eines davon in Bytes konvertieren möchten und es als an diese Zeile übergeben InputImg, funktioniert dies nicht. Es erwartet ein System.Drawing.ImageObjekt.
Vapcguy
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.