【问题标题】:Saving bitmap in a paint program在绘图程序中保存位图
【发布时间】:2017-08-18 16:13:39
【问题描述】:

我正在开发一个完全用 c# 编写的类似 MS 绘画的程序。这是非常基本的,但我偶然发现了一个问题。所以我看到了另一个关于 MS 油漆模型的 SO 帖子。这是关于如何将最终结果保存为 .bmp 文件。我尝试使用提供的解决方案和答案并且它有效。

文件已保存。然而,当它保存时,它只保存了空白面板(我正在制作一个表单应用程序)。我只看到一篇处理此问题的 SO 帖子,但我无法合并以允许用户进行交互。以下是我的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

    namespace Paint
    {
    public partial class Form1 : Form
    {
    Graphics g;
    Pen p = new Pen(Color.Black, 1);
    Point sp = new Point(0, 0);
    Point ep = new Point(0, 0);
    int k = 0;

    public Form1()
    {
        InitializeComponent();
    }

    private void pictureBox2_Click(object sender, EventArgs e)
    {
        p.Color = red.BackColor;
        default1.BackColor = red.BackColor;


    }

    private void blue_Click(object sender, EventArgs e)
    {
        p.Color = blue.BackColor;
        default1.BackColor = blue.BackColor;
    }

    private void green_Click(object sender, EventArgs e)
    {
        p.Color = green.BackColor;
        default1.BackColor = green.BackColor;
    }



    private void panel2_MouseDown(object sender, MouseEventArgs e)
    {
        sp = e.Location;
        if (e.Button == MouseButtons.Left)
            k = 1;
    }

    private void panel2_MouseUp(object sender, MouseEventArgs e)
    {
        k = 0;
    }

    private void panel2_MouseMove(object sender, MouseEventArgs e)
    {
        if (k == 1)
        {
            ep = e.Location;
            g = panel2.CreateGraphics();
            g.DrawLine(p, sp, ep);

        }
        sp = ep;
    }



    private void panel2_MouseLeave(object sender, EventArgs e)
    {
        k = 0;        }

    private void panel2_Paint(object sender, PaintEventArgs e)
    {

    }

    private void button1_Click(object sender, EventArgs e)
    {
        SaveFileDialog dialog = new SaveFileDialog();
        if (dialog.ShowDialog() == DialogResult.OK)
        {
            int width = Convert.ToInt32(panel2.Width);
            int height = Convert.ToInt32(panel2.Height);
            Bitmap bmp = new Bitmap(width, height);
            panel2.DrawToBitmap(bmp, new Rectangle(0, 0, width, height));
            bmp.Save(dialog.FileName, System.Drawing.Imaging.ImageFormat.Bmp);
        }
    }
}
}

所以我的问题是......我如何在我的 c# 表单应用程序中成功保存 .bmp 图像,就像我如何不让它保存为空白一样。在此先感谢:)

编辑

所以我尝试了第一个答案,并且我尝试了个人在 cmets 中提出的想法以及一些方法,而不是仅仅保存空白画布。该应用程序实际上只是保存了一个黑色图像。这是我最终得到的代码。我哪里做错了?

using System;

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks; 
using System.Windows.Forms;

namespace Paint
{
public partial class Form1 : Form
{
    Graphics g;
    Graphics h;
    Pen p = new Pen(Color.Black, 1);
    Point sp = new Point(0, 0);
    Point ep = new Point(0, 0);
    int k = 0;
    Bitmap bmp =null;

    public Form1()
    {
        InitializeComponent();
    }

    private void pictureBox2_Click(object sender, EventArgs e)
    {
        p.Color = red.BackColor;
        default1.BackColor = red.BackColor;


    }

    private void blue_Click(object sender, EventArgs e)
    {
        p.Color = blue.BackColor;
        default1.BackColor = blue.BackColor;
    }

    private void green_Click(object sender, EventArgs e)
    {
        p.Color = green.BackColor;
        default1.BackColor = green.BackColor;
    }



    private void panel2_MouseDown(object sender, MouseEventArgs e)
    {
        sp = e.Location;
        if (e.Button == MouseButtons.Left)
            k = 1;
    }

    private void panel2_MouseUp(object sender, MouseEventArgs e)
    {
        k = 0;
    }

    private void panel2_MouseMove(object sender, MouseEventArgs e)
    {
        if (k == 1)
        {
            ep = e.Location;
            int width = Convert.ToInt32(panel2.Width);
            int height = Convert.ToInt32(panel2.Height);
            Bitmap bmp = new Bitmap(width, height);

            g = Graphics.FromImage(bmp);
            g.DrawLine(p, sp, ep);
            h = panel2.CreateGraphics();
            h.DrawLine(p, sp, ep);
        }
        sp = ep;
    }



    private void panel2_MouseLeave(object sender, EventArgs e)
    {
        k = 0;        }

    private void panel2_Paint(object sender, PaintEventArgs e)
    {

    }

    private void button1_Click(object sender, EventArgs e)
    {
        SaveFileDialog dialog = new SaveFileDialog();
        if (dialog.ShowDialog() == DialogResult.OK)
        {
            /*
            Bitmap bmp = Bitmap.FromHbitmap(panel2.CreateGraphics().GetHdc());
            panel2.DrawToBitmap(bmp, new Rectangle(0, 0, width, height));*/
            int width = panel2.Width;
            int height = Convert.ToInt32(panel2.Height);
            if (bmp == null)

                bmp = new Bitmap(width, height);
            bmp.Save(dialog.FileName, System.Drawing.Imaging.ImageFormat.Jpeg);
        }
    }
}

}

