Mohamed Ali
Mohamed Ali

Reputation: 3995

Clear A Bitmap in .Net

I'm using PictureBox control to draw complicated charts, and to optimize for performance i use a cache Bitmap for each layer of the drawing, and draw them on the control image, the upper layers have transparent backgrounds, i need to clear them and redraw on every change.

Assuming g instance of Graphics class of the Bitmap, using g.Clear(Color.White) draws a white rectangle over everything and so hiding lower layers, and g.Clear(Color.Transparent) draws Transparent rectangle over, what means doing nothing.

Isn't there a way to clear the Bitmap returning it to its original state?

Upvotes: 4

Views: 10209

Answers (2)

HEWhoDoesn'tKnow
HEWhoDoesn'tKnow

Reputation: 347

private void btn_CancelImage_Click(object sender, EventArgs e)
    {
        DialogResult dialogResult = MessageBox.Show("Cancel and delete this Image?", "Cancel", MessageBoxButtons.YesNo);
        if (dialogResult == DialogResult.Yes)
        {
            ClearImage();
            pictureBox1.Refresh();
        }
        else if (dialogResult == DialogResult.No)
        {
            return;
        }
    }
    public void ClearImage()
    {
        Graphics g = Graphics.FromImage(ImageBitmap);
        g.Clear(Color.White);
    }

Upvotes: 6

TaW
TaW

Reputation: 54433

This is maybe not the answer you were looking for but I think it is an insteresting alternative to what you have.

Instead of having to draw all the layers upwards from every change, I stack as many layers on top of each other by nesting a number of PictureBoxes into one bottom PictureBox pBox0:

List<PictureBox> Layers = new List<PictureBox>();

private void Form1_Load(object sender, EventArgs e)
{
    Layers.Add(pBox0);
    setUpLayers(pBox0 , 20);  // stacking 20 layers onto the botton one
    timer1.Start();           // simulate changes
}

The stacking is set up like this:

void setUpLayers(Control parent, int count)
{
    for (int i = 0; i < count; i++)
    {
        PictureBox pb = new PictureBox();
        pb.BorderStyle = BorderStyle.None;
        pb.Size = parent.ClientSize;
        Bitmap bmp = new Bitmap(pb.Size.Width,pb.Size.Height,PixelFormat.Format32bppPArgb);
        pb.Image = bmp;
        pb.Parent = i == 0 ? pBox0 : Layers[i - 1];
        Layers.Add(pb);
    }
}

For best performance I use Format32bppPArgb as the pixel format.

For testing I run a Tick event that randomly draws onto a layer:

Random R = new Random(9);
private void timer1_Tick(object sender, EventArgs e)
{
    int l = R.Next(Layers.Count-1) + 1;

    Bitmap bmp = (Bitmap) Layers[l].Image;
    using (Graphics G = Graphics.FromImage(Layers[l].Image))
    {
        G.Clear(Color.Transparent);
        using (Font font = new Font("Consolas", 33f))
        G.DrawString(l + " " + DateTime.Now.Second , font, Brushes.Gold, 
            R.Next(bmp.Size.Width),  R.Next(bmp.Size.Height));
    }
    Layers[l].Image = bmp;
}

To collect all layers into one Bitmap you would make use of the DrawToBitmap method:

Bitmap GetComposite(Control ctl)
{
    Bitmap bmp = new Bitmap(ctl.ClientSize.Width, ctl.ClientSize.Height,
                            PixelFormat.Format32bppArgb);
    ctl.DrawToBitmap(bmp, ctl.ClientRectangle);
    return bmp;
}

The result can then be saved or used in any other way..

Note that creating too many layers this way will hit a limit for window handles; I hit that limit at around 90 layers. If you need more that a few dozen layers a more intricate caching strategy is called for..

Upvotes: 1

Related Questions