在 .Net 中清除位图
Clear A Bitmap in .Net
我在用PictureBox控件绘制复杂的图表,为了优化性能我对每层绘图都使用了一个缓存Bitmap,并绘制在控件图像上,上层有透明背景,我需要清除它们并在每次更改时重新绘制。
假设 Bitmap 的 Graphics class 的 g 实例,使用 g.Clear(Color.White)
在所有内容上绘制一个白色矩形,从而隐藏较低层,并且 g.Clear(Color.Transparent)
在其上绘制透明矩形,这意味着什么什么都不做。
没有办法清除 Bitmap 使其恢复到原来的状态吗?
这可能不是您正在寻找的答案,但我认为它是您现有答案的有趣替代品。
我不必每次更改都向上绘制所有层,而是通过 嵌套 将多个 PictureBoxes
层叠成一个层底部 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
}
堆叠是这样设置的:
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;
}
结果可以保存或以任何其他方式使用..
请注意,以这种方式创建太多图层会达到 window 个句柄的限制;我在大约 90 层时达到了这个限制。如果您需要的层数超过几十层,则需要更复杂的缓存策略..
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);
}
我在用PictureBox控件绘制复杂的图表,为了优化性能我对每层绘图都使用了一个缓存Bitmap,并绘制在控件图像上,上层有透明背景,我需要清除它们并在每次更改时重新绘制。
假设 Bitmap 的 Graphics class 的 g 实例,使用 g.Clear(Color.White)
在所有内容上绘制一个白色矩形,从而隐藏较低层,并且 g.Clear(Color.Transparent)
在其上绘制透明矩形,这意味着什么什么都不做。
没有办法清除 Bitmap 使其恢复到原来的状态吗?
这可能不是您正在寻找的答案,但我认为它是您现有答案的有趣替代品。
我不必每次更改都向上绘制所有层,而是通过 嵌套 将多个 PictureBoxes
层叠成一个层底部 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
}
堆叠是这样设置的:
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;
}
结果可以保存或以任何其他方式使用..
请注意,以这种方式创建太多图层会达到 window 个句柄的限制;我在大约 90 层时达到了这个限制。如果您需要的层数超过几十层,则需要更复杂的缓存策略..
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);
}