Keep Picturebox Image While Painting on top of it - c#

In my form, I have a picturebox. I wanted to be able to draw arrows on top of an image. I managed to get halfway there. On the Form load event, I assign an image to the picturebox. I'm able to create arrows with the code below. The problem is every time I create the arrow the picture I assigned on my form load event gets erased. Why does my image get erased? How do I maintain my image that I assigned on form load while drawing arrows on top of it?
private bool isMoving = false;
private Point mouseDownPosition = Point.Empty;
private Point mouseMovePosition = Point.Empty;
private List<Tuple<Point, Point>> lines = new List<Tuple<Point, Point>>();
Pen _Pen;
private void Test_Load(object sender, EventArgs e)
{
pictureBox1.Image = Properties.Resources.background;
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (isMoving)
{
if (pictureBox1.Image == null)
{
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.White);
}
pictureBox1.Image = bmp;
}
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
g.Clear(pictureBox1.BackColor);
AdjustableArrowCap bigArrow = new AdjustableArrowCap(5, 5);
_Pen = new Pen(Color.IndianRed, 3);
_Pen.CustomEndCap = bigArrow;
g.DrawLine(_Pen, mouseDownPosition, mouseMovePosition);
_Pen.Dispose();
}
}
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
isMoving = true;
mouseDownPosition = e.Location;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (isMoving)
{
mouseMovePosition = e.Location;
pictureBox1.Invalidate();
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (isMoving)
{
lines.Add(Tuple.Create(mouseDownPosition, mouseMovePosition));
}
isMoving = false;
}
I think the problem is with this line here g.Clear(pictureBox1.BackColor);

Yes, problem is with this line here g.Clear(pictureBox1.BackColor); You erase entire the control area before you draw the line.
You should draw to e.Graphics directly:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (isMoving)
{
if (pictureBox1.Image == null) e.Graphics.Clear(Color.White);
// Add this line for high quality drawing:
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
AdjustableArrowCap bigArrow = new AdjustableArrowCap(5, 5);
_Pen = new Pen(Color.IndianRed, 3);
_Pen.CustomEndCap = bigArrow;
e.Graphics.DrawLine(_Pen, mouseDownPosition, mouseMovePosition);
_Pen.Dispose();
}
}

Related

Paint Drawline Image into Picturebox Image

