This is the code I have so far:
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
int maxX, minX, maxY, minY;
minX = pictureBox2.Location.X;
minY = pictureBox2.Location.Y;
maxX = (pictureBox2.Size.Width) + minX;
maxY = (pictureBox2.Size.Height) + minY;
Point PictureLocation = new Point(e.X, e.Y);
if ( (PictureLocation.X <= maxX)
&& (PictureLocation.X >= minX)
&& (PictureLocation.Y <= maxY)
&& (PictureLocation.Y >= minY) )
{
MessageBox.Show("The drag is working");
//Rest of the program is fine
}
else
{
MessageBox.Show("Please re-drag the item into the area");
}
}
At the moment all it comes up with is the else statement and I can't quite figure out why.
ADDITIONAL:
If it helps, I am also using a faint form during the drag in this way which could effect the position as I've found that the ABOVE CODE HAS A CORRECT ZONE to the right and below of where I need it:
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
mdown = e.Location;
form2.BackgroundImageLayout = ImageLayout.Zoom;
form2.BackgroundImage = pictureBox1.Image;
form2.Opacity = 0.5f;
form2.MaximizeBox = false;
form2.ControlBox = false;
form2.Text = "";
form2.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
form2.Size = new Size(150, 150);
form2.Show();
Point pt = pictureBox1.PointToScreen(pictureBox1.Location);
form2.Location = pt;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
Point pt = pictureBox1.PointToScreen(new Point(-(form2.Width / 2) + e.X, -(form2.Height / 2) + e.Y));
form2.Location = pt;
}
}
The point you are given by e.X and e.Y is relative to the control that raised the event (the picturebox).
So you actually want:
minX = 0;
minY = 0;
maxX = pictureBox2.Size.Width;
maxY = pictureBox2.Size.Height;
as the first picture box was taking a datum at it's own location 0,0, so by using that, and the fact that my pictureboxes are on the same y location starting you get this:
minX = (pictureBox2.Location.X)-(pictureBox1.Location.X);
minY = 0;
maxX = ((pictureBox2.Location.X) - (pictureBox1.Location.X)) + (pictureBox2.Width);
maxY = 0 + (pictureBox2.Height);
Thanks for everyone's help!
Related
Problem - I'm writing a program that draws graphics, and zooming is one of the features. Currently, a picturebox is placed on a panel, and the picturebox has vertical and horizontal scroll bars on the right and bottom. How to combine scrollbar with mouse wheel zooming? And I'm not sure if I should use paint to draw the graphics or set a bitmap to draw the graphics onto it?
Expected - When the mouse wheel is scrolled, the entire canvas(picturebox) include drawn graphics are scaled according to the current mouse position as the center (the horizontal and vertical scroll bars change according to the zoom center). When the mouse wheel is pressed and moved, the canvas can be dragged freely.
Expected as follows:
The initial code
private List<Point> _points;
private int _pointRadius = 50;
private float _scale = 1f;
private float _offsetX = 0f;
private float _offsetY = 0f;
private void picturebox_MouseDown(object sender, MouseEventArgs e)
{
_points.Add(e.Location);
}
private void picturebox_MouseWheel(object sender, MouseEvnetArgs e)
{
if(e.Delta < 0)
{
_scale += 0.1f;
_offsetX = e.X * (1f - _scale);
_offsetY = e.X * (1f - _scale);
}
else
{
_scale -= 0.1f;
_offsetX = e.X * (1f - _scale);
_offsetY = e.X * (1f - _scale);
}
picturebox.Invalidate();
}
private void picturebox_Paint(object sender, PaintEventArgs e)
{
e.Graphics.TranslateTransform(_offsetX, _offsetY);
e.Graphics.ScaleTransform(_scaleX, _scaleY);
foreach (Point p in _points)
{
e.Graphics.FillEllipse(Brushes.Black, p.X, - _pointRadius, p.Y - _pointRadius, 2 * _pointRadius, 2 * _pointRadius);
}
}
Hope the answer is modified based on the initial code.
Thanks in advance to everyone who helped me.
Would it be easier if I drew the graphics on a Bitmap?
Considering the nature of your task and the already implemented solutions in my ImageViewer I created a solution that draws the result in a Metafile, which is both elegant, consumes minimal memory and allows zooming without quality issues.
Here is the stripped version of my ImageViewer:
public class MetafileViewer : Control
{
private HScrollBar sbHorizontal = new HScrollBar { Visible = false };
private VScrollBar sbVertical = new VScrollBar { Visible = false };
private Metafile? image;
private Size imageSize;
private Rectangle targetRectangle;
private Rectangle clientRectangle;
private float zoom = 1;
private bool sbHorizontalVisible;
private bool sbVerticalVisible;
private int scrollFractionVertical;
public MetafileViewer()
{
Controls.AddRange(new Control[] { sbHorizontal, sbVertical });
sbHorizontal.ValueChanged += ScrollbarValueChanged;
sbVertical.ValueChanged += ScrollbarValueChanged;
}
void ScrollbarValueChanged(object? sender, EventArgs e) => Invalidate();
public Metafile? Image
{
get => image;
set
{
image = value;
imageSize = image?.Size ?? default;
InvalidateLayout();
}
}
public bool TryTranslate(Point mouseCoord, out PointF canvasCoord)
{
canvasCoord = default;
if (!targetRectangle.Contains(mouseCoord))
return false;
canvasCoord = new PointF((mouseCoord.X - targetRectangle.X) / zoom, (mouseCoord.Y - targetRectangle.Y) / zoom);
if (sbHorizontalVisible)
canvasCoord.X += sbHorizontal.Value / zoom;
if (sbVerticalVisible)
canvasCoord.Y += sbVertical.Value / zoom;
return true;
}
private void InvalidateLayout()
{
Invalidate();
if (imageSize.IsEmpty)
{
sbHorizontal.Visible = sbVertical.Visible = sbHorizontalVisible = sbVerticalVisible = false;
targetRectangle = Rectangle.Empty;
return;
}
Size clientSize = ClientSize;
if (clientSize.Width < 1 || clientSize.Height < 1)
{
targetRectangle = Rectangle.Empty;
return;
}
Size scaledSize = imageSize.Scale(zoom);
// scrollbars visibility
sbHorizontalVisible = scaledSize.Width > clientSize.Width
|| scaledSize.Width > clientSize.Width - SystemInformation.VerticalScrollBarWidth && scaledSize.Height > clientSize.Height;
sbVerticalVisible = scaledSize.Height > clientSize.Height
|| scaledSize.Height > clientSize.Height - SystemInformation.HorizontalScrollBarHeight && scaledSize.Width > clientSize.Width;
if (sbHorizontalVisible)
clientSize.Height -= SystemInformation.HorizontalScrollBarHeight;
if (sbVerticalVisible)
clientSize.Width -= SystemInformation.VerticalScrollBarWidth;
if (clientSize.Width < 1 || clientSize.Height < 1)
{
targetRectangle = Rectangle.Empty;
return;
}
Point clientLocation = Point.Empty;
var targetLocation = new Point((clientSize.Width >> 1) - (scaledSize.Width >> 1),
(clientSize.Height >> 1) - (scaledSize.Height >> 1));
// both scrollbars
if (sbHorizontalVisible && sbVerticalVisible)
{
sbHorizontal.Dock = sbVertical.Dock = DockStyle.None;
sbHorizontal.Width = clientSize.Width;
sbHorizontal.Top = clientSize.Height;
sbHorizontal.Left = 0;
sbVertical.Height = clientSize.Height;
sbVertical.Left = clientSize.Width;
}
// horizontal scrollbar
else if (sbHorizontalVisible)
sbHorizontal.Dock = DockStyle.Bottom;
// vertical scrollbar
else if (sbVerticalVisible)
sbVertical.Dock = DockStyle.Right;
// adjust scrollbar values
if (sbHorizontalVisible)
{
sbHorizontal.Minimum = targetLocation.X;
sbHorizontal.Maximum = targetLocation.X + scaledSize.Width;
sbHorizontal.LargeChange = clientSize.Width;
sbHorizontal.SmallChange = 32;
sbHorizontal.Value = Math.Min(sbHorizontal.Value, sbHorizontal.Maximum - sbHorizontal.LargeChange);
}
if (sbVerticalVisible)
{
sbVertical.Minimum = targetLocation.Y;
sbVertical.Maximum = targetLocation.Y + scaledSize.Height;
sbVertical.LargeChange = clientSize.Height;
sbVertical.SmallChange = 32;
sbVertical.Value = Math.Min(sbVertical.Value, sbVertical.Maximum - sbVertical.LargeChange);
}
sbHorizontal.Visible = sbHorizontalVisible;
sbVertical.Visible = sbVerticalVisible;
clientRectangle = new Rectangle(clientLocation, clientSize);
targetRectangle = new Rectangle(targetLocation, scaledSize);
if (sbVerticalVisible)
clientRectangle.X = SystemInformation.VerticalScrollBarWidth;
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
InvalidateLayout();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (image == null || e.ClipRectangle.Width <= 0 || e.ClipRectangle.Height <= 0)
return;
if (targetRectangle.IsEmpty)
InvalidateLayout();
if (targetRectangle.IsEmpty)
return;
Graphics g = e.Graphics;
g.IntersectClip(clientRectangle);
Rectangle dest = targetRectangle;
if (sbHorizontalVisible)
dest.X -= sbHorizontal.Value;
if (sbVerticalVisible)
dest.Y -= sbVertical.Value;
g.DrawImage(image, dest);
g.DrawRectangle(SystemPens.ControlText, Rectangle.Inflate(targetRectangle, 1, 1));
}
protected override void OnMouseWheel(MouseEventArgs e)
{
base.OnMouseWheel(e);
switch (ModifierKeys)
{
// zoom
case Keys.Control:
float delta = (float)e.Delta / SystemInformation.MouseWheelScrollDelta / 5;
if (delta.Equals(0f))
return;
delta += 1;
SetZoom(zoom * delta);
break;
// vertical scroll
case Keys.None:
VerticalScroll(e.Delta);
break;
}
}
private void VerticalScroll(int delta)
{
// When scrolling by mouse, delta is always +-120 so this will be a small change on the scrollbar.
// But we collect the fractional changes caused by the touchpad scrolling so it will not be lost either.
int totalDelta = scrollFractionVertical + delta * sbVertical.SmallChange;
scrollFractionVertical = totalDelta % SystemInformation.MouseWheelScrollDelta;
int newValue = sbVertical.Value - totalDelta / SystemInformation.MouseWheelScrollDelta;
SetValueSafe(sbVertical, newValue);
}
internal static void SetValueSafe(ScrollBar scrollBar, int value)
{
if (value < scrollBar.Minimum)
value = scrollBar.Minimum;
else if (value > scrollBar.Maximum - scrollBar.LargeChange + 1)
value = scrollBar.Maximum - scrollBar.LargeChange + 1;
scrollBar.Value = value;
}
private void SetZoom(float value)
{
const float maxZoom = 10f;
float minZoom = image == null ? 1f : 1f / Math.Min(imageSize.Width, imageSize.Height);
if (value < minZoom)
value = minZoom;
if (value > maxZoom)
value = maxZoom;
if (zoom.Equals(value))
return;
zoom = value;
InvalidateLayout();
}
}
And then the updated version of your initial code (add a new point by right click, zoom by Ctrl + mouse scroll):
public partial class RenderMetafileForm : Form
{
private static Size canvasSize = new Size(300, 200);
private List<PointF> points = new List<PointF>();
private const float pointRadius = 5;
public RenderMetafileForm()
{
InitializeComponent();
metafileViewer.MouseClick += MetafileViewer_MouseClick;
UpdateMetafile();
}
private void MetafileViewer_MouseClick(object? sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right && metafileViewer.TryTranslate(e.Location, out var coord))
{
points.Add(coord);
UpdateMetafile();
}
}
private void UpdateMetafile()
{
Graphics refGraph = Graphics.FromHwnd(IntPtr.Zero);
IntPtr hdc = refGraph.GetHdc();
Metafile result;
try
{
result = new Metafile(hdc, new Rectangle(Point.Empty, canvasSize), MetafileFrameUnit.Pixel, EmfType.EmfOnly, "Canvas");
using (var g = Graphics.FromImage(result))
{
foreach (PointF point in points)
g.FillEllipse(Brushes.Navy, point.X - pointRadius, point.Y - pointRadius, pointRadius * 2, pointRadius * 2);
}
}
finally
{
refGraph.ReleaseHdc(hdc);
refGraph.Dispose();
}
Metafile? previous = metafileViewer.Image;
metafileViewer.Image = result;
previous?.Dispose();
}
}
Result:
⚠️ Note: I did not add panning by keyboard or by grabbing the image but you can extract those from the original ImageViewer. Also, I removed DPI-aware scaling but see the ScaleSize extensions in the linked project.
I have a problem where I need to draw a line using a mouse and lock the angle every 5 degrees.
I can lock the line horizontally and vertically but I can't lock in an angle
if (e.Button == MouseButtons.Left)
{
if (e.Button != MouseButtons.Left)
{
return;
}
startLine = new Point();
endLine = new Point();
if (ModifierKeys == Keys.Control)
{
pointLineDest = new Point(e.X, pointLineOrigin.Y);
}
else if (ModifierKeys == (Keys.Control | Keys.Shift))
{
pointLineDest = new Point(pointLineOrigin.X, e.Y);
}
else
{
pointLineDest = e.Location;
Globals.AddOutputLog($"{CalculeAngle(pointLineOrigin, pointLineDest)}");
}
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
canvas.Refresh();
}
in the above code i lock to 0 degree when hold ctrl and hold 90 degree when hold shift + ctrl.
But I need to allow the user to move the line 5 degrees if he wants and I have no idea how to do that.
Can anyone help me, please?
sorry for my English.
Edit -----------------
I think I solved the problem but there is still a detail.
Using the follow method i can rotate 5 degrees when i move the mouse.
static Point RotatePoint(Point pointToRotate, Point centerPoint, double angleInDegrees)
{
double angleInRadians = angleInDegrees * (Math.PI / 180);
double cosTheta = Math.Cos(angleInRadians);
double sinTheta = Math.Sin(angleInRadians);
return new Point
{
X = (int)(cosTheta * (pointToRotate.X - centerPoint.X) -
sinTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.X),
Y = (int)(sinTheta * (pointToRotate.X - centerPoint.X) +
cosTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.Y)
};
}
I call the method inside mouseMove event like this:
Point tempP = new Point(e.X, pointLineOrigin.Y);
int dy = e.Y - pointLineOrigin.Y;
int dir = (dy > 0) ? -1 : 1;
if (dir == -1)
pointLineDest = RotatePoint(tempP, pointLineOrigin, -5);
else
pointLineDest = RotatePoint(tempP, pointLineOrigin, 5);
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
So I have a line that starts at 0 degrees and if I move the mouse up it changes to 5 degrees, if I move down it changes to -5 degrees. Perfect! But if I keep moving the mouse up or down it doesn't increase the incline by 5 degrees. That is, I can only move 5 degrees up or down once.
How can I keep the line rotating as I move the mouse?
Edit --------------------
Ok, i got it with help from #amin29 a. Thank you mate!
_rad5 = DegreeToRadian(5);
float rad = (float)Math.Atan2(e.Y - pointLineOrigin.Y, e.X - pointLineOrigin.X);
int x = pointLineOrigin.X;
int y = pointLineOrigin.Y;
float angle = rad;
double step = _rad5;
double finalAngle;
double c = rad % _rad5;
finalAngle = angle - c;
if (c > step / 2)
finalAngle = (angle - c) + step;
double length = Math.Sqrt((Math.Pow(pointLineOrigin.X - e.X, 2) + Math.Pow(pointLineOrigin.Y - e.Y, 2)));
// Create points that define line.
Point point1 = new Point(x, y);
Point point2 = new Point((int)(x + Math.Cos(finalAngle) * length), (int)(y + Math.Sin(finalAngle) * length));
startLine = point1;
endLine = point2;
use these methods
private double DegreeToRadian(double degree)
{
return degree * Math.PI / 180;
}
private Point LockInAngle(Point pt, double degree)
{
int y = (int)(pt.X * Math.Tan(DegreeToRadian(degree)));
return new Point(pt.X, y);
}
and your code shoud be like this
if (e.Button == MouseButtons.Left)
{
startLine = new Point();
endLine = new Point();
if (ModifierKeys == Keys.Control)
{
pointLineDest = new Point(e.X, pointLineOrigin.Y);
}
else if (ModifierKeys == (Keys.Control | Keys.Shift))
{
pointLineDest = new Point(pointLineOrigin.X, e.Y);
}
else
{
pointLineDest = LockInAngle(e.Location, 5);
}
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
canvas.Refresh();
}
Edit ---------------------------------------------------------
check this code ,it is windows forms
public partial class Form1 : Form
{
Point startLine;
Point endLine;
Point pointLineDest;
Point pointLineOrigin;
double _rad5;
public Form1()
{
InitializeComponent();
startLine = Point.Empty;
endLine = Point.Empty;
pointLineOrigin = new Point(Width / 2, Height / 2);
Paint += Form1_Paint;
SizeChanged += Form1_SizeChanged;
_rad5 = DegreeToRadian(5);
}
private void Form1_SizeChanged(object sender, EventArgs e)
{
pointLineOrigin = new Point(Width / 2, Height / 2);
Invalidate(false);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; ;
e.Graphics.DrawLine(Pens.Red, startLine, endLine);
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (ModifierKeys == Keys.Control)
{
pointLineDest = new Point(e.X, pointLineOrigin.Y);
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
Invalidate(false);
}
else if (ModifierKeys == (Keys.Control | Keys.Shift))
{
pointLineDest = new Point(pointLineOrigin.X, e.Y);
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
Invalidate(false);
}
else
{
float rad =(float) Math.Atan2(e.Y - pointLineOrigin.Y, e.X - pointLineOrigin.X);
if (Math.Abs(rad % _rad5) < 0.005)
{
pointLineDest = e.Location;
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
Invalidate(false);
}
}
}
private double DegreeToRadian(double degree)
{
return degree * Math.PI / 180;
}
}
Edit----------
I edited your code for better performance and you can add MouseUp and MouseDown event if you want to work with left click. (If your canvas have DoubleBuffered property set it to true)
public partial class Form1 : Form
{
bool _isMouseDown;
Point startLine;
Point endLine;
Point pointLineDest;
Point pointLineOrigin;
float _rad5;
float _rad5DivideBy2;
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
_rad5 = DegreeToRadian(5);
_rad5DivideBy2 = _rad5 / 2;
startLine = Point.Empty;
endLine = Point.Empty;
pointLineOrigin = new Point(Width / 2, Height / 2);
Paint += Form1_Paint;
SizeChanged += Form1_SizeChanged;
}
private void Form1_SizeChanged(object sender, EventArgs e)
{
pointLineOrigin = new Point(Width / 2, Height / 2);
Invalidate(false);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
e.Graphics.DrawLine(Pens.Red, startLine, endLine);
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_isMouseDown = true;
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_isMouseDown = false;
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (_isMouseDown)
{
if (ModifierKeys == Keys.Control)
{
pointLineDest = new Point(e.X, pointLineOrigin.Y);
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
Invalidate(false);
}
else if (ModifierKeys == (Keys.Control | Keys.Shift))
{
pointLineDest = new Point(pointLineOrigin.X, e.Y);
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
Invalidate(false);
}
else
{
int dx = e.X - pointLineOrigin.X;
int dy = e.Y - pointLineOrigin.Y;
float rad = (float)Math.Atan2(dy, dx);
if (rad < 0)
{
rad += (float)(2 * Math.PI);
}
float rem = rad % _rad5;
float finalAngle = rad - rem;
if (rem > _rad5DivideBy2)
{
finalAngle += _rad5;
}
float length = (float)Math.Sqrt(dx * dx + dy * dy);
pointLineDest = new Point((int)(Math.Cos(finalAngle) * length), (int)(Math.Sin(finalAngle) * length));
pointLineDest.Offset(pointLineOrigin);
startLine = new Point(pointLineOrigin.X, pointLineOrigin.Y);
endLine = new Point(pointLineDest.X, pointLineDest.Y);
Invalidate(false);
}
}
}
private float DegreeToRadian(float degree)
{
return (float)(degree * Math.PI / 180);
}
}
How can I make a free-form selection (like in paint or photoshop) in a picture box and then crop that selection and save it to a folder?
I already did a rectangle crop but I want that free-form selection..
Here is my rectangle crop:
Image img;
bool mouseClicked;
Point startPoint = new Point();
Point endPoint = new Point();
Rectangle rectCropArea;
private void Button1_Click(System.Object sender, System.EventArgs e)
{
}
private void OnLoad(System.Object sender, System.EventArgs e)
{
loadPrimaryImage();
}
private void loadPrimaryImage()
{
img = Image.FromFile("..\\..\\images.jpg");
PictureBox1.Image = img;
}
private void PicBox_MouseUp(System.Object sender, System.Windows.Forms.MouseEventArgs e)
{
mouseClicked = false;
if ((endPoint.X != -1)) {
Point currentPoint = new Point(e.X, e.Y);
Y1.Text = e.X.ToString();
Y2.Text = e.Y.ToString();
}
endPoint.X = -1;
endPoint.Y = -1;
startPoint.X = -1;
startPoint.Y = -1;
}
private void PicBox_MouseDown(System.Object sender, System.Windows.Forms.MouseEventArgs e)
{
mouseClicked = true;
startPoint.X = e.X;
startPoint.Y = e.Y;
//Display coordinates
X1.Text = startPoint.X.ToString();
Y1.Text = startPoint.Y.ToString();
endPoint.X = -1;
endPoint.Y = -1;
rectCropArea = new Rectangle(new Point(e.X, e.Y), new Size());
}
private void PicBox_MouseMove(System.Object sender, System.Windows.Forms.MouseEventArgs e)
{
Point ptCurrent = new Point(e.X, e.Y);
if ((mouseClicked)) {
if ((endPoint.X != -1)) {
//Display Coordinates
X1.Text = startPoint.X.ToString();
Y1.Text = startPoint.Y.ToString();
X2.Text = e.X.ToString();
Y2.Text = e.Y.ToString();
}
endPoint = ptCurrent;
if ((e.X > startPoint.X & e.Y > startPoint.Y)) {
rectCropArea.Width = e.X - startPoint.X;
rectCropArea.Height = e.Y - startPoint.Y;
} else if ((e.X < startPoint.X & e.Y > startPoint.Y)) {
rectCropArea.Width = startPoint.X - e.X;
rectCropArea.Height = e.Y - startPoint.Y;
rectCropArea.X = e.X;
rectCropArea.Y = startPoint.Y;
} else if ((e.X > startPoint.X & e.Y < startPoint.Y)) {
rectCropArea.Width = e.X - startPoint.X;
rectCropArea.Height = startPoint.Y - e.Y;
rectCropArea.X = startPoint.X;
rectCropArea.Y = e.Y;
} else {
rectCropArea.Width = startPoint.X - e.X;
rectCropArea.Height = startPoint.Y - e.Y;
rectCropArea.X = e.X;
rectCropArea.Y = e.Y;
}
PictureBox1.Refresh();
}
}
private void PicBox_Paint(System.Object sender, System.Windows.Forms.PaintEventArgs e)
{
Pen drawLine = new Pen(Color.Red);
drawLine.DashStyle = DashStyle.Dash;
e.Graphics.DrawRectangle(drawLine, rectCropArea);
}
private void btnCrop_Click(System.Object sender, System.EventArgs e)
{
PictureBox2.Refresh();
Bitmap sourceBitmap = new Bitmap(PictureBox1.Image, PictureBox1.Width, PictureBox1.Height);
Graphics g = PictureBox2.CreateGraphics();
if (!(CheckBox1.Checked)) {
g.DrawImage(sourceBitmap, new Rectangle(0, 0, PictureBox2.Width, PictureBox2.Height), rectCropArea, GraphicsUnit.Pixel);
sourceBitmap.Dispose();
} else {
int x1 = 0;
int x2 = 0;
int y1 = 0;
int y2 = 0;
try {
x1 = Convert.ToInt32(CX1.Text);
x2 = Convert.ToInt32(CX2.Text);
y1 = Convert.ToInt32(CY1.Text);
y2 = Convert.ToInt32(CY2.Text);
} catch (Exception ex) {
MessageBox.Show("Enter valid Coordinates (only Integer values)");
}
if (((x1 < x2 & y1 < y2))) {
rectCropArea = new Rectangle(x1, y1, x2 - x1, y2 - y1);
} else if ((x2 < x1 & y2 > y1)) {
rectCropArea = new Rectangle(x2, y1, x1 - x2, y2 - y1);
} else if ((x2 > x1 & y2 < y1)) {
rectCropArea = new Rectangle(x1, y2, x2 - x1, y1 - y2);
} else {
rectCropArea = new Rectangle(x2, y2, x1 - x2, y1 - y2);
}
PictureBox1.Refresh();
//This repositions the dashed box to new location as per coordinates entered.
g.DrawImage(sourceBitmap, new Rectangle(0, 0, PictureBox2.Width, PictureBox2.Height), rectCropArea, GraphicsUnit.Pixel);
sourceBitmap.Dispose();
}
}
private void pictureBox1_MouseClick(System.Object sender, System.Windows.Forms.MouseEventArgs e)
{
PictureBox1.Refresh();
}
private void CheckBox1_CheckedChanged(System.Object sender, System.EventArgs e)
{
if ((CheckBox1.Checked)) {
CX1.Visible = true;
Label10.Visible = true;
CY1.Visible = true;
Label9.Visible = true;
CX2.Visible = true;
Label8.Visible = true;
CY2.Visible = true;
Label7.Visible = true;
X1.Text = "0";
X2.Text = "0";
Y1.Text = "0";
Y2.Text = "0";
} else {
CX1.Visible = false;
Label10.Visible = false;
CY1.Visible = false;
Label9.Visible = false;
CX2.Visible = false;
Label8.Visible = false;
CY2.Visible = false;
Label7.Visible = false;
}
}
public Form1()
{
Load += OnLoad;
}
}
To copy a free-form selection you need to work with polygons.
Here is a complete example. Just paste this into a new solution and try it out (just change the path to the images).
It will create 2 pictureboxes and load an image into the first one and also create an image. Then you can click on the first image and when you have clicked 2 times it will start to show a selection, when you are finished just press the button and it will copy the selection to the other pictureBox and then save it as an png image.
What it does is to create a brush from the first image and then paint the polygon onto another image and set the other pixels in the rectangle to a background color of your choice, in this case the color: Color.Transparent.
Example:
public partial class Form1 : Form {
private List<Point> _points = new List<Point>();
private PictureBox _pictureBox1;
private PictureBox _pictureBox2;
private Button _button1;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
Size = new Size(1366, 675);
_pictureBox1 = new PictureBox {
Location = new Point(12, 51),
Size = new Size(651, 474),
BorderStyle = BorderStyle.FixedSingle
};
_pictureBox2 = new PictureBox
{
Location = new Point(669, 51),
Size = new Size(651, 474),
BorderStyle = BorderStyle.FixedSingle
};
_button1 = new Button {
Text = #"Copy selected area",
Location = new Point(13, 13),
Size = new Size(175, 23)
};
Controls.AddRange(new Control[] { _pictureBox1, _pictureBox2, _button1 });
_pictureBox1.Image = Image.FromFile(#"d:\temp\Hopetoun_falls.jpg");
_points = new List<Point>();
_pictureBox1.MouseDown += delegate(object o, MouseEventArgs args) { _points.Add(args.Location); _pictureBox1.Refresh(); };
_pictureBox1.Paint += pictureBox1_Paint;
_button1.Click += button_Click;
}
private void pictureBox1_Paint(object sender, PaintEventArgs e) {
if (_points.Count < 2) {
return;
}
var max = _points.Count;
for (int i = 1; i < max; i++) {
e.Graphics.DrawLine(Pens.Red, _points[i-1].X, _points[i-1].Y, _points[i].X, _points[i].Y);
}
e.Graphics.DrawLine(Pens.Red, _points[max - 1].X, _points[max - 1].Y, _points[0].X, _points[0].Y);
}
private static Bitmap GetSelectedArea(Image source, Color bgColor, List<Point> points) {
var bigBm = new Bitmap(source);
using (var gr = Graphics.FromImage(bigBm)) {
// Set the background color.
gr.Clear(bgColor);
// Make a brush out of the original image.
using (var br = new TextureBrush(source)) {
// Fill the selected area with the brush.
gr.FillPolygon(br, points.ToArray());
// Find the bounds of the selected area.
var sourceRect = GetPointListBounds(points);
// Make a bitmap that only holds the selected area.
var result = new Bitmap(sourceRect.Width, sourceRect.Height);
// Copy the selected area to the result bitmap.
using (var resultGr = Graphics.FromImage(result)) {
var destRect = new Rectangle(0, 0, sourceRect.Width, sourceRect.Height);
resultGr.DrawImage(bigBm, destRect, sourceRect, GraphicsUnit.Pixel);
}
// Return the result.
return result;
}
}
}
private static Rectangle GetPointListBounds(List<Point> points) {
int xmin = points[0].X;
int xmax = xmin;
int ymin = points[0].Y;
int ymax = ymin;
for (int i = 1; i < points.Count; i++) {
if (xmin > points[i].X) xmin = points[i].X;
if (xmax < points[i].X) xmax = points[i].X;
if (ymin > points[i].Y) ymin = points[i].Y;
if (ymax < points[i].Y) ymax = points[i].Y;
}
return new Rectangle(xmin, ymin, xmax - xmin, ymax - ymin);
}
private void button_Click(object sender, EventArgs e) {
if (_points.Count < 3) {
return;
}
var img = GetSelectedArea(_pictureBox1.Image, Color.Transparent, _points);
_pictureBox2.Image = img;
_pictureBox2.Image.Save(#"d:\temp\sample.png", ImageFormat.Png);
}
}
I am messing with this for the first time. I am going for something like Gyazo does. I have the code below but it won't actually capture the image. It is a bit late and I am a bit tired so could be missing something awfully easy. What it does now is just prints an empty picture at some random size.
private Point start = Point.Empty;
private Point end = Point.Empty;
private void Form2_MouseDown(object sender, MouseEventArgs e)
{
start.X = e.X;
start.Y = e.Y;
}
private void Form2_MouseMove(object sender, MouseEventArgs e)
{
Point p1;
Point p2;
if (((e.Button & MouseButtons.Left) != 0) && (start != Point.Empty))
{
using (Graphics g = this.CreateGraphics())
{
p1 = PointToScreen(start);
end.X = e.X;
end.Y = e.Y;
p2 = PointToScreen(end);
Console.WriteLine(end);
}
}
}
private void Form2_MouseUp(object sender, MouseEventArgs e)
{
Point p1;
Point p2;
Console.WriteLine("Mouse Up");
if ((end != Point.Empty) && (start != Point.Empty))
{
using (Graphics g = this.CreateGraphics())
{
p1 = PointToScreen(start);
p2 = PointToScreen(end);
int x1 = p1.X;
int y1 = p1.Y;
int x2 = p2.X;
int y2 = p2.Y;
using (Bitmap bmpScreenCapture = new Bitmap(x1,y1))
{
using (Graphics gra = Graphics.FromImage(bmpScreenCapture))
{
gra.CopyFromScreen(x1, y1, x2, y2, bmpScreenCapture.Size, CopyPixelOperation.SourceCopy);
bmpScreenCapture.Save("test.png", ImageFormat.Png);
Console.WriteLine("Image Saved");
}
}
}
}
start = Point.Empty;
end = Point.Empty;
Console.WriteLine("Image Saved1");
}
The pictures: http://imgur.com/zcDMbgk,wH1k0uP,PIsiQjw#1 OF course there is nothing there but that shows its printing something at some size.
I have made a slight mistake in calculations.
New Code that works wonders.
#region ============================Dragging============================
private Point start = Point.Empty;
private Point end = Point.Empty;
private void Form2_MouseDown(object sender, MouseEventArgs e)
{
start.X = e.X;
start.Y = e.Y;
}
private void Form2_MouseMove(object sender, MouseEventArgs e)
{
Point p1;
Point p2;
if (((e.Button & MouseButtons.Left) != 0) && (start != Point.Empty))
{
using (Graphics g = this.CreateGraphics())
{
p1 = PointToScreen(start);
end.X = e.X;
end.Y = e.Y;
p2 = PointToScreen(end);
Console.WriteLine(end);
}
}
}
private void Form2_MouseUp(object sender, MouseEventArgs e)
{
Point p1;
Point p2;
Console.WriteLine("Mouse Up");
if ((end != Point.Empty) && (start != Point.Empty))
{
using (Graphics g = this.CreateGraphics())
{
p1 = PointToScreen(start);
p2 = PointToScreen(end);
int x1 = p1.X;
int y1 = p1.Y;
int x2 = p2.X;
int y2 = p2.Y;
int x = x1 - x2;
int y = y1 - y2;
Console.WriteLine(x);
Console.WriteLine(y);
string[] xsp = x.ToString().Split('-');
string[] ysp = y.ToString().Split('-');
int rx = Convert.ToInt32(xsp[1]);
int ry = Convert.ToInt32(ysp[1]);
using (Bitmap bmpScreenCapture = new Bitmap(rx, ry, g))
{
using (Graphics gra = Graphics.FromImage(bmpScreenCapture))
{
gra.CopyFromScreen(x1, y1, 0, 0, bmpScreenCapture.Size, CopyPixelOperation.SourceCopy);
string filename = GenerateRandomString(20) + ".png";
bmpScreenCapture.Save(Path.GetTempPath() + "" + filename, ImageFormat.Png);
Upload(Path.GetTempPath() + "" + filename, filename);
}
}
}
}
start = Point.Empty;
end = Point.Empty;
}
#endregion
I have a image in a picture box.it contains a Triangle.
I have a another picture box that contain a little Circle. i should put Circle on top of Triangle . i Zoom first image(Triangle ) to find top of it and then put Circle there.i do it correctly . but when i reset zoom , top of Triangle will be lose and Circle will be on a wrong position.
my code for zoom:
protected override void OnMouseWheel(MouseEventArgs e)
{
this.Cursor = Cursors.Default;
float oldzoom = zoom;
if (e.Delta > 0)
{
zoom += 0.625f;
zoomPerectNum += 50;
_txt_precentZoom.Text = zoomPerectNum.ToString() + "%";
}
else if (e.Delta < 0)
{
// zoom = Math.Max(zoom - 1F, 1F);
zoom = zoom - 0.625F;
if (zoom < 0.2503874F)
{
zoom = 0.2503874F;
}
else
{
zoomPerectNum -= 50;
_txt_precentZoom.Text = zoomPerectNum.ToString() + "%";
}
}
MouseEventArgs mouse = e as MouseEventArgs;
Point mousePosNow = mouse.Location;
int x = mousePosNow.X - _pic_image.Location.X; // Where location of the mouse in the pictureframe
int y = mousePosNow.Y - _pic_image.Location.Y;
int oldimagex = (int)(x / oldzoom); // Where in the IMAGE is it now
int oldimagey = (int)(y / oldzoom);
int newimagex = (int)(x / zoom); // Where in the IMAGE will it be when the new zoom i made
int newimagey = (int)(y / zoom);
imgx = newimagex - oldimagex + imgx; // Where to move image to keep focus on one point
imgy = newimagey - oldimagey + imgy;
_pic_image.Refresh(); // calls imageBox_Paint
}
private void imageBox_Paint(object sender, PaintEventArgs e)
{
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.ScaleTransform(zoom, zoom);
if (img != null)
{
e.Graphics.DrawImage(img, imgx, imgy);
}
}
_pic_Circle:
private void _pic_Circle_MouseDown(object sender, MouseEventArgs e)
{
dragging = true;
dragPoint = new Point(e.X, e.Y);
}
private void _pic_Circle_MouseMove(object sender, MouseEventArgs e)
{
if (dragging)
{
_pic_Circle.Location = new Point(_pic_Circle.Location.X + e.X - dragPoint.X, _pic_Circle.Location.Y + e.Y - dragPoint.Y);
}
}
private void _pic_Circle_MouseUp(object sender, MouseEventArgs e)
{
dragging = false;
}