I am currently starting to build a simple version of the Game of Life following the same logic. I am using a picture box. In order to know where an area is clicked, it is advised to use 2 x 2 squares. How can I create 2 x 2 squares and give it a grid like style inside the pictureBox?
CODE
private void Form1_Load(object sender, EventArgs e)
{
this.pictureBox1.Image = this.Draw(this.pictureBox1.Width, this.pictureBox1.Height);
}
public Bitmap Draw(int width, int height)
{
var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
var graphics = Graphics.FromImage(bitmap);
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.FillRectangle(new SolidBrush(Color.Tomato), 60, 60, 10, 10);
return bitmap;
}
EXAMPLE of outlook
Related
Is it possible to create another Graphics form an existing Graphics with a different coordinate system? For example, let's say that the black rectangle is the ClipRectangle of the Graphics object I got in OnPaint(). If I only want to draw inside the blue rectangle, I would have to constantly calculate the offset. That is, to draw at the logical point (0,0) in the blue rectangle, I would have to add the x and y offsets. That makes drawing code complicated.
Is there a way to create some sort of virtual Graphics using the Graphics above but with a different coordinate system? Something like below
//not actual code
var virtualG = Graphics.FromExistingGraphics(e.Graphics, 200/*x1*/, 200/*y1*/, 1000/*x2*/, 600/*y2*/);
//Doing the same thing as e.Graphics.DrawLine(pen, 200, 200, 400, 400)
virtualG.DrawLine(pen, 0, 0, 200, 200);
//Draws nothing, NOT the same as e.Graphics.DrawLine(pen, 1100, 200, 1200, 400)
//, because its outside of the virtualG's bounds.
virtualG.DrawLine(pen, 900, 0, 1000, 200);
I thought about creating a new Graphics using bitmap, draw there and then copy the bitmap to the specified location of the Graphics from OnPaint, but that could be slow.
If you don't want any scaling, and simply want to move the origin to (200, 200), then use TranslateTransform as suggested previously. If you want to clip any drawings outside that rectangle, then use SetClip.
Here's an example, showing the same set of lines drawn before and after translating and clipping. The black lines are before, while the blue line is after (the second blue line is clipped and therefore not visible). The red rectangle shows the clipping region:
Code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public class Line
{
public Point ptA;
public Point ptB;
public void Draw(Graphics G, Color color)
{
using (Pen P = new Pen(color))
{
G.DrawLine(P, ptA, ptB);
}
}
}
private List<Line> Lines = new List<Line>();
private void Form1_Load(object sender, EventArgs e)
{
Lines.Add(new Line() { ptA = new Point(0,0), ptB = new Point(200, 200)});
Lines.Add(new Line() { ptA = new Point(900, 0), ptB = new Point(1000, 200) });
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics G = e.Graphics;
G.Clear(Color.DarkGray);
foreach(Line line in Lines)
{
line.Draw(G, Color.Black);
}
Rectangle rc = new Rectangle(new Point(200, 200), new Size(800, 400));
G.DrawRectangle(Pens.Red, rc);
G.SetClip(rc);
G.TranslateTransform(rc.Left, rc.Top); // origin is now at (200, 200)
foreach (Line line in Lines)
{
line.Draw(G, Color.Blue);
}
}
}
I'm triying to cover an image with another in order to provide a watermark but it has to cover the entire source image. The problem is that the watermark provided is of 600x600 and the source image can have any size and aspect ratio. So far it does not cover the source image entirely.
I solved it like this (in a very straightforward way).
private void button1_Click(object sender, EventArgs e)
{
var image = new Bitmap( this.pictureBox1.Image.Width, this.pictureBox1.Image.Height);
var rect = new Rectangle(0, 0, this.pictureBox1.Image.Width, this.pictureBox1.Image.Height);
Graphics graphics = Graphics.FromImage(image);
graphics.DrawImage(this.pictureBox1.Image, 0, 0);
var waterMarkImage = new Bitmap(this.pictureBox2.Image.Width, this.pictureBox2.Image.Height);
for (int y = 0; y < waterMarkImage.Height; y++)
{
for (int x = 0; x < waterMarkImage.Width; x++)
{
var color = (this.pictureBox2.Image as Bitmap).GetPixel(x, y);
color = Color.FromArgb(50, color.R, color.G, color.B);
waterMarkImage.SetPixel(x, y, color);
}
}
graphics.DrawImage(waterMarkImage, rect);
this.pictureBox3.Image = image;
}
In pictureBox1 I loaded main image. In pictureBox2 I loaded "water mark". In the event handler I created resulting image (first main image then the second) and loaded it into pictureBox3. To get water mark affect I reduced alpha component of color (I set it to 50).
Below is my code for changing my panel information into a Bitmap.
The Bitmap is first generated by my panel information and then saved to as a image file.
I confirmed that the width, height, and bounds represent the right information given by my panel.
I am currently unsure of why my result bmp/jpeg file is different from the image on my panel.
//bitmap saving function
Bitmap bmp = new Bitmap(panel1.ClientSize.Width, panel1.ClientSize.Height);
Debug.WriteLine("bounds: " + panel1.ClientRectangle);
this.panel1.DrawToBitmap(bmp, panel1.ClientRectangle);
bmp.Save(#"C:\Documents and Settings\Flaw\Desktop\Test.bmp", ImageFormat.Bmp);
//drawing function
System.Drawing.Graphics graphicsObj;
graphicsObj = this.panel1.CreateGraphics();
Pen myPen = new Pen(System.Drawing.Color.Black, 5);
graphicsObj.Clear(Color.White);
//graphicsObj.DrawLine(myPen, 50, 50, 100, 100);
if (bCircle)
{
graphicsObj.DrawEllipse(myPen, x, y, 100, 100);
}
else if (bSquare)
{
graphicsObj.DrawRectangle(myPen, x, y, 100, 100);
}
The result I get by saving the bitmap.
The image that is on my panel1 (cropped from my Window Form)
Your Bounds property is the relationship the panel has to the parent container, so this won't always work:
this.panel1.DrawToBitmap(bmp, panel1.Bounds);
Try this instead:
this.panel1.DrawToBitmap(bmp, panel1.ClientRectangle);
Your bitmap size should also use the ClientSize properties, since the panel's Width and Height properties include any border sizes:
Bitmap bmp = new Bitmap(panel1.ClientSize.Width, panel1.ClientSize.Height);
Per your update, CreateGraphics is a temporary canvas and won't be a part of the panel, so there was nothing to save. Use the panel's paint event instead:
private void panel1_Paint(object sender, PaintEventArgs e) {
using (Pen myPen = new Pen(Color.Black, 5)) {
e.Graphics.Clear(Color.White);
if (bCircle) {
e.Graphics.DrawEllipse(myPen, x, y, 100, 100);
} else if (bSquare) {
e.Graphics.DrawRectangle(myPen, x, y, 100, 100);
}
}
}
To make an update, you just need to invalidate the control:
panel1.Invalidate();
I want to zoom picture box along with graphics.
this will Zoom the only image part not the graphics part.
public Image PictureBoxZoom(Image imgP, Size size)
{
Bitmap bm = new Bitmap(imgP, Convert.ToInt32(imgP.Width * size.Width), Convert.ToInt32(imgP.Height * size.Height));
Graphics grap = Graphics.FromImage(bm);
grap.InterpolationMode = InterpolationMode.HighQualityBicubic;
return bm;
}
private void zoomSlider_Scroll(object sender, EventArgs e)
{
if (zoomSlider.Value > 0 && img != null)
{
pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;
pictureBox1.Image = null;
pictureBox1.Image = PictureBoxZoom(img, new Size(zoomSlider.Value, zoomSlider.Value));
}
}
the source of image is:
img = Image.FromStream(openFileDialog1.OpenFile());
Picture is zooming but when we draw the rectangle outside image then it's not zooming along with image.
See image:
You can do this (rather) easily by scaling the e.Graphics object in the Paint event.. See here for an example!
So to work with you code you probably should add this to the Paint event:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.ScaleTransform(zoom, zoom);
// now do your drawing..
// here just a demo ellipse and a line..
Rectangle rect = panel1.ClientRectangle;
g.DrawEllipse(Pens.Firebrick, rect);
using (Pen pen = new Pen(Color.DarkBlue, 4f)) g.DrawLine(pen, 22, 22, 88, 88);
}
To calculate the zoom factor you need to do a little calculation.
Usually you would not create a zoomed Image but leave that job to the PictureBox with a SizeMode=Zoom.
Then you could write:
float zoom = 1f * pictureBox1.ClientSize.Width / pictureBox1.Image.Width;
To center the image one usually moves the PictureBox inside a Panel. And to allow scrolling one sets the Panel to Autocroll=true;
But since you are creating a zoomed Image you should keep track of the current zoom by some other means.
Note:
But as you use PictureBoxSizeMode.CenterImage maybe your problem is not with the zooming after all?? If your issue really is the placement, not the size of the drawn graphics you need to do a e.Graphics.TranslateTransform to move it to the right spot..
I'm just starting to learn the GDI+ system for drawing lines, circles etc. I've created a component (scanner) that inherits a Panel to draw on (not sure if panel or picture box is best).
On the "Scanner" Im currently drawing a circle on it. the component can be added to a winform and using docking will resize when the winform resizes. At the moment I'm getting the size of the component to calculate the size of the circle but what I want to do is basically say no matter what size the component is the "canvas" is always 300 x 300 wide, so I can say the circle should be positioned at 25,25 with a size of 250x250.
As you might guess from the name "Scanner" I want to plot points on it, but these will be calculated from the center (150,150) location.
Below is the code I have that basically draws the circle.
Many thanks for any help on this.
public partial class Scanner : Panel
{
public Scanner() {
InitializeComponent();
this.DoubleBuffered = true;
}
protected override void OnPaint(PaintEventArgs e) {
Graphics g = e.Graphics;
Draw(g);
base.OnPaint(e);
}
protected override void OnResize(EventArgs e) {
Graphics g = this.CreateGraphics();
Draw(g);
base.OnResize(e);
}
private void Draw(Graphics g) {
g.Clear(Color.Black);
g.PageUnit = GraphicsUnit.Pixel;
Pen green = new Pen(Color.Green);
Font fnt = new Font("Arial", 10);
SolidBrush sb = new SolidBrush(Color.Red);
int pos = (this.Width < this.Height ? this.Width : this.Height) / 2;
int size = (int)(pos * 1.9);
pos -= ((int)size / 2);
g.DrawEllipse(green, pos, pos, size, size);
g.DrawString(this.Width.ToString(), fnt, sb, new Point(0, 0));
}
}
Based on your recent comment, I understand you want to do your drawing on a fixed-size canvas, and plot this canvas inside the control, as large as will fit in the control.
Try the code below:
public class Scanner : Panel
{
private Image _scanner;
public Scanner()
{
this.SetStyle(ControlStyles.ResizeRedraw, true);
CreateScanner();
}
private void CreateScanner()
{
Bitmap scanner = new Bitmap(300, 300);
Graphics g = Graphics.FromImage(scanner);
g.DrawEllipse(Pens.Green, 25, 25, 250, 250);
g.Dispose();
_scanner = scanner;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
int shortestSide = Math.Min(this.Width, this.Height);
if (null != _scanner)
e.Graphics.DrawImage(_scanner, 0, 0, shortestSide, shortestSide);
}
}