In my Form, I have 2 picturebox controls. I loaded a blue background image on pictureBox1 and left pictureBox2 control alone. With the code below I'm able to draw arrows on top of my picturebox1 image.
Goal: On my pictureBox1_MouseUp event I want to add all the arrows which I drew on pictureBox1 to pictureBox2.
Issue: The problem is on my pictureBox1_MouseUp event when I wrote pictureBox2.Image = pictureBox1.Imageit doesn't add the painted arrow which I drew on pictureBox1. It only adds the pictureBox1 image that I assigned in my form load event.
private bool isMoving = false;
private Point mouseDownPosition = Point.Empty;
private Point mouseMovePosition = Point.Empty;
private List<Tuple<Point, Point>> lines = new List<Tuple<Point, Point>>();
Pen _Pen;
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (isMoving)
{
if (pictureBox1.Image == null) e.Graphics.Clear(Color.White);
// Add this line for high quality drawing:
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
AdjustableArrowCap bigArrow = new AdjustableArrowCap(5, 5);
_Pen = new Pen(Color.IndianRed, 3);
_Pen.CustomEndCap = bigArrow;
e.Graphics.DrawLine(_Pen, mouseDownPosition, mouseMovePosition);
_Pen.Dispose();
}
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
isMoving = true;
mouseDownPosition = e.Location;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (isMoving)
{
mouseMovePosition = e.Location;
pictureBox1.Invalidate();
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (isMoving)
{
lines.Add(Tuple.Create(mouseDownPosition, mouseMovePosition));
}
isMoving = false;
pictureBox2.Image = pictureBox1.Image;
}
Test 1: (Changed pictureBox1_Paint code)
With this code, it draws the arrow on pictureBox2, but it looks like it is drawing multiple arrows.
if (isMoving)
{
if (pictureBox1.Image == null) e.Graphics.Clear(Color.White);
// Add this line for high quality drawing:
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
AdjustableArrowCap bigArrow = new AdjustableArrowCap(5, 5);
_Pen = new Pen(Color.IndianRed, 3);
Bitmap BitImg = (Bitmap)pictureBox1.Image;
_Pen.CustomEndCap = bigArrow;
using (var graphics = Graphics.FromImage(BitImg))
{
graphics.DrawLine(_Pen, mouseDownPosition, mouseMovePosition);
}
pictureBox1.Image = BitImg;
_Pen.Dispose();
}
Test 2: (I took the code from the paint event and pasted it MouseMove Event with some modifications. This uses too much memory and it doesn't draw on pictureBox1 but the arrow is now visible in pictureBox2)
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (isMoving)
{
mouseMovePosition = e.Location;
if (isMoving)
{
AdjustableArrowCap bigArrow = new AdjustableArrowCap(5, 5);
_Pen = new Pen(Color.IndianRed, 3);
BitImg = new Bitmap(pictureBox1.Image);
_Pen.CustomEndCap = bigArrow;
using (var graphics = Graphics.FromImage(BitImg))
{
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.DrawLine(_Pen, mouseDownPosition, mouseMovePosition);
}
_Pen.Dispose();
}
pictureBox1.Invalidate();
}
}
Draw all lines to pictureBox1:
Draw only last line to pictureBox1:
In pictureBox2 control, add Paint event to pictureBox2_Paint.
I suggest you make pen and cap global varriable:
// Make pen and cap global varriable to boost the perfomane.
// Create and delete them each draw will cost alot of CPU
Pen pen = new Pen(Color.IndianRed, 3);
AdjustableArrowCap bigArrow = new AdjustableArrowCap(5, 5);
In Form1() event, add this line:
pen.CustomEndCap = bigArrow;
and do as following:
public partial class Form1 : Form
{
private bool isMoving = false;
private Point mouseDownPosition = Point.Empty;
private Point mouseMovePosition = Point.Empty;
private List<Tuple<Point, Point>> lines = new List<Tuple<Point, Point>>();
public Form1()
{
InitializeComponent();
pen.CustomEndCap = bigArrow;
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
isMoving = true;
mouseDownPosition = e.Location;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (isMoving)
{
mouseMovePosition = e.Location;
pictureBox1.Invalidate();
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (isMoving)
{
lines.Add(Tuple.Create(mouseDownPosition, mouseMovePosition));
pictureBox2.Invalidate();
}
isMoving = false;
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (isMoving)
{
if ((sender as PictureBox).Image == null) e.Graphics.Clear(Color.White);
// Add this line for high quality drawing:
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.DrawLine(pen, mouseDownPosition, mouseMovePosition);
// If you want draw all previous lines here, add bellow code:
//foreach (var line in lines)
//{
// e.Graphics.DrawLine(pen, line.Item1, line.Item2);
//}
}
}
private void pictureBox2_Paint(object sender, PaintEventArgs e)
{
if ((sender as PictureBox).Image == null) e.Graphics.Clear(Color.White);
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
foreach (var line in lines)
{
e.Graphics.DrawLine(pen, line.Item1, line.Item2);
}
}
}
Above code draw lines to PictureBox control, not to image, this allow you remove some lines or clear all lines you draw to picturebox if you want later.
If you want draw directly to image, things event much easier, you don't need pictureBox2_Paint at all:
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (isMoving)
{
// You event don't need this line
//lines.Add(Tuple.Create(mouseDownPosition, mouseMovePosition));
if (pictureBox1.Image != null)
{
using (var g = Graphics.FromImage(pictureBox1.Image))
{
g.SmoothingMode = SmoothingMode.HighQuality;
g.DrawLine(pen, mouseDownPosition, mouseMovePosition);
}
pictureBox2.Image = pictureBox1.Image;
}
}
isMoving = false;
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (isMoving)
{
if ((sender as PictureBox).Image == null) e.Graphics.Clear(Color.White);
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.DrawLine(pen, mouseDownPosition, mouseMovePosition);
}
}
private void pictureBox2_Paint(object sender, PaintEventArgs e)
{
}
You have two problems here:
You paint on Control rather than an image. The image remains unchanged.
Both pictureBox1 and pictureBox2 refer to the same image. When you change the image, both controls will be affected on the next paint event.
So in pictureBox1_Paint you need create a copy of pictureBox1.Image (try using Bitmap), then paint on it and assign the updated image to pictureBox1.Image. It will be painted automatically.

C#, How do i save picture using savefiledialog for paint-like program

