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);
}
}
Related
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);
}
}
I am working on a project where I have to align series of images so for that I use lines created using bitmap. Now user can move and rotate this line in anywhere inside panel which has that image as background. Now I have already tried to make panel double buffered which solves the problem of background snapshot while rotating, but when I move that line it takes a piece of background with it. I also tried to refresh panel but that's not working.
Heres the code:
private bool _rotating;
private bool _dragging;
private int _clickX;
private int _clickY;
private Point _clickCoords;
private int _middleX;
private int _middleY;
private int _centerX;
private int _centerY;
private double _radius;
private DateTime lastRotate = DateTime.Today;
public void UpdateCircle(Line l)
{
_centerX = (l.EndPoint.X + l.StartPoint.X) / 2 + l.Left;
_centerY = (l.EndPoint.Y + l.StartPoint.Y) / 2 + l.Top;
_radius = GetDistance(l.StartPoint.X, l.StartPoint.Y, l.EndPoint.X, l.EndPoint.Y) / 2;
// panel5.Refresh();
}
public void UpdateMiddle(Line l)
{
_middleX = (l.EndPoint.X + l.StartPoint.X) / 2;
_middleY = (l.EndPoint.Y + l.StartPoint.Y) / 2;
// panel5.Refresh();
}
public double GetDistance(double x1, double y1, double x2, double y2)
{
return Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
public void LineMouseDown(object sender, MouseEventArgs e)
{
var l = (Line)sender;
if (GetDistance(e.X, e.Y, l.StartPoint.X, l.StartPoint.Y) < 30 ||
GetDistance(e.X, e.Y, l.EndPoint.X, l.EndPoint.Y) < 30)
{
_rotating = true;
}
else
{
_dragging = true;
panel5.Refresh();
}
_clickX = e.X;
_clickY = e.Y;
panel5.Refresh();
_clickCoords = new Point(l.Left + e.X, l.Top + e.Y);
UpdateCircle(l);
UpdateMiddle(l);
// panel5.Refresh();
}
public void LineMouseUp(object sender, MouseEventArgs e)
{
_rotating = false;
_dragging = false;
panel5.Refresh();
}
public void LineMouseMove(object sender, MouseEventArgs e)
{
// panel5.Refresh();
var l = (Line)sender;
if (_rotating)
{
if ((DateTime.Now - lastRotate).TotalMilliseconds > 60)
{
try
{
var angle = GetAngle(l.Left + e.X, l.Top + e.Y, _centerX, 0, _centerX, _centerY);
var newStartPoint = new Point(
(int)Math.Round(_middleX + _radius * Math.Sin(angle)),
(int)Math.Round(_middleY + _radius * Math.Cos(angle))
);
var newEndPoint = new Point(2 * _middleX - newStartPoint.X, 2 * _middleY - newStartPoint.Y);
l.SetPoints(newStartPoint, newEndPoint);
UpdateMiddle(l);
lastRotate = DateTime.Now;
}
catch
{
//ignored
}
}
}
else if (_dragging)
{
l.Left = l.Left + e.X - _clickX;
l.Top = l.Top + e.Y - _clickY;
// panel5.Refresh();
}
}
public double GetAngle(int x2, int y2, int x1, int y1, int x0, int y0)
{
double angle = Math.Atan2(y1 - y0, x1 - x0) - Math.Atan2(y2 - y0, x2 - x0);
return angle;
}
And heres how I create lines:
bitLine = new Line { LineColor = Color.Red, LineWidth = 2, StartPoint = new Point(x1, y1), EndPoint = new Point(x2, y2) };
bitLine2 = new Line { LineColor = Color.Red, LineWidth = 2, StartPoint = new Point(x1, y1), EndPoint = new Point(x2, y2) };
//bitLine.Cursor = Cursors.SizeAll;
bitLine.MouseDown += LineMouseDown;
bitLine.MouseUp += LineMouseUp;
bitLine.MouseMove += LineMouseMove;
bitLine2.MouseDown += LineMouseDown;
bitLine2.MouseUp += LineMouseUp;
bitLine2.MouseMove += LineMouseMove;
bitLine2.Click += bitLine2_Click;
bitLine.Click += bitLine_Click;
panel5.Controls.Add(bitLine);
panel5.Controls.Add(bitLine2);
pb.WireControl(bitLine);
pb.WireControl(bitLine2);
bitLine.Location = Program.line1_location;
bitLine2.Location = Program.line2_location;
So please any suggestions will be helpful. I am really stuck in this.
Here is screenshot of what is the problem
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 the below which draws a rectangle on mouse drag and also a grid drawing script which draws a 32x32 grid on the picture box what I'm trying to do is snap the rectangle to the grid then screen shot inside the rectangle.
I've got the screen shot bit and the drawing of the rectangle just not the snapping to grid bit working.
private bool _selecting;
private Rectangle _selection;
private void picCanvas_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_selecting = true;
_selection = new Rectangle(new Point(e.X, e.Y), new Size());
}
}
private void picCanvas_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (_selecting)
{
_selection.Width = e.X - _selection.X;
_selection.Height = e.Y - _selection.Y;
pictureBox1.Refresh();
}
}
public Image Crop(Image image, Rectangle selection)
{
Bitmap bmp = image as Bitmap;
// Check if it is a bitmap:
if (bmp == null)
throw new ArgumentException("No valid bitmap");
// Crop the image:
Bitmap cropBmp = bmp.Clone(selection, bmp.PixelFormat);
// Release the resources:
image.Dispose();
return cropBmp;
}
private void picCanvas_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left &&
_selecting &&
_selection.Size != new Size())
{
// Create cropped image:
//Image img = Crop(pictureBox1.Image, _selection);
// Fit image to the picturebox:
//pictureBox1.Image = img;
_selecting = false;
}
else
_selecting = false;
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (_selecting)
{
// Draw a rectangle displaying the current selection
Pen pen = Pens.GreenYellow;
e.Graphics.DrawRectangle(pen, _selection);
}
Graphics g = e.Graphics;
int numOfCells = amount;
Pen p = new Pen(Color.LightGray);
for (int y = 0; y < numOfCells; ++y)
{
g.DrawLine(p, 0, y * ysize, numOfCells * ysize, y * ysize);
}
for (int x = 0; x < numOfCells; ++x)
{
g.DrawLine(p, x * xsize, 0, x * xsize, numOfCells * xsize);
}
}
First I would declare a snapping method
private Point SnapToGrid(Point p)
{
double x = Math.Round((double)p.X / xsize) * xsize;
double y = Math.Round((double)p.Y / ysize) * ysize;
return new Point((int)x, (int)y);
}
Then you can initialize the selection like this in MouseDown:
_selection = new Rectangle(SnapToGrid(e.Location), new Size());
And you can adjust the width in MouseMove like this:
Point dest = SnapToGrid(e.Location);
_selection.Width = dest.X - _selection.X;
_selection.Height = dest.Y - _selection.Y;
In my .net c# program i draw few lines using values from text boxes (i use DrawLine function). I want to be able to move one of this lines by clik on it and move this line with mouse - is it possible?
public class LineMover : Form
{
public LineMover()
{
this.DoubleBuffered = true;
this.Paint += new PaintEventHandler(LineMover_Paint);
this.MouseMove += new MouseEventHandler(LineMover_MouseMove);
this.MouseDown += new MouseEventHandler(LineMover_MouseDown);
this.MouseUp += new MouseEventHandler(LineMover_MouseUp);
this.Lines = new List<GraphLine>()
{
new GraphLine (10, 10, 100, 200),
new GraphLine (10, 150, 120, 40),
};
}
void LineMover_MouseUp(object sender, MouseEventArgs e)
{
if (Moving != null)
{
this.Capture = false;
Moving = null;
}
RefreshLineSelection(e.Location);
}
void LineMover_MouseDown(object sender, MouseEventArgs e)
{
RefreshLineSelection(e.Location);
if (this.SelectedLine != null && Moving == null)
{
this.Capture = true;
Moving = new MoveInfo
{
Line = this.SelectedLine,
StartLinePoint = SelectedLine.StartPoint,
EndLinePoint = SelectedLine.EndPoint,
StartMoveMousePoint = e.Location
};
}
RefreshLineSelection(e.Location);
}
void LineMover_Paint(object sender, PaintEventArgs e)
{
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
foreach (var line in Lines)
{
var color = line == SelectedLine ? Color.Red : Color.Black;
var pen = new Pen(color, 2);
e.Graphics.DrawLine(pen, line.StartPoint, line.EndPoint);
}
}
void LineMover_MouseMove(object sender, MouseEventArgs e)
{
if (Moving != null)
{
Moving.Line.StartPoint = new PointF(Moving.StartLinePoint.X + e.X - Moving.StartMoveMousePoint.X, Moving.StartLinePoint.Y + e.Y - Moving.StartMoveMousePoint.Y);
Moving.Line.EndPoint = new PointF(Moving.EndLinePoint.X + e.X - Moving.StartMoveMousePoint.X, Moving.EndLinePoint.Y + e.Y - Moving.StartMoveMousePoint.Y);
}
RefreshLineSelection(e.Location);
}
private void RefreshLineSelection(Point point)
{
var selectedLine = FindLineByPoint(Lines, point);
if (selectedLine != this.SelectedLine)
{
this.SelectedLine = selectedLine;
this.Invalidate();
}
if (Moving != null)
this.Invalidate();
this.Cursor =
Moving != null ? Cursors.Hand :
SelectedLine != null ? Cursors.SizeAll :
Cursors.Default;
}
public List<GraphLine> Lines = new List<GraphLine>();
GraphLine SelectedLine = null;
MoveInfo Moving = null;
static GraphLine FindLineByPoint(List<GraphLine> lines, Point p)
{
var size = 10;
var buffer = new Bitmap(size * 2, size * 2);
foreach (var line in lines)
{
//draw each line on small region around current point p and check pixel in point p
using (var g = Graphics.FromImage(buffer))
{
g.Clear(Color.Black);
g.DrawLine(new Pen(Color.Green, 3), line.StartPoint.X - p.X + size, line.StartPoint.Y - p.Y + size, line.EndPoint.X - p.X + size, line.EndPoint.Y - p.Y + size);
}
if (buffer.GetPixel(size, size).ToArgb() != Color.Black.ToArgb())
return line;
}
return null;
}
public static void Main()
{
Application.Run(new LineMover());
}
}
public class MoveInfo
{
public GraphLine Line;
public PointF StartLinePoint;
public PointF EndLinePoint;
public Point StartMoveMousePoint;
}
public class GraphLine
{
public GraphLine(float x1, float y1, float x2, float y2)
{
this.StartPoint = new PointF(x1, y1);
this.EndPoint = new PointF(x2, y2);
}
public PointF StartPoint;
public PointF EndPoint;
}