C# WinForms problem with draw image - c#

class OriginalImage: Form
{
private Image image;
private PictureBox pb;
public OriginalImage()
{
pb = new PictureBox {SizeMode = PictureBoxSizeMode.CenterImage};
pb.SizeMode = PictureBoxSizeMode.StretchImage;
Controls.Add(pb);
image = Image.FromFile(#"Image/original.jpg");
this.Width = image.Width;
this.Height = image.Height;
this.Text = "Original image";
this.Paint += new PaintEventHandler(Drawer);
}
public virtual void Drawer(object source, PaintEventArgs e)
{
Graphics g = pb.CreateGraphics();
g.DrawImage(image,0,0);
}
I call this create object OriginalImage in other form on button click, but image is not draw? Where is problem?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var oi = new OriginalImage();
oi.Show();
}
}

You're creating a PictureBox and adding it to your controls, but you never actually use it (you're drawing the image manually in the Paint event). Why? This control is likely obscuring the drawing area of the form, as any controls go on top of whatever you draw in the Paint event.
In addition, you're getting the Graphics object by calling CreateGraphics on the PictureBox rather than the Form itself. This is wrong, as the PictureBox's Paint event will fire after this code, erasing whatever you draw.
I would recommend changing your OriginalForm code to the following:
class OriginalImage: Form
{
private Image image;
private PictureBox pb;
public OriginalImage()
{
pb = new PictureBox();
pb.SizeMode = PictureBoxSizeMode.StretchImage;
pb.Dock = DockStyle.Fill; // this will make the PictureBox occupy the
// whole form
Controls.Add(pb);
image = Image.FromFile(#"Image/original.jpg");
this.ClientSize = new Size(image.Width, image.Height); // this allows you to
// size the form while
// accounting for the
// border
this.Text = "Original image";
pb.Image = image; // use this instead of drawing it yourself.
}
}

Related

Using control functions in a bitmap in C#

I was thinking of implementing a bitmap into a picturebox (or the otherway round), such that I could have the option to:
1.drag and drop the item (Control function with mousebuttons)
2.rotate the item (bitmap function).
This is what I have currently:
Bitmap bmp = new Bitmap(#"my source");
PictureBox item = new System.Windows.Forms.PictureBox();
I create the picturebox on the click of a button:
private void button2_Click(object sender, EventArgs e)
{
item.BackColor = Color.Blue;
item.Location = new Point(400, 200);
item.MouseDown += new MouseEventHandler(textbox_MouseDown);
item.MouseMove += new MouseEventHandler(textbox_MouseMove);
item.MouseUp += new MouseEventHandler(textbox_MouseUp);
item.MouseWheel += new MouseEventHandler(textbox_MouseWheel);
item.Image = bmp;
item.SizeMode = PictureBoxSizeMode.StretchImage;
this.Controls.Add(item);
item.BringToFront();
}
and in the textbox_MouseMove void, I try to use the middle button to signal the rotation of the image
void textbox_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Middle )
{
if (activeControl == null || activeControl != sender)
{
return;
}
this.Paint += new PaintEventHandler(objectrotation_Paint);
Invalidate();
}
}
where the PaintEvent is responsible for the rotation of the image
private void objectrotation_Paint(object sender, PaintEventArgs d)
{
int dpi = 96;
bmp.SetResolution(dpi, dpi);
if (bmp != null)
{
float bw2 = bmp.Width / 2f;
float bh2 = bmp.Height / 2f;
d.Graphics.TranslateTransform(bw2, bh2);
d.Graphics.RotateTransform(angle);
d.Graphics.TranslateTransform(-bw2, -bh2);
d.Graphics.DrawImage(bmp,0,0);
d.Graphics.ResetTransform();
}
}
This however would create two sets of images, i.e. when I press button 2 I get one image, when I move my mouse with middle button down I get the second image (rotating).Refering to some of the questions on here, people recommend using
item.Image = bmp;
but it simply copies the from picturebox to the bitmap while they have seperate controls. While the picturebox class could not perform rotations without implementing a Bitmap, the Bitmap class does not have the option to perform actions like OnMouseMove etc.
Is there any way to combine my bitmap and the picturebox such that I could achieve my two goals?

Create rectangle drawing inside the picturebox