I've tried many methods including bitmap converting and etc.
Here's my code. Would love it someone will explain to me how to save it and why. Thanks!
public partial class Form1 : Form
{
Graphics G;
Pen myPen = new Pen(Color.Black);
Point sp = new Point(0, 0);
Point ep = new Point(0, 0);
int ctrl = 0;
public Form1()
{
InitializeComponent();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
sp = e.Location;
if(e.Button == MouseButtons.Left)
{
ctrl = 1;
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
ctrl = 0;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if(ctrl == 1)
{
ep = e.Location;
G = panel1.CreateGraphics();
G.DrawLine(myPen, sp, ep);
}
sp = ep;
}
private void button1_Click(object sender, EventArgs e)
{
colorDialog1.ShowDialog();
myPen.Color = colorDialog1.Color;
colourBtn.BackColor = colorDialog1.Color;
}
private void clrBtn_Click(object sender, EventArgs e)
{
G.Clear(colorDialog2.Color);
}
private void button1_Click_1(object sender, EventArgs e)
{
colorDialog2.ShowDialog();
panel1.BackColor = colorDialog2.Color;
panel1Colourbtn.BackColor = colorDialog2.Color;
}
private void button1_Click_2(object sender, EventArgs e)
{
SaveFileDialog dlgSave = new SaveFileDialog();
dlgSave.Title = "Save Image";
dlgSave.Filter = "Bitmap Images (*.bmp)|*.bmp|All Files (*.*)|*.*";
if (dlgSave.ShowDialog(this) == DialogResult.OK)
{
using (Bitmap bmp = new Bitmap(panel1.Width, panel1.Height))
{
// how do i save my drawing using savefiledialog?
}
}
}
After you edited your question I suggest to do the following:
create a Bitmap member in your Form with the same dimensions as the panel
create the Graphics G from that bitmap
in your panel1_MouseMove draw on that Graphics (effectivly drawing into the bitmp`
in your panel1_Paint draw that bitmap on the panel and
in your button1_Click_2 save that bitmap:
Code example:
public partial class Form1 : Form
{
Bitmap bmp;
Graphics G;
Pen myPen = new Pen(Color.Black);
Point sp = new Point(0, 0);
Point ep = new Point(0, 0);
int ctrl = 0;
public Form1()
{
InitializeComponent();
// create bitmap
bmp = new Bitmap(panel1.Width, panel1.Height);
// create Graphics
G = Graphics.FromImage(bmp);
G.Clear(Color.Black);
// redraw panel
panel1.Invalidate();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
// draw bitmap on panel
if (bmp != null)
e.Grahics.DrawImage(bmp, Point.Empty);
}
// shortened for clarity
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if(ctrl == 1)
{
ep = e.Location;
// draw onto graphics -> bmp
G.DrawLine(myPen, sp, ep);
}
sp = ep;
// redraw panel
panel1.Invalidate();
}
private void button1_Click_2(object sender, EventArgs e)
{
SaveFileDialog dlgSave = new SaveFileDialog();
dlgSave.Title = "Save Image";
dlgSave.Filter = "Bitmap Images (*.bmp)|*.bmp|All Files (*.*)|*.*";
if (dlgSave.ShowDialog(this) == DialogResult.OK)
{
bmp.Save(dlgSave.FileName);
}
}
}
Try this:
panel1.DrawToBitmap(bmp, new Rectangle(0, 0, panel1.Width, panel1.Height));
bmp.Save(dlgSave.FileName);

Partial screenshot with rectangle of selection c#

I'm trying to take a partial screenshot of the screen and put it in a picturebox. The user has to draw a rectangle and then i have to get the portion inside the rectangle.
protected override void OnMouseDown(MouseEventArgs e)
{
mRect = new Rectangle(e.X, e.Y, 0, 0);
this.Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e)
{
if( e.Button == MouseButtons.Left)
{
mRect = new Rectangle(mRect.Left, mRect.Top, e.X - mRect.Left, e.Y - mRect.Top);
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e)
{
using(Pen pen = new Pen(Color.Red, 1))
{
e.Graphics.DrawRectangle(pen, mRect);
}
}
With this code i can draw a recangle, but i don't know how to do the screenshot. Maybe with the fonction CopyToScreen?
If someone have an idea?
Thanks!
Here is some code I use - it grabs the whole desktop
public static Bitmap GetScreenAsBmp()
{
int min_x=0, max_x=0, min_y=0, max_y=0;
foreach (Screen s in Screen.AllScreens)
{
min_x = System.Math.Min(min_x, s.Bounds.Left);
max_x = System.Math.Max(max_x, s.Bounds.Right);
min_y = System.Math.Min(min_y, s.Bounds.Top);
max_y = System.Math.Max(max_y, s.Bounds.Bottom);
}
Bitmap bmp = new Bitmap(max_x - min_x, max_y - min_y);
Graphics dst_dc = Graphics.FromImage(bmp);
dst_dc.CopyFromScreen(min_x, min_y, 0, 0, new Size(max_x - min_x, max_y - min_y));
dst_dc.Dispose();
return bmp;
}
This is a complete solution for the problem.
It is triggered by a Button and then:
creates and styles a second Form which
is transparent without borders etc and fills the screen
has all events needed to draw a Rectangle
copies the screen after the rectangle is drawn, i.e. after the MouseUp
and copies the Bitmap into the Image of a PictureBox on the 1st Form.
Finally it closes the 2nd form. During the screencopy process both windows are hidden, so you can grab the screen itself with all its content.
Note that many video overlays can't be captured this way!
Note that this code always captures from the 1st screen!
For best usability the users should somehow be informed that he is expected to draw the frame after the Button is pressed and the window has disappeared!
To use it simply add a Button and a PictureBox to your Form..
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Form form2;
Point MD = Point.Empty;
Rectangle rect = Rectangle.Empty;
private void button2_Click(object sender, EventArgs e)
{
Hide();
form2 = new Form();
form2.BackColor = Color.Wheat;
form2.TransparencyKey = form2.BackColor;
form2.ControlBox = false;
form2.MaximizeBox = false;
form2.MinimizeBox = false;
form2.FormBorderStyle = FormBorderStyle.None;
form2.WindowState = FormWindowState.Maximized;
form2.MouseDown += form2_MouseDown;
form2.MouseMove += form2_MouseMove;
form2.Paint += form2_Paint;
form2.MouseUp += form2_MouseUp;
form2.Show();
}
void form2_MouseDown(object sender, MouseEventArgs e)
{
MD = e.Location;
}
void form2_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button !=MouseButtons.Left) return;
Point MM = e.Location;
rect = new Rectangle(Math.Min(MD.X, MM.X), Math.Min(MD.Y, MM.Y),
Math.Abs(MD.X - MM.X), Math.Abs(MD.Y - MM.Y));
form2.Invalidate();
}
void form2_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawRectangle(Pens.Red, rect);
}
void form2_MouseUp(object sender, MouseEventArgs e)
{
form2.Hide();
Screen scr = Screen.AllScreens[0];
Bitmap bmp = new Bitmap(rect.Width, rect.Height);
using (Graphics G = Graphics.FromImage(bmp))
{
G.CopyFromScreen(rect.Location, Point.Empty, rect.Size,
CopyPixelOperation.SourceCopy);
pictureBox1.Image = bmp;
}
form2.Close();
Show();
}
}

Draw on Panel, save as Bitmap

I'm trying to make a simple application where the user can draw on the Panel and save it to their computer as a bitmap. When I proceed to the save part, however, all I get is an empty (white) bitmap.
I've been browsing many other solutions and I am pretty sure I am saving the bitmap the correct way, so I am starting to wonder if my drawing process is incorrect. What exactly is wrong here?
public partial class Form1 : Form
{
SolidBrush brush;
Pen pen;
Point[] points = new Point[3];
Graphics display;
Bitmap bmap;
public Form1()
{
InitializeComponent();
display = panel1.CreateGraphics();
bmap = new Bitmap(panel1.Width, panel1.Height);
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
brush = new SolidBrush(Color.Black);
pen = new Pen(Color.Black);
display.FillEllipse(brush, e.X, e.Y, 10, 10);
panel1.DrawToBitmap(bmap, new Rectangle(0, 0, panel1.Width, panel1.Height));
//this.Invalidate();
}
private void clearToolStripMenuItem_Click(object sender, EventArgs e)
{
Graphics display = panel1.CreateGraphics();
display.Clear(panel1.BackColor);
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
bmap.Save(#"C:\Temp\Test.bmp");
}
}
EDIT
With this revision, I just get a black bmp and I don't even see elipses being created anymore on my screen. Although I did notice that if I put invalidate and Draw to bitmap back in the mousedown event, then the save button will save the last ellipse, while there is still nothing appearing on my screen.
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
mousedown = true;
x = e.X;
y = e.Y;
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
//Graphics g = e.Graphics;
if(mousedown==true)
{
brush = new SolidBrush(Color.Black);
pen = new Pen(Color.Black);
Graphics.FromImage(bmap).FillEllipse(brush, x, y, 10, 10);
panel1.Invalidate();
//panel1.DrawToBitmap(bmap, new Rectangle(0, 0, panel1.Width, panel1.Height));
//panel1.Invalidate();
}
}
As Hans did most of the work in his comment, here is how your code should probably look:
public partial class Form1 : Form {
Bitmap bmap;
public Form1() {
InitializeComponent();
bmap = new Bitmap(panel1.ClientWidth, panel1.ClientHeight);
panel1.MouseDown += panel1_MouseDown;
panel1.Paint += panel1_Paint;
}
void panel1_Paint(object sender, PaintEventArgs e) {
e.Graphics.DrawImage(bmap, Point.Empty);
}
void panel1_MouseDown(object sender, MouseEventArgs e) {
using (Graphics g = Graphics.FromImage(bmap)) {
g.FillEllipse(Brushes.Black, e.X, e.Y, 10, 10);
}
panel1.Invalidate();
}
private void clearToolStripMenuItem_Click(object sender, EventArgs e) {
using (Graphics g = Graphics.FromImage(bmap)) {
g.Clear(Color.White);
}
panel1.Invalidate();
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e) {
bmap.Save(#"c:\temp\bmap.bmp");
}
}
CreateGraphics is just a temporary canvas, so you rarely, if ever, use that for drawing purposes, especially since you are trying to save an image.
This will works fine. I tested it and worked well
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace drawing
{
public partial class Form2 : Form
{
Graphics g;
bool startPaint = false;
int? initX = null;
int? initY = null;
bool drawSquare = false;
bool drawRectangle = false;
bool drawCircle = false;
public Form2()
{
InitializeComponent();
bmp = new Bitmap(panel1.ClientSize.Width, panel1.ClientSize.Height);
}
Bitmap bmp;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
}
void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (startPaint)
{
using ( g = Graphics.FromImage(bmp))
{
// g.FillEllipse(Brushes.Black, new Rectangle(e.X, e.Y , 5, 5));
Pen p = new Pen(btn_PenColor.BackColor, float.Parse(cmb_PenSize.Text));
g.DrawLine(p, new Point(initX ?? e.X, initY ?? e.Y), new Point(e.X, e.Y));
initX = e.X;
initY = e.Y;
//g.DrawImage(bmp, new Rectangle(e.X - 4, e.Y - 4, 8, 8));
}
panel1.Invalidate();
}
}
private void pnl_Draw_MouseDown(object sender, MouseEventArgs e)
{
startPaint = true;
if (drawSquare)
{
//Use Solid Brush for filling the graphic shapes
SolidBrush sb = new SolidBrush(btn_PenColor.BackColor);
//setting the width and height same for creating square.
//Getting the width and Heigt value from Textbox(txt_ShapeSize)
g.FillRectangle(sb, e.X, e.Y, int.Parse(txt_ShapeSize.Text), int.Parse(txt_ShapeSize.Text));
//setting startPaint and drawSquare value to false for creating one graphic on one click.
startPaint = false;
drawSquare = false;
}
if (drawRectangle)
{
SolidBrush sb = new SolidBrush(btn_PenColor.BackColor);
//setting the width twice of the height
g.FillRectangle(sb, e.X, e.Y, 2 * int.Parse(txt_ShapeSize.Text), int.Parse(txt_ShapeSize.Text));
startPaint = false;
drawRectangle = false;
}
if (drawCircle)
{
SolidBrush sb = new SolidBrush(btn_PenColor.BackColor);
g.FillEllipse(sb, e.X, e.Y, int.Parse(txt_ShapeSize.Text), int.Parse(txt_ShapeSize.Text));
startPaint = false;
drawCircle = false;
}
}
private void pnl_Draw_MouseUp(object sender, MouseEventArgs e)
{
startPaint = false;
initX = null;
initY = null;
}
void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(bmp, Point.Empty);
}
private void button1_Click(object sender, EventArgs e)
{
bmp.Save("D://filename.jpg", ImageFormat.Png);
}
}
}

How to select an area on a PictureBox.Image with mouse in C#

i just wanted to put a selection on my picturebox.image but this has just become worse than some little annoying situation. I thought on another picture box over the main picturebox but it seemed so lazy work to me. I need to know if there is a way to create a selection area (which is gonna be half transparent blue area) on a picturebox.image which im gonna draw with mouse and it shouldnt change the image im working on.
sample:
// Start Rectangle
//
private void pictureBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
// Determine the initial rectangle coordinates...
RectStartPoint = e.Location;
Invalidate();
}
// Draw Rectangle
//
private void pictureBox1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;
Point tempEndPoint = e.Location;
Rect =
new Rectangle(
Math.Min(RectStartPoint.X, tempEndPoint.X),
Math.Min(RectStartPoint.Y, tempEndPoint.Y),
Math.Abs(RectStartPoint.X - tempEndPoint.X),
Math.Abs(RectStartPoint.Y - tempEndPoint.Y));
Invalidate(Rect);
}
// Draw Area
//
private void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
// Draw the rectangle...
if (pictureBox1.Image != null)
{
Brush brush = new SolidBrush(Color.FromArgb(128, 72, 145, 220));
e.Graphics.FillRectangle(brush, Rect);
}
}
I used your code, you were nearly there. You needed to Invalidate the pictureBox1 instead of the rectangle. I also added a check for the Rect so it doesn't get drawn when it's not initialized or has no size.
Another important change: I created the Rectangle only once and I adjusted its location and size. Less garbage to clean up!
EDIT
I added a mouse right-click handler for the Rectangle.
private Point RectStartPoint;
private Rectangle Rect = new Rectangle();
private Brush selectionBrush = new SolidBrush(Color.FromArgb(128, 72, 145, 220));
// Start Rectangle
//
private void pictureBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
// Determine the initial rectangle coordinates...
RectStartPoint = e.Location;
Invalidate();
}
// Draw Rectangle
//
private void pictureBox1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;
Point tempEndPoint = e.Location;
Rect.Location = new Point(
Math.Min(RectStartPoint.X, tempEndPoint.X),
Math.Min(RectStartPoint.Y, tempEndPoint.Y));
Rect.Size = new Size(
Math.Abs(RectStartPoint.X - tempEndPoint.X),
Math.Abs(RectStartPoint.Y - tempEndPoint.Y));
pictureBox1.Invalidate();
}
// Draw Area
//
private void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
// Draw the rectangle...
if (pictureBox1.Image != null)
{
if (Rect != null && Rect.Width > 0 && Rect.Height > 0)
{
e.Graphics.FillRectangle(selectionBrush, Rect);
}
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
if (Rect.Contains(e.Location))
{
Debug.WriteLine("Right click");
}
}
}
private int xUp, yUp, xDown,yDown;
private Rectangle rectCropArea;
private void SrcPicBox_MouseUp(object sender, MouseEventArgs e)
{
//pictureBox1.Image.Clone();
xUp = e.X;
yUp = e.Y;
Rectangle rec = new Rectangle(xDown,yDown,Math.Abs(xUp xDown),Math.Abs(yUp-yDown));
using (Pen pen = new Pen(Color.YellowGreen, 3))
{
SrcPicBox.CreateGraphics().DrawRectangle(pen, rec);
}
rectCropArea = rec;
}
private void SrcPicBox_MouseDown(object sender, MouseEventArgs e)
{
SrcPicBox.Invalidate();
xDown = e.X;
yDown = e.Y;
}
private void btn_upload_Click(object sender, EventArgs e)
{
OpenFileDialog opf = new OpenFileDialog();
// PictureBox SrcPicBox = new PictureBox();
opf.Filter = "ALL images(*.*)|*.*";
if (opf.ShowDialog() == DialogResult.OK)
{
string name = opf.SafeFileName;
string filepath = opf.FileName;
File.Copy(filepath, name, true);
SrcPicBox.Image = Image.FromFile(opf.FileName);
}
private void btn_crop_Click(object sender, EventArgs e)
{
pictureBox3.Refresh();
//Prepare a new Bitmap on which the cropped image will be drawn
Bitmap sourceBitmap = new Bitmap(SrcPicBox.Image, SrcPicBox.Width, SrcPicBox.Height);
Graphics g = pictureBox3.CreateGraphics();
//Draw the image on the Graphics object with the new dimesions
g.DrawImage(sourceBitmap, new Rectangle(0, 0, pictureBox3.Width, pictureBox3.Height), rectCropArea, GraphicsUnit.Pixel);
sourceBitmap.Dispose();
}

Categories