简体   繁体   English

如何在C#Windows窗体中的可缩放图像上绘制

[英]How to Draw on Zoomable Image in C# windows Forms

so am implementing a project that can read image pan it, zoom it and do other stuff.. everything was going well until i tried implementing a draw with right mouse button. 因此,我正在实施一个可以读取图像的项目,将其平移,缩放和执行其他操作..一切都进行得很好,直到我尝试使用鼠标右键实施绘制。

the problem is when i draw a line, the line that appears on the image does not correspond to the line i drew on screen, meaning its shifted and i know its because of the re-sizing and zooming of the image, but when i draw lines on the image with its original size(the image) and with panning also ; 问题是当我画一条线时,图像上出现的线与我在屏幕上画的线不对应,这意味着它已移动并且由于图像的调整大小和缩放我知道了它,但是当我画线时在图像上的线条具有其原始大小(图像)并进行平移; i have no problem. 我没有问题。

here's the code. 这是代码。

so first here is how i load the image when i click browse and select image 所以首先这里是我单击浏览并选择图像时如何加载图像

Myimage = new Bitmap(ImagePath);
resized = myImage.Size;
imageResize();
pictureBox.Paint += new    System.Windows.Forms.PaintEventHandler(this.pictureBox_Paint);
                pictureBox.Invalidate();

the imageResize function does the following: imageResize函数执行以下操作:

void imageResize()
{     
//calculated the size to fit the control i will draw the image on   
 resized.Height = someMath;
 resized.Width = someMath;
}

then in the event handler for the pictureBox_Paint event i wrote: 然后在pictureBox_Paint事件的事件处理程序中,我写道:

private void pictureBox_Paint(object sender,      System.Windows.Forms.PaintEventArgs e)
{
// Create a local version of the graphics object for the PictureBox.
Graphics PboxGraphics = e.Graphics;
PboxGraphics.DrawImage(myImage, imageULcorner.X, imageULcorner.Y,     resized.Width, resized.Height);
}

as you can see the resized size is not the original image size i did this because i wanted the image to show on the picturebox control centralized and filled now the next part IS WHERE MY PROBLEM BEGINS 如您所见,调整大小后的尺寸不是原始图像的尺寸,我这样做是因为我希望图像可以集中显示在PictureBox控件上,并且现在填充下一部分,这是我的问题开始的地方

i have to draw lines on image using right mouse button so i implemented pictureBox_MouseDown & pictureBox_MouseUp event handlers 我必须使用鼠标右键在图像上绘制线条,所以我实现了pictureBox_MouseDown和pictureBox_MouseUp事件处理程序

// mouse down event handler
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
else if (mouse.Button == MouseButtons.Right)
{
mouseDown = mouse.Location;
mouseDown.X = mouseDown.X - imageULcorner.X;
mouseDown.Y = mouseDown.Y - imageULcorner.Y;
draw = true;
}
}

here is the mouse up event handler 这是鼠标悬停事件处理程序

