7
\$\begingroup\$

I am trying to upload an image (screenshot from desktop) to an SQL database as fast as possible. I would like to optimize my current procedure in terms of speed:

bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
                       Screen.PrimaryScreen.Bounds.Height,
                       System.Drawing.Imaging.PixelFormat.Format32bppArgb);
gfxScreenshot = Graphics.FromImage(bmpScreenshot);
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
                                    Screen.PrimaryScreen.Bounds.Y,
                                    0,
                                    0,
                                    Screen.PrimaryScreen.Bounds.Size,
                                    CopyPixelOperation.SourceCopy);

byte[] imageBytes = convertImageToByteArray(bmpScreenshot);
MemoryStream mem = new MemoryStream(imageBytes);
using (Bitmap bmp1 = (Bitmap)Image.FromStream(mem))
{

     ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
     ImageCodecInfo jgpEncoder = codecs[1];

     System.Drawing.Imaging.Encoder myEncoder =
     System.Drawing.Imaging.Encoder.Quality;

}

  using (MemoryStream m = new MemoryStream())
                    {
                        EncoderParameters myEncoderParameters = new EncoderParameters(1);
                        EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 23L);
                        myEncoderParameters.Param[0] = myEncoderParameter;
                        bmp1.Save(m, jgpEncoder, myEncoderParameters);
   using (Bitmap bmpLast = (Bitmap)Image.FromStream(m))
                        {
                    string query = "UPDATE ScreenCapture SET ScreenCapture=@Image,BroadcastTime=@BroadcastTime WHERE ID = 1";
                    SqlCommand sqlCommand = new SqlCommand(query, SQLconn);
                    ImageConverter converter = new ImageConverter();
                    byte[] beforeUpload = (byte[])converter.ConvertTo(bmpLast, typeof(byte[]));
                    sqlCommand.Parameters.AddWithValue("@Image", beforeUpload);
                    sqlCommand.Parameters.AddWithValue("@BroadcastTime", DateTime.Now);
                    SQLconn.Open();
                    sqlCommand.ExecuteNonQuery();
                    SQLconn.Close();
                }
            }
        }

Profiling - Performance and Diagnostics in Visual Studio 2013

The method I posted has following usage:

  • 40,8% - byte[] imageBytes = convertImageToByteArray(bmpScreenshot);
  • 10,4% - MemoryStream mem = new MemoryStream(imageBytes);
  • 37,8% - mp1.Save(m, jgpEncoder, myEncoderParameters);

From captureUpload which takes 93.6% in System.Windows.Forms.ni.dll:

  • 69.9% - System.Drawing.ni.dll
  • 26.8% - convertImageToByteArray
  • 8.8 - PresentationFramework.ni.dll

convertImageToByteArray takes 26.8% on return ms.ToArray().

It now takes me about 1 second to upload and download on client side, which is not so efficient in my case. If anyone have idea how this procedure is possible to make faster I would be glad to know. The image has around 60 KB, which is quite a lot.

\$\endgroup\$
  • \$\begingroup\$ Have you profiled your code? Which part takes the most time? \$\endgroup\$ – svick Mar 7 '14 at 16:58
  • 1
    \$\begingroup\$ Do you need to be able to see every pixel on the screen? If not, reduce the size of the image to half the height and width. Your image size will drop by about 75%. You can also lower the image quality of the JPEG by setting that attribute in the codec parameters (are you doing that with the 23 parameter?). \$\endgroup\$ – Adam Zuckerman Mar 7 '14 at 20:38
  • \$\begingroup\$ Which database are you using? Some are more efficient about BLOB storage than others. \$\endgroup\$ – Adam Zuckerman Mar 7 '14 at 20:39
  • \$\begingroup\$ @AdamZuckerman I'm using SQL Database to upload. I thought that it would be efficient to change the image quality then the image size but I will definetly try out! Thanks for recomendation! \$\endgroup\$ – Marek Mar 7 '14 at 20:55
  • 1
    \$\begingroup\$ Are there absolute values on the profiling results apart from percents. What amount of that 1 sec is spent on establishing a connection from client to app server and from app server to DB server. \$\endgroup\$ – abuzittin gillifirca Mar 12 '14 at 8:44
2
\$\begingroup\$

For graphic part :

I think Gdi++ of .NET framework is very slow. Mainly the Bitmap() construtor and Save() method.

If it's possible for screenshot, I recommend to use : Either directly gdi32.dll or (maybe, im not sure that is good idea) direct2d (benefits on hardware acceleration).

For transfert :

For your upload, run the transfert in other thread. (async or Delegate with BeginInvoke). After it depends on your internet connection speed.

However, i don't understand why you recreate your Bitmap object twice :

using (Bitmap bmp1 = (Bitmap)Image.FromStream(mem))
using (Bitmap bmpLast = (Bitmap)Image.FromStream(m))

Don't reload with Bitmap, create only one Bitmap for your screenshot, save it with encoding in memory stream and send memory stream to your database. With your memory stream you can get directly byte array with no conversion.

MemoryStream.Read(byte[] buffer, int offset, int count)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.