Wie erstelle ich eine Bitmap aus einem Byte-Array?

70

Ich habe alle Fragen zum Byte-Array durchsucht, bin aber immer gescheitert. Ich habe noch nie c # codiert. Ich bin neu auf dieser Seite. Könnten Sie mir helfen, wie man eine Bilddatei aus einem Byte-Array erstellt?

Hier ist meine Funktion, die Bytes im Array mit dem Namen speichert imageData

public void imageReady( byte[] imageData, int fWidth, int fHeight))
goGud
quelle

Antworten:

116

Sie müssen diese bytesin eine MemoryStream:

Bitmap bmp;
using (var ms = new MemoryStream(imageData))
{
    bmp = new Bitmap(ms);
}

Das nutzt die Bitmap(Stream stream)Konstruktorüberladung.

UPDATE: Denken Sie daran, dass gemäß der Dokumentation und dem Quellcode, den ich gelesen habe, folgende ArgumentExceptionBedingungen erfüllt sind:

stream does not contain image data or is null.
-or-
stream contains a PNG image file with a single dimension greater than 65,535 pixels.
Mike Perrenoud
quelle
Und dann reicht es aus, bmp.Save (c: \\ image.jpg) zu schreiben; ??
GoGud
1
Ich erhalte die gleiche Fehlermeldung wie die Antwort von @mario: In System.Drawing.dll ist eine nicht behandelte Ausnahme vom Typ 'System.ArgumentException' aufgetreten. Zusätzliche Informationen: Parameter ist ungültig
goGud
@goGud, in welcher Zeile?
Mike Perrenoud
9
Nein! Entsorgen Sie den Stream nicht! Von Bitmap(Stream): "Sie müssen den Stream für die Lebensdauer der Bitmap offen halten."
Piedar
2
Wie @piedar hervorhob, sollte der Stream erst nach dem Entsorgen der Bitmap geschlossen / entsorgt werden. Wenn Sie jedoch ein verwenden MemoryStream, müssen Sie sich keine Sorgen machen, es jemals zu schließen, da das MemoryStreamnichts tut, wenn es sowieso entsorgt wird. Die System.Drawing.ImageConverter.ConvertFromMethode nutzt diese Tatsache tatsächlich aus, so dass es sicher erscheint, diese Annahme zu treffen. Tun, einfach var bmp = new Bitmap(new MemoryStream(imageData));wird ausreichen.
Steven Doggart
29

Jungs, danke für deine Hilfe. Ich denke, all diese Antworten funktionieren. Ich denke jedoch, dass mein Byte-Array Rohbytes enthält. Deshalb haben all diese Lösungen für meinen Code nicht funktioniert.

Ich habe jedoch eine Lösung gefunden. Vielleicht hilft diese Lösung anderen Programmierern, die Probleme wie meine haben.

static byte[] PadLines(byte[] bytes, int rows, int columns) {
   int currentStride = columns; // 3
   int newStride = columns;  // 4
   byte[] newBytes = new byte[newStride * rows];
   for (int i = 0; i < rows; i++)
       Buffer.BlockCopy(bytes, currentStride * i, newBytes, newStride * i, currentStride);
   return newBytes;
 }

 int columns = imageWidth;
 int rows = imageHeight;
 int stride = columns;
 byte[] newbytes = PadLines(imageData, rows, columns);

 Bitmap im = new Bitmap(columns, rows, stride, 
          PixelFormat.Format8bppIndexed, 
          Marshal.UnsafeAddrOfPinnedArrayElement(newbytes, 0));

 im.Save("C:\\Users\\musa\\Documents\\Hobby\\image21.bmp");

Diese Lösung funktioniert für 8 Bit 256 bpp (Format8bppIndexed). Wenn Ihr Bild ein anderes Format hat, sollten Sie es ändernPixelFormat .

Und im Moment gibt es ein Problem mit Farben. Sobald ich dieses Problem gelöst habe, werde ich meine Antwort für andere Benutzer bearbeiten.

