0
\$\begingroup\$

Below I have posted the code I use for drawing pictures. The problem is that when I want to generate more images in full hd size (in loop), the generation time increases significantly. Can somehow optimize my code to speed it up a lot?

  Bitmap bmp = new Bitmap(imageMask.Width, imageMask.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
        bmp.MakeTransparent();

        Bitmap bmpLevel = new Bitmap(imageMask.Width, imageMask.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
        using (Graphics g = Graphics.FromImage(bmpLevel))
        {
            int rectX = levelX.Value;
            int rectY = levelY.Value + levelHeight.Value - valproc;
            int rectWidth = levelWidth.Value;
            int rectHeight = valproc;
            g.FillRectangle(new SolidBrush(levelColor), rectX, rectY, rectWidth, rectHeight);
            g.DrawImage(imageMask, new Rectangle(0, 0, bmpLevel.Width, bmpLevel.Height), new Rectangle(0, 0, imageMask.Width, imageMask.Height), GraphicsUnit.Pixel);
        }
        bmpLevel.MakeTransparent(Color.Black);

        Bitmap contour = new Bitmap(imageMaskCountour.Width, imageMaskCountour.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
        contour.MakeTransparent();
        using (Graphics g = Graphics.FromImage(contour))
        {
            g.FillRectangle(ContourBrush, 0, 0, contour.Width, contour.Height);
            g.DrawImage(imageMaskCountour, new Rectangle(0, 0, contour.Width, contour.Height), new Rectangle(0, 0, imageMaskCountour.Width, imageMaskCountour.Height), GraphicsUnit.Pixel);
        }
        contour.MakeTransparent(Color.Black);

        bmp.MakeTransparent(Color.Black);
        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.DrawImage(contour, new Rectangle(0, 0, bmp.Width, bmp.Height), new Rectangle(0, 0, contour.Width, contour.Height), GraphicsUnit.Pixel);
            g.DrawImage(bmpLevel, new Rectangle(0, 0, bmp.Width, bmp.Height), new Rectangle(0, 0, bmpLevel.Width, bmpLevel.Height), GraphicsUnit.Pixel);
        }

        if (this.HiHiLevel.HasValue)
        {
            using (Graphics g = Graphics.FromImage(bmp))
            {
                int alarmlevel = (int)(((double)this.HiHiLevel.Value / 100.0) * (double)levelHeight);
                int x = levelX.Value;
                int y = levelY.Value + levelHeight.Value - alarmlevel;
                Pen drawPen = new Pen(Color.Red, 2);
                g.DrawLine(drawPen, new Point(x, y + 5), new Point(x + levelWidth.Value, y + 5));
            }
        }
        if (this.HiLevel.HasValue)
        {
            using (Graphics g = Graphics.FromImage(bmp))
            {
                int alarmlevel = (int)(((double)this.HiLevel.Value / 100.0) * (double)levelHeight);

                int x = levelX.Value;
                int y = levelY.Value + levelHeight.Value - alarmlevel;
                Pen drawPen = new Pen(Color.Yellow, 2);
                g.DrawLine(drawPen, new Point(x, y + 5), new Point(x + levelWidth.Value, y + 5));
            }
        }
        if (this.LoLevel.HasValue)
        {
            using (Graphics g = Graphics.FromImage(bmp))
            {
                int alarmlevel = (int)(((double)this.LoLevel.Value / 100.0) * (double)levelHeight);

                int x = levelX.Value;
                int y = levelY.Value + levelHeight.Value - alarmlevel;
                Pen drawPen = new Pen(Color.Yellow, 2);
                g.DrawLine(drawPen, new Point(x, y + 5), new Point(x + levelWidth.Value, y + 5));
            }
        }
        if (this.LoLoLevel.HasValue)
        {
            using (Graphics g = Graphics.FromImage(bmp))
            {
                int alarmlevel = (int)(((double)this.LoLoLevel.Value / 100.0) * (double)levelHeight);

                int x = levelX.Value;
                int y = levelY.Value + levelHeight.Value - alarmlevel;
                Pen drawPen = new Pen(Color.Red, 2);
                g.DrawLine(drawPen, new Point(x, y + 5), new Point(x + levelWidth.Value, y + 5));
            }
        }
        using (System.IO.MemoryStream msItem = new System.IO.MemoryStream())
        {
            bmp.Save(msItem, System.Drawing.Imaging.ImageFormat.Png);
            Schema = msItem.ToArray();
        }
\$\endgroup\$
  • 2
    \$\begingroup\$ Could you please explain what this is doing exactly? It's hard to follow the code expecially that it's not a complete class. \$\endgroup\$ – t3chb0t Mar 29 '17 at 20:02
  • \$\begingroup\$ I have a photo of the tank, and the code above shows the current water level. \$\endgroup\$ – Drakoo Mar 30 '17 at 5:43
  • 1
    \$\begingroup\$ Is there a specific reason why you're creating several Graphics and Bitmaps instead of reusing one? Note that MakeTransparent will convert an image to 32 bpp ARGB, so you may as well specify that format when creating your bitmaps (and remove any redundant MakeTransparent calls). Also, Pens must be disposed. Either way, the code you've shown here is not complete, which makes it difficult to give proper advice. You may want to update your post. \$\endgroup\$ – Pieter Witvoet Mar 30 '17 at 7:17
  • \$\begingroup\$ I wanted to know if I could somehow optimize only the piece of code I gave \$\endgroup\$ – Drakoo Mar 30 '17 at 11:38
  • \$\begingroup\$ For the test I have done the same code, but creating a bitmap only once. Unfortunately, it did not improve its performance. \$\endgroup\$ – Drakoo Mar 30 '17 at 11:52
1
\$\begingroup\$

You can try using the Bitmap.LockBits method (as explained in the link) to speed things up a bit.

Also, since you mentioned you are generating HD images in a loop (if I understood properly), you could run each loop on its own thread.

\$\endgroup\$
1
\$\begingroup\$

As you are not giving code that can be compiled, and I don't want to spend the afternoon filling the gaps to make it run, I'll just list you all the things you can do to speed up the thing:

First of all, Graphics.FromImage is painfully SLOW. And you are using it a lot, when you can just get it the first time and dispose at the end:

using() {} 

to dispose objects it's not like a religious observation.

Linked to the first point there is the fact that the entire code seems quite overcomplicated to just draw a couple of things; i think you simplify it a bit, to avoid many operations. When dealing with graphic, the less steps the better. For example: in the second step you create a bitmap the size of the mask, draw a rectangle on it, then you draw the mask (I suppose to fill the voids). Why don't you just build the bitmap from the mask itself with the appropriate constructor, and then draw the rectangle on top?

Finally, when you want to join together two images masking part of one with the other and you want to do it really fast, use (god, now I feel really old) bitblt. You need to work a bit with pInvoke, but with big images is worth it.

\$\endgroup\$
  • 2
    \$\begingroup\$ I don't like the tone of this answer. \$\endgroup\$ – t3chb0t May 6 '17 at 12:34

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.