I am drawing a box with certain measurements and updating the angle at which it is viewed which I set as a double 'offset'. I am trying to get the view to change as I click a button to increase its offset. How would I update the bitmap to reflect the button click.
"
public void Form1_Load(object sender, EventArgs e)
{
myBitmap = new Bitmap(this.ClientRectangle.Width,
this.ClientRectangle.Height);
graphicsObj = Graphics.FromImage(myBitmap);
Pen linePen = new Pen(Color.Red, 3);
graphicsObj.Drawline(linePen, 50, 50, 100, 50);
public void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics graphicsObj = e.Graphics;
graphicsObj.DrawImage(myBitmap, 0, 0, myBitmap.Width, myBitmap.Height);
}
public void button1_Click(object sender, EventArgs e)
{
offsetButton = offsetButton + .10;
**call or update bitmap**
}
"
Related
I'm doing a school project using C# in which I designed a Form in C# that I can draw on and now I need to copy what I draw into a 9 different Images and save them. So far, I tried using the copy from screen function like that:
Size s = this.Size;
Bitmap memoryImage = new Bitmap(s.Width, s.Height, this.CreateGraphics());
Graphics.FromImage(memoryImage).CopyFromScreen(this.Location.X, this.Location.Y, 0, 0, s);
memoryImage.Save(#"C:\Users\omerm\Desktop\projectFinals\ProjectFiles\C-Sharp\Drawing\WinFormsApp1\Digits\1.jpg");
My problem is that the image I get from this code includes parts of my screen that aren't part of my Form. And I also need to copy 9 different images who are fractions of this one instead of just the one and make sure those 9 are around the same shape(squares). does anyone know how to do that?
I'm terrible at explaining this so think that I need to take the original image and cut into 9 like in a tic tac toe board and save each one of them as a different image in the shape of squares instead of the original.
full code:
namespace WinFormsApp1
{
public partial class Form1 : Form
{
Pen Pen = new Pen(Color.Black, 2);
int pX, pY;
Graphics g;
public object MemoryImage { get; private set; }
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
pX = e.X;
pY = e.Y;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Graphics g = pictureBox1.CreateGraphics();
g.DrawLine(Pen, pX, pY, e.X, e.Y);
pX = e.X;
pY = e.Y;
}
}
private void button1_Click(object sender, EventArgs e)
{
Size s = this.Size;
Bitmap memoryImage = new Bitmap(s.Width, s.Height, this.CreateGraphics());
Graphics.FromImage(memoryImage).CopyFromScreen(this.Location.X, this.Location.Y, 0, 0, s);
memoryImage.Save(#"C:\Users\omerm\Desktop\projectFinals\ProjectFiles\C-Sharp\Drawing\WinFormsApp1\Digits\1.jpg");
}
private void ChooseColor(object sender, EventArgs e)
{
Pen.Color = ((PictureBox)sender).BackColor;
}
}
}
Tried looking online but what I look for is really specific.
Here's an example of persisting the data in a structure and drawing it in the Paint() event. Additionally, I've demonstrated how to tell the PictureBox to draw itself instead of copying the screen:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private List<Point> curSquiggle;
private List<List<Point>> Squiggles = new List<List<Point>>();
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
curSquiggle = new List<Point>();
curSquiggle.Add(e.Location);
Squiggles.Add(curSquiggle);
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
curSquiggle.Add(e.Location);
pictureBox1.Invalidate();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
foreach(List<Point> squiggle in Squiggles)
{
e.Graphics.DrawLines(Pens.Black, squiggle.ToArray());
}
}
private void button1_Click_1(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap(pictureBox1.ClientRectangle.Width, pictureBox1.ClientRectangle.Height);
pictureBox1.DrawToBitmap(bmp, pictureBox1.ClientRectangle);
// Do something with the bmp, like display it in another form:
Form frm = new Form();
frm.AutoSize = true;
PictureBox pb = new PictureBox();
pb.SizeMode = PictureBoxSizeMode.AutoSize;
pb.Image = bmp;
pb.Location = new Point(0, 0);
frm.Controls.Add(pb);
frm.Show();
}
}
Example run:
Here's a different version of the save code which splits the main picture into 9 pieces:
private void button1_Click_1(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap(pictureBox1.ClientRectangle.Width, pictureBox1.ClientRectangle.Height);
pictureBox1.DrawToBitmap(bmp, pictureBox1.ClientRectangle);
int cols = 3;
int rows = 3;
int cellWidth = bmp.Width / cols;
int cellHeight = bmp.Height / rows;
Rectangle destRect = new Rectangle(0, 0, cellWidth, cellHeight);
List<Bitmap> cells = new List<Bitmap>();
for(int r=0; r<rows; r++)
{
for(int c=0; c<cols; c++)
{
Bitmap cell = new Bitmap(cellWidth, cellHeight);
Rectangle srcRect = new Rectangle(c * cellWidth, r * cellHeight, cellWidth, cellHeight);
using (Graphics g = Graphics.FromImage(cell))
{
g.DrawImage(bmp, destRect, srcRect, GraphicsUnit.Pixel);
}
cells.Add(cell);
}
}
foreach(Bitmap cell in cells)
{
Form frm = new Form();
frm.AutoSize = true;
frm.AutoSizeMode = AutoSizeMode.GrowAndShrink;
PictureBox pb = new PictureBox();
pb.SizeMode = PictureBoxSizeMode.AutoSize;
pb.Image = cell;
pb.Location = new Point(0, 0);
frm.Controls.Add(pb);
frm.Show();
}
}
Splitting into nine pieces:
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();
}
}
private void MainImage_Paint(object sender, PaintEventArgs e)
{
Point[] destinationPoints = {
new Point(200, 20),
new Point(110, 100),
new Point(250, 30)};
Bitmap image = new Bitmap(MainImage.Image);
e.Graphics.DrawImage(image, 0, 0);
e.Graphics.DrawImage(image, destinationPoints);
}
private void button7_Click(object sender, EventArgs e)
{
}
How would I call the paint event on mouse click?
Upon firing the "on click" event, it should draw a image over the MainImage.
Use this.Invalidate(); or this.Update(); or this.Refresh();
And try this:
Graphics.FromImage(MainImage);
GraphicsUnit units = GraphicsUnit.Point;
MainImage_Paint(MainImage,new PaintEventArgs ( Graphics.FromImage(MainImage),Rectangle.Round(MainImage.GetBounds(ref units)));
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);
}
}
}
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();
}