I have drawn and saved the Rectangle on the image i loaded in the picture box. How i like to draw multiple rectangles for that i tried array in the rectangle but it gives error ("Object reference not set to an instance of an object." (Null reference Exception was unhandled).
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (mybitmap == null)
{
mybitmap = new Bitmap(sz.Width, sz.Height);
}
rect[count] = new Rectangle(e.X, e.Y, 0, 0);
this.Invalidate();
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (stayToolStripMenuItem.Checked == true)
{
switch (e.Button)
{
case MouseButtons.Left:
{
rect[count] = new Rectangle(rect[count].Left, rect[count].Top, e.X - rect[count].Left, e.Y - rect[count].Top);
pictureBox1.Invalidate();
count++:
break;
}
}
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (stayToolStripMenuItem.Checked == true)
{
button1.Visible = true;
button2.Visible = true;
if (mybitmap == null)
{
return;
}
using (g = Graphics.FromImage(mybitmap))
{
using (Pen pen = new Pen(Color.Red, 2))
{
//g.Clear(Color.Transparent);
e.Graphics.DrawRectangle(pen, rect);
label1.Top = rect[count].Top; label1[count].Left = rect[count].Left; label1.Width = rect[count].Width;
label1.Height = rect[count].Height;
if (label1.TextAlign == ContentAlignment.TopLeft)
{
e.Graphics.DrawString(label1.Text, label1.Font, new SolidBrush(label1.ForeColor), rect);
g.DrawString(label1.Text, label1.Font, new SolidBrush(label1.ForeColor), rect);
g.DrawRectangle(pen, rect[count]);
}
}
}
}
}
How can i do this.....
You're incrementing the count variable after filling the rect array. By the time pictureBox1_Paint is executed, this increment has already taken place, so rect[count] is now a null reference, which you then try to draw :)
Also, there appears to be a compiler error in pictureBox1_MouseDown. The count++ inside the switch statement doesn't belong to any case block. Put it before the break; statement.
I imagine your intention is something like this:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (mybitmap == null)
return;
using (g = Graphics.FromImage(mybitmap))
using (Pen pen = new Pen(Color.Red, 2))
{
g.Clear(Color.Transparent);
for (int i = 0; i < count; i++)
{
// Code to draw rect[i], instead of rect[count]
}
}
}
How large is your rect array, by the way? Arrays do not automatically grow to accommodate your needs. You may want to look at using List<Rectangle> instead.
Have change the code little bit. Instead of mouse move event used Mouse click event.
On using mouse move event it calls every time when mouse move on the picture box. so list rectangle count gets increased. for this i used mouse click event.
When list rectangle added in Mouse down event, it's only get the values for height and width of the rectangle (if use (0,0,e.X,e.Y))and also rectangle always starts from top left corner (not able to start the rectangle point where user likes) and it's gets only X and Y values (if use(e.X, e.Y,0,0))
to over come this I used the list rectangle in the mouse click event, so I get all values.
List<Rectangle> rectangles = new List<Rectangle>();
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (stayToolStripMenuItem.Checked == true)
{
if (mybitmap == null)
{
mybitmap = new Bitmap(sz.Width, sz.Height);
}
rect = new Rectangle(e.X, e.Y, 0, 0);
this.Invalidate();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (stayToolStripMenuItem.Checked == true)
{
button1.Visible = true;
button2.Visible = true;
if (mybitmap == null)
{
return;
}
using (g = Graphics.FromImage(mybitmap))
{
using (Pen pen = new Pen(Color.Red, 2))
{
//g.Clear(Color.Transparent);
e.Graphics.DrawRectangle(pen, rect);
label1.Top = rect.Top; label1.Left = rect.Left; label1.Width = rect.Width;
label1.Height = rect.Height;
if (label1.TextAlign == ContentAlignment.TopLeft)
{
e.Graphics.DrawString(label1.Text, label1.Font, new SolidBrush(label1.ForeColor), rect);
g.DrawString(label1.Text, label1.Font, new SolidBrush(label1.ForeColor), rect);
g.DrawRectangle(pen, rect);
}
}
}
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
rect = new Rectangle(rect.Left, rect.Top, e.X - rect.Left, e.Y - rect.Top);
rectangles.Add(rect);
pictureBox1.Invalidate();
f = 0;
}
}
What ever rectangle I draw get saved in the list rectangles and get saved when i saved the work (could see all the drawn rectangles when i opened the saved file).
Now the problem is, when I draw a new rectangle the previous one get disappeared (on run time. However this added in list rectangle).
How to display all the rectangles drawn on run time, so user can know how many rectangles drawn and where.
Related
I've drawn a grid on a picturebox with .drawline I then let users click a cell on this grid to change the colour. I'm doing this through setting a value for colour for each cell (clicking sets it to 1)
The only way I can get it to update is on mouse up which causes problems with the pathfinding algorithms I'm testing. I tried putting it on a timer but it flickers too much.
You can see the problem here
The pathfinding algorithm finishes but the grid doesn't update until I click the grid.
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
GetX(this, e);
GetY(this, e);
if (DrawCase == "Wall") {
if (gridmatrix[XClick, YClick].COLOUR == 0) //If tile is white and left mouse is pressed
{
gridmatrix[XClick, YClick].COLOUR = 1; //Set colour to 1 (place a wall)
}
else if (gridmatrix[XClick, YClick].COLOUR == 1) //If tile is a wall and left mouse is pressed
{
gridmatrix[XClick, YClick].COLOUR = 0; //Set to empty
}
}
Grid is updated on MouseUp... (How else could I update the grid?)
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
mousedown = false;
int rowcolumn = Convert.ToInt32(textBox1.Text); //Gets the dimensions from the users input
cellsize = (pictureBox1.Width / rowcolumn);
if (pictureBox1.Image == null)//if no available bitmap exists on the picturebox to draw on
{
//create a new bitmap
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
pictureBox1.Image = bmp; //assign the picturebox.Image property to the bitmap created
}
for (int i = 0; i < gridmatrix.GetLength(0); i++)
{
for (int j = 0; j < gridmatrix.GetLength(1); j++)
{
Rectangle rect = new Rectangle(gridmatrix[i, j].X * cellsize, reverseYvalues[gridmatrix[i, j].Y] * cellsize, cellsize, cellsize); //Positioning and sizing for the rectangle
if (gridmatrix[i, j].COLOUR == 0)
{
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
g.FillRectangle(Brushes.White, rect);
}
}
else if (gridmatrix[i, j].COLOUR == 1)
{
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
g.FillRectangle(Brushes.Blue, rect);
}
}
}
}
}
I have a winforms app where I draw on an image in a picturebox. The drawing part works really well, except for lag when PictureBox.SizeMode = PictureBoxSizeMode.Zoom. The reason I set the SizeMode to Zoom is so I could zoom in and out of the image while preserving memory. Is there any way to speed up the drawing process?
The code for the PictureBox's Paint method looks like so:
pen = new Pen(color, 5);
solidBrush = new SolidBrush(solid);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.ScaleTransform(PictureScale, PictureScale);
foreach (List<Point> polygon in Polygons)
{
e.Graphics.DrawLines(pen, polygon.ToArray());
}
if (NewPolygon != null)
{
Pen pp = new Pen(color, 5);
if (NewPolygon.Count > 1)
{
e.Graphics.DrawLines(pp, NewPolygon.ToArray());
}
if (NewPolygon.Count > 0)
{
using (Pen dashed_pen = pp)
{
dashed_pen.DashPattern = new float[] { 3, 3 };
e.Graphics.DrawLine(dashed_pen, NewPolygon[NewPolygon.Count - 1], NewPoint);
}
}
}
The code allows the user to draw a series of points connected by some solid lines. After adding the first point, there is a dotted line going from the previous point to the mouse's current position. The program 'fills' in the line when the user adds a new Point NewPolygon is a List<Point> object, and the program adds a point every time the user clicks. Pol is a List<List<Point>> object which holds NewPolygon. I attached a GIF of the drawing process because an image is worth 1000 words. The lag in the gif is not noticeable at all in different size modes.
The if (NewPolygon.Count > 1) loop draws solid lines between at least 2 points. The if (NewPolygon.Count > 0) draws a dotted line between spot and NewPoint when there is at least one point.
EDIT : full drawing code
int x = 0;
int y = 0;
bool drag = false;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
Point spot = new Point((int)((float)(e.Location.X) / PictureScale), (int)((float)(e.Location.Y) / PictureScale));
if (e.Button == MouseButtons.Middle)
{
x = e.X;
y = e.Y;
drag = true;
}
else
{
if (NewPolygon != null)
{
if (e.Button == MouseButtons.Right)
{
if (NewPolygon.Count > 1)
{
int counter = NewPolygon.Count;
Polygons.Add(NewPolygon);
}
NewPolygon = null;
}
else if (e.Button == MouseButtons.Left)
{
if (NewPolygon[NewPolygon.Count - 1] != spot)
{
NewPolygon.Add(spot);
scaffolds.Add(new Rectangle(spot.X - 3, spot.Y - 3, 6, 6));
}
}
}
else
{
NewPolygon = new List<Point>();
NewPoint = spot;
NewPolygon.Add(spot);
scaffolds.Add(new Rectangle(spot.X - 3, spot.Y - 3, 6, 6));
}
}
//this.Capture = true;
pictureBox1.Refresh();
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (drag)
{
pictureBox1.Top += e.Y - y;
pictureBox1.Left += e.X - x;
this.Cursor = Cursors.SizeAll;
}
else
{
if (NewPolygon == null)
return;
NewPoint = new Point((int)((float)(e.Location.X) / PictureScale), (int)((float)(e.Location.Y) / PictureScale));
pictureBox1.Refresh();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.ScaleTransform(PictureScale, PictureScale);
foreach (Rectangle rect in scaffolds)
{
e.Graphics.DrawEllipse(pen, rect);
}
foreach (List<Point> polygon in Polygons)
{
e.Graphics.DrawLines(pen, polygon.ToArray());
}
if (NewPolygon != null)
{
Pen pp = new Pen(color, 5);
if (NewPolygon.Count > 0)
{
if (NewPolygon.Count > 1)
{
e.Graphics.DrawLines(pp, NewPolygon.ToArray());
}
using (Pen dashed_pen = pp)
{
dashed_pen.DashPattern = new float[] { 3, 3 };
e.Graphics.DrawLine(dashed_pen, NewPolygon[NewPolygon.Count - 1], NewPoint);
}
}
}
}
Here is my source code. I can't seem to get the bitmap to show the lines drawn on the panel when I move the mouse with the button pressed. Frustrated and looking for someone to help me finish the code so I can complete the app for my 9-yo daughter. Thank you in advance...
namespace TV_PAINT
{
public partial class ALANA_PAINT : Form
{
Graphics g;
Pen p = new Pen(Color.Black, 7);
Point sp = new Point(0, 0);
Point ep = new Point(0, 0);
int m = 0;
Bitmap BP;
public ALANA_PAINT()
{
InitializeComponent();
tb1.Text = p.Width.ToString();
BP = new Bitmap(pnl1.ClientSize.Width, pnl1.ClientSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
}
private void closeButton_Click(object sender, EventArgs e)
{
pnl1.Dispose();
p.Dispose();
this.Close();
}
private void clearButton_Click(object sender, EventArgs e)
{
//pnl1.Invalidate();
p.Color = System.Drawing.Color.Black;
p.Width = 7;
tb1.Text = p.Width.ToString();
//pnl1.Invalidate();
}
private void pnl1_MouseDown(object sender, MouseEventArgs e)
{
sp = e.Location;
if (e.Button == MouseButtons.Left)
m = 1;
if (e.Button == MouseButtons.Right)
m = 1;
}
private void pnl1_MouseMove(object sender, MouseEventArgs e)
{
if (m == 1)
{
ep = e.Location;
//g = pnl1.CreateGraphics();
Graphics g = Graphics.FromImage(BP);
g.DrawLine(p, sp, ep);
}
sp = ep;
}
private void pnl1_MouseUp(object sender, MouseEventArgs e)
{
m = 0;
}
BP is just a variable in the form. As I can see, it is not displayed anywhere in your form. Why do you need a bitmap for it.
You can do something like this, just get the graphics of your form, and draw using that graphic. https://msdn.microsoft.com/en-us/library/ztxk24yx(v=vs.110).aspx
Noted: you need to do it on PaintEvent of the form, otherwise your drawing will be removed after the next repaint, so you need some variables to store all of your lines, then draw all of them in the paint event.
System.Drawing.SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Red);
System.Drawing.Graphics formGraphics;
formGraphics = this.CreateGraphics();
formGraphics.FillRectangle(myBrush, new Rectangle(0, 0, 200, 300));
myBrush.Dispose();
formGraphics.Dispose();
Updated:
If you want to save your change to a bitmap. You can use Form.DrawToBitmap to save your drawing in the form to a bitmap, then call bitmap.Save() to a file in directory.
I'm using WinForms. In my form i have a picturebox that contains an image. I provided my code which highlights images by right-clicking and dragging the mouse.
How do I print the image and what i highlighted in the picturebox?
private Random _rnd = new Random();
private Point _pt;
private Point _pt2;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
//set the upper left point of our selection rectangle
if (e.Button == MouseButtons.Left)
_pt = e.Location;
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
//display the selected part when mouse button gets released
if (e.Button == MouseButtons.Left)
{
GenerateBmp();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
//if we have a valid rectangle, draw it
if (_pt.X - _pt2.X != 0 && _pt.Y - _pt2.Y != 0)
{
//fill
using (SolidBrush sb = new SolidBrush(Color.FromArgb(95, 255, 255, 0)))
e.Graphics.FillRectangle(sb, new Rectangle(_pt.X, _pt.Y, _pt2.X - _pt.X, _pt2.Y - _pt.Y));
//draw
e.Graphics.DrawRectangle(Pens.Blue, new Rectangle(_pt.X, _pt.Y, _pt2.X - _pt.X, _pt2.Y - _pt.Y));
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
//set the bottom right one
if (e.Button == MouseButtons.Left)
{
_pt2 = e.Location;
this.pictureBox1.Invalidate();
}
}
private void GenerateBmp()
{
//check, if we have a valid rectangle
if (_pt2.X - _pt.X > 0 && _pt2.Y - _pt.Y > 0)
{
//create that rectangle
Rectangle r = new Rectangle(_pt.X, _pt.Y, _pt2.X - _pt.X, _pt2.Y - _pt.Y);
//create a new Bitmap with the size of the selection-rectangle
Bitmap bmp = new Bitmap(r.Width, r.Height);
//draw the selectex part of the original image
using (Graphics g = Graphics.FromImage(bmp))
g.DrawImage(this.pictureBox1.Image, new Rectangle(0, 0, r.Width, r.Height), r, GraphicsUnit.Pixel);
}
}
private Bitmap SetUpPictures(PictureBox pb)
{
//create a bitmap to display
Bitmap bmp1 = new Bitmap(pb.ClientSize.Width, pb.ClientSize.Height);
//get the graphics-context
using (Graphics g = Graphics.FromImage(bmp1))
{
//get a random, opaque, color
Color c = Color.FromArgb(255, _rnd.Next(256), _rnd.Next(256), _rnd.Next(256));
g.Clear(c);
//better smoothinmode for round shapes
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
//draw ten shapes to the bitmap
for (int i = 0; i < 10; i++)
{
//loaction and size rectangle
Rectangle r = new Rectangle(_rnd.Next(pb.ClientSize.Width / 2), _rnd.Next(pb.ClientSize.Height / 2),
_rnd.Next(pb.ClientSize.Width / 2), _rnd.Next(pb.ClientSize.Height / 2));
//random color
Color c2 = Color.FromArgb(_rnd.Next(256), _rnd.Next(256), _rnd.Next(256), _rnd.Next(256));
//one color brush
using (SolidBrush sb = new SolidBrush(c2))
{
//check, if i is odd or even and decide on that to draw rectangles or ellipses
if ((i & 0x01) == 1)
g.FillEllipse(sb, r);
else
g.FillRectangle(sb, r);
}
}
}
//return our artwork
return bmp1;
}
private void Btn_Print_Click(object sender, EventArgs e)
{
System.Drawing.Printing.PrintDocument myPrintDocument1 = new System.Drawing.Printing.PrintDocument();
PrintDialog myPrinDialog1 = new PrintDialog();
myPrintDocument1.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(DVPrintDocument_PrintPage);
myPrinDialog1.Document = myPrintDocument1;
if (myPrinDialog1.ShowDialog() == DialogResult.OK)
{
myPrintDocument1.Print();
}
}
private void DVPrintDocument_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawImage(pictureBox1.Image, 25, 25, 800, 1050);
var rc = new RectangleF(0, 0, pictureBox1.Image.Width / 100f, pictureBox1.Image.Height / 100f);
e.Graphics.DrawImage(pictureBox1.Image, rc);
}
You can draw the content of picturebox simply using DrawToBitmap method:
For example:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawRectangle(Pens.Red, new Rectangle(10, 10, 100, 100));
}
private void button1_Click(object sender, EventArgs e)
{
this.printDocument1.Print();
}
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
var bmp=new Bitmap(this.pictureBox1.Width, this.pictureBox1.Height);
this.pictureBox1.DrawToBitmap(bmp,this.pictureBox1.ClientRectangle);
e.Graphics.DrawImageUnscaled(bmp, 0, 0);
}
And here is the printed result:
I want to crop an image in c#. As in most photo editing software I want to use the rectangle box which can be resized and repositioned via a mouse. In addition, I would like to know how to highlight the cropped area, as show in this photo.
Your image link is no longer available.
So assuming that in a panel you have your picturebox with the image to crop.
First you need to create event handlers for mouse actions to be able to draw a rectangular region which you wish to crop :
private void picBox_MouseDown(object sender, MouseEventArgs e)
{
Cursor = Cursors.Default;
if (Makeselection)
{
try
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
Cursor = Cursors.Cross;
cropX = e.X;
cropY = e.Y;
cropPen = new Pen(Color.Crimson, 1);
cropPen.DashStyle = DashStyle.Solid;
}
picBox.Refresh();
}
catch (Exception ex)
{
}
}
}
private void picBox_MouseUp(object sender, MouseEventArgs e)
{
if (Makeselection)
{
Cursor = Cursors.Default;
}
}
private void picBox_MouseMove(object sender, MouseEventArgs e)
{
Cursor = Cursors.Default;
if (Makeselection)
{
picBox.Cursor = Cursors.Cross;
try
{
if (picBox.Image == null)
return;
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
picBox.Refresh();
cropWidth = e.X - cropX;
cropHeight = e.Y - cropY;
picBox.CreateGraphics().DrawRectangle(cropPen, cropX, cropY, cropWidth, cropHeight);
}
}
catch (Exception ex)
{
}
}
}
private void picBox_MouseLeave(object sender, EventArgs e)
{
tabControl.Focus();
}
private void picBox_MouseEnter(object sender, EventArgs e)
{
picBox.Focus();
}
Now, comes the button click function for cropping the image :
private void btnCrop_Click_1(object sender, EventArgs e)
{
Cursor = Cursors.Default;
try
{
if (cropWidth < 1)
{
return;
}
Rectangle rect = new Rectangle(cropX, cropY, cropWidth, cropHeight);
//First we define a rectangle with the help of already calculated points
Bitmap OriginalImage = new Bitmap(picBoxScreenshot.Image, picBoxScreenshot.Width, picBoxScreenshot.Height);
//Original image
Bitmap _img = new Bitmap(cropWidth, cropHeight);
// for cropinfo image
Graphics g = Graphics.FromImage(_img);
// create graphics
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
//set image attributes
g.DrawImage(OriginalImage, 0, 0, rect, GraphicsUnit.Pixel);
picBox.Image = _img;
picBox.Width = _img.Width;
picBox.Height = _img.Height;
PictureBoxLocation();
cropWidth = 0;
}
catch (Exception ex){}
}
private void PictureBoxLocation()
{
int _x = 0;
int _y = 0;
if (panel1.Width > picBox.Width)
{
_x = (panel1.Width - picBox.Width) / 2;
}
if (panel1.Height > picBox.Height)
{
_y = (panel1.Height - picBox.Height) / 2;
}
picBox.Location = new Point(_x, _y);
picBox.Refresh();
}
In order to draw a picture lighter or darker (or alter the colors in any way) you use a ColorMatrix, like this.
The outside of the selection box seems to have a black image laid over it with a alpha of about 30%. To do this you would just take each pixel outside of the content area and draw a black pixel with a 30% alpha on top of it. This would give the desired dimmed out effect.
As for how you can get a rectangle to be dynamically seizable in C#.