After button click event I want the program to draw a rectangle inside a picturebox. I don't know how to do that. So far I made only a rectangle outside of picture box like this. Afterwards I want to implement a flood fill algorithm to fill the rectangle with a color. That's why I have to have those bitmaps there.
namespace howto_floodfill
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// The background image.
private Bitmap bm;
private Bitmap32 bm32;
// Make a rectangle
private void button1_Click(object sender, EventArgs e)
{
bm = new Bitmap(ClientSize.Width, ClientSize.Height);
using (Graphics gr = Graphics.FromImage(bm))
{
gr.Clear(Color.Silver);
gr.DrawRectangle(Pens.Black, 5, 5, 100, 60);
}
bm32 = new Bitmap32(bm);
this.BackgroundImage = bm;
}
}
}
You can set a Paint event handler for the PictureBox that will allow you to do drawing over the top of the PictureBox contents:
public partial class Form1 : Form
{
private bool _drawRectangle = false;
public Form1()
{
InitializeComponent();
pictureBox1.Paint += new PaintEventHandler(this.pictureBox1_Paint);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (_drawRectangle) {
Graphics g = e.Graphics;
// use g to do your drawing
}
}
}
Just set _drawRectangle to true in your button click handler and call pictureBox1.Invalidate(). Doing your drawing in the Paint event handler guarantees that whenever the PictureBox is redrawn (say, because another window was over it), your rectangle gets drawn as well.
This will let you draw a rectangle over the PictureBox's contents. Rather than a flood fill algorithm, have you considered just using FillRectangle?
If you really want to do a flood fill, you'll have to work with an image as you're already doing, so you can read pixels from the image to know if a boundary has been reached. Then you could set the PictureBox's Image property with the resulting bitmap. (In this case, it wouldn't be necessary to do the graphics work in the Paint event handler, since the PictureBox will make sure its Image is drawn on every paint.)
You can use the control.CreateGraphics() method invoked from your picturebox.
namespace WindowsFormsApplication_Test
{
public partial class Form1 : Form
{
private Bitmap bm;
public Form1()
{
InitializeComponent();
bm = new Bitmap(pB.ClientRectangle.Width, pB.ClientRectangle.Height);
}
private void btn_Click(object sender, EventArgs e)
{
Graphics gF = pB.CreateGraphics();
gF.Clear(Color.Silver);
gF.DrawRectangle(Pens.Black, 5, 5, 100, 60);
}
private void button1_Click(object sender, EventArgs e)
{
Graphics gF = Graphics.FromImage(bm);
gF.Clear(Color.Silver);
gF.DrawRectangle(Pens.Black, 5, 5, 100, 60);
pB.Image = bm;
}
}
}
btn_click() is an example of getting the graphics context from the control and drawing directly.
Form prior to clicking...
Clicking the button will draw on the control directly - note that by default it gives you the clientRectangle portion of the control, which is nice...
Clicking on the button gives you this.
Now I resized the form.
Unfortunately, drawing on the form this way makes you responsible for redrawing your data any time the window is invalidated.
You can also just set the Image property of the form to be your private bitmap and then the framework handles redrawing for you. This is shown in the button1_Click() method.
You can still draw directly on the control if you wish, but you'll need to hook into the control events and redraw when the form does. For example, adding a flag as a private bool to the form class, overriding the OnPaint method, and adding code to your button event to swap the flag. Rather than duplicating the drawing code in the button event, you can just flip the flag and call this.Invalidate();
public partial class Form1 : Form
{
private Bitmap bm;
private bool bDrawn = false;
public Form1()
{
InitializeComponent();
bm = new Bitmap(pB.ClientRectangle.Width, pB.ClientRectangle.Height);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (bDrawn)
{
Graphics gF = pB.CreateGraphics();
gF.Clear(Color.Silver);
gF.DrawRectangle(Pens.Black, 5, 5, 100, 60);
}
}
private void btn_Click(object sender, EventArgs e)
{
//Graphics gF = pB.CreateGraphics();
//gF.Clear(Color.Silver);
///gF.DrawRectangle(Pens.Black, 5, 5, 100, 60);
bDrawn = true;
this.Invalidate();
}
Assign the created bitmap to the Image property of the picture box. Now you can draw whatever you want on the bitmap, and then manipulate it's data.
namespace howto_floodfill {
public partial class Form1 : Form {
private Bitmap bitmap;
public Form1() {
InitializeComponent();
this.bitmap = new Bitmap(100, 100);
this.pictureBox1.Image = this.bitmap;
}
// Make a rectangle
private void button1_Click(object sender, EventArgs e) {
if (this.bitmap != null) {
this.bitmap.Dispose();
}
this.bitmap = new Bitmap(ClientSize.Width, ClientSize.Height);
using (Graphics gr = Graphics.FromImage(bitmap)) {
gr.Clear(Color.Silver);
gr.DrawRectangle(Pens.Black, 5, 5, 100, 60);
}
this.pictureBox1.Image = this.bitmap;
}
}
}
Note that you may not need to re-create the bitmap each time if it has a fixed size.

How to call function with PaintEventArgs argumnt?

Given the following code example from MSDN:
private void GetPixel_Example(PaintEventArgs e)
{
// Create a Bitmap object from an image file.
Bitmap myBitmap = new Bitmap(#"C:\Users\tanyalebershtein\Desktop\Sample Pictures\Tulips.jpg");
// Get the color of a pixel within myBitmap.
Color pixelColor = myBitmap.GetPixel(50, 50);
// Fill a rectangle with pixelColor.
SolidBrush pixelBrush = new SolidBrush(pixelColor);
e.Graphics.FillRectangle(pixelBrush, 0, 0, 100, 100);
}
How can one call the Paint function?
from the paint event something like this
private PictureBox pictureBox1 = new PictureBox();
pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint);
private void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
GetPixel_Example(e) ;
}
You can call this method from a PaintEvent of a form e.g.
public class Form1 : Form
{
public Form1()
{
this.Paint += new PaintEventHandler(Form1_Paint);
}
//....
private void Form1_Paint(object sender, PaintEventArgs e)
{
GetPixel_Example(e);
}
private void GetPixel_Example(PaintEventArgs e)
{
// Create a Bitmap object from an image file.
Bitmap myBitmap = new Bitmap(#"C:\Users\tanyalebershtein\Desktop\Sample Pictures\Tulips.jpg");
// Get the color of a pixel within myBitmap.
Color pixelColor = myBitmap.GetPixel(50, 50);
// Fill a rectangle with pixelColor.
SolidBrush pixelBrush = new SolidBrush(pixelColor);
e.Graphics.FillRectangle(pixelBrush, 0, 0, 100, 100);
}
}
Loads the image
Get the color of the pixel at x=50,y=50
Draw a filled rectangle with that color at 0,0 with a size of 100,100
on the Graphics-Object of the form
You should't call the Paint method yourself. The Paint method will be called by the .NET framework whenever your component needs to be painted. This typically happens when the window is moved, minimized, etc.
If you want to tell the .NET framework to repaint your component, call Refresh() on either the component or one of its parents.

How do i insert a Box which i drew out from pen to a picturebox image?

i need help on inserting a box which i drew out from into a picturebox.
here is the code of the pen that i code out, i do not know how to put it in the picturebox.
there will be a webcam running on the background of the picturebox, i want my rectangle to be inside the picturebox.
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text == "Start")
{
Graphics myGraphics = base.CreateGraphics();
myGraphics.Clear(Color.White);
Pen myPen = new Pen(Color.DarkBlue);
Rectangle rect = new Rectangle(480, 70, 120, 120);
myGraphics.DrawRectangle(myPen, rect);
stopWebcam = false;
button1.Text = "Stop";
}
else
{
stopWebcam = true;
button1.Text = "Start";
}
}
Paining in winforms is primarily done in the OnPaint event. Your ButtonClick event handler should only setup the stage for OnPaint and possibly activate it. Example:
public class MyForm : Form
...
private Rectangle? _boxRectangle;
private void OnMyButtonClick(object sender, EventArgs e)
{
if (button1.Text == "Start")
{
_boxRectangle = new Rectangle(...);
button1.Text = "Stop";
}
else
{
_boxRectangle = null;
button1.Text = "Start";
}
Invalidate(); // repaint
}
protected override OnPaint(PaintEventArgs e)
{
if (_boxRectangle != null)
{
Graphics g = e.Graphics.
Pen pen = new Pen(Color.DarkBlue);
g.DrawRectangle(_boxRectangle);
}
}
}
You may have to draw the web cam image onto a bitmap buffer and use that as an image for the picture box.
Here is the msdn page with examples at the bottom:
http://msdn.microsoft.com/en-us/library/system.windows.forms.picturebox.aspx
Here is my method for doing it.
public void GraphicsToPictureBox (ref PictureBox pb, Graphics graphics,
Int32 width, Int32 height)
{
Bitmap bitmap = new Bitmap(width,height,graphics);
pb.Image = bitmap;
}