【问题讨论】:

  • g = panel2.CreateGraphics(); Winforms 图形基本规则#1:永远不要使用control.CreateGraphics!永远不要尝试缓存 Graphics 对象!使用Graphics g = Graphics.FromImage(bmp) 或在控件的Paint 事件中使用e.Graphics 参数绘制到Bitmap bmp 中。-您可以将代码用于临时内容,但用于真实的持久内容,这将是在 DrawToBitmap 中使用,您需要在 Paint 事件及其 e.Graphics 对象中进行绘制。为此,请收集您在 List.. 中绘制的每个元素
  • 好的,我将如何在我的代码中实施您的第一个建议:Graphics g = Graphics.FromImage(bmp)。我是新手,如果我测试你的耐心,我很抱歉。 (我的意思是我把它放在代码的什么地方,我还需要修改什么)
  • 在类级别创建位图 bmp 后,您可以简单地将 g = panel2.CreateGraphics(); 替换为 g = Graphics.FromImage(bmp);。这没关系,但不允许您实现一些不错的撤消操作,这对于绘图应用程序来说非常好......所以最好选择更大的解决方案/重写。 Here 是一大堆例子..
  • 当我替换它时,它说 bmp 在当前上下文中不存在。这是因为我还没有定义它,所以我要向上移动它还是用按钮单击功能做什么
  • 是的,将其定义为类级别并在表单加载中创建它。或者在某个条件下使用它之前 (if (bmp==null) bmp= new Bitmap(, w, h);)

标签: c# winforms bitmap


【解决方案1】:

这是一个修订版,和我在 cmets 中告诉你的差不多……:

public partial class Form2 : Form
{
    Graphics g;
    Graphics h;
    Pen p = new Pen(Color.Black, 1);
    Point sp = new Point(0, 0);
    Point ep = new Point(0, 0);
    int k = 0;
    Bitmap bmp =null;

    public Form2()
    {
        InitializeComponent();
        bmp = new Bitmap(panel2.ClientSize.Width, panel2.ClientSize.Height);
        g = Graphics.FromImage(bmp);
        g.Clear(panel2.BackColor);
    }

    private void pictureBox2_Click(object sender, EventArgs e)
    {
        p.Color = red.BackColor;
        default1.BackColor = red.BackColor;
     }

    private void color_Click(object sender, EventArgs e)
    {
        Control ctl = sender as Control;
        p.Color = ctl.BackColor;
        default1.BackColor = ctl.BackColor;
    }

    private void panel2_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            ep = e.Location;
            g.DrawLine(p, sp, ep);
            h = panel2.CreateGraphics();
            h.DrawLine(p, sp, ep);
        }
        sp = ep;
    }

    private void panel2_MouseDown(object sender, MouseEventArgs e)
    {
        sp = e.Location;
    }


    private void button1_Click(object sender, EventArgs e)
    {
        SaveFileDialog dialog = new SaveFileDialog();
        if (dialog.ShowDialog() == DialogResult.OK)
        {
            bmp.Save(dialog.FileName, System.Drawing.Imaging.ImageFormat.Jpeg);
        }
    }
}

一些注意事项:

  • 我将调色板控件的所有点击都映射为一个。
  • 我通过移动中的按钮测试消除了标志k
  • 我保留了缓存的图形g;这通常是不推荐的,但是当我们继续绘制成一个并且相同的位图是可以的。
  • 我已删除位图bmp 的所有重复声明。
  • 不知道picturebox是做什么的,所以没碰代码。

该方案的缺点:

  • 由于您没有跟踪所有移动,因此您无法很好地撤消
  • 由于所有线条都是单独绘制的,因此使用更宽和/或半透明的 Pen 无法获得良好的效果,因为重叠的端点看起来很糟糕。

对于简单涂鸦的更好解决方案,请参阅here,在您研究它之后,您可以解决更好的解决方案,这将允许您使用各种绘图工具here..

【讨论】:

  • 一个简单的问题(ps 感谢您的回答):现在保存为黑色背景。如何让它保存到白色背景?
  • g.Clear(panel2.BackColor); 实际上它保存到面板的背景色。请注意,默认情况下面板是透明的,还有很多查看器,例如Irfanview 无法显示透明度。 (IrfanView 将其显示为黑色!)所以也许你看到的实际上是透明的?您可以将面板更改为白色或简单地清除为 Color.White..
【解决方案2】:

使用Graphics.GetHdc Method 并像这样保存它:

Bitmap bitMap = Bitmap.FromHbitmap(g.GetHdc());
bitMap.Save(dialog.FileName, System.Drawing.Imaging.ImageFormat.Bmp);

【讨论】:

  • 我已经重写了我的函数:` if (dialog.ShowDialog() == DialogResult.OK) { int width = Convert.ToInt32(panel2.Width); int 高度 = Convert.ToInt32(panel2.Height);位图 bitMap = Bitmap.FromHbitmap(g.GetHdc()); bitMap.Save(dialog.FileName, System.Drawing.Imaging.ImageFormat.Bmp); }`
  • 并且 System.Drawing.dll 错误中发生了“System.InvalidOperationException”。它表示该对象(即 g)正在其他地方使用
  • 试试这个:Bitmap bitMap = Bitmap.FromHbitmap(panel2.CreateGraphics());
  • 它给我的错误是它无法将 System.drawing.graphics 转换为 system.IntPtr
  • 抱歉,打错字了。试试Bitmap bitMap = Bitmap.FromHbitmap(panel2.CreateGraphics().GetHdc())
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多