Ubah bitmap menjadi array byte

233

Menggunakan C #, apakah ada cara yang lebih baik untuk mengkonversi Windows Bitmapke byte[]daripada menyimpan ke file sementara dan membaca hasilnya menggunakan FileStream?

Jeremy McGee
sumber

Jawaban:

419

Ada beberapa cara.

ImageConverter

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

Yang ini nyaman karena tidak memerlukan banyak kode.

Aliran Memori

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

Yang ini setara dengan apa yang Anda lakukan, kecuali file disimpan ke memori, bukan ke disk. Meskipun lebih banyak kode Anda memiliki pilihan ImageFormat dan dapat dengan mudah dimodifikasi antara menyimpan ke memori atau disk.

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

prestomanifesto
sumber
2
Anda juga dapat menggunakan bitmap.Lockbits dan Marshal.Copy untuk salinan cepat sederhana tanpa ada
stream memori
4
Perlu diketahui bahwa ImageConvertermetode ini akan menyimpan gambar sebagai Png, menghasilkan file BESAR.
skolima
8
Anda tidak perlu menutup aliran saat menggunakan 'menggunakan'
LastTribunal
2
Adakah yang bisa memberi saya sedikit informasi lebih lanjut tentang bagaimana array ini disusun? Apakah ini dimulai dengan x = 0 dan siklus setiap y dan kemudian bertambah x? Dan kemudian simpan seperti ini: [0,0,1,1,1,1,0,0,1,1]?
Raymond Timmermans
1
ImageConverterbukan standar .net yang mungkin Anda gunakanMemoryStream
Alexandre
95

Sebuah MemoryStream dapat membantu untuk ini. Anda bisa memasukkannya dalam metode ekstensi:

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

Anda bisa menggunakannya seperti:

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

Saya sebagian tidak setuju dengan jawaban prestomanifto sehubungan dengan ImageConverter. Jangan gunakan ImageConverter. Tidak ada yang salah secara teknis dengan itu, tetapi hanya fakta bahwa ia menggunakan tinju / unboxing dari objek memberitahu saya itu kode dari tempat-tempat gelap tua dari kerangka NET. Dan itu tidak ideal untuk digunakan dengan pemrosesan gambar (itu terlalu banyak untuk mengkonversi ke byte [] setidaknya), terutama ketika Anda mempertimbangkan yang berikut ini.

Saya melihat ImageConverterkode yang digunakan oleh .Net framework, dan secara internal ia menggunakan kode yang hampir identik dengan yang saya berikan di atas. Itu menciptakan yang baru MemoryStream, menyimpan Bitmapdalam format apa pun itu ketika Anda memberikannya, dan mengembalikan array. Lewati overhead tambahan untuk membuat ImageConverterkelas dengan menggunakanMemoryStream

Christopher Currens
sumber
Menyenangkan. Itu akan berhasil! Saya kira Anda akan ingin membuang MemoryStream, meskipun - peduli untuk memperbarui?
Jeremy McGee
Saya telah memperbarui jawaban saya dengan beberapa diskusi tentang mengapa tidak menggunakan ImageConverter, seperti jawaban pilihan Anda menyarankan, serta penambahan pembuangan.
Christopher Currens
Penggunaan metode ekstensi yang bagus, saya suka!
Dude Pascalou
3
+1 untuk melihat ke ImageConverter dan melaporkan hasil penelitian Anda. Tapi saya tidak berpikir apa yang Anda temukan menjamin pernyataan "Jangan gunakan ImageConverter." Ini pasti memberikan layanan yang bermanfaat dengan cara lain, dari array byte ke Gambar, misalnya mengatur resolusi gambar (dpi). Dan "overhead tambahan untuk menciptakan kelas ImageConverter" mungkin diabaikan, dan hanya perlu dilakukan sekali terlepas dari berapa kali Anda menggunakannya.
RenniePet
1
Saya menemukan ImageConverter juga membantu karena dapat menentukan jenis gambar secara otomatis - misalnya jika Anda memiliki array byte gambar, tetapi tidak tahu formatnya - Anda dapat mencoba membaca header dan mendapatkan petunjuk dari sana, tetapi, baik, ... menggunakan (Gambar img = (Gambar) myImgConverter.ConvertFrom (byteImage)) dan kemudian memeriksa img.PixelFormat dll. lebih mudah .. - tentu saja tergantung pada apa yang ingin Anda lakukan
hello_earth
46

Anda juga bisa Marshal. Salin data bitmap. Tidak ada aliran memori perantara dll. Dan salinan memori cepat. Ini harus bekerja pada bitmap 24-bit dan 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);
    }

}

.

Deegee
sumber
1
Hai, saya menggunakan metode ini, tetapi saya tidak dapat mengubah array byte ini kembali ke gambar lagi. Bitmap bitmap1 = Bitmap baru (MemoryStream (array) baru)); itu melempar pengecualian parameter yang tidak valid. Apakah ada kesalahan?
Howard
1
Hai, bagian komentar terlalu kecil bagi saya untuk mengirim kode bersih penuh. Cara paling sederhana adalah menyematkan array: GCHandle handle = GCHandle.Alloc (bufferarray, GCHandleType.Pinned); dapatkan pointer ke array IntPtr iptr = Marshal.UnsafeAddrOfPinnedArrayElement (bufferarray, 0); kemudian buat bitmap baru menggunakan IntPtr: bitmap = Bitmap baru (lebar, tinggi, (lebar * 4), PixelFormat.Format32bppArgb, iptr); tetapi Anda harus menggunakan parameter pembuatan bitmap yang sesuai untuk format bitmap Anda. Pastikan untuk membersihkan: iptr = IntPtr.Zero; handle.Free ();
Deegee
3
Apa bugnya? Banyak programmer termasuk saya menggunakan gaya kode ini dan berfungsi dengan baik.
deegee
4
@ mini-me - Saya sarankan mencari apa langkah bitmap versus lebar bitmap. Ini bukan bug dalam kode saya, ini adalah bagaimana Windows menangani bitmap. Stride dapat menyertakan data tambahan di akhir setiap baris (lebar) agar masing-masing ujung baris dan mulai pada batas 32-bit untuk penyelarasan dan kinerja memori.
Deegee
3
Itu bukan bug. msdn.microsoft.com/en-us/library/…
deegee
16

Simpan Gambar ke MemoryStream dan kemudian ambil array 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();
  }
Chris Baxter
sumber
Tidak ada metode Simpan di Gambar.
Prescott Chartier
@PrescottChartier Contoh di atas mengasumsikan Anda bekerja dari jenis yang berasal dari System.Drawing.Image (lihat: docs.microsoft.com/en-us/dotnet/api/… )
Chris Baxter
Ya dan saya mengerti System.Drawing.Image does not exist. Jadi .. tidak, tidak bekerja :(
Prescott Chartier
Anda dapat melihat apa yang saya coba lakukan di sini: stackoverflow.com/questions/55084620/…
Prescott Chartier
10

Gunakan MemoryStreambukan FileStream, a , seperti ini:

MemoryStream ms = new MemoryStream();
bmp.Save (ms, ImageFormat.Jpeg);
byte[] bmpBytes = ms.ToArray();
Jeff Reddy
sumber
Anda mungkin ingin ToArray, bukan GetBuffer.
vcsjones
GetBuffer mengembalikan array byte yang tidak ditandatangani (byte array)
Jeff Reddy
4
Itu bisa memiliki data pengisi yang bukan bagian dari gambar. Dari dokumen: 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.Jadi sekarang array byte dari GetBufferakan mengembalikan gambar plus byte yang tidak digunakan, yang mungkin akan menghasilkan gambar yang rusak.
vcsjones
1
Senang mendengarnya. Terima kasih atas vcs komentar!
Jeff Reddy
Pendekatan ini menyimpan gambar sebagai jpeg dengan pengaturan kompresi default, yang akan memperkenalkan artefak kompresi yang mungkin secara nyata menurunkan gambar Anda.
Richard Ev
8

Coba yang berikut ini:

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

byte[] byteArray = stream.GetBuffer();

Pastikan Anda menggunakan:

System.Drawing & using System.Drawing.Imaging;
Francis Gilbert
sumber
1
Pendekatan ini menyimpan gambar sebagai jpeg dengan pengaturan kompresi default, yang akan memperkenalkan artefak kompresi yang mungkin secara nyata menurunkan gambar Anda.
Richard Ev
Sekali lagi, tidak ada metode Simpan di bitmap.
Prescott Chartier
7

Saya yakin Anda bisa melakukannya:

ImageConverter converter = new ImageConverter();
var bytes = (byte[])converter.ConvertTo(img, typeof(byte[]));
Kevek
sumber
6
MemoryStream ms = new MemoryStream();
yourBitmap.Save(ms, ImageFormat.Bmp);
byte[] bitmapData = ms.ToArray();
62071072SP
sumber
5

Lebih sederhana:

return (byte[])System.ComponentModel.TypeDescriptor.GetConverter(pImagen).ConvertTo(pImagen, typeof(byte[]))
Moises Conejo
sumber
-4

Sangat sederhana gunakan ini hanya dalam satu baris:

byte[] imgdata = File.ReadAllBytes(@"C:\download.png");
Karan
sumber
op mengatakan dia tidak tertarik dengan opsi ini
Mauro Sampietro