Converti una bitmap in un array di byte


233

Usando C #, c'è un modo migliore per convertire un Windows Bitmapin byte[]che salvarlo in un file temporaneo e leggere il risultato usando un FileStream?

Risposte:


419

Ci sono un paio di modi.

ImageConverter

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

Questo è conveniente perché non richiede molto codice.

Flusso di memoria

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

Questo equivale a quello che stai facendo, tranne per il fatto che il file viene salvato in memoria anziché su disco. Anche se più codice hai l'opzione di ImageFormat e può essere facilmente modificato tra il salvataggio in memoria o su disco.

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


2
Puoi anche usare bitmap.Lockbits e Marshal.Copy per una semplice copia veloce senza alcun
flusso di memoria

4
Tieni presente che il ImageConvertermetodo salverà l'immagine come Png, risultando in file ENORMI.
skolima,

8
non è necessario chiudere lo stream quando si utilizza 'using'
LastTribunal

2
Qualcuno può darmi qualche informazione in più su come è strutturato questo array? Comincia con x = 0 e scorre ciclicamente ogni y e quindi incrementando x? E quindi conservalo in questo modo: [0,0,1,1,1,1,0,0,1,1]?
Raymond Timmermans,

1
ImageConverternon è lo standard .net che potresti usareMemoryStream
Alexandre

95

Un MemoryStream può essere utile per questo. Potresti metterlo in un metodo di estensione:

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();
        }
    }
}

Potresti semplicemente usarlo come:

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

In parte non sono d'accordo con la risposta di prestomanifto riguardo a ImageConverter. Non utilizzare ImageConverter. Non c'è nulla di tecnicamente sbagliato in esso, ma semplicemente il fatto che usi il boxing / unboxing dall'oggetto mi dice che è il codice dai vecchi luoghi bui del framework .NET e non è l'ideale da usare con l'elaborazione delle immagini (è eccessivo per la conversione in byte [] almeno), soprattutto se si considera quanto segue.

Ho dato un'occhiata al ImageConvertercodice utilizzato dal framework .Net e internamente utilizza un codice quasi identico a quello che ho fornito sopra. Crea un nuovo MemoryStream, salva il Bitmapformato in qualunque formato fosse quando lo hai fornito e restituisce l'array. Salta il sovraccarico extra di creare una ImageConverterclasse utilizzandoMemoryStream


Bello. Quello lo farà! Suppongo che vorrai smaltire MemoryStream, però: ti interessa aggiornare?
Jeremy McGee,

Ho aggiornato la mia risposta con alcune discussioni sul perché non utilizzare ImageConverter, come suggerisce la risposta selezionata, nonché l'aggiunta di smaltimento.
Christopher Currens,

Bello l'uso di un metodo di estensione, mi piace!
Amico Pascalou,

3
+1 per esaminare ImageConverter e riportare i risultati della tua ricerca. Ma non credo che ciò che hai scoperto meriti l'affermazione "Non usare ImageConverter". Fornisce sicuramente servizi utili andando dall'altra parte, dall'array di byte all'immagine, ad esempio impostando la risoluzione dell'immagine (dpi). E il "sovraccarico extra della creazione di una classe ImageConverter" è presumibilmente trascurabile, e deve essere fatto solo una volta, indipendentemente da quante volte lo usi.
RenniePet,

1
Ho trovato utile ImageConverter anche perché può determinare automaticamente il tipo di immagine, ad esempio se disponi di una matrice di byte dell'immagine, ma non conosci il formato, puoi provare a leggere le intestazioni e ottenere suggerimenti da lì, ma, bene, ... usare (Image img = (Image) myImgConverter.ConvertFrom (byteImage)) e quindi controllare img.PixelFormat ecc. è semplicemente più semplice .. - ovviamente a seconda di cosa vuoi fare
hello_earth

46

