C# 如何在C windows窗体中绘制可缩放图像

C# 如何在C windows窗体中绘制可缩放图像,c#,winforms,graphics,zooming,line,C#,Winforms,Graphics,Zooming,Line,因此,我正在实施一个项目,可以读取图像平移,缩放和做其他事情。。一切都进行得很顺利,直到我尝试用鼠标右键实现绘图 问题是,当我画一条线时,图像上出现的线与我在屏幕上画的线不对应,这意味着它发生了移动,我知道它是因为图像的重新大小和缩放,但当我在图像上画线时,它的原始大小是图像,并且还有平移;我没有问题 这是密码 因此,首先,当我单击browse并选择image时,我是如何加载图像的 Myimage = new Bitmap(ImagePath); resized = myImage.Size;

因此,我正在实施一个项目,可以读取图像平移,缩放和做其他事情。。一切都进行得很顺利,直到我尝试用鼠标右键实现绘图

问题是,当我画一条线时,图像上出现的线与我在屏幕上画的线不对应,这意味着它发生了移动,我知道它是因为图像的重新大小和缩放,但当我在图像上画线时,它的原始大小是图像,并且还有平移;我没有问题

这是密码

因此,首先,当我单击browse并选择image时,我是如何加载图像的

Myimage = new Bitmap(ImagePath);
resized = myImage.Size;
imageResize();
pictureBox.Paint += new    System.Windows.Forms.PaintEventHandler(this.pictureBox_Paint);
                pictureBox.Invalidate();
imageResize函数执行以下操作:

void imageResize()
{     
//calculated the size to fit the control i will draw the image on   
 resized.Height = someMath;
 resized.Width = someMath;
}
然后在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);
}
正如您所看到的,调整大小的大小不是原始图像大小,我这样做是因为我希望图像显示在picturebox控件上,现在集中并填充。下一部分是我的问题开始的地方

我必须使用鼠标右键在图像上画线,所以我实现了pictureBox\u MouseDown和pictureBox\u 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;
}
}
这是鼠标移动事件处理程序

//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;
}
最后,我希望能够在重新调整大小的图像上绘制,使其与真实图像以及绘制线条的屏幕相对应 感谢并抱歉这篇长文章,但这个问题让我抓狂。

这里有一个PictureBox子类,它不仅支持对图像进行缩放,还支持对绘制到其表面的图形进行缩放

它包括一个SetZoom函数,通过缩放自身和矩阵来放大

它还有一个ScalePoint函数,可用于根据鼠标事件中接收到的像素坐标计算未缩放的坐标

其思想是使用变换矩阵缩放图形对象将在绘制事件中绘制的任何像素

我为表单提供了一个小代码,用于测试

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

}
以下是执行测试的代码:

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));
    }
}
以下是绘制几个点后的结果,这些点在四种不同的缩放设置下显示相同的点;缩放的PictureBox显然放置在AutoScroll面板中。这些线显示了如何使用常规图形命令


简短的版本是:您需要a计算鼠标事件的点以适应向后缩放,因为您的目标是缩放的世界,b向前缩放图形对象,使用矩阵变换以与picturebox中的图像相同的缩放。如果您愿意使用WPF,我在过去问过类似的问题。问题和答案可能会有帮助-@TaW我知道A,但我不知道B的存在。。。听起来是找到解决方案的好途径。。谢谢。使用矩阵来完成缩放是个好主意,然后你也可以得到逆矩阵,并使用它将用户输入的鼠标坐标转换回图像的坐标空间。基本上,您在原始图像坐标空间中完成所有实际工作,使用矩阵将用户输入转换回图像坐标空间,并从图像坐标空间(即图像本身和其上的任何其他渲染)进行转换,比如在绘画活动中选择一条直线回到屏幕上。虽然我想你可以按照彼得和我给你的提示来做,我认为添加一个代码示例以供将来参考也不会有什么坏处。非常感谢您的提示已经足够了:但是感谢您为编写代码所做的所有努力,当然它看起来更高效、更有条理。。不幸的是,给我这个任务的人明确要求不要使用C语言的转换来实现它。我已经解决了代码的问题,但我不会发布我的答案,因为我认为你的答案更好。很有趣。如果不进行变换缩放,坐标也会起作用。在这里,您还需要缩放笔的宽度,然后缩放一些。。