【问题标题】:Clear A Bitmap in .Net在.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上
  • 好的;我们在谈论什么数字,即大约有多少层和位图大小?

标签: c# winforms drawing gdi+ graphics2d


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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-16
      • 1970-01-01
      • 2017-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多