Puoi anche solo Marshal.Copia i dati bitmap. Nessun memorystream intermedio ecc. E una copia di memoria veloce. Questo dovrebbe funzionare su bitmap a 24 e 32 bit.

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
Ciao, ho usato questo metodo, ma non riesco a riconvertire nuovamente questa matrice di byte in un'immagine. Bitmap bitmap1 = nuovo Bitmap (nuovo MemoryStream (array)); genera un'eccezione di parametri non validi. C'è qualche errore?
Howard,

1
Salve, la sezione dei commenti è troppo piccola per pubblicare un codice pulito completo. Il modo più semplice è bloccare l'array: GCHandle handle = GCHandle.Alloc (bufferarray, GCHandleType.Pinned); ottenere il puntatore alla matrice IntPtr iptr = Marshal.UnsafeAddrOfPinnedArrayElement (bufferarray, 0); quindi creare una nuova bitmap usando IntPtr: bitmap = new Bitmap (larghezza, altezza, (larghezza * 4), PixelFormat.Format32bppArgb, iptr); ma dovrai utilizzare i parametri di creazione bitmap appropriati per il tuo formato bitmap. Assicurati di pulire: iptr = IntPtr.Zero; handle.Free ();
deceduto il

3
Qual è il bug? Molti programmatori incluso me stesso stanno usando questo stile di codice e funziona benissimo.
deceduto il

4
@ mini-me - Consiglio di cercare quale sia il passo della bitmap rispetto alla larghezza della bitmap. Questo non è un bug nel mio codice, questo è il modo in cui Windows gestisce le bitmap. Stride può includere dati extra alla fine di ogni riga (larghezza) per far terminare ciascuna riga e iniziare su un limite di 32 bit per l'allineamento e le prestazioni della memoria.
deceduto il


16

Salvare l'immagine su MemoryStream e afferrare l'array di byte.

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

  Byte[] data;

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

    data = memoryStream.ToArray();
  }

Non esiste un metodo Salva sull'immagine.
Prescott Chartier,

@PrescottChartier L'esempio precedente presuppone che tu stia lavorando da un tipo derivato da System.Drawing.Image (vedi: docs.microsoft.com/en-us/dotnet/api/… )
Chris Baxter,

Sì e io capiamo System.Drawing.Image does not exist. Quindi .. no, non funziona :(
Prescott Chartier

Puoi vedere cosa sto cercando di fare qui: stackoverflow.com/questions/55084620/…
Prescott Chartier

10

Usa a MemoryStreaminvece di a FileStream, in questo modo:

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

Probabilmente vuoi ToArray, no GetBuffer.
vcsjones,

GetBuffer restituisce una matrice di byte senza segno (matrice di byte)
Jeff Reddy,

4
Potrebbe contenere dati di riempimento che non fanno parte dell'immagine. Da documenti: 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.Quindi ora l'array di byte GetBufferrestituirà l'immagine più i byte non utilizzati, il che probabilmente provocherà un'immagine corrotta.
vcsjones,

1
Buono a sapersi. Grazie per il commento vcs!
Jeff Reddy,

Questo approccio salva l'immagine come jpeg con impostazioni di compressione predefinite, che introdurrà artefatti di compressione che potrebbero degradare visibilmente l'immagine.
Richard Ev,

8

Prova quanto segue:

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

byte[] byteArray = stream.GetBuffer();

Assicurati di utilizzare:

System.Drawing & using System.Drawing.Imaging;

1
Questo approccio salva l'immagine come jpeg con impostazioni di compressione predefinite, che introdurrà artefatti di compressione che potrebbero degradare visibilmente l'immagine.
Richard Ev,

Ancora una volta, nessun metodo di salvataggio su bitmap.
Prescott Chartier,

7

Credo che potresti semplicemente fare:

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

Più semplice:

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

-4

Molto semplice usalo solo in una riga:

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

op ha dichiarato di non essere interessato a questa opzione
Mauro Sampietro,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.