ToByteArray performance issue

Oct 29, 2014 at 6:24 AM
Hi,

I have to convert bitmap to byte[] but compress rate when i use Encoder of .NET is not good.
I found Magick.NET with compress rate good!! Yeah!! Thanks dlemstra!
But performance of Magick.NET to convert MagickImage to bytes are high(about 300ms) . Encoder of .NET almost instantaneous (0-5ms)
Here is my test code:
byte[] bytes = null;
            MagickImage mImage = new MagickImage();

            Stopwatch total = new Stopwatch();
            Stopwatch read = new Stopwatch();
            Stopwatch toBytes = new Stopwatch();
            // Stopwatch resize = new Stopwatch();
            total.Start();
            for (int i = 0; i < 100; i++)
            {
                read.Start();
                // image is bitmap image object in memory
                mImage.Read(image);
                read.Stop();
                //resize.Start();
                //mImage.Resize(80);
                //resize.Stop();
                toBytes.Start();
                bytes = mImage.ToByteArray(MagickFormat.WebP);
                //mImage.Format = MagickFormat.WebP;
                //mImage.Write("image.webp");
                toBytes.Stop();
            }
            total.Stop();

            Console.WriteLine("Time: {0}, {1}", read.ElapsedMilliseconds, bytes.ElapsedMilliseconds);
The result:
Read: 6340
To byte array: 31159
Image resolution: 1366 * 768

Please tell me my code have some thing wrong? How to increase performance?
One again, thank U for written a useful lib
Coordinator
Oct 29, 2014 at 6:37 AM
Edited Oct 29, 2014 at 6:38 AM
What ToByteArray actually does is create a 'blob' (byte array) and call Write with that byte array as an argument.

Your comparison with the default .NET encoder does not seem fair. You are writing images in the webP format which is not supported by the .NET encoder. Writing to webP will compress the pixels much better but this will of course cost time.
Oct 29, 2014 at 6:58 AM
Oke! I know Webp are higher compress format and cost time much better.
Would U like suggest me format with high compress rate and cost time lower. Input bitmap image is desktop screen capture. What I can do to increase performance ( lower than 100ms)?

I changed source to test convert to Jpg format
// bytes = mImage.ToByteArray(MagickFormat.WebP);
bytes = mImage.ToByteArray(MagickFormat.Jpg);
and result:
Read: 6185
To byte array: 5168
Coordinator
Oct 29, 2014 at 8:11 AM
As you can see your performance increased from 31159/100=311ms to 5168/100=50ms by choosing a different output format. But JPEG compression is lossy, what do you want to do with the image after you have written it?
Oct 29, 2014 at 5:39 PM
I capture desktop screen and send to viewer. The viewer only view screen image. Requirement is high compress rate and cost time lower.

As U see, total time to capture screen, convert from bitmap image in memory to byte [] with Jpg format (Read() and ToByteArray()) is (5932 + 6185 +5168)/100 = 172ms -> FPS: 1000/172 = 5.8 so slow :(
Coordinator
Oct 30, 2014 at 1:47 PM
Edited Oct 30, 2014 at 1:48 PM
Can you explain what are the numbers: 5932 + 6185 +5168? And are you using Magick.NET to take a screenshot? You can do that by reading an image with the name "screenshot:"
// Can you also use screenshot:[1] if you have multiple monitors.
using (MagickImage mImage = new MagickImage("screenshot:"))
{
  bytes = mImage.ToByteArray(MagickFormat.Jpg);
}
Oct 31, 2014 at 3:11 AM
  • 5932 is the average time to capture desktop screen image (use bitmap format), compare with previous screen image and crop the "different zone". If different zone is empty then do not do next step. I use algorithm in http://bobcravens.com/2009/04/create-a-remote-desktop-viewer-using-c-and-wcf/
  • 6185 is the time to Read() method of MagickImage instance execute
  • 5168 is the time to ToByteArray(MagickFormat.Jpg) method of MagickImage instance execute
Your solution is good but not reduce bandwidth because all image is fixed size (screen resolution)
I thinks the my solution is balance between performance and bandwidth. Anyway, thanks for help :)
Coordinator
Nov 1, 2014 at 12:14 PM
Edited Nov 1, 2014 at 12:15 PM
You could also re-implement GetBoundingBoxForChanges in Magick.NET with the GetReadOnlyPixels method and use Crop to resize the image. This will probably be faster because you don't have the overhead of reading/writing the image.