* PS = Ich bin mir über den Schrittwert nicht sicher, aber für 8 Bit sollte er gleich den Spalten sein.

Und auch diese Funktion funktioniert bei mir. Diese Funktion kopiert 8-Bit-Graustufenbilder in ein 32-Bit-Layout.

public void SaveBitmap(string fileName, int width, int height, byte[] imageData)
        {

            byte[] data = new byte[width * height * 4];

            int o = 0;

            for (int i = 0; i < width * height; i++)
            {
                byte value = imageData[i];


                data[o++] = value;
                data[o++] = value;
                data[o++] = value;
                data[o++] = 0; 
            }

            unsafe
            {
                fixed (byte* ptr = data)
                {

                    using (Bitmap image = new Bitmap(width, height, width * 4,
                                PixelFormat.Format32bppRgb, new IntPtr(ptr)))
                    {

                        image.Save(Path.ChangeExtension(fileName, ".jpg"));
                    }
                }
            }
        }
goGud
quelle
4
Hallo goGud. Sie müssen die Daten nicht auffüllen, "Format32bppRgb" verwendet 4 Bytes pro Pixel (oder 32 Bit pro Pixel, wie der Name schon sagt, 8 Bit == 1 Byte). "Format32bppRgb" ist eigentlich RGBX, während Ihre Daten "RGB" gespeichert zu sein scheinen, daher die 3 Bytes pro Pixel. Versuchen Sie Format24bppRGB, dies sind 3 Bytes pro Pixel. und Ihr Schritt wird Breite * 3 sein. Schließlich ist es erwähnenswert, den IntPtr-Teil zu erwähnen. Sie müssen einen separaten Verweis darauf behalten. Wenn die Bitmap beibehalten werden soll
chrispepper1989
18

Kann so einfach sein wie:

var ms = new MemoryStream(imageData);
System.Drawing.Image image = Image.FromStream(ms);

image.Save("c:\\image.jpg");

Testen Sie es aus:

byte[] imageData;

// Create the byte array.
var originalImage = Image.FromFile(@"C:\original.jpg");
using (var ms = new MemoryStream())
{
    originalImage.Save(ms, ImageFormat.Jpeg);
    imageData = ms.ToArray();
}

// Convert back to image.
using (var ms = new MemoryStream(imageData))
{
    Image image = Image.FromStream(ms);
    image.Save(@"C:\newImage.jpg");
}
Mario S.
quelle
1
+1 für eine andere Art, die Katze mit dem zu häuten static Accessor zu häuten, aber ja, Sie möchten, dass diese MemoryStreamin eine eingewickelt wird using.
Mike Perrenoud
1
@goGud Ich habe die Antwort aktualisiert. System.Windows.Controls.Imageist ein Steuerelement zum Anzeigen eines Bildes. Hier wird die Klasse System.Drawing.Imageverwendet.
Mario S
Ty, ich habe die letzte Frage und ich denke, es wird ein Ende sein. Wenn ich Ihren Code verwendet habe, erhalte ich diesen Fehler beim Debuggen. In System.Drawing.dll ist eine nicht behandelte Ausnahme vom Typ 'System.ArgumentException' aufgetreten. Zusätzliche Informationen: Der Parameter ist ungültig.
GoGud
@goGud Es klingt wie das Byte-Array, das Sie an das senden Image.FromStream Methode kein gültiges Bild ist.
Mario S
1
Das Problem hierbei ist, dass es sich nicht um einen Stream von rohem RGB handelt. Um Daten abzurufen, für die keine Dimensionen angegeben sind, werden Bilder gespeichert, so wie jedes Objekt gespeichert werden kann, bei dem das Objekt selbst bereits ein Bild mit Make-up war (z. B. Pixelformat usw.).
user3800527
0

Darüber hinaus können Sie einfach konvertieren byte arrayzu Bitmap.

var bmp = new Bitmap(new MemoryStream(imgByte));

Sie können auch direkt Bitmapaus dem Dateipfad abrufen .

Bitmap bmp = new Bitmap(Image.FromFile(filePath));
Majedur Rahaman
quelle