如何在放大的图像上绘图? [英] How to draw on a zoomed image?

查看:20
本文介绍了如何在放大的图像上绘图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序中有一个 Size 400X400 的图片框.图片框的SizeMode 设置为Zoomed.我已经在图片框中加载了 700X446 的 png 图片.

I have a picturebox of Size 400X400 in my application. The SizeMode of the picturebox is set to Zoomed. I have loaded a png image of 700X446 in the picturebox.

我有以下问题,

即使我沿着红色路径画了一条黑色直线,实际上它是在透视之外沿着加载的图像显示的.

Even though I am drawing a black straight line along the red path, actually it is being shown along the loaded image out of perspective.

我该如何解决问题?

P.S.我只想在图像上绘制,而不是整个图片框.

P.S. I want to draw only on the image, not the entire picturebox.

源代码:

 public partial class MainForm : Form
 {
    Bitmap _inputImage = null;
    //Graphics _imageGraphics = null;

    #region ctor
    public MainForm()
    {
        InitializeComponent();

        _inputImage = Bitmap.FromFile(@"E:cracked.png") as Bitmap;

        this.inputImagePictureBox.Image = _inputImage;
    }
    #endregion

    #region Mouse Up and Down
    Point _startPoint = Point.Empty;

    private void left_MouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            _startPoint = e.Location;

            Circle tempCircle = new Circle(_startPoint, 10);

            Bitmap tempImage = (Bitmap)_inputImage.Clone();

            Graphics g = Graphics.FromImage(tempImage);

            tempCircle.Draw(g);

            inputImagePictureBox.Image = tempImage;
        }
    }

    private void pressed_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            if (_startPoint != e.Location)
            {
                Line tempLine = new Line(_startPoint, e.Location);

                Bitmap tempImage = (Bitmap)_inputImage.Clone();

                Graphics g = Graphics.FromImage(tempImage);

                tempLine.Draw(g);

                inputImagePictureBox.Image = tempImage;
            }
        }
    }

    Bitmap _savedImage;

    private void left__MouseUp(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            if (_startPoint != e.Location)
            {
                Line tempLine = new Line(_startPoint, e.Location);

                Bitmap tempImage = (Bitmap)_inputImage.Clone();

                Graphics g = Graphics.FromImage(tempImage);

                tempLine.Draw(g);

                _savedImage = tempImage;

                inputImagePictureBox.Image = tempImage;
            }
            else
            {
                Bitmap tempImage = (Bitmap)_inputImage.Clone();
                Graphics g = Graphics.FromImage(tempImage);

                inputImagePictureBox.Image = tempImage;
            }
        }
    } 
}

推荐答案

你需要解决两个问题:

  • 剪辑Graphics 区域到实际的Image 而不是整个PictureBox.ClientArea

  • Clip the Graphics area to the actual Image instead of the whole PictureBox.ClientArea

缩放在接收和记录鼠标事件时将鼠标事件的坐标缩放到实际图像,并在您使用它们在 Paint 事件中绘制时再次返回.

Scale the coordinates of the mouse events to the actual image when receiving and recording them and back again when you use them to draw in the Paint event.

对于两者,我们都需要知道Image缩放因子;对于剪辑,我们还需要知道 ImageArea,而对于绘图,我只需要存储两个鼠标位置.

For both we need to know the zoom factor of the Image; for the clipping we also need to know the ImageArea and for drawing I simply store two mouse locations.

这里是我使用的类级别变量:

Here are the class level variable I use:

PointF mDown = Point.Empty;
PointF mLast = Point.Empty;
float zoom = 1f;
RectangleF ImgArea = RectangleF.Empty;

请注意,我全部使用 floats,因为我们需要做一些划分..

Note that I use floats for all, since we will need to do some dividing..

首先我们将计算 zoomImageArea:

First we'll calculate the zoom and the ImageArea:

void GetImageScaleData(PictureBox pbox)
{
    SizeF sp = pbox.ClientSize;
    SizeF si = pbox.Image.Size;
    float rp = 1f * sp.Width / sp.Height;   // calculate the ratios of
    float ri = 1f * si.Width / si.Height;   // pbox and image

    if (rp > ri)
    {
        zoom = sp.Height / si.Height;
        float width = si.Width * zoom;
        float left = (sp.Width - width) / 2;
        ImgArea = new RectangleF(left, 0, width, sp.Height);
    }
    else
    {
        zoom = sp.Width / si.Width;
        float height = si.Height * zoom;
        float top = (sp.Height - height) / 2;
        ImgArea = new RectangleF(0, top, sp.Width, height);
    }
}

每次加载新的 Image 以及 PictureBox 的任何 调整大小 时都应调用此例程:

This routine should be called each time a new Image is loaded and also upon any Resizing of the PictureBox:

private void pictureBox1_Resize(object sender, EventArgs e)
{
    GetImageScaleData(pictureBox1);
}

现在需要存储鼠标位置.由于它们必须在调整大小后可重用,我们需要将它们转换为图像坐标.这个例程可以做到这一点,也可以再次返回:

Now ne need store the mouse locations. Since they must be reusable after a resize we need to tranfsorm them to image coordinates. This routine can do that and also back again:

PointF scalePoint(PointF pt, bool scale)
{
    return scale ? new PointF( (pt.X - ImgArea.X) / zoom, (pt.Y - ImgArea.Y) / zoom)
                 : new PointF( pt.X * zoom + ImgArea.X, pt.Y * zoom + ImgArea.Y);
}

最后我们可以编写Paint事件

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    using (Pen pen = new Pen(Color.Fuchsia, 2.5f) { DashStyle = DashStyle.Dot})
        e.Graphics.DrawRectangle(pen, Rectangle.Round(ImgArea));

    e.Graphics.SetClip(ImgArea);
    e.Graphics.DrawLine(Pens.Red, scalePoint(mDown, false), scalePoint(mLast, false));
}

.. 和鼠标事件:

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

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == System.Windows.Forms.MouseButtons.Left)
    {
        mLast = scalePoint(e.Location, true);
        pictureBox1.Invalidate();
    }
}

对于更复杂的绘图,您可以将坐标存储在 List 中并将它们转换回来,就像上面一样..:

For more complex drawing you would store the coordinates in List<PointF> and transform them back, pretty much like above..:

List<PointF> points = new List<PointF>();

然后:

e.Graphics.DrawCurve(Pens.Orange, points.Select(x => scalePoint(x, false)).ToArray());

这篇关于如何在放大的图像上绘图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