在.Net中清除位图

Posted

技术标签:

【中文标题】在.Net中清除位图【英文标题】:Clear A Bitmap in .Net 【发布时间】:2016-03-19 07:43:53 【问题描述】:

我使用PictureBox控件绘制复杂的图表,为了优化性能我对绘图的每一层都使用缓存位图,并将它们绘制在控件图像上,上层有透明背景,我需要清除他们并重绘每一个变化。

假设位图的 Graphics 类的 g 实例,使用 g.Clear(Color.White) 在所有内容上绘制一个白色矩形,因此隐藏较低层,g.Clear(Color.Transparent) 在上面绘制透明矩形,这意味着什么都不做。

有没有办法清除位图使其恢复到原始状态?

【问题讨论】:

如果它们不经常更改,我会考虑将较低级别绘制成一个位图,我将其显示为 PictureBox.Image 甚至 BackgroundImage。除了我不认为有任何一种方法可以在任何一个更改时绘制构成整个图像的所有位图。不过,您不仅可以缓存单个图层,还可以缓存它们的合成;但是您仍然需要从更改的图层向上重新创建所有位图。 - 顺便说一句:我不确定你选择的词:看起来你不是在询问清除 Bitmap 而是部分或全部复合图形? 每当发生变化(比如移动)时,我都会在图层的缓存图像上重新绘制变化所在的图层中的形状(在用其背景颜色清除后),然后绘制所有图层在picturebox.image上从下向上的图像,当清除具有“透明”以外的任何颜色的图层图像时可以,但是如果图层是透明的(因为它是覆盖图层),移动的形状仍然会在两个位置绘制(旧的和新的)。 让我们明确一点:您将所有这些图层绘制到一个 pb 的顶部?不是图像?没有嵌套面板? (这是避免重绘的好方法..) 所有图层都绘制在pictureBox.image上 好的;我们在谈论什么数字,即大约有多少层和位图大小? 【参考方案1】:
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);
    

【讨论】:

【参考方案2】:

这可能不是您要寻找的答案,但我认为它是您所拥有的有趣的替代方案。

我不必每次更改都向上绘制所有图层,而是通过嵌套多个PictureBoxes到一个底部PictureBox pBox0,将尽可能多的图层堆叠在一起: p>

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

堆叠是这样设置的:

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 层左右达到了这个限制。如果您需要更多的几十层,则需要更复杂的缓存策略..

【讨论】:

以上是关于在.Net中清除位图的主要内容,如果未能解决你的问题,请参考以下文章

Android 清除画布上绘制的位图

如何在 .NET 中使用大位图?

在 .NET 2.0 中将位图转换为一个多页 TIFF 图像

VB.NET 在图片框中绘制与设备无关的位图

.Net Core 无法使用位图

.NET Core 2.0 中的位图图像