2013-06-27 11 views
86

Wykonuję aplikację do udostępniania pulpitu zdalnego, w której przechwytuję obraz pulpitu i kompresuję go i wysyłam do odbiorcy. Aby skompresować obraz, muszę go przekonwertować na bajt [].Najszybszy sposób konwertowania obrazu na tablicę bajtową

Obecnie używam to:

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

Ale nie podoba mi się to, bo muszę zapisać go w ImageFormat i które mogą także korzystać z zasobów (Slow Down), jak również produkować inną kompresją Wyniki. Przeczytałem na Marshal.Copy i memcpy, ale nie jestem w stanie ich zrozumieć.

Czy jest jakaś inna metoda osiągnięcia tego celu?

+0

zarówno MemoryStream Image mieć metodę zbyć, upewnij się, że je usuwałeś, ponieważ może to spowodować MemoryLeaks. – abc123

+3

@ abc123: Nie musisz pozbywać się 'MemoryStream'; jest to całkowicie zarządzany zasób, chyba że używasz go do zdalnego zarządzania. W obu tych przypadkach niewłaściwe byłoby dysponowanie zasobami. –

+1

@JonSkeet ciekawe, czy zrobiłeś test porównawczy? aby zobaczyć szybkość, z jaką .net zwalnia obiekt? Wiem, że istnieje podobny argument dla DataTable, a jednak zauważalna jest różnica w szybkości, z jaką GarbageCollector zbiera pamięć przydzieloną, gdy używane jest utylizowanie. – abc123

Odpowiedz

33

Czy jest jakaś inna metoda osiągnięcia tego celu?

No. W celu konwersji obrazu do tablicy bajtów masz aby określić format obrazu - tak jak trzeba określić kodowanie podczas konwersji tekstu do tablicy bajtów.

Jeśli martwisz się o artefakty kompresji, wybierz bezstratny format. Jeśli martwisz się o zasoby procesora, wybierz format, który nie komplikuje - na przykład tylko surowe piksele ARGB. Ale oczywiście to doprowadzi do większej tablicy bajtów.

Należy zauważyć, że jeśli wybierzesz format, który obejmuje kompresję ,, nie ma sensu kompresować matrycy bajtowej - jest prawie pewne, że nie ma ona żadnego korzystnego efektu.

+11

zamiast "wybierz bezstratny format" możesz wybrać 'imageIn.RawFormat', który próbuje zapisać bajty surowego obrazu bez dalszego ponownego kodowania. –

11

Nie jestem pewien, czy osiągniesz ogromne zyski z powodów wskazanych przez Jona Skeeta. Można jednak wypróbować i przetestować metodę TypeConvert.ConvertTo i sprawdzić, jak to się dzieje w przypadku korzystania z obecnej metody.

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

Nie można rzutować obiektu typu "System.Byte []", aby wpisać "System.Drawing.Image". – user123

9
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

Witamy na stackoverflow.com, czy możesz dodać trochę szczegółów wyjaśniających, dlaczego powyższy przykład kodu pomaga. To jest dla innych użytkowników SO, którzy mogą nie rozumieć tego całkowicie ... http: //stackoverflow.com/help/how-to-answer – Mack

+0

To jest dla plików do bajtów, ale OP chciał obiektu rysunkowego przekonwertowanego na bajty. Obiekty rysunkowe mogą być przechowywane w bazach danych, niekoniecznie w systemie plików, jako tablica bajtów, a zatem muszą być przekształcane w tę iz powrotem ... ale nie jako pliki w FileStream, które mają być konwertowane na bajty - chyba że podczas początkowe przesłanie. – vapcguy

+0

Pomogło mi to, gdy szukałem tego z plikami. Dobrze mieć w pobliżu, jak to jest związane. – CPlayer

33

Istnieje właściwość RawFormat parametrów obrazu, który powraca format pliku obrazu. Można spróbować wykonać następujące czynności:

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

Polecam albo wyrzucenie MemoryStream, albo zawijanie treści tej metody w użyciu() {} statement –

+0

@ Neil.Allen Jestem tu nowy, czy możesz powiedzieć dlaczego? –

+2

@FirstStep Bo posprzątaj po sobie :) – Sinaesthetic

2

Najszybszy sposób mogę dowiedzieć się, jest taka:

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

nadzieję być przydatne

+0

Należy zachować ostrożność, zwłaszcza jeśli używasz WPF, w której miałbyś obiekt 'System.Windows.Controls.Image'. Jeśli chcesz przekonwertować jeden z tych na bajty i przekazujesz go do tego wiersza jako 'InputImg', to nie zadziała. Oczekuje obiektu 'System.Drawing.Image'. – vapcguy

3
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; 
    } 
} 
+0

dzięki za odpowiedź. –