Drawing on PictureBox inside of Panel - C#

The question I have here is sort of a 2 parter.
I have a picturebox that is positioned inside of a panel. When I open an image, the picturebox is resized to the size of the image, while the panel stays the same size. The panel just has scrollbars to see the whole image.
There are 2 things going wrong with this.
When I resize the picturebox, for some reason I can only draw in the previous portion of the picturebox. Ex. The imagebox starts out by default as 200x200. I open an image that is 500x400. And I can only still draw in the 200x200 portion of the image.
The second issue that I am having is that when I do draw in that selective portion of the picturebox, when I scroll to where my painting is out of view, and come back, the image that i painted gone. I know there is some sort of picturebox.invalidate() that I need. I am just not sure how to use it.
Here is my code to get a good grasp on what I'm doing.
public Form1()
{
InitializeComponent();
DrawArea = new Bitmap(pictureBox1.Size.Width, pictureBox1.Size.Height );
pictureBox1.Image = DrawArea;
objGraphics = this.pictureBox1.CreateGraphics();
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
drawImage(e);
}
public void drawImage(MouseEventArgs e)
{
Rectangle rDraw = new Rectangle();
if (e.Button == MouseButtons.Left)
{
rDraw.X = e.X;
rDraw.Y = e.Y;
rDraw.Width = 3;
rDraw.Height = 3;
objGraphics.DrawEllipse(System.Drawing.Pens.Black, rDraw);
}
}
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
OpenFileDialog open = new OpenFileDialog();
open.Filter = "Image Files(*.jpg; *.bmp)|*.jpg; *.bmp";
if (open.ShowDialog() == DialogResult.OK)
{
Bitmap bit = new Bitmap(open.FileName);
pictureBox1.Size = bit.Size;
DrawArea = bit;
pictureBox1.Image = bit;
}
}
catch (Exception)
{
throw new ApplicationException("Failed loading image");
}
}
Thanks Alot!
You need to draw in the picturebox's Paint event.
You should (almost) never draw on CreateGraphics().

Categories