在.Net中清除位图

4
我使用PictureBox控件绘制复杂的图表,并为了性能优化,为每个绘图层使用缓存位图,并在控件图像上绘制它们,上层具有透明背景,我需要在每次更改时清除它们并重新绘制。
假设g是Bitmap的Graphics类实例,使用会覆盖所有内容并隐藏较低的层,而g.Clear(Color.Transparent)会绘制透明矩形,这意味着什么都不做。
难道没有一种方法可以清除位图并将其返回到原始状态吗?

如果它们不经常更改,我会考虑将较低级别绘制成位图,然后显示为PictureBox.Image甚至BackgroundImage。除此之外,我认为没有办法避免在任何一个更改时绘制组成总图像的所有位图。您不仅可以缓存单个图层,还可以缓存它们的复合图像;但是您仍然需要从更改的图层向上重新创建所有位图。顺便说一句:我不确定您选择的词语是否正确:看起来您并不是很清楚如何清除__Bitmap__,而是部分或全部清除您的复合图形? - TaW
每当发生变化(比如移动),我就在发生变化的图层中重新绘制形状(在清除其背景颜色后),并将所有图层的图像从下往上绘制在picturebox.image上。如果使用任何颜色清除图层的图像,都没有问题,但如果该图层是透明的(因为它是叠加图层),则移动的形状仍会在两个位置(旧位置和新位置)绘制。 - Mohamed Ali
让我们搞清楚:您是将所有这些图层绘制到一个pb的顶部,而不是图像吗?没有嵌套面板吗?(这是避免大量重绘的好方法..) - TaW
好的,我们在谈论哪些数字,即大约有多少层和什么位图大小? - TaW
让我们在聊天中继续这个讨论。点击此处进入聊天室 - TaW
显示剩余3条评论
2个回答

6
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);
    }

1
这也许不是你要找的答案,但我认为它是一个有趣的替代方案。与其必须从每次更改中向上绘制所有图层,我通过将多个 PictureBox 嵌套到一个底部的 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
}

这段话的意思是:“堆叠设置如下:”。其中,“html”是一种标记语言,用于创建网页。
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);
    }
}

为了获得最佳性能,我使用Format32bppPArgb作为像素格式。
为了测试,我运行一个Tick事件,随机绘制到一个图层上:
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;
}

要将所有图层合并为一个位图,您可以使用DrawToBitmap方法:

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

结果可以保存或以任何其他方式使用。
请注意,通过这种方式创建太多的层会达到窗口句柄的限制;我在约90个层时达到了该限制。如果您需要更多的层,需要采用更复杂的缓存策略。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接