So I have a small logo in the lower right corner of a Form that I want to fade in and out at a preset speed, about 6 seconds per fade. I have tried a few different methods but I can never get the picture to fade back in again once the first timer has finished. Here's my code for the the 2 timers and their respective tick methods.
EDIT The declarations for the timers included now.
Timer fade = new Timer();
Timer fade2 = new Timer();
fade.Interval = (200);
fade.Tick += new EventHandler(fade_Tick);
fade2.Interval = (200);
fade2.Tick += new EventHandler(fade_Tick_Two);
fade.Start();
private void fade_Tick(object sender, EventArgs e)
{
if (alpha < 255)
{
image = picboxPic.Image;
using (Graphics g = Graphics.FromImage(image))
{
Pen pen = new Pen(Color.FromArgb(alpha, 255, 255, 255), image.Width);
g.DrawLine(pen, -1, -1, image.Width, image.Height);
g.Save();
}
picboxPic.Image = image;
this.Invalidate();
alpha++;
}
else
{
fade.Stop();
fade2.Start();
}
}
private void fade_Tick_Two(object sender, EventArgs e)
{
if (alpha > 0)
{
image = picboxPic.Image;
using (Graphics g = Graphics.FromImage(image))
{
Pen pen = new Pen(Color.FromArgb(alpha, 255, 255, 255), image.Width);
g.DrawLine(pen, -1, -1, image.Width, image.Height);
g.Save();
}
picboxPic.Image = image;
this.Invalidate();
alpha--;
}
else
{
fade2.Stop();
fade.Start();
}
}
Any ideas as to why the second timer won't start? I've used breakpoints and the alpha level does reach 255 but then it doesn't trigger the second Tick event.
The method described in the link I quoted works for me:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
test();
}
System.Timers.Timer fade = new System.Timers.Timer(50);
System.Timers.Timer fade2 = new System.Timers.Timer(50);
Image originalImage = Image.FromFile(#"D:\kevin\Pictures\odds&Sods\kitchener.jpg");
int alpha = 100;
void test()
{
fade.Elapsed +=new System.Timers.ElapsedEventHandler(fade_Tick);
fade2.Elapsed+=new System.Timers.ElapsedEventHandler(fade_Tick_Two);
fade.Start();
}
delegate void timerDelegate(object sender, EventArgs e);
private void fade_Tick(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.Invoke(new timerDelegate(fade_Tick), sender, e);
return;
}
if (alpha >= 0)
{
picboxPic.Image = SetImgOpacity(originalImage, alphaToOpacity(alpha));
picboxPic.Invalidate();
alpha--;
}
if (alpha < 0)
{
alpha = 0;
fade.Stop();
fade2.Start();
}
}
private void fade_Tick_Two(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.Invoke(new timerDelegate(fade_Tick_Two), sender, e);
return;
}
if (alpha <= 100)
{
picboxPic.Image = SetImgOpacity(originalImage, alphaToOpacity(alpha));
picboxPic.Invalidate();
alpha++;
}
if (alpha > 100)
{
alpha = 100;
fade2.Stop();
fade.Start();
}
}
float alphaToOpacity(int alpha)
{
if (alpha == 0)
return 0.0f;
return (float)alpha / 100.0f;
}
//Setting the opacity of the image
public static Image SetImgOpacity(Image imgPic, float imgOpac)
{
Bitmap bmpPic = new Bitmap(imgPic.Width, imgPic.Height);
Graphics gfxPic = Graphics.FromImage(bmpPic);
ColorMatrix cmxPic = new ColorMatrix();
cmxPic.Matrix33 = imgOpac;
ImageAttributes iaPic = new ImageAttributes();
iaPic.SetColorMatrix(cmxPic, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
gfxPic.DrawImage(imgPic, new Rectangle(0, 0, bmpPic.Width, bmpPic.Height), 0, 0, imgPic.Width, imgPic.Height, GraphicsUnit.Pixel, iaPic);
gfxPic.Dispose();
return bmpPic;
}
}
The code is a bit crude and you will need to take care of the dispose when you close the form, but it fades up and and down and the rest can easily be taken care of - I also made it quicker for testing 'cos life's short :-)
Related
So I have some code that creates a highlight effect on top of a picture box with gdi32.dll and I am wondering if there is a simpler way to do it with System.Drawing.Graphics? Basically with the gdi32.dll, I have to capture a screen shot after drawing, post that to my picturebox and then I am able to draw more stuff and change the color of the pen that I use. If I just try to change the pen thickness and color and draw on the screen again, if changes what I already drew.
Now I have a version of this that uses System.Drawing.Graphics and lots of math with FillPolygon but if I draw over an area I already drew on, it just makes the area I drew on darker. It does not do this with gdi32.dll which justr shades as long as you have not already shaded the area with the mouse. Any suggestions?
public partial class Form9 : Form
{
private bool is_mouse_down { get; set; } // Will check if the mouse is down or not.
private Color Pen_Color = new Color();
private int Pen_Type { get; set; }
private int Thickness { get; set; }
private bool Start { get; set; }
List<Point> Points = new List<Point>();
public Form9()
{
InitializeComponent();
pictureBox1.Dock = DockStyle.Fill;
Pen_Color = Color.Blue;
Pen_Type = 13; // Type = 9 for highlighter, Type = 13 for solid.
Thickness = 2;
Start = false;
pictureBox1.MouseDown += pictureBox1_MouseDown;
pictureBox1.MouseUp += pictureBox1_MouseUp;
pictureBox1.MouseMove += pictureBox1_MouseMove;
pictureBox1.Paint += pictureBox1_OnPaint;
}
private void DrawHighlight(Graphics g, Point[] usePoints, int brushSize, int penType, Color brushColor)
{
int useColor = System.Drawing.ColorTranslator.ToWin32(brushColor);
IntPtr pen = GetImage.GDI32.CreatePen(GetImage.GDI32.PS_SOLID, brushSize, (uint)useColor);
IntPtr hDC = g.GetHdc();
IntPtr xDC = GetImage.GDI32.SelectObject(hDC, pen);
GetImage.GDI32.SetROP2(hDC, penType);//GetImage.GDI32.R2_MASKPEN);
for (int i = 1; i <= usePoints.Length - 1; i++)
{
Point p1 = usePoints[i - 1];
Point p2 = usePoints[i];
GetImage.GDI32.MoveToEx(hDC, p1.X, p1.Y, IntPtr.Zero);
GetImage.GDI32.LineTo(hDC, p2.X, p2.Y);
}
GetImage.GDI32.SetROP2(hDC, GetImage.GDI32.R2_COPYPEN);
GetImage.GDI32.SelectObject(hDC, xDC);
GetImage.GDI32.DeleteObject(pen);
g.ReleaseHdc(hDC);
}
private void pictureBox1_OnPaint(object sender, PaintEventArgs e)
{
if (Start)
{
base.OnPaint(e);
if (is_mouse_down)
{
DrawHighlight(e.Graphics, Points.ToArray(), Thickness, Pen_Type, Pen_Color);
}
}
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
Points.Clear();
Start = true;
is_mouse_down = true;
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
is_mouse_down = false;
using (Image img = CaptureScreen())
{
try
{
if (System.IO.File.Exists(Program.ProgramPath + #"\Temp\marked.bmp"))
{
System.IO.File.Delete(Program.ProgramPath + #"\Temp\marked.bmp");
}
}
catch (Exception Ex)
{
MessageBox.Show("File Delete Error" + Environment.NewLine + Convert.ToString(Ex));
}
try
{
img.Save(Program.ProgramPath + #"\Temp\marked.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
}
catch (Exception Ex)
{
MessageBox.Show("Unable to save Screenshot" + Environment.NewLine + Convert.ToString(Ex));
}
}
if (System.IO.File.Exists(Program.ProgramPath + #"\Temp\marked.bmp"))
{
using (FileStream fs = new System.IO.FileStream(Program.ProgramPath + #"\Temp\marked.bmp", System.IO.FileMode.Open, System.IO.FileAccess.Read, FileShare.Read))
{
pictureBox1.Image = Image.FromStream(fs);
}
}
pictureBox1.Invalidate(); // Refreshes picturebox image.
}
public Image CaptureScreen()
{
GetImage gi = new GetImage();
return gi.CaptureWindow(GetImage.User32.GetDesktopWindow());
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (is_mouse_down == true) // Check to see if the mouse button is down while moving over the form.
{
Points.Add(new Point(e.X, e.Y));
pictureBox1.Invalidate(); // Refreshes picturebox image.
}
}
Here are a couple photos of what I am talking about:
Using System.Drawing.Graphics:
Using gdi32.dll:
UPDATE
After testing some of your code...I got a some strange stuff.
This is a way to draw multiple independent stroke of semi-transparent color without piling up the alpha:
It uses tow lists, one for the strokes and one for the current stroke:
List<List<Point>> strokes = new List<List<Point>>();
List<Point> currentStroke = new List<Point>();
They are filled in the usual way
private void canvas_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button.HasFlag(MouseButtons.Left))
{
currentStroke.Add(e.Location);
if (currentStroke.Count == 1)
currentStroke.Add(new Point(currentStroke[0].X + 1,
currentStroke[0].Y));
canvasInvalidate();
}
}
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button.HasFlag(MouseButtons.Left))
{
currentStroke.Add(e.Location);
canvas.Invalidate();
}
}
private void canvas_MouseUp(object sender, MouseEventArgs e)
{
if (currentStroke.Count > 1)
{
strokes.Add(currentStroke.ToList());
currentStroke.Clear();
}
canvas.Invalidate();
}
In this version we avoid overlay effects of overlapping strokes by drawing all pixels in only one call. All the pixels are painted by creating a GraphicsPath from the strokes and and filling it:
private void canvas_Paint(object sender, PaintEventArgs e)
{
if (strokes.Count > 0 || currentStroke.Count > 0)
{
GraphicsPath gp = new GraphicsPath();
gp.FillMode = FillMode.Winding;
if (currentStroke.Count > 0)
{
gp.AddCurve(currentStroke.ToArray());
gp.CloseFigure();
}
foreach (var stroke in strokes)
{
gp.AddCurve(stroke.ToArray());
gp.CloseFigure();
}
using (SolidBrush b = new SolidBrush(Color.FromArgb(77, 177, 99, 22)))
{
e.Graphics.FillPath(b, gp);
}
}
}
Note that you should take care not to move back onto the current stroke while drawing it or else the croosing path parts will create holes!
A Clear or Save Button are simple, the former Clears the two list and invalidates, the latter would use DrawToBitmap to save the control..
Note: To avoid flicker do make sure the canval Panel is DoubleBuffered!
Update:
Here is another way that uses a Pen to draw the overlay. To avoid the piling up of alpha and changed color values (depending on the PixelFormat) it uses a fast function to modify all set pixels in the overlay to have the same overlay color:
The stroke collection code is the same. The Paint is reduced to calling a function to create an overlay bitmap and drawing it:
private void canvas_Paint(object sender, PaintEventArgs e)
{
using (Bitmap bmp = new Bitmap(canvas.ClientSize.Width,
canvas.ClientSize.Height, PixelFormat.Format32bppPArgb))
{
PaintToBitmap(bmp);
e.Graphics.DrawImage(bmp, 0, 0);
}
The first function does the drawing, pretty much like before, but with simple pen strokes:
private void PaintToBitmap(Bitmap bmp)
{
Color overlayColor = Color.FromArgb(77, 22, 99, 99);
using (Graphics g = Graphics.FromImage(bmp))
using (Pen p = new Pen(overlayColor, 15f))
{
p.MiterLimit = p.Width / 2;
p.EndCap = LineCap.Round;
p.StartCap = LineCap.Round;
p.LineJoin = LineJoin.Round;
g.SmoothingMode = SmoothingMode.AntiAlias;
if (currentStroke.Count > 0)
{
g.DrawCurve(p, currentStroke.ToArray());
}
foreach (var stroke in strokes)
g.DrawCurve(p, stroke.ToArray());
}
SetAlphaOverlay(bmp, overlayColor);
}
It also calls the function that 'flattens' all set pixels to the overlay color:
void SetAlphaOverlay(Bitmap bmp, Color col)
{
Size s = bmp.Size;
PixelFormat fmt = bmp.PixelFormat;
Rectangle rect = new Rectangle(Point.Empty, s);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, fmt);
int size1 = bmpData.Stride * bmpData.Height;
byte[] data = new byte[size1];
System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, data, 0, size1);
for (int y = 0; y < s.Height; y++)
{
for (int x = 0; x < s.Width; x++)
{
int index = y * bmpData.Stride + x * 4;
if (data[index + 0] + data[index + 1] + data[index + 2] > 0)
{
data[index + 0] = col.B;
data[index + 1] = col.G;
data[index + 2] = col.R;
data[index + 3] = col.A;
}
}
}
System.Runtime.InteropServices.Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
bmp.UnlockBits(bmpData);
}
It uses LockBits, so it is pretty fast..
Here it is in action:
Update 2:
Just for the fun of it here is an extension of only a few lines that adds the option of drawing filled curves:
The fill mode is stored in a cheapo hack by having the 1st element twice. These are the changes:
In the MouseDown:
currentStroke.Add(e.Location);
if (cbx_Fill.Checked)
currentStroke.Add(e.Location);
And in the PaintToBitmap:
g.SmoothingMode = SmoothingMode.AntiAlias;
if (currentStroke.Count > 0)
{
if (cbx_Fill.Checked)
g.FillClosedCurve(b, currentStroke.ToArray());
else
g.DrawCurve(p, currentStroke.ToArray());
}
foreach (var stroke in strokes)
if (stroke[0]==stroke[1])
g.FillClosedCurve(b, stroke.ToArray());
else
g.DrawCurve(p, stroke.ToArray());
And one more demo:
I create a code give that allow me to resize a circle and move it
first mouse click give me the center for the circle.
the circle radius will change with the cursor movement (closer to the center smaller radius farther from the center bigger radius).
click second time the radius will not be changed and the circle will be finalized.
This is an image similar to what I want to do:
http://lh6.ggpht.com/_wQH6U92SY04/S_6lAJI7E-I/AAAAAAAAKwE/i-Jkq-nI5Ss/GoogleMapCircle%5B11%5D.gif?imgmax=800
The problems are :
the center is not exactly where I click the mouse first time.
the cursor should be exactly at the circle border when I move it.
the biggest problem is after clicking second time the circle is move farther from the center .
PLEASE HELP
using System;
using System.Drawing;
using System.Windows.Forms;
namespace project
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
Bitmap background;
Graphics scG;
Rectangle rectangleObj;
int clikno = 0;
private Point clickCurrent = Point.Empty;
private Point clickPrev = Point.Empty;
private void Form1_Load(object sender, EventArgs e)
{
background = new Bitmap(this.Width, this.Height);
rectangleObj = new Rectangle(10, 10, 100, 100);
scG = Graphics.FromImage(background);
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
clickCurrent = this.PointToClient(Cursor.Position);
clickPrev = clickCurrent;
rectangleObj.X = e.X;
rectangleObj.Y = e.Y;
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.DrawImage(Draw(), 0, 0);
}
public Bitmap Draw()
{
Graphics scG = Graphics.FromImage(background);
Pen myPen = new Pen(System.Drawing.Color.Red, 3);
scG.Clear(SystemColors.Control);
scG.DrawEllipse(myPen, rectangleObj);
return background;
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
clikno = clikno + 1;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
double oradius = Math.Sqrt((Math.Pow(clickPrev.X - e.X, 2)) + (Math.Pow(clickPrev.Y - e.Y, 2)));
int radius = Convert.ToInt32(oradius);
if (clikno == 1)
{
rectangleObj.Height = radius;
rectangleObj.Width = radius;
rectangleObj.X = clickPrev.X;
rectangleObj.Y = clickPrev.Y;
Refresh();
}
if (clikno == 2)
clikno = 0;
Refresh();
}
}
}
I figured it out
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
namespace Project
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
Bitmap background;
Graphics scG;
Rectangle rectangleObj;
Rectangle center;
int clikno = 0;
private Point clickCurrent = Point.Empty;
private Point clickPrev = Point.Empty;
private void Form1_Load(object sender, EventArgs e)
{
background = new Bitmap(this.Width, this.Height);//, this.Width,this.Height);
rectangleObj = new Rectangle(10, 10, 100, 100);
center = new Rectangle(10, 10, 3, 3);
scG = Graphics.FromImage(background);
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
clickCurrent = this.PointToClient(Cursor.Position);
clickPrev = clickCurrent;
if (clickPrev == Point.Empty) return;
Refresh();
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.DrawImage(Draw(), 0, 0);
}
public Bitmap Draw()
{
Graphics scG = Graphics.FromImage(background);
Pen myPen = new Pen(System.Drawing.Color.Red, 3);
scG.Clear(SystemColors.Control);
scG.DrawEllipse(myPen, rectangleObj);
// scG.DrawRectangle(myPen, rectangleObj);
scG.DrawEllipse(myPen, center);
return background;
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
clikno = clikno + 1;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
double oradius = Math.Sqrt((Math.Pow(clickPrev.X - e.X, 2)) + (Math.Pow(clickPrev.Y - e.Y, 2)));
int radius = Convert.ToInt32(oradius);
if (clikno == 1)
{
rectangleObj.Height = radius;
rectangleObj.Width = radius;
rectangleObj.X = clickPrev.X- rectangleObj.Height /2;// +radius;
rectangleObj.Y = clickPrev.Y - rectangleObj.Width / 2;// +radius;
center.X = clickPrev.X - center.Height / 2;// +radius;
center.Y = clickPrev.Y - center.Width / 2;// +radius;
Refresh();
}
if (clikno == 2)
clikno = 0;
Refresh();
}
string myString = 5.ToString();
}
}
I'd like to draw animation where the airplane crossing form from leftside to the right.
public partial class Form1 : Form
{
Bitmap sky, plane, background;
int currentX, currentY;
Random rndHeight;
Rectangle planeRect;
Graphics g;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
sky = new Bitmap("sky.jpg");
plane = new Bitmap("plane1.png");
int planeWidth = plane.Width; int planeHeight = plane.Height;
}
catch (Exception) { MessageBox.Show("No files!"); }
this.ClientSize = new System.Drawing.Size(sky.Width, sky.Height);
this.FormBorderStyle = FormBorderStyle.FixedSingle;
background = new Bitmap(sky);
g = Graphics.FromImage(background);
rndHeight = new Random();
currentX = -plane.Width; currentY = rndHeight.Next(0, this.Height);
this.BackgroundImage = background;
timer1.Interval = 1;
timer1.Enabled = true;
timer1.Start();
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawImage(sky, 0, 0);
e.Graphics.DrawImage(plane, planeRect);
}
private void timer1_Tick(object sender, EventArgs e)
{
g.DrawImage(sky, 0, 0);
planeRect.X = currentX; planeRect.Y = currentY; planeRect.Width = plane.Width; planeRect.Height = plane.Height;
g.DrawImage(plane, planeRect);
Rectangle myNewPlane = new Rectangle(planeRect.X - 10, planeRect.Y - 10, planeRect.Width + 20, planeRect.Height + 20);
this.Invalidate(myNewPlane);
if (currentX >= this.Width) currentX = -plane.Width; else currentX += 2;
currentY += rndHeight.Next(-2, 2);
}
}
This code works, but the Rectangle of plane flickers with the frequency of timer1.Interval. My question is: how can I avoid these flickers?
p.s.: background image resolution 1024x768; plane - 160x87. plane is transparent
You fix this by setting the DoubleBuffering style for your Form to remove the flicker, e.g.
DoubleBuffered = true;
You probably want to set a few more control styles as well for automatic double-buffering (after InitializeComponents)
this.SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer,true);
More information about automatic and manual double-buffering is on MSDN here
I'm doing a small project where my vc# application needs to include a text scroller / news ticker. Application will be running on 30+ screens showing off internal ad production at my workplace.
I've been googling and testing for a couple of months now but has yet to find / create a good solution where the movement is smooth and not choppy.
So my question is: is it possible to create perfect smooth scroll motion in c# or do I need to go about it some other way?
The code I'm using at the moment, part of a sample I edited, is running almost smooth except it seems to lag every 100 ms or so.
Here is the code I'm using:
namespace ScrollDemo1
{
public partial class NewsTicker : Panel
{
private Timer mScroller;
private int mOffset;
private string mText;
private Size mPixels;
private Bitmap mBuffer;
public NewsTicker()
{
mScroller = new Timer();
mScroller.Interval = 1;
mScroller.Enabled = false;
mScroller.Tick += DoScroll;
}
[Browsable(true)]
public override string Text
{
get { return mText; }
set
{
mText = value;
mScroller.Enabled = mText.Length > 0;
mPixels = TextRenderer.MeasureText(mText, this.Font);
mOffset = this.Width;
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
}
private void DoScroll(object sender, EventArgs e)
{
mOffset -= 1;
if (mOffset < -mPixels.Width) mOffset = this.Width;
Invalidate();
Update();
}
protected override void OnPaint(PaintEventArgs e)
{
if (mBuffer == null || mBuffer.Width != this.Width || mBuffer.Height != this.Height)
mBuffer = new Bitmap(this.Width, this.Height);
Graphics gr = Graphics.FromImage(mBuffer);
Brush bbr = new SolidBrush(this.BackColor);
Brush fbr = new SolidBrush(this.ForeColor);
Bitmap bmp = global::ScrollDemo1.Properties.Resources.text_bg1;
TextureBrush tb = new TextureBrush(bmp);
int iLoc = (this.Height / 2) - (mPixels.Height / 2);
//Console.WriteLine(iLoc.ToString());
//gr.FillRectangle(bbr, new Rectangle(0, 0, this.Width, this.Height));
gr.FillRectangle(tb, new Rectangle(0, 0, this.Width, this.Height));
gr.DrawString(mText, this.Font, fbr, mOffset, iLoc);
e.Graphics.DrawImage(mBuffer, 0, 0);
bbr.Dispose();
fbr.Dispose();
gr.Dispose();
}
}
}
I'd suggest you go with WPF. It has rich and easy to use support for animations and tends to be be very smooth since it is Direct3D based.
So, let me just start out by showing you the code I have now:
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
currentPos = startPos = e.Location;
drawing = true;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
currentPos = e.Location;
//Calculate X Coordinates
if (e.X < startPos.X)
{
CurrentTopLeft.X = e.X;
}
else
{
CurrentTopLeft.X = startPos.X;
}
//Calculate Y Coordinates
if (e.Y < startPos.Y)
{
CurrentTopLeft.Y = e.Y;
}
else
{
CurrentTopLeft.Y = startPos.Y;
}
if (drawing)
this.Invalidate();
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (drawing)
{
this.Hide();
SaveScreen();
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Color col = Color.FromArgb(75, 100, 100, 100);
SolidBrush b = new SolidBrush(col);
if (drawing)
e.Graphics.FillRectangle(b, getRectangle());
}
My SaveScreen function:
private void SaveScreen()
{
ScreenShot.CaptureImage(CurrentTopLeft, Point.Empty, getRectangle());
}
The CaptureImage function:
public static void CaptureImage(Point SourcePoint, Point DestinationPoint, Rectangle SelectionRectangle)
{
string FilePath = "temp.jpg";
using (Bitmap bitmap = new Bitmap(SelectionRectangle.Width, SelectionRectangle.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(SourcePoint, DestinationPoint, SelectionRectangle.Size);
}
bitmap.Save(FilePath, ImageFormat.Jpeg);
}
string Filename = String.Format("{0:yyyy-M-d-HH-mm-ss}", DateTime.Now) + ".jpg";
string Server = "";
System.Net.WebClient Client = new System.Net.WebClient();
Client.Headers.Add("Content-Type", "image/jpeg");
byte[] result = Client.UploadFile(Server + "upload.php?filename=" + Filename + "", "POST", FilePath);
string s = System.Text.Encoding.UTF8.GetString(result, 0, result.Length);
Program.mainForm.Notify(Server + Filename);
File.Delete(FilePath);
}
This is just the basic code I have for drawing a rectangle on the screen. When the rectangle is drawn, it takes an image, works perfectly.
The problem is, that the drawing of the rectangle is not smooth at all. I have enabled doublebuffering and pretty much tried everything, but with no luck.
Also, I would like to grab the current screen, or freeze it, and then be able to draw on that frozen screen, instead of just drawing on top of the active screen if you understand me. How would this be done?
Any help is much appreciated!
Maybe that post will help you:
How to draw directly on the Windows desktop, C#?
You could try something like this:
int width =
Screen.PrimaryScreen.Bounds.Width,
height = Screen.PrimaryScreen.Bounds.Height;
Bitmap screen = default( Bitmap );
try
{
screen = new Bitmap
(
width,
height,
Screen.PrimaryScreen.BitsPerPixel == 32 ?
PixelFormat.Format32bppRgb :
PixelFormat.Format16bppRgb565
);
using (Graphics graphics = Graphics.FromImage(screen))
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.CopyFromScreen
(
new Point() { X = 0, Y = 0 },
new Point() { X = 0, Y = 0 },
new Size() { Width = width, Height = height },
CopyPixelOperation.SourceCopy
);
// Draw over the "capture" with Graphics object
}
}
finally
{
if (screen != null)
{
screen.Dispose();
}
}