如何将我在面板上绘制的形状保存为二进制

本文关键字:保存 二进制 绘制 | 更新日期: 2023-09-27 18:17:54

我有一个小的绘画程序。我想创建一个保存按钮,保存面板的细节(形状和一切正在绘制)作为二进制文件。我这样做了:

 SaveFileDialog sfd = new SaveFileDialog();
 BinaryFormatter bf = new BinaryFormatter();
 var stream = new BinaryReader(File.Open(sfd.FileName,FileMode.Create));
 bf.Serialize(stream,object);

,但它有一个错误,使用对象是无效的bf.Serialize。我该怎么做呢?

如何将我在面板上绘制的形状保存为二进制

你不需要序列化面板,面板是不可序列化的。您可以考虑以下两个选项之一:

  1. 您可以在位图上绘制然后保存位图,或者将控件绘制到图像并保存图像。这样你就可以将所有的形状平铺成一张图片,在加载图片之后,它们就不再是可编辑的形状了。就像油漆一样。
  2. 你可以让你的形状序列化,然后在一个文件中序列化你的可序列化形状列表。然后你可以再次反序列化它们。这样你就可以加载你的形状并让用户编辑它们,例如像Visio。

我在这里分享了两个例子:

  • 保存图像示例:它只是将您在面板上绘制的图形保存为位图图像文件。

  • 序列化示例:在这个示例中,我创建了一些可序列化的形状类,其中包含一些属性,如坐标和颜色,然后我创建了SaveLoad方法,允许您在文件中序列化您的形状,也可以从文件中反序列化它们并再次显示它们。您可以简单地扩展这个示例,添加一些功能,如命中测试和移动形状。你也可以使用一个xml序列化器来代替二进制序列化器。

保存图像示例

为了保持简单,在这个例子中,我只是保存面板绘画在一个文件中。

如果你在面板的Paint事件中放置绘画逻辑,那么你可以使用DrawToBitmap将控件的图像保存到文件:

private void button1_Click(object sender, EventArgs e)
{
    using (var bm = new Bitmap(panel1.Width, panel1.Height))
    {
        panel1.DrawToBitmap(bm, new Rectangle(0, 0, bm.Width, bm.Height));
        bm.Save(@"d:'panel.bmp", System.Drawing.Imaging.ImageFormat.Bmp); 
    }
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.FillRectangle(Brushes.Red, 0, 0, 100, 100);
    e.Graphics.FillRectangle(Brushes.Blue, 50, 50, 100, 100);
}
<<p> 序列化例子/strong>

你可以创建一些可序列化的形状,如LineShapeRectangleShape派生自serializable Shape类。我们在这个类中存储形状的属性,这些类也包含绘图逻辑:

[Serializable]
public abstract class Shape
{
    public abstract void Draw(Graphics g);
    public override string ToString() { return GetType().Name; }
}
[Serializable]
public class LineShape : Shape
{
    public LineShape(){ Color = Color.Blue; Width = 2; }
    public Point Point1 { get; set; }
    public Point Point2 { get; set; }
    public int Width { get; set; }
    public Color Color { get; set; }
    public override void Draw(Graphics g)
    {
        using (var pen = new Pen(Color, Width))
            g.DrawLine(pen, Point1, Point2);
    }
}
[Serializable]
public class RectangleShape : Shape
{
    public RectangleShape() { Color = Color.Red; }
    public Rectangle Rectangle { get; set; }
    public Color Color { get; set; }
    public override void Draw(Graphics g)
    {
        using (var brush = new SolidBrush(Color))
            g.FillRectangle(brush, Rectangle);
    }
}

您可以创建一个ShapesList类来保存形状,并包含保存和加载形状的逻辑。还有在表面上绘制所有形状的逻辑:

[Serializable]
public class ShapesList : List<Shape>
{
    public void Save(string file)
    {
        using (Stream stream = File.Open(file, FileMode.Create))
        {
            BinaryFormatter bin = new BinaryFormatter();
            bin.Serialize(stream, this);
        }
    }
    public void Load(string file)
    {
        using (Stream stream = File.Open(file, FileMode.Open))
        {
            BinaryFormatter bin = new BinaryFormatter();
            var shapes = (ShapesList)bin.Deserialize(stream);
            this.Clear();
            this.AddRange(shapes);
        }
    }
    public void Draw(Graphics g)
    {
        this.ForEach(x => x.Draw(g));
    }
}

那么你可以这样使用这些形状和形状列表:

ShapesList Shapes;
private void Form3_Load(object sender, EventArgs e)
{
    Shapes = new ShapesList();
    Shapes.Add(new RectangleShape() { Rectangle = new Rectangle(0, 0, 100, 100), 
        Color = Color.Green });
    Shapes.Add(new RectangleShape() { Rectangle = new Rectangle(50, 50, 100, 100), 
        Color = Color.Blue });
    Shapes.Add(new LineShape() { Point1 = new Point(0, 0), Point2 = new Point(150, 150), 
        Color = Color.Red });
    this.panel1.Invalidate();
}
private void button1_Click(object sender, EventArgs e)
{
    Shapes.Save(@"d:'shapes.bin");
    Shapes.Clear();
    this.panel1.Invalidate();
    MessageBox.Show("Shapes saved successfully.");
    Shapes.Load(@"d:'shapes.bin");
    this.panel1.Invalidate();
    MessageBox.Show("Shapes loaded successfully.");
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    Shapes.Draw(e.Graphics);
}