Create Bitmap from control DrawToBitmap()

Mantisuma

New member
Joined
Jul 23, 2018
Messages
2
Programming Experience
1-3
?# Visual Studio 2017 Windows forms
Panel Mainpanel:
....
MainBitmap memoryImage;
Rectangle rect = new Rectangle();
rect.Height = Mainpanel.Height;
rect.Width = Mainpanel.Width;
rect.X = 0;
rect.Y = 0;
memoryImage = new Bitmap(Mainpanel.Width, Mainpanel.Height);
Mainpanel.DrawToBitmap(memoryImage, rect);
pictureBoxMiniature.Image = memoryImage;

the DrawToBitmap method returns a picture of only the visible part of the control (Mainpanel)
I need a picture of everything
 
What you said is not correct, but I think you meant something other than what you said. DrawToBitmap will draw the viewport of the Panel, so even if part of that viewport is not visible to the user, it will still be drawn. If you're saying that you want to draw child controls that are not visible through that viewport then you are absolutely correct, and there's nothing you can do about that. In that case, you just can't use DrawToBitmap, or not on the Panel at least. You need to do your own calculations to determine the size of the Bitmap you need based on the maximum Right and Bottom values of the child controls and then you need to draw each child yourself. You can still call DrawToBitmap on each child control and just specify the appropriate target Rectangle. Here's a basic example:
private Bitmap DrawToBitmap(Control container)
{
    // Get child controls based on z-order.
    var childControls = container.Controls.Cast<Control>().ToArray();

    // Reverse order so frontmost control is last.
    Array.Reverse(childControls);

    var maxBottom = childControls.Max(ctrl => ctrl.Bottom);
    var maxRight=childControls.Max(ctrl => ctrl.Right);

    // Create Bitmap with 10 pixels clearance in each direction.
    var bmp = new Bitmap(maxRight + 10, maxBottom + 10);

    foreach (var childControl in childControls)
    {
        childControl.DrawToBitmap(bmp, childControl.Bounds);
    }

    return bmp;
}
 
Thank you
C#:
private void timerMiniature_Tick(object sender, EventArgs e)
        {
            if (tabControl2.SelectedIndex != 1)
                return;
            pictureBoxMiniature.Image = DrawToBitmap(Mainpanel);
            pictureBoxMiniature.SizeMode = PictureBoxSizeMode.Zoom;
        }
        private Bitmap DrawToBitmap(Control container)
        {
            // Get child controls based on z-order.
            var childControls = container.Controls.Cast<Control>().ToArray();

            // Reverse order so frontmost control is last.
            Array.Reverse(childControls);

            var maxRight = Mainpanel.AutoScrollPosition.X * -1 + childControls.Max(ctrl => ctrl.Right);
            var maxBottom = Mainpanel.AutoScrollPosition.Y * -1 + childControls.Max(ctrl => ctrl.Bottom);

            // Create Bitmap with 10 pixels clearance in each direction.
            var bmp = new Bitmap(maxRight + 10, maxBottom + 10);

            foreach (var childControl in childControls)
            {
                Rectangle rect = new Rectangle();
                rect.Height = childControl.Size.Height;
                rect.Width = childControl.Size.Width;
                rect.X = Mainpanel.AutoScrollPosition.X * -1 + childControl.Left; 
                rect.Y = Mainpanel.AutoScrollPosition.Y * -1 + childControl.Top;
                childControl.DrawToBitmap(bmp, rect);
            }
            return bmp;
        }
 
Just one thing I would say about that is that you should always dispose Image objects once you're done with them. If you're assigning a new Bitmap to the Image property of a PictureBox and discarding an existing one, you should dispose that existing one. The easiest way to do that is like this:
pictureBoxMiniature.Image?.Dispose();
pictureBoxMiniature.Image = DrawToBitmap(Mainpanel);

The reason I have used '?.' there is because basically says "call Dispose on pictureBoxMiniature.Image unless it is null". That way, the same code will work without throwing an exception or requiring an 'if' statement on the first occasion that you set the Image property.

Also, unless you're changing the SizeMode somewhere, that is something that you should do in the designer and then not touch in code at all.
 
Back
Top Bottom