112

I am making Remote Desktop sharing application in which I capture an image of the Desktop and Compress it and Send it to the receiver. To compress the image I need to convert it to a byte[].

Currently I am using this:

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

But I don't like it because I have to save it in a ImageFormat and that may also use up resources (Slow Down) as well as produce different compression results.I have read on using Marshal.Copy and memcpy but I am unable to understand them.

So is there any other method to achieve this goal?

user2529551
  • 1,129
  • 2
  • 7
  • 5
  • both MemoryStream and Image have a dispose method, make sure you are Disposing of them as this can cause MemoryLeaks. – abc123 Jun 27 '13 at 19:57
  • 3
    @abc123: You don't need to dispose of a `MemoryStream`; it's an entirely managed resource, unless you're using it in remoting. In both of these cases it would be inappropriate to dispose of the resource. – Jon Skeet Jun 27 '13 at 19:57
  • 1
    @JonSkeet interesting, have you done a benchmark on that? to see the speed at which .net releases the object? I know that there is a similar argument for DataTable and yet there is a noticeable difference in the speed that the GarbageCollector collects the memory allocated when a dispose is used. – abc123 Jun 27 '13 at 20:08
  • @abc123: I really wouldn't expect there to be - disposing of the stream doesn't do anything to the array, and MemoryStream doesn't have a finalizer (unlike DataTable, which inherits one from MarshalByValueComponent). – Jon Skeet Jun 27 '13 at 20:12
  • 2
    any final solution with full source code ? – Kiquenet Nov 29 '13 at 19:12
  • Nice thing. This question already answeres my question. According to other examples this one is really short and compact. I cant get your problem with this. Im trying to create a quite same application. You code already fits for me. :) Upvoted. – C4d Jan 23 '15 at 12:59

7 Answers7

56

There is a RawFormat property of Image parameter which returns the file format of the image. You might try the following:

// extension method
public static byte[] imageToByteArray(this System.Drawing.Image image)
{
    using(var ms = new MemoryStream())
    {
        image.Save(ms, image.RawFormat);
        return ms.ToArray();
    }
}
LatentDenis
  • 2,839
  • 12
  • 48
  • 99
Newt
  • 569
  • 4
  • 2
  • 10
    I'd recommend either disposing of the MemoryStream or wrapping the body of this method in a using(){} statement – Neil.Allen Nov 10 '14 at 21:10
  • @Neil.Allen I am new here can you please tell why? – Khalil Khalaf Mar 28 '16 at 04:14
  • 4
    @FirstStep Because clean up after yourself :) – Sinaesthetic Apr 08 '16 at 17:55
  • @Sinaesthetic I see. And the routine is to put whatever function I want to execute, in a using(){}? – Khalil Khalaf Apr 08 '16 at 17:56
  • 2
    @FirstStep Not quite. More accurately: If you use an object that has implemented IDisposable, then you should be sure to call Dispose() when you're done with it so that it'll clean up any resources that it has tied up. The using(){} statement just calls it for you when the object goes out of scope of that statement. So you can do `myObject.Dispose()` or `using(myObject){}` -- both do the same thing, but the using statement basically creates a scope that will clean up for you. – Sinaesthetic Apr 08 '16 at 20:11
  • 1
    @Neil.Allen using statement will call Dispose – Mevius Sep 22 '16 at 17:43
40

So is there any other method to achieve this goal?

No. In order to convert an image to a byte array you have to specify an image format - just as you have to specify an encoding when you convert text to a byte array.

If you're worried about compression artefacts, pick a lossless format. If you're worried about CPU resources, pick a format which doesn't bother compressing - just raw ARGB pixels, for example. But of course that will lead to a larger byte array.

Note that if you pick a format which does include compression, there's no point in then compressing the byte array afterwards - it's almost certain to have no beneficial effect.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 12
    rather than 'pick a lossless format' you can pick `imageIn.RawFormat` which attempts to save the raw image bytes without further re-encoding. – Chris F Carroll Mar 27 '15 at 12:35
16
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
  • 445
  • 5
  • 15
  • 5
    Welcome to stackoverflow.com, could you add a little detail explaining why the code sample above helps. It's for other SO users who may not understand it entirely...http://stackoverflow.com/help/how-to-answer – Mack May 02 '14 at 08:54
  • This is for files to bytes, but the OP wanted a drawing object converted to bytes. Drawing objects can be stored in databases, not necessarily the file system, as an array of bytes, and therefore have to be transformed back and forth... but not as files in a FileStream to be converted to bytes - unless perhaps, during the initial upload. – vapcguy Mar 10 '15 at 01:18
  • This helped me as I was looking to do this with files. Good to have around as its related. – Justin Oct 13 '15 at 20:56
14

I'm not sure if you're going to get any huge gains for reasons Jon Skeet pointed out. However, you could try and benchmark the TypeConvert.ConvertTo method and see how it compares to using your current method.

ImageConverter converter = new ImageConverter();
byte[] imgArray = (byte[])converter.ConvertTo(imageIn, typeof(byte[]));
keyboardP
  • 68,824
  • 13
  • 156
  • 205
6
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
  • 16,571
  • 12
  • 101
  • 98
4

The fastest way i could find out is this :

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

Hope to be useful

alireza amini
  • 1,712
  • 1
  • 18
  • 33
  • Be careful with this, especially if using WPF where you would have `System.Windows.Controls.Image` objects. If you want to convert one of those to bytes, and you pass it to this line as `InputImg`, this won't work. It expects a `System.Drawing.Image` object. – vapcguy May 19 '17 at 23:02
-1

Try following Code:

public Byte[] ConvertPictureToByte(System.Drawing.Image PictureFile)
{
   using (var MemStrm = new MemoryStream())
   {
      PictureFile.Save(MemStrm,PictureFile.RawFormat);
      return  MemStrm.ToArray();
   }
}
AliNajafZadeh
  • 1,216
  • 2
  • 13
  • 22