将画线图像绘制到图片框图像中

Paint Drawline Image into Picturebox Image

在我的表单中,我有 2 个 picturebox 控件。我在 pictureBox1 上加载了蓝色背景图像,并单独留下了 pictureBox2 控件。使用下面的代码,我可以在我的 picturebox1 图像上绘制箭头。

目标: 在我的 pictureBox1_MouseUp 事件中,我想将我在 pictureBox1 上绘制的所有箭头添加到 pictureBox2

问题: 问题出在我的 pictureBox1_MouseUp 事件上,当我写 pictureBox2.Image = pictureBox1.Image 它没有添加我在 pictureBox1 上绘制的彩绘箭头。它只添加我在表单加载事件中分配的 pictureBox1 图像。

    private bool isMoving = false;
    private Point mouseDownPosition = Point.Empty;
    private Point mouseMovePosition = Point.Empty;
    private List<Tuple<Point, Point>> lines = new List<Tuple<Point, Point>>();
    Pen _Pen;

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {

        if (isMoving)
        {
            if (pictureBox1.Image == null) e.Graphics.Clear(Color.White);

            // Add this line for high quality drawing:
            e.Graphics.SmoothingMode = SmoothingMode.HighQuality;

            AdjustableArrowCap bigArrow = new AdjustableArrowCap(5, 5);
            _Pen = new Pen(Color.IndianRed, 3);
            _Pen.CustomEndCap = bigArrow;
            e.Graphics.DrawLine(_Pen, mouseDownPosition, mouseMovePosition);
            _Pen.Dispose();
        }
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
        isMoving = true;
        mouseDownPosition = e.Location;
    }

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
        if (isMoving)
        {
            mouseMovePosition = e.Location;
            pictureBox1.Invalidate();
        }
    }

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
    {

        if (isMoving)
        {
            lines.Add(Tuple.Create(mouseDownPosition, mouseMovePosition));
        }
        isMoving = false;

        pictureBox2.Image = pictureBox1.Image;
    }

测试 1:(更改 pictureBox1_Paint 代码)

使用这段代码,它在 pictureBox2 上绘制了箭头,但看起来它正在绘制多个箭头。

        if (isMoving)
        {
            if (pictureBox1.Image == null) e.Graphics.Clear(Color.White);

            // Add this line for high quality drawing:
            e.Graphics.SmoothingMode = SmoothingMode.HighQuality;

            AdjustableArrowCap bigArrow = new AdjustableArrowCap(5, 5);
            _Pen = new Pen(Color.IndianRed, 3);
            Bitmap BitImg = (Bitmap)pictureBox1.Image;
            _Pen.CustomEndCap = bigArrow;
            using (var graphics = Graphics.FromImage(BitImg))
            {
                graphics.DrawLine(_Pen, mouseDownPosition, mouseMovePosition);
            }
            pictureBox1.Image = BitImg;
            _Pen.Dispose();
        } 

测试 2:(我从绘画事件中取出代码并粘贴了一些修改的 MouseMove 事件。这使用了太多内存并且它没有在 pictureBox1 上绘制但箭头现在可见在 pictureBox2)

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
        if (isMoving)
        {
            mouseMovePosition = e.Location;

            if (isMoving)
            {

                AdjustableArrowCap bigArrow = new AdjustableArrowCap(5, 5);
                _Pen = new Pen(Color.IndianRed, 3);
                BitImg = new Bitmap(pictureBox1.Image);                    
                _Pen.CustomEndCap = bigArrow;
                using (var graphics = Graphics.FromImage(BitImg))
                {
                    graphics.SmoothingMode = SmoothingMode.HighQuality;
                    graphics.DrawLine(_Pen, mouseDownPosition, mouseMovePosition);
                }

                _Pen.Dispose();
            }

            pictureBox1.Invalidate();

        }
    }

你这里有两个问题:

  1. 您在控件而不是图像上作画。图片保持不变

  2. pictureBox1pictureBox2 指的是同一张图片。当您更改图像时,两个控件都将在下一个绘制事件中受到影响。

因此,在 pictureBox1_Paint 中,您需要创建 pictureBox1.Image 的副本(尝试使用 Bitmap),然后在其上绘画并将更新后的图像分配给 pictureBox1.Image。会自动上色

将所有线条绘制到 pictureBox1:

只绘制 pictureBox1 的最后一行:

pictureBox2控件中,添加Paint事件到pictureBox2_Paint

我建议你将 pen 和 cap 设为全局变量:

// Make pen and cap global varriable to boost the perfomane.
// Create and delete them each draw will cost alot of CPU
Pen pen = new Pen(Color.IndianRed, 3);
AdjustableArrowCap bigArrow = new AdjustableArrowCap(5, 5);

Form1() 事件中,添加此行:

pen.CustomEndCap = bigArrow;

并进行如下操作:

public partial class Form1 : Form
{
    private bool isMoving = false;
    private Point mouseDownPosition = Point.Empty;
    private Point mouseMovePosition = Point.Empty;
    private List<Tuple<Point, Point>> lines = new List<Tuple<Point, Point>>();

    public Form1()
    {
        InitializeComponent();
        pen.CustomEndCap = bigArrow;
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
        isMoving = true;
        mouseDownPosition = e.Location;
    }

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
        if (isMoving)
        {
            mouseMovePosition = e.Location;
            pictureBox1.Invalidate();
        }
    }

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
    {
        if (isMoving)
        {
            lines.Add(Tuple.Create(mouseDownPosition, mouseMovePosition));
            pictureBox2.Invalidate();
        }
        isMoving = false;
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        if (isMoving)
        {
            if ((sender as PictureBox).Image == null) e.Graphics.Clear(Color.White);

            // Add this line for high quality drawing:
            e.Graphics.SmoothingMode = SmoothingMode.HighQuality;

            e.Graphics.DrawLine(pen, mouseDownPosition, mouseMovePosition);

            // If you want draw all previous lines here, add bellow code:
            //foreach (var line in lines)
            //{
            //    e.Graphics.DrawLine(pen, line.Item1, line.Item2);
            //}
        }
    }

    private void pictureBox2_Paint(object sender, PaintEventArgs e)
    {
        if ((sender as PictureBox).Image == null) e.Graphics.Clear(Color.White);

        e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
        foreach (var line in lines)
        {
            e.Graphics.DrawLine(pen, line.Item1, line.Item2);
        }
    }
}

以上代码将线条绘制到 PictureBox 控件,而不是图像,如果您以后需要,这允许您删除一些线条或清除绘制到图片框的所有线条。

如果你想直接绘制到图像上,事情就容易多了,你根本不需要pictureBox2_Paint:

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
    if (isMoving)
    {
        // You event don't need this line
        //lines.Add(Tuple.Create(mouseDownPosition, mouseMovePosition));

        if (pictureBox1.Image != null)
        {
            using (var g = Graphics.FromImage(pictureBox1.Image))
            {
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.DrawLine(pen, mouseDownPosition, mouseMovePosition);
            }
            pictureBox2.Image = pictureBox1.Image;
        }
    }
    isMoving = false;
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    if (isMoving)
    {
        if ((sender as PictureBox).Image == null) e.Graphics.Clear(Color.White);

        e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
        e.Graphics.DrawLine(pen, mouseDownPosition, mouseMovePosition);
    }
}

private void pictureBox2_Paint(object sender, PaintEventArgs e)
{
}