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

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

问题描述

我的应用程序中有一个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.

我该如何解决这个问题?

How can I solve the issue?

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

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;
            }
        }
    } 
}

推荐答案

您需要解决两个问题:

  • 将区域剪切到实际的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 zoom 因子;对于剪裁,我们还需要知道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:

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事件进行编码

Finally we can code the Paint event

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<PointF>中,然后将它们转换回去,就像上面的..:

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天全站免登陆