Cara tercepat untuk mengonversi array Gambar ke Byte

106

Saya membuat aplikasi berbagi Desktop Jarak Jauh di mana saya mengambil gambar dari Desktop dan Mengompresnya dan Mengirimkannya ke penerima. Untuk mengompres gambar saya perlu mengubahnya menjadi byte [].

Saat ini saya menggunakan ini:

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

Tetapi saya tidak menyukainya karena saya harus menyimpannya dalam ImageFormat dan itu juga dapat menggunakan sumber daya (Perlambat) serta menghasilkan hasil kompresi yang berbeda. Saya telah membaca tentang menggunakan Marshal.Copy dan memcpy tetapi saya tidak dapat melakukannya mengerti mereka.

Jadi, apakah ada metode lain untuk mencapai tujuan ini?

pengguna2529551
sumber
baik MemoryStream dan Image memiliki metode pembuangan, pastikan Anda membuangnya karena ini dapat menyebabkan MemoryLeaks.
abc123
3
@ abc123: Anda tidak perlu membuang MemoryStream; itu adalah sumber daya yang sepenuhnya dikelola, kecuali jika Anda menggunakannya di remote. Dalam kedua kasus ini, akan menjadi tidak tepat untuk membuang sumber daya.
Jon Skeet
1
@JonSkeet menarik, apakah Anda sudah melakukan benchmark tentang itu? untuk melihat kecepatan di mana. bersih melepaskan objek? Saya tahu bahwa ada argumen serupa untuk DataTable, namun ada perbedaan mencolok dalam kecepatan GarbageCollector mengumpulkan memori yang dialokasikan saat pembuangan digunakan.
abc123
@ abc123: Saya benar-benar tidak berharap akan ada - membuang aliran tidak melakukan apa pun pada array, dan MemoryStream tidak memiliki finalizer (tidak seperti DataTable, yang mewarisi satu dari MarshalByValueComponent).
Jon Skeet
2
ada solusi akhir dengan kode sumber lengkap?
Kiquenet

Jawaban:

39

Jadi, apakah ada metode lain untuk mencapai tujuan ini?

Tidak. Untuk mengonversi gambar ke array byte Anda harus menentukan format gambar - sama seperti Anda harus menentukan pengkodean saat Anda mengubah teks menjadi array byte.

Jika Anda khawatir tentang artefak kompresi, pilih format lossless. Jika Anda khawatir tentang sumber daya CPU, pilih format yang tidak mengganggu kompresi - hanya piksel ARGB mentah, misalnya. Tapi tentu saja itu akan menghasilkan array byte yang lebih besar.

Perhatikan bahwa jika Anda memilih format yang tidak termasuk kompresi, tidak ada gunanya di kemudian mengompresi array byte setelah itu - itu hampir pasti tidak berpengaruh menguntungkan.

Jon Skeet
sumber
12
daripada 'memilih format lossless' Anda dapat memilih imageIn.RawFormatyang mencoba menyimpan byte gambar mentah tanpa encoding ulang lebih lanjut.
Chris F Carroll
52

Ada properti RawFormat dari parameter Gambar yang mengembalikan format file gambar. Anda dapat mencoba yang berikut ini:

// extension method
public static byte[] imageToByteArray(this System.Drawing.Image image)
{
    using(var ms = new MemoryStream())
    {
        image.Save(ms, image.RawFormat);
        return ms.ToArray();
    }
}
Kadal air
sumber
9
Saya akan merekomendasikan baik membuang MemoryStream atau membungkus tubuh metode ini dalam pernyataan using () {}
Neil. Allen
@ Neil.Allen Saya baru di sini, bisakah Anda memberi tahu alasannya?
Khalil Khalaf
3
@FirStep Karena bersih-bersih setelah dirimu :)
Sinaesthetic
@Sinaesthetic, begitu. Dan rutinitasnya adalah untuk meletakkan fungsi apa pun yang ingin saya jalankan, dalam using () {}?
Khalil Khalaf
2
@Langkah Pertama Kurang tepat. Lebih akuratnya: Jika Anda menggunakan objek yang telah mengimplementasikan IDisposable, maka Anda harus memastikan untuk memanggil Dispose () setelah Anda selesai melakukannya sehingga itu akan membersihkan sumber daya yang telah diikat. Pernyataan using () {} hanya memanggilnya untuk Anda saat objek berada di luar cakupan pernyataan itu. Jadi Anda dapat melakukan myObject.Dispose()atau using(myObject){}- keduanya melakukan hal yang sama, tetapi menggunakan pernyataan pada dasarnya menciptakan ruang lingkup yang akan membersihkan untuk Anda.
Sinaesthetic
14

Saya tidak yakin apakah Anda akan mendapatkan keuntungan besar karena alasan yang ditunjukkan Jon Skeet. Namun, Anda dapat mencoba dan mengukur metode TypeConvert.ConvertTo dan melihat perbandingannya dengan metode Anda saat ini.

ImageConverter converter = new ImageConverter();
byte[] imgArray = (byte[])converter.ConvertTo(imageIn, typeof(byte[]));
keyboardP
sumber
Tak dapat mentransmisikan objek berjenis 'System.Byte []' untuk mengetik 'System.Drawing.Image'.
pengguna123
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;
    }
bhadresh
sumber
5
Selamat datang di stackoverflow.com, dapatkah Anda menambahkan sedikit detail yang menjelaskan mengapa contoh kode di atas membantu. Ini untuk pengguna SO lain yang mungkin tidak sepenuhnya memahaminya ... stackoverflow.com/help/how-to-answer
Mack
Ini untuk file menjadi byte, tetapi OP ingin objek gambar diubah menjadi byte. Objek gambar dapat disimpan dalam database, tidak harus sistem file, sebagai array byte, dan oleh karena itu harus diubah bolak-balik ... tetapi tidak sebagai file dalam FileStream untuk diubah menjadi byte - kecuali mungkin, selama unggahan awal.
vapcguy
Ini membantu saya karena saya ingin melakukan ini dengan file. Baik untuk dimiliki karena terkait.
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;
    }
}
Ahmad Aghazadeh
sumber
2

Cara tercepat yang bisa saya temukan adalah ini:

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

Semoga bermanfaat

alireza amini
sumber
Hati-hati dengan ini, terutama jika menggunakan WPF di mana Anda akan memiliki System.Windows.Controls.Imageobjek. Jika Anda ingin mengubah salah satunya menjadi byte, dan Anda meneruskannya ke baris ini karena InputImg, ini tidak akan berhasil. Ia mengharapkan sebuah System.Drawing.Imageobjek.
vapcguy