0

I got help in a previous question on how to send an image. The thing done was to first send the lenght of the image(size), and then the actual image, then it would know when it was done.

IT looks like this:

BinaryWriter writer = new BinaryWriter(netStream);
while (someCondition) {
  Image img = SomeImage();
  MemoryStream ms = new MemoryStream();
  img.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
  byte[] buffer = new byte[ms.Length];
  ms.Seek(0, SeekOrigin.Begin);
  ms.Read(buffer, 0, buffer.Length);
  writer.Write(buffer.Length);
  writer.Write(buffer);

This code is from: Angelo Geels , who helped me in my previous question.

Now, i tried to optimize this in a way. And well, it works. But ONLY when the file is bmp (uncompressed), and i don´t know why.

                    using (MemoryStream ms = PrintWindow(process))
                    {
                        writer.Write((int)ms.Length);
                        writer.Write(ms.GetBuffer());
                    }

So PrintWindow save an image to a memorystream and returns it. so ms = memorystream with my image in it.

So for me this should work perfectly, cause form what i can se i do the same thing.

i send the size of the file (length of the memorystream). Then i send the byte[] data in the memorystream.

So, it´s the same thing.

But, it only works with bmp.

The only thing i can think of is that when i save in a compressed format, the bmp is first written and then encoded, which messes up the getbuffer() or something.

But i still think it should work.

Zerowalker
  • 761
  • 2
  • 8
  • 27

2 Answers2

3

You write too many bytes, use the Write() overload that lets you specify how much to write:

    using (MemoryStream ms = PrintWindow(process)) {
        writer.Write((int)ms.Length);
        writer.Write(ms.GetBuffer(), 0, (int)ms.Length);
    }
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Great, it works, and this why i don´t have to convert to a byte array from the looks of it. Thanks:) – Zerowalker Aug 06 '13 at 05:15
  • btw, there isn´t a way to optimize it more? I mean, i have to write the lenght of the file before the file, so it knows where to end. Is it possible to improve that somehow with this? – Zerowalker Aug 06 '13 at 05:16
  • @user2587718 You were never converting to a byte array. Instead, you were reading chunks out of ms, into a temporary buffer, and then writing that. You are worrying FAR too much about "optimizing", and you're "optimizing" the wrong thing. If you're running into performance issues, grab a profiler and see where they are. If they are indeed in this segment of code, you'd get better performance by moving to a native language instead of trying to wring more out of C#. – Xcelled Aug 06 '13 at 16:27
  • 1
    Some numbers for you: over 10,000 tests, your original code saved a 500x500 image in an average of 1,401,749 **nano** seconds. Hans' code did the same in an average of 1,368,200 **nano** seconds. There is little-to-no appreciable difference between these numbers. Writing the length of the stream takes just _31_ **nano** seconds, so you'll gain no performance by eliminating it. – Xcelled Aug 06 '13 at 16:32
2

Don't use GetBuffer. From the documentation:

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; however, ToArray creates a copy of the data in memory.

Use:

 writer.Write(ms.ToArray());

Or if you are in 4.0 use the CopyTo method:

 ms.CopyTo(netStream);

Check this if you are not in 4.0 for a way to copy streams: How do I copy the contents of one stream to another?

Community
  • 1
  • 1
fcuesta
  • 4,429
  • 1
  • 18
  • 13
  • But, how come it works with bmp and not compressed? As ToArray will create a copy (slower?) then GetBuffer? Tried it, it is much slower. And i get "Hickups" from time to times in the proccess time, which goes from 2ms to 12ms, GetBuffer is always 0-2ms. – Zerowalker Aug 06 '13 at 04:27
  • @user2587718 It works by sheer luck, basically. GetBuffer and ToArray are **not** interchangeable. – Xcelled Aug 06 '13 at 04:44
  • I am on 4.5, but can i write directly to the networkstream that way;S? how till it know where to end without a binaryreader/writer? – Zerowalker Aug 06 '13 at 05:18
  • 1
    @user2587718 BinaryWriter is nothing more than a convenient wrapper over some methods. You could write the length by writing the bytes returned from BitConverter.GetBytes and then do CopyTo and achieve the same result. – Xcelled Aug 06 '13 at 16:14