c# winforms bitmap picturebox

c# - ¿Cómo dibujar en una imagen ampliada?



winforms bitmap (1)

Tengo un cuadro de imagen de Size 400X400 en mi aplicación. El SizeMode del SizeMode de imagen está configurado en Zoomed . He cargado una imagen png de 700X446 en el cuadro de imagen.

Tengo el siguiente problema,

Aunque estoy dibujando una línea recta negra a lo largo del camino rojo, en realidad se muestra a lo largo de la imagen cargada fuera de perspectiva.

¿Cómo puedo resolver el problema?

PD : Quiero dibujar solo en la imagen, no en todo el cuadro de imagen.

Código fuente:

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


Debe abordar dos problemas:

  • Recorte el área de Graphics a la Image real en lugar de todo el PictureBox.ClientArea

  • Escale las coordenadas de los eventos del mouse a la imagen real al recibirlos y grabarlos y viceversa cuando los use para dibujar en el evento Paint .

Para ambos necesitamos saber el factor de zoom de la Image ; para el recorte también necesitamos conocer ImageArea y para dibujar simplemente ImageArea dos ubicaciones del mouse.

Aquí están las variables de nivel de clase que uso:

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

Tenga en cuenta que uso floats para todos, ya que tendremos que dividir un poco ...

Primero calcularemos el zoom y el 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); } }

Se debe llamar a esta rutina cada vez que se carga una nueva Image y también al cambiar el tamaño de PictureBox :

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

Ahora no es necesario almacenar las ubicaciones del mouse. Dado que deben ser reutilizables después de un cambio de tamaño, tenemos que transferirlos a las coordenadas de la imagen. Esta rutina puede hacer eso y también volver de nuevo:

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

Finalmente podemos codificar el evento 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)); }

.. y los eventos del mouse:

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

Para un dibujo más complejo, debe almacenar las coordenadas en List<PointF> y transformarlas de nuevo, más o menos como en el caso anterior.

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

y entonces:

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