//Mouse UP
private void pictureBox_MouseUp(object sender, MouseEventArgs e)
{
else if (mouse.Button == MouseButtons.Right)
{
if (draw)
 {
mouseLocationNow.X = mouse.X - imageULcorner.X;
mouseLocationNow.Y = mouse.Y - imageULcorner.Y;
//
// get graphics object of the image ( the original not the resized)
// as the resized image only appears when i draw on the graphics of the
// pictureBox control
// i know the problem lies here but how can i fix it
//
Graphics image = Graphics.FromImage(myImage);
Pen pen = new Pen(Color.Red, 2);
image.DrawLine(pen, mouseLocationNow, mouseDown);
pictureBox.Invalidate();
}
draw = false;
}

so in the end i want to be able to draw on the re-sized image and make it correspond to the real image and also to the screen where i draw the line thanks and sorry for the long post but this problem has been driving me crazy. 所以最后,我希望能够在调整大小后的图像上进行绘制,使其与真实图像以及屏幕上绘制线条的屏幕相对应,感谢和对不起,很长的帖子,但是这个问题一直让我发疯。

Here is a PictureBox subclass that supports the ability to apply zooming not only to the Image but also to graphics you draw onto its surface. 这是一个PictureBox子类,该子类不仅支持将缩放应用于Image而且还支持将缩放应用于绘制在其表面上的图形。

It includes a SetZoom function to zoom in by scaling both itself and a Matrix. 它包含一个SetZoom功能,可通过缩放自身和矩阵来放大。

It also has a ScalePoint function you can use to calculate the unscaled coordinates from the pixel coordinates you receive in the mouse events. 它还具有ScalePoint函数,可用于根据在鼠标事件中收到的像素坐标来计算未缩放的坐标。

The idea is to use a Transformation Matrix to scale any pixels the Graphics object will draw in the Paint event. 这个想法是使用Transformation Matrix来缩放Graphics对象将在Paint事件中绘制的任何像素。

I include a little code for the form for testing. 我为测试表格提供了一些代码。

public partial class ScaledPictureBox : PictureBox
{
    public Matrix ScaleM { get; set; }

    float Zoom { get; set; }
    Size ImgSize { get; set; }

    public ScaledPictureBox()
    {
        InitializeComponent();
        ScaleM = new Matrix();
        SizeMode = PictureBoxSizeMode.Zoom;
    }

    public void InitImage()
    {
        if (Image != null)
        {
            ImgSize = Image.Size;
            Size = ImgSize;
            SetZoom(100);
        }
    }

    public void SetZoom(float zoomfactor)
    {
        if (zoomfactor <= 0) throw new Exception("Zoom must be positive");
        float oldZoom = Zoom;
        Zoom = zoomfactor / 100f;
        ScaleM.Reset();
        ScaleM.Scale(Zoom , Zoom );
        if (ImgSize != Size.Empty) Size = new Size((int)(ImgSize.Width * Zoom), 
                                                   (int)(ImgSize.Height * Zoom));

    }

    public PointF ScalePoint(PointF pt)
    {   return new PointF(pt.X / Zoom , pt.Y / Zoom );     }

}

Here is the code in the Form that does the testing: 这是执行测试的表单中的代码:

public List<PointF> somePoints = new List<PointF>();

private void scaledPictureBox1_MouseClick(object sender, MouseEventArgs e)
{
    somePoints.Add(scaledPictureBox1.ScalePoint(e.Location) );
    scaledPictureBox1.Invalidate();
}

private void scaledPictureBox1_Paint(object sender, PaintEventArgs e)
{
    // here we apply the scaling matrix to the graphics object:
    e.Graphics.MultiplyTransform(scaledPictureBox1.ScaleM);
    using (Pen pen = new Pen(Color.Red, 10f))
    {
        PointF center = new PointF(scaledPictureBox1.Width / 2f, 
                                   scaledPictureBox1.Height / 2f);
        center = scaledPictureBox1.ScalePoint(center);
        foreach (PointF pt in somePoints)
        {
            DrawPoint(e.Graphics, pt, pen);
            e.Graphics.DrawLine(Pens.Yellow, center, pt);
        }
    }
}

public void DrawPoint(Graphics G, PointF pt, Pen pen)
{
    using (SolidBrush brush = new SolidBrush(pen.Color))
    {
        float pw = pen.Width;
        float pr = pw / 2f;
        G.FillEllipse(brush, new RectangleF(pt.X - pr, pt.Y - pr, pw, pw));
    }
}

Here are the results after drawing a few points showing the same points in four different zoom settings; 这是绘制几个点后的结果,这些点显示了四种不同缩放设置中的相同点; the ScaledPictureBox is obviously placed in an AutoScroll-Panel . ScaledPictureBox显然放置在AutoScroll-Panel The lines show how to use the regular drawing commands.. 这些行显示了如何使用常规绘图命令。

在此处输入图片说明在此处输入图片说明在此处输入图片说明在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM