如何在缩放图像上绘图?

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

在此处输入图像描述

我有以下问题,

即使我沿着红色路径绘制黑色直线,实际上它也是从透视图中沿着加载的图像显示的。

我该如何解决这个问题?

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

源代码:

  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

  • 在接收和记录鼠标事件时,将鼠标事件的坐标缩放到实际图像,当您使用它们在Paint事件中绘制时,将其重新调回。

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

这是我使用的类级变量:

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

请注意,我为所有人使用floats ,因为我们需要做一些划分..

首先我们将计算zoomImageArea

 void GetImageScaleData(PictureBox pbox) { SizeF sp = pbox.ClientSize; SizeF si = pbox.Image.Size; float rp = sp.Width / sp.Height; // calculate the ratios of float ri = 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 大小时都应调用此例程:

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

现在需要存储鼠标位置。 由于在resize后它们必须可重复使用,我们需要将它们转换为图像坐标。 这个例程可以做到这一点,也可以回来:

 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并将其转换回来,就像上面那样..:

 List points = new List(); 

